tanuki-context 0.4.1 → 0.5.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
@@ -73,6 +73,13 @@ No AI client at all, just curious what it would save you:
73
73
  npx tanuki-context estimate some-big-file.log 0
74
74
  ```
75
75
 
76
+ Price the decision in real dollars — a cache-read token costs ~0.1× a fresh
77
+ one, so `--cached` flips the verdict when the text would ride the prompt cache:
78
+
79
+ ```
80
+ npx tanuki-context estimate some-big-file.log 0 --model claude-opus-4 --cached
81
+ ```
82
+
76
83
  ## Installing it: two ways, same tools
77
84
 
78
85
  **npm (the default).** `npx -y tanuki-context` downloads a 0.98 MB tarball
@@ -122,13 +129,16 @@ Leave it alone when:
122
129
  proxy gate both say so.
123
130
  - **your bill is output-dominated.** tanuki cuts input tokens only. If
124
131
  most of your spend is the model's own output, fix that first.
125
- - **you are not on Anthropic pricing.** Verdicts use Anthropic's
126
- 28-px patch grid. OpenAI and Google price images differently (tiles,
127
- fixed per-image rates), so every verdict needs re-deriving before you
128
- trust it there.
129
- - **the bulk is already prompt-cached.** Cache reads cost a tenth of
130
- fresh input; imaging content that was riding the cache can be a net
131
- loss. The proxy never touches `cache_control` blocks for this reason.
132
+ - **you are not on Anthropic pricing.** Image-token *counts* use Anthropic's
133
+ 28-px patch grid; OpenAI and Google price images differently (tiles, fixed
134
+ per-image rates). Pass `model` to `tanuki_estimate` for a cost verdict with
135
+ that provider's rates — but the count itself is Anthropic-calibrated, and the
136
+ result's `note` says so. Re-derive before trusting dollars there.
137
+ - **the bulk is already prompt-cached.** Cache reads cost a tenth of fresh
138
+ input, so imaging content that was riding the cache is usually a net loss.
139
+ Pass `cached:true` to `tanuki_estimate` and the `cost` verdict computes it —
140
+ it flips to "TEXT cheaper" exactly when the cache makes text the cheaper byte.
141
+ The proxy never touches `cache_control` blocks for the same reason.
132
142
 
133
143
  ## The three ways to run it
134
144
 
package/dist/agent.js CHANGED
@@ -1,19 +1,29 @@
1
- import{createRequire as KQ}from"node:module";var EJ=KQ(import.meta.url);import{existsSync as OZ}from"node:fs";import{fileURLToPath as UZ}from"node:url";function BQ(J){if(J===32||J>=9&&J<=13)return!0;if(J<133)return!1;return J===133||J===160||J===5760||J>=8192&&J<=8202||J===8232||J===8233||J===8239||J===8287||J===12288}function KJ(J){let Q=0;for(let Z=0;Z<J.length;Z++){let $=J.charCodeAt(Z);if($>=55296&&$<=56319&&Z+1<J.length){let V=J.charCodeAt(Z+1);if(V>=56320&&V<=57343)Z++}Q++}return Q}function XQ(J,Q){let Z=0,$=0;while(Z<J.length&&$<Q.length){let V=J.codePointAt(Z),G=Q.codePointAt($);if(V!==G)return V-G;Z+=V>65535?2:1,$+=G>65535?2:1}return J.length-Z-(Q.length-$)}function t(J){let Q=new Map,Z=(X)=>{Q.set(X,(Q.get(X)??0)+1)},$=(X)=>{if(KJ(X)>=12)Z(X);if(X.includes("/")){let q=X.split("/"),D="";for(let M=0;M<q.length;M++){if(M>0)D+="/";if(D+=q[M],M>=2){let R=D+"/";if(KJ(R)>=12)Z(R)}}}},V=-1;for(let X=0;X<J.length;){let q=J.codePointAt(X),D=q>65535?2:1;if(BQ(q)){if(V>=0)$(J.slice(V,X)),V=-1}else if(V<0)V=X;X+=D}if(V>=0)$(J.slice(V));let G=[];for(let[X,q]of Q)if(q>=3){let D=KJ(X);G.push({k:X,c:q,len:D,saved:(D-1)*q})}G.sort((X,q)=>q.saved-X.saved||XQ(X.k,q.k));let Y=[];for(let X of"§¤¢£¥µ¶ª°±¬×÷ØÞßæðøþ¡¿")if(!J.includes(X))Y.push(X);let H=[],z=[];for(let{k:X,c:q,len:D}of G){if(H.length>=Y.length)break;if((D-1)*q<=D+3)continue;let M=!1;for(let P=0;P<z.length;P++){let T=z[P];if(T.startsWith(X)||X.startsWith(T)){M=!0;break}}if(M)continue;let R=Y[H.length];z.push(X),H.push({sig:R,val:X,len:D})}if(H.length===0)return{text:J,entries:0};let K=H.map((X,q)=>q);K.sort((X,q)=>H[q].len-H[X].len);let O=J;for(let X=0;X<K.length;X++){let{sig:q,val:D}=H[K[X]];O=O.replaceAll(D,q)}let B=`
2
- ·legend· `;for(let X=0;X<H.length;X++)B+=H[X].sig+"="+H[X].val+" ";return O+=B.slice(0,-1),{text:O,entries:H.length}}import{Buffer as CJ}from"node:buffer";var OQ=/\x1b\[[0-9;]*[A-Za-z]/g,BJ=/\b([0-9A-Za-z_]*(error|exception)s?|err|warn(ing)?s?|fail(s|ed|ure|ures)?|panic(s|ked)?|fatal|critical|traceback|denied|refused|timeouts?|timed.?out|assert(s|ed|ion|ions)?|segfault(s|ed)?)\b/i,UQ=/[0-9]{4}-[0-9]{2}-[0-9]{2}[T ][0-9]{2}:[0-9]{2}:[0-9]{2}([.,][0-9]+)?(Z|[+-][0-9]{2}:?[0-9]{2})?/g,DQ=/\b[0-9]{2}:[0-9]{2}:[0-9]{2}([.,][0-9]+)?\b/g,qQ=/\b[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}\b/gi,MQ=/\b[0-9a-f]{7,64}\b/gi,FQ=/\b[0-9]+(\.[0-9]+)?[ \t\u00a0]?(ms|us|µs|ns|s|m|h|%|[KMGT]i?B)?\b/gi,WQ=/[0-9a-f]/i,jQ=3,NQ=8,XJ=2,SJ=40;function IQ(J){if(!WQ.test(J))return J;let Q=J.replace(UQ,"<ts>");return Q=Q.replace(DQ,"<time>"),Q=Q.replace(qQ,"<uuid>"),Q=Q.replace(MQ,"<hex>"),Q.replace(FQ,"<n>")}function m(J){if(J===32)return!0;if(J<9)return!1;if(J<=13)return!0;if(J<133)return!1;return J===133||J===160||J===5760||J>=8192&&J<=8202||J===8232||J===8233||J===8239||J===8287||J===12288}function p(J){let Q=0,Z=J.length;while(Q<Z&&m(J.charCodeAt(Q)))Q++;while(Z>Q&&m(J.charCodeAt(Z-1)))Z--;return Q===0&&Z===J.length?J:J.slice(Q,Z)}function RQ(J,Q){let Z=0,$=J.length;while(Z<$&&m(J.charCodeAt(Z)))Z++;while($>Z&&m(J.charCodeAt($-1)))$--;let V=0;for(let G=Z;G<$&&V<Q;V++){let Y=J.charCodeAt(G);G+=Y>=55296&&Y<=56319&&G+1<$?2:1}return V<Q}function PQ(J){let Q=0,Z=J.length;while(Q<Z&&m(J.charCodeAt(Q)))Q++;return J.charCodeAt(Q)===91&&J.charCodeAt(Q+1)===215}function AQ(J){let Q=[],Z=-1,$=!0,V=!1,G=!1,Y=!0;for(let H=0;H<J.length;){let z=J.codePointAt(H),K=z>65535?2:1,O=m(z);if(Y){if(Y=!1,O)Q.push("<v>")}if(O){if(Z>=0)Q.push($?J.slice(Z,H):"<v>"),Z=-1;G=!0}else{if(V=!0,G=!1,Z<0)Z=H,$=!0;if($){let B=z|32;if(B<97||B>122||z>127)$=!1}}H+=K}if(Z>=0)Q.push($?J.slice(Z):"<v>");if(V&&G)Q.push("<v>");return Q.join(" ")}function n(J,Q){let Z=0,$=0,V=J.length;while(Z<V&&$<Q){let G=J.charCodeAt(Z);Z+=G>=55296&&G<=56319&&Z+1<V?2:1,$++}return Z>=V?J:J.slice(0,Z)}var _Q=/[.*+?^${}()|[\]\\]/g;function b(J,Q=null,Z=2){let $=Z,G=J.replace(OQ,"").split(`
3
- `).map((U)=>{let F=U.endsWith("\r")?U.slice(0,-1):U,W=F.lastIndexOf("\r");return W===-1?F:F.slice(W+1)}),Y=G.length,H=Y,z=Array(Y),K=Array(Y),O=0;for(let U=0;U<Y;U++){z[U]=IQ(G[U]);let F=BJ.test(G[U]);if(K[U]=F,F)O++}let B=[],X=[],q=[],D=0,M=0;while(M<Y){let U=0,F=0;for(let W=1;W<=NQ&&M+2*W<=Y;W++){if(K[M+W-1])break;let N=1;J:for(;;){let j=M+N*W;if(j+W>Y)break;for(let _=0;_<W;_++)if(K[j+_]||z[j+_]!==z[M+_])break J;N++}if(N>=jQ&&W*(N-1)>U*(F>0?F-1:0))U=W,F=N}if(U>0){for(let W=M;W<M+U;W++)B.push(G[W]),X.push(K[W]),q.push(z[W]);B.push(U===1?` [×${F} similar]`:` [×${F} similar ${U}-line blocks]`),X.push(!1),q.push(null),D++,M+=U*F}else B.push(G[M]),X.push(K[M]),q.push(z[M]),M++}let R=new Map,P=new Map,T=XJ+1,E=[],A=[],y=0,w=0;for(let U=0;U<B.length;U++){let F=B[U],W=X[U];if(W||PQ(F)||RQ(F,4)){E.push(F),A.push(W);continue}let N=q[U],j=R.get(N);if(j!==void 0){if(j.count++,j.count<=XJ)E.push(F),A.push(!1);else y++;continue}let _=AQ(N);R.set(N,{count:1,exemplar:F});let l=P.get(_);if(l!==void 0)if(l.count++,l.count<=T)E.push(F),A.push(!1);else w++;else P.set(_,{count:1,exemplar:F}),E.push(F),A.push(!1)}let k=[];for(let U of R.values())if(U.count>XJ)k.push([U.count,"exact",U.exemplar]);for(let U of P.values())if(U.count>T)k.push([U.count,"template",U.exemplar]);if(k.sort((U,F)=>F[0]-U[0]),k.length>SJ)k.length=SJ;if(y+w>0){let U=`── ${y+w} repeated lines suppressed (${y} exact ×N, ${w} same-template; first occurrences kept above) ──`;E.push(U),A.push(BJ.test(U));for(let[F,W,N]of k){let _=` ×${F}${W==="template"?" (template)":""} ${n(p(N),160)}`;E.push(_),A.push(BJ.test(_))}}let f;if(Q!=null){let U;try{U=new RegExp(Q,"i")}catch{U=new RegExp(Q.replace(_Q,"\\$&"),"i")}let F=E.length,W=new Uint8Array(F);for(let j=0;j<F;j++)if(A[j]||U.test(E[j])){let _=j>$?j-$:0,l=Math.min(j+$,F-1);W.fill(1,_,l+1)}f=[];let N=0;for(let j=0;j<F;j++)if(W[j]){if(N>0)f.push(`… ${N} lines omitted`),N=0;f.push(E[j])}else N++;if(N>0)f.push(`… ${N} lines omitted`)}else f=E;let PJ=f.join(`
4
- `),AJ=CJ.byteLength(J),_J=CJ.byteLength(PJ),zJ=(1-_J/AJ)*100,YQ=J.length===0?0:zJ<0?-Math.round(-zJ):Math.round(zJ),HQ=k.map(([U,F,W])=>({count:U,exemplar:n(p(W),160),kind:F})),zQ={collapsedRuns:D,importantKept:O,origChars:AJ,origLines:H,outChars:_J,outLines:f.length,query:Q??null,savedPct:YQ,suppressedLines:y,templateSuppressed:w,topRepeats:HQ};return{distilled:PJ,stats:zQ}}var s=[["none","none","passthrough (baseline)"],["whitespace","lossless","trailing whitespace + blank-line runs collapsed; safe for code"],["prose","light","L1 + prose lines: collapse spaces, cut redundant filler phrases (code/IDs protected)"],["dense","medium","L2 + prose: drop articles & intensifiers"],["caveman","heavy","L3 + prose: telegraphic — drop function words; gist only, NOT verbatim"]];var C=(J)=>new RegExp(`(?<![\\p{Alphabetic}\\p{Mark}\\p{Decimal_Number}\\p{Connector_Punctuation}\\p{Join_Control}])(?:${J})(?![\\p{Alphabetic}\\p{Mark}\\p{Decimal_Number}\\p{Connector_Punctuation}\\p{Join_Control}])`,"giu"),OJ=[[C("in order to"),"to"],[C("due to the fact that"),"because"],[C("at this point in time"),"now"],[C("in the event that"),"if"],[C("for the purpose of"),"for"],[C("with regard to"),"about"],[C("a large number of"),"many"],[C("it is important to note that"),""],[C("please note that"),""],[C("as a matter of fact"),""],[C("in terms of"),"for"],[C("the fact that"),"that"]],EQ=new RegExp("(?<![\\p{Alphabetic}\\p{Mark}\\p{Decimal_Number}\\p{Connector_Punctuation}\\p{Join_Control}])(?:the|an|a)[\\t\\n\\x0B\\f\\r \\u0085\\u00A0\\u1680\\u2000-\\u200A\\u2028\\u2029\\u202F\\u205F\\u3000]+","giu"),CQ=new RegExp("(?<![\\p{Alphabetic}\\p{Mark}\\p{Decimal_Number}\\p{Connector_Punctuation}\\p{Join_Control}])(?:very|really|just|actually|basically|simply|quite|rather|essentially|literally)[\\t\\n\\x0B\\f\\r \\u0085\\u00A0\\u1680\\u2000-\\u200A\\u2028\\u2029\\u202F\\u205F\\u3000]+","giu"),SQ=new RegExp("(?<![\\p{Alphabetic}\\p{Mark}\\p{Decimal_Number}\\p{Connector_Punctuation}\\p{Join_Control}])(?:is|are|was|were|am|be|been|being|do|does|did|have|has|had|will|would|shall|should|can|could|may|might|of|to|in|on|at|for|with|that|this|these|those|it|its|there|here)(?![\\p{Alphabetic}\\p{Mark}\\p{Decimal_Number}\\p{Connector_Punctuation}\\p{Join_Control}])[\\t\\n\\x0B\\f\\r \\u0085\\u00A0\\u1680\\u2000-\\u200A\\u2028\\u2029\\u202F\\u205F\\u3000]*","giu"),LJ=/ {2,}/g,LQ=new RegExp("[\\t\\n\\x0B\\f\\r \\u0085\\u00A0\\u1680\\u2000-\\u200A\\u2028\\u2029\\u202F\\u205F\\u3000]+([.,;:!?])","gu"),TQ=/\n{3,}/g;function UJ(J){if(J===32||J>=9&&J<=13)return!0;if(J<133)return!1;return J===133||J===160||J===5760||J>=8192&&J<=8202||J===8232||J===8233||J===8239||J===8287||J===12288}function yQ(J){let Q=0,Z=J.length;while(Q<Z){let $=J.codePointAt(Q);if(!UJ($))break;Q+=$>65535?2:1}while(Z>Q){let $=J.charCodeAt(Z-1);if(!UJ($))break;Z--}return Q===0&&Z===J.length?J:J.slice(Q,Z)}function wQ(J){if(J.length===0)return!1;let Q=J.charCodeAt(0);if(Q===32||Q===9)return!0;let Z=0,$=0,V=0,G=!1;for(let Y=0;Y<J.length;){let H=J.codePointAt(Y);if(Y+=H>65535?2:1,Z++,UJ(H)){V=0;continue}if(V++,V>=24)G=!0;if(H>=48&&H<=57||H>=65&&H<=90||H>=97&&H<=122)continue;switch(H){case 46:case 44:case 59:case 58:case 39:case 34:case 33:case 63:case 40:case 41:case 45:continue}$++}if($/Z>0.3)return!0;return G}function bQ(J,Q){let Z=J.replace(LJ," ");for(let V=0;V<OJ.length;V++)Z=Z.replace(OJ[V][0],OJ[V][1]);if(Q>=3)Z=Z.replace(EQ,""),Z=Z.replace(CQ,"");if(Q>=4)Z=Z.replace(SQ,"");Z=Z.replace(LJ," "),Z=yQ(Z.replace(LQ,"$1"));let $=Z.charCodeAt(0);if($>=97&&$<=122)Z=String.fromCharCode($-32)+Z.slice(1);return Z}function e(J,Q){let Z=Math.min(Q,4);if(Z===0)return{compressed:J,protectedLines:0,level:Z};let $=0,V=J.split(`
5
- `),G=Array(V.length);for(let H=0;H<V.length;H++){let z=V[H],K=z.length;while(K>0){let B=z.charCodeAt(K-1);if(B!==32&&B!==9)break;K--}let O=K===z.length?z:z.slice(0,K);if(Z===1){G[H]=O;continue}if(wQ(O)){$++,G[H]=O;continue}G[H]=bQ(O,Z)}return{compressed:G.join(`
6
- `).replace(TQ,`
1
+ import{createRequire as OQ}from"node:module";var CJ=OQ(import.meta.url);import{existsSync as jZ}from"node:fs";import{fileURLToPath as NZ}from"node:url";function DQ(J){if(J===32||J>=9&&J<=13)return!0;if(J<133)return!1;return J===133||J===160||J===5760||J>=8192&&J<=8202||J===8232||J===8233||J===8239||J===8287||J===12288}function XJ(J){let Q=0;for(let Z=0;Z<J.length;Z++){let $=J.charCodeAt(Z);if($>=55296&&$<=56319&&Z+1<J.length){let G=J.charCodeAt(Z+1);if(G>=56320&&G<=57343)Z++}Q++}return Q}function qQ(J,Q){let Z=0,$=0;while(Z<J.length&&$<Q.length){let G=J.codePointAt(Z),V=Q.codePointAt($);if(G!==V)return G-V;Z+=G>65535?2:1,$+=V>65535?2:1}return J.length-Z-(Q.length-$)}function s(J){let Q=new Map,Z=(B)=>{Q.set(B,(Q.get(B)??0)+1)},$=(B)=>{if(XJ(B)>=12)Z(B);if(B.includes("/")){let q=B.split("/"),M="";for(let U=0;U<q.length;U++){if(U>0)M+="/";if(M+=q[U],U>=2){let P=M+"/";if(XJ(P)>=12)Z(P)}}}},G=-1;for(let B=0;B<J.length;){let q=J.codePointAt(B),M=q>65535?2:1;if(DQ(q)){if(G>=0)$(J.slice(G,B)),G=-1}else if(G<0)G=B;B+=M}if(G>=0)$(J.slice(G));let V=[];for(let[B,q]of Q)if(q>=3){let M=XJ(B);V.push({k:B,c:q,len:M,saved:(M-1)*q})}V.sort((B,q)=>q.saved-B.saved||qQ(B.k,q.k));let Y=[];for(let B of"§¤¢£¥µ¶ª°±¬×÷ØÞßæðøþ¡¿")if(!J.includes(B))Y.push(B);let H=[],K=[];for(let{k:B,c:q,len:M}of V){if(H.length>=Y.length)break;if((M-1)*q<=M+3)continue;let U=!1;for(let R=0;R<K.length;R++){let T=K[R];if(T.startsWith(B)||B.startsWith(T)){U=!0;break}}if(U)continue;let P=Y[H.length];K.push(B),H.push({sig:P,val:B,len:M})}if(H.length===0)return{text:J,entries:0};let z=H.map((B,q)=>q);z.sort((B,q)=>H[q].len-H[B].len);let O=J;for(let B=0;B<z.length;B++){let{sig:q,val:M}=H[z[B]];O=O.replaceAll(M,q)}let X=`
2
+ ·legend· `;for(let B=0;B<H.length;B++)X+=H[B].sig+"="+H[B].val+" ";return O+=X.slice(0,-1),{text:O,entries:H.length}}//! Situation-aware cost model the "codeburn calculation." tanuki's verdict
3
+ //! compares token COUNTS, which equals real cost only when both sides bill at
4
+ //! the same per-token rate. They do not: on Anthropic a cache-read costs ~0.1×
5
+ //! a fresh input token, while image (visual) tokens bill AT the input rate. So
6
+ //! the cheapest technique depends on the SITUATION — is the text already cached
7
+ //! this turn, and which provider prices it. Only the RATIOS drive the verdict;
8
+ //! absolute $/Mtok (list prices, overridable via TANUKI_RATES) drive the
9
+ //! optional dollar figure. Image-token COUNTS here are Anthropic's 28px patch
10
+ //! grid, so the dollars are calibrated for Anthropic; other providers count
11
+ //! image tokens on a different (tile) model — flagged in `note`, never hidden.
12
+ function MQ(J){return J<0?-Math.round(-J):Math.round(J)}function SJ(J){return Math.round(J*1e6)/1e6}var UQ="2026-07",e={opus:{input:15,output:75,cacheReadMult:0.1,imageMult:1,anthropicGrid:!0},sonnet:{input:3,output:15,cacheReadMult:0.1,imageMult:1,anthropicGrid:!0},haiku:{input:1,output:5,cacheReadMult:0.1,imageMult:1,anthropicGrid:!0},gpt:{input:1.25,output:10,cacheReadMult:0.5,imageMult:1,anthropicGrid:!1},gemini:{input:1.25,output:10,cacheReadMult:0.25,imageMult:1,anthropicGrid:!1},default:{input:3,output:15,cacheReadMult:0.1,imageMult:1,anthropicGrid:!0}};function WQ(){let J=process.env.TANUKI_RATES;if(J===void 0||J.length===0)return e;try{let Q=JSON.parse(J),Z={...e};for(let[$,G]of Object.entries(Q))Z[$]={...Z[$]??e.default,...G};return Z}catch{return e}}function FQ(J){let Q=WQ(),Z=(J??"").toLowerCase();for(let $ of["opus","sonnet","haiku","gpt","gemini"])if(Z.includes($)&&Q[$]!==void 0)return{key:$,rate:Q[$]};return{key:"default",rate:Q.default}}function LJ(J,Q,Z){let{key:$,rate:G}=FQ(Z.model),V=Z.cached===!0,Y=G.input/1e6,H=Y*(V?G.cacheReadMult:1),K=Y*G.imageMult,z=J*H,O=Q*K,X=K>0?Math.floor(J*H/K):1/0,B=O<z?"PIPELINE":"TEXT",q=z>0?MQ((1-O/z)*100):0,M;if(!G.anthropicGrid)M=`image-token counts use Anthropic's 28px patch grid; ${$} prices images on a different (tile) model — treat dollars as approximate`;else if(V)M=`text priced at cache-read rate (${G.cacheReadMult}× input); imaging already-cached content usually loses`;return{model:$,cached:V,ratesAsOf:UQ,textUsd:SJ(z),imageUsd:SJ(O),cheaper:B,savedPct:q,breakevenImageTokens:X,note:M}}import{Buffer as TJ}from"node:buffer";var jQ=/\x1b\[[0-9;]*[A-Za-z]/g,BJ=/\b([0-9A-Za-z_]*(error|exception)s?|err|warn(ing)?s?|fail(s|ed|ure|ures)?|panic(s|ked)?|fatal|critical|traceback|denied|refused|timeouts?|timed.?out|assert(s|ed|ion|ions)?|segfault(s|ed)?)\b/i,NQ=/[0-9]{4}-[0-9]{2}-[0-9]{2}[T ][0-9]{2}:[0-9]{2}:[0-9]{2}([.,][0-9]+)?(Z|[+-][0-9]{2}:?[0-9]{2})?/g,IQ=/\b[0-9]{2}:[0-9]{2}:[0-9]{2}([.,][0-9]+)?\b/g,PQ=/\b[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}\b/gi,RQ=/\b[0-9a-f]{7,64}\b/gi,AQ=/\b[0-9]+(\.[0-9]+)?[ \t\u00a0]?(ms|us|µs|ns|s|m|h|%|[KMGT]i?B)?\b/gi,_Q=/[0-9a-f]/i,EQ=3,CQ=8,OJ=2,yJ=40;function SQ(J){if(!_Q.test(J))return J;let Q=J.replace(NQ,"<ts>");return Q=Q.replace(IQ,"<time>"),Q=Q.replace(PQ,"<uuid>"),Q=Q.replace(RQ,"<hex>"),Q.replace(AQ,"<n>")}function m(J){if(J===32)return!0;if(J<9)return!1;if(J<=13)return!0;if(J<133)return!1;return J===133||J===160||J===5760||J>=8192&&J<=8202||J===8232||J===8233||J===8239||J===8287||J===12288}function p(J){let Q=0,Z=J.length;while(Q<Z&&m(J.charCodeAt(Q)))Q++;while(Z>Q&&m(J.charCodeAt(Z-1)))Z--;return Q===0&&Z===J.length?J:J.slice(Q,Z)}function LQ(J,Q){let Z=0,$=J.length;while(Z<$&&m(J.charCodeAt(Z)))Z++;while($>Z&&m(J.charCodeAt($-1)))$--;let G=0;for(let V=Z;V<$&&G<Q;G++){let Y=J.charCodeAt(V);V+=Y>=55296&&Y<=56319&&V+1<$?2:1}return G<Q}function TQ(J){let Q=0,Z=J.length;while(Q<Z&&m(J.charCodeAt(Q)))Q++;return J.charCodeAt(Q)===91&&J.charCodeAt(Q+1)===215}function yQ(J){let Q=[],Z=-1,$=!0,G=!1,V=!1,Y=!0;for(let H=0;H<J.length;){let K=J.codePointAt(H),z=K>65535?2:1,O=m(K);if(Y){if(Y=!1,O)Q.push("<v>")}if(O){if(Z>=0)Q.push($?J.slice(Z,H):"<v>"),Z=-1;V=!0}else{if(G=!0,V=!1,Z<0)Z=H,$=!0;if($){let X=K|32;if(X<97||X>122||K>127)$=!1}}H+=z}if(Z>=0)Q.push($?J.slice(Z):"<v>");if(G&&V)Q.push("<v>");return Q.join(" ")}function n(J,Q){let Z=0,$=0,G=J.length;while(Z<G&&$<Q){let V=J.charCodeAt(Z);Z+=V>=55296&&V<=56319&&Z+1<G?2:1,$++}return Z>=G?J:J.slice(0,Z)}var wQ=/[.*+?^${}()|[\]\\]/g;function b(J,Q=null,Z=2){let $=Z,V=J.replace(jQ,"").split(`
13
+ `).map((D)=>{let W=D.endsWith("\r")?D.slice(0,-1):D,F=W.lastIndexOf("\r");return F===-1?W:W.slice(F+1)}),Y=V.length,H=Y,K=Array(Y),z=Array(Y),O=0;for(let D=0;D<Y;D++){K[D]=SQ(V[D]);let W=BJ.test(V[D]);if(z[D]=W,W)O++}let X=[],B=[],q=[],M=0,U=0;while(U<Y){let D=0,W=0;for(let F=1;F<=CQ&&U+2*F<=Y;F++){if(z[U+F-1])break;let N=1;J:for(;;){let j=U+N*F;if(j+F>Y)break;for(let _=0;_<F;_++)if(z[j+_]||K[j+_]!==K[U+_])break J;N++}if(N>=EQ&&F*(N-1)>D*(W>0?W-1:0))D=F,W=N}if(D>0){for(let F=U;F<U+D;F++)X.push(V[F]),B.push(z[F]),q.push(K[F]);X.push(D===1?` [×${W} similar]`:` [×${W} similar ${D}-line blocks]`),B.push(!1),q.push(null),M++,U+=D*W}else X.push(V[U]),B.push(z[U]),q.push(K[U]),U++}let P=new Map,R=new Map,T=OJ+1,E=[],A=[],y=0,w=0;for(let D=0;D<X.length;D++){let W=X[D],F=B[D];if(F||TQ(W)||LQ(W,4)){E.push(W),A.push(F);continue}let N=q[D],j=P.get(N);if(j!==void 0){if(j.count++,j.count<=OJ)E.push(W),A.push(!1);else y++;continue}let _=yQ(N);P.set(N,{count:1,exemplar:W});let l=R.get(_);if(l!==void 0)if(l.count++,l.count<=T)E.push(W),A.push(!1);else w++;else R.set(_,{count:1,exemplar:W}),E.push(W),A.push(!1)}let x=[];for(let D of P.values())if(D.count>OJ)x.push([D.count,"exact",D.exemplar]);for(let D of R.values())if(D.count>T)x.push([D.count,"template",D.exemplar]);if(x.sort((D,W)=>W[0]-D[0]),x.length>yJ)x.length=yJ;if(y+w>0){let D=`── ${y+w} repeated lines suppressed (${y} exact ×N, ${w} same-template; first occurrences kept above) ──`;E.push(D),A.push(BJ.test(D));for(let[W,F,N]of x){let _=` ×${W}${F==="template"?" (template)":""} ${n(p(N),160)}`;E.push(_),A.push(BJ.test(_))}}let k;if(Q!=null){let D;try{D=new RegExp(Q,"i")}catch{D=new RegExp(Q.replace(wQ,"\\$&"),"i")}let W=E.length,F=new Uint8Array(W);for(let j=0;j<W;j++)if(A[j]||D.test(E[j])){let _=j>$?j-$:0,l=Math.min(j+$,W-1);F.fill(1,_,l+1)}k=[];let N=0;for(let j=0;j<W;j++)if(F[j]){if(N>0)k.push(`… ${N} lines omitted`),N=0;k.push(E[j])}else N++;if(N>0)k.push(`… ${N} lines omitted`)}else k=E;let AJ=k.join(`
14
+ `),_J=TJ.byteLength(J),EJ=TJ.byteLength(AJ),zJ=(1-EJ/_J)*100,zQ=J.length===0?0:zJ<0?-Math.round(-zJ):Math.round(zJ),XQ=x.map(([D,W,F])=>({count:D,exemplar:n(p(F),160),kind:W})),BQ={collapsedRuns:M,importantKept:O,origChars:_J,origLines:H,outChars:EJ,outLines:k.length,query:Q??null,savedPct:zQ,suppressedLines:y,templateSuppressed:w,topRepeats:XQ};return{distilled:AJ,stats:BQ}}var JJ=[["none","none","passthrough (baseline)"],["whitespace","lossless","trailing whitespace + blank-line runs collapsed; safe for code"],["prose","light","L1 + prose lines: collapse spaces, cut redundant filler phrases (code/IDs protected)"],["dense","medium","L2 + prose: drop articles & intensifiers"],["caveman","heavy","L3 + prose: telegraphic — drop function words; gist only, NOT verbatim"]];var C=(J)=>new RegExp(`(?<![\\p{Alphabetic}\\p{Mark}\\p{Decimal_Number}\\p{Connector_Punctuation}\\p{Join_Control}])(?:${J})(?![\\p{Alphabetic}\\p{Mark}\\p{Decimal_Number}\\p{Connector_Punctuation}\\p{Join_Control}])`,"giu"),DJ=[[C("in order to"),"to"],[C("due to the fact that"),"because"],[C("at this point in time"),"now"],[C("in the event that"),"if"],[C("for the purpose of"),"for"],[C("with regard to"),"about"],[C("a large number of"),"many"],[C("it is important to note that"),""],[C("please note that"),""],[C("as a matter of fact"),""],[C("in terms of"),"for"],[C("the fact that"),"that"]],bQ=new RegExp("(?<![\\p{Alphabetic}\\p{Mark}\\p{Decimal_Number}\\p{Connector_Punctuation}\\p{Join_Control}])(?:the|an|a)[\\t\\n\\x0B\\f\\r \\u0085\\u00A0\\u1680\\u2000-\\u200A\\u2028\\u2029\\u202F\\u205F\\u3000]+","giu"),vQ=new RegExp("(?<![\\p{Alphabetic}\\p{Mark}\\p{Decimal_Number}\\p{Connector_Punctuation}\\p{Join_Control}])(?:very|really|just|actually|basically|simply|quite|rather|essentially|literally)[\\t\\n\\x0B\\f\\r \\u0085\\u00A0\\u1680\\u2000-\\u200A\\u2028\\u2029\\u202F\\u205F\\u3000]+","giu"),fQ=new RegExp("(?<![\\p{Alphabetic}\\p{Mark}\\p{Decimal_Number}\\p{Connector_Punctuation}\\p{Join_Control}])(?:is|are|was|were|am|be|been|being|do|does|did|have|has|had|will|would|shall|should|can|could|may|might|of|to|in|on|at|for|with|that|this|these|those|it|its|there|here)(?![\\p{Alphabetic}\\p{Mark}\\p{Decimal_Number}\\p{Connector_Punctuation}\\p{Join_Control}])[\\t\\n\\x0B\\f\\r \\u0085\\u00A0\\u1680\\u2000-\\u200A\\u2028\\u2029\\u202F\\u205F\\u3000]*","giu"),wJ=/ {2,}/g,xQ=new RegExp("[\\t\\n\\x0B\\f\\r \\u0085\\u00A0\\u1680\\u2000-\\u200A\\u2028\\u2029\\u202F\\u205F\\u3000]+([.,;:!?])","gu"),kQ=/\n{3,}/g;function qJ(J){if(J===32||J>=9&&J<=13)return!0;if(J<133)return!1;return J===133||J===160||J===5760||J>=8192&&J<=8202||J===8232||J===8233||J===8239||J===8287||J===12288}function hQ(J){let Q=0,Z=J.length;while(Q<Z){let $=J.codePointAt(Q);if(!qJ($))break;Q+=$>65535?2:1}while(Z>Q){let $=J.charCodeAt(Z-1);if(!qJ($))break;Z--}return Q===0&&Z===J.length?J:J.slice(Q,Z)}function mQ(J){if(J.length===0)return!1;let Q=J.charCodeAt(0);if(Q===32||Q===9)return!0;let Z=0,$=0,G=0,V=!1;for(let Y=0;Y<J.length;){let H=J.codePointAt(Y);if(Y+=H>65535?2:1,Z++,qJ(H)){G=0;continue}if(G++,G>=24)V=!0;if(H>=48&&H<=57||H>=65&&H<=90||H>=97&&H<=122)continue;switch(H){case 46:case 44:case 59:case 58:case 39:case 34:case 33:case 63:case 40:case 41:case 45:continue}$++}if($/Z>0.3)return!0;return V}function uQ(J,Q){let Z=J.replace(wJ," ");for(let G=0;G<DJ.length;G++)Z=Z.replace(DJ[G][0],DJ[G][1]);if(Q>=3)Z=Z.replace(bQ,""),Z=Z.replace(vQ,"");if(Q>=4)Z=Z.replace(fQ,"");Z=Z.replace(wJ," "),Z=hQ(Z.replace(xQ,"$1"));let $=Z.charCodeAt(0);if($>=97&&$<=122)Z=String.fromCharCode($-32)+Z.slice(1);return Z}function QJ(J,Q){let Z=Math.min(Q,4);if(Z===0)return{compressed:J,protectedLines:0,level:Z};let $=0,G=J.split(`
15
+ `),V=Array(G.length);for(let H=0;H<G.length;H++){let K=G[H],z=K.length;while(z>0){let X=K.charCodeAt(z-1);if(X!==32&&X!==9)break;z--}let O=z===K.length?K:K.slice(0,z);if(Z===1){V[H]=O;continue}if(mQ(O)){$++,V[H]=O;continue}V[H]=uQ(O,Z)}return{compressed:V.join(`
16
+ `).replace(kQ,`
7
17
 
8
- `),protectedLines:$,level:Z}}import{readFileSync as qJ}from"node:fs";import{inflateSync as vQ}from"node:zlib";//! Full-BMP glyph atlas (Spleen 5x8 for ASCII/code + Unifont fallback),
18
+ `),protectedLines:$,level:Z}}import{readFileSync as UJ}from"node:fs";import{inflateSync as gQ}from"node:zlib";//! Full-BMP glyph atlas (Spleen 5x8 for ASCII/code + Unifont fallback),
9
19
  //! extracted from pxpipe's generated gray atlas by `tools/gen-glyphs.mjs`.
10
20
  //!
11
21
  //! Codepoints + wide flags load eagerly (~175 KB, needed for wrap math);
12
22
  //! coverage pixels stay zlib-packed on disk and decompress lazily on the
13
23
  //! first blit, so `estimate` never pays for them.
14
- var v=5,c=8,h=qJ(new URL("../assets/glyphs.cps",import.meta.url)),JJ=qJ(new URL("../assets/glyphs.wide",import.meta.url)),TJ=(()=>{let J=h.byteLength>>>2;if((h.byteOffset&3)===0)return new Uint32Array(h.buffer,h.byteOffset,J);return new Uint32Array(h.buffer.slice(h.byteOffset,h.byteOffset+(J<<2)))})(),xQ=(()=>{let J=new Uint32Array(JJ.length),Q=0;for(let Z=0;Z<JJ.length;Z++)J[Z]=Q,Q+=(JJ[Z]===1?2*v:v)*c;return J})(),DJ=null;function o(J){let Q=0,Z=TJ.length-1;while(Q<=Z){let $=Q+Z>>>1,V=TJ[$];if(V<J)Q=$+1;else if(V>J)Z=$-1;else return $}return-1}function u(J){return JJ[J]===1}function MJ(J){if(DJ===null)DJ=vQ(qJ(new URL("../assets/glyphs.pix.z",import.meta.url)));let Q=xQ[J],Z=u(J)?2*v:v;return DJ.subarray(Q,Q+Z*c)}function yJ(J,Q,Z){let $=MJ(J),V=u(J)?2*v:v;return kQ($,V,c,Q,Z)}function kQ(J,Q,Z,$,V){let G=new Uint8Array($*V),Y=Q/$,H=Z/V;for(let z=0;z<V;z++){let K=z*H,O=(z+1)*H;for(let B=0;B<$;B++){let X=B*Y,q=(B+1)*Y,D=0,M=0,R=Math.min(Math.ceil(O),Z);for(let P=Math.floor(K);P<R;P++){let T=Math.min(P+1,O)-Math.max(P,K);if(T<=0)continue;let E=Math.min(Math.ceil(q),Q);for(let A=Math.floor(X);A<E;A++){let y=Math.min(A+1,q)-Math.max(A,X);if(y<=0)continue;let w=y*T;D+=w*J[P*Q+A],M+=w}}G[z*$+B]=M>0?Math.min(255,Math.max(0,Math.round(D/M))):0}}return G}import{deflateSync as fQ}from"node:zlib";//! Minimal grayscale PNG encoder (bit depth 8, color type 0), mirroring
24
+ var v=5,c=8,h=UJ(new URL("../assets/glyphs.cps",import.meta.url)),ZJ=UJ(new URL("../assets/glyphs.wide",import.meta.url)),bJ=(()=>{let J=h.byteLength>>>2;if((h.byteOffset&3)===0)return new Uint32Array(h.buffer,h.byteOffset,J);return new Uint32Array(h.buffer.slice(h.byteOffset,h.byteOffset+(J<<2)))})(),dQ=(()=>{let J=new Uint32Array(ZJ.length),Q=0;for(let Z=0;Z<ZJ.length;Z++)J[Z]=Q,Q+=(ZJ[Z]===1?2*v:v)*c;return J})(),MJ=null;function o(J){let Q=0,Z=bJ.length-1;while(Q<=Z){let $=Q+Z>>>1,G=bJ[$];if(G<J)Q=$+1;else if(G>J)Z=$-1;else return $}return-1}function u(J){return ZJ[J]===1}function WJ(J){if(MJ===null)MJ=gQ(UJ(new URL("../assets/glyphs.pix.z",import.meta.url)));let Q=dQ[J],Z=u(J)?2*v:v;return MJ.subarray(Q,Q+Z*c)}function vJ(J,Q,Z){let $=WJ(J),G=u(J)?2*v:v;return lQ($,G,c,Q,Z)}function lQ(J,Q,Z,$,G){let V=new Uint8Array($*G),Y=Q/$,H=Z/G;for(let K=0;K<G;K++){let z=K*H,O=(K+1)*H;for(let X=0;X<$;X++){let B=X*Y,q=(X+1)*Y,M=0,U=0,P=Math.min(Math.ceil(O),Z);for(let R=Math.floor(z);R<P;R++){let T=Math.min(R+1,O)-Math.max(R,z);if(T<=0)continue;let E=Math.min(Math.ceil(q),Q);for(let A=Math.floor(B);A<E;A++){let y=Math.min(A+1,q)-Math.max(A,B);if(y<=0)continue;let w=y*T;M+=w*J[R*Q+A],U+=w}}V[K*$+X]=U>0?Math.min(255,Math.max(0,Math.round(M/U))):0}}return V}import{deflateSync as pQ}from"node:zlib";//! Minimal grayscale PNG encoder (bit depth 8, color type 0), mirroring
15
25
  //! pxpipe's png.ts: IHDR + one IDAT (zlib) + IEND, filter byte 0 per row.
16
- var hQ=(()=>{let J=new Uint32Array(256);for(let Q=0;Q<256;Q++){let Z=Q;for(let $=0;$<8;$++)Z=(Z&1)!==0?3988292384^Z>>>1:Z>>>1;J[Q]=Z>>>0}return J})();function FJ(J,Q,Z,$){let V=$.length;J[Q]=V>>>24&255,J[Q+1]=V>>>16&255,J[Q+2]=V>>>8&255,J[Q+3]=V&255;let G=Q+4;for(let z=0;z<4;z++)J[G+z]=Z.charCodeAt(z);J.set($,G+4);let Y=4294967295;for(let z=G;z<G+4+V;z++)Y=hQ[(Y^J[z])&255]^Y>>>8;Y=~Y>>>0;let H=G+4+V;return J[H]=Y>>>24&255,J[H+1]=Y>>>16&255,J[H+2]=Y>>>8&255,J[H+3]=Y&255,H+4}function wJ(J,Q,Z){let $=new Uint8Array(Z*(Q+1));for(let z=0,K=0,O=0;z<Z;z++)$[K++]=0,$.set(J.subarray(O,O+Q),K),K+=Q,O+=Q;let V=fQ($,{level:6}),G=new Uint8Array(33+(12+V.length)+12);G[0]=137,G[1]=80,G[2]=78,G[3]=71,G[4]=13,G[5]=10,G[6]=26,G[7]=10;let Y=new Uint8Array(13);Y[0]=Q>>>24&255,Y[1]=Q>>>16&255,Y[2]=Q>>>8&255,Y[3]=Q&255,Y[4]=Z>>>24&255,Y[5]=Z>>>16&255,Y[6]=Z>>>8&255,Y[7]=Z&255,Y[8]=8,Y[9]=0;let H=FJ(G,8,"IHDR",Y);return H=FJ(G,H,"IDAT",V),FJ(G,H,"IEND",new Uint8Array(0)),G}//! Stage 2: the `pxpipe` imaging engine, ported from pxpipe's render.ts
26
+ var nQ=(()=>{let J=new Uint32Array(256);for(let Q=0;Q<256;Q++){let Z=Q;for(let $=0;$<8;$++)Z=(Z&1)!==0?3988292384^Z>>>1:Z>>>1;J[Q]=Z>>>0}return J})();function FJ(J,Q,Z,$){let G=$.length;J[Q]=G>>>24&255,J[Q+1]=G>>>16&255,J[Q+2]=G>>>8&255,J[Q+3]=G&255;let V=Q+4;for(let K=0;K<4;K++)J[V+K]=Z.charCodeAt(K);J.set($,V+4);let Y=4294967295;for(let K=V;K<V+4+G;K++)Y=nQ[(Y^J[K])&255]^Y>>>8;Y=~Y>>>0;let H=V+4+G;return J[H]=Y>>>24&255,J[H+1]=Y>>>16&255,J[H+2]=Y>>>8&255,J[H+3]=Y&255,H+4}function fJ(J,Q,Z){let $=new Uint8Array(Z*(Q+1));for(let K=0,z=0,O=0;K<Z;K++)$[z++]=0,$.set(J.subarray(O,O+Q),z),z+=Q,O+=Q;let G=pQ($,{level:6}),V=new Uint8Array(33+(12+G.length)+12);V[0]=137,V[1]=80,V[2]=78,V[3]=71,V[4]=13,V[5]=10,V[6]=26,V[7]=10;let Y=new Uint8Array(13);Y[0]=Q>>>24&255,Y[1]=Q>>>16&255,Y[2]=Q>>>8&255,Y[3]=Q&255,Y[4]=Z>>>24&255,Y[5]=Z>>>16&255,Y[6]=Z>>>8&255,Y[7]=Z&255,Y[8]=8,Y[9]=0;let H=FJ(V,8,"IHDR",Y);return H=FJ(V,H,"IDAT",G),FJ(V,H,"IEND",new Uint8Array(0)),V}//! Stage 2: the `pxpipe` imaging engine, ported from pxpipe's render.ts
17
27
  //! production dense path (bare 5x8 AA cell, 312 cols, 1568x728 pages).
18
28
  //! Glyphs cover BMP (pxpipe's atlas: Spleen for ASCII/code, Unifont fallback)
19
29
  //! PLUS the astral planes (unifont_upper, incl. emoji) — beyond pxpipe, which
@@ -28,19 +38,19 @@ var hQ=(()=>{let J=new Uint32Array(256);for(let Q=0;Q<256;Q++){let Z=Q;for(let $
28
38
  //! * `font` — `Tiny` renders the same atlas box-filtered into a 4x6 cell
29
39
  //! (390 cols x 120 rows/page), ~40% fewer image-tokens; opt-in,
30
40
  //! transcription-accuracy gated.
31
- var i=4,QJ=4,mQ=1568,uQ=728,ZJ="↵",gQ="⏎",$J="→",dQ="⇢",WJ="⇥",lQ="⇨",pQ=9647,bJ=4,nQ=3,vJ="0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz",cQ=/\n{4,}/g;function g(J){return J.length===4&&J.replace(/[A-Z]/g,(Q)=>Q.toLowerCase())==="tiny"?"tiny":"normal"}function hJ(J){let Q=J==="tiny"?4:v,Z=J==="tiny"?6:c,$=Math.floor((mQ-2*i)/Q),V=Math.floor((uQ-2*QJ)/Z);return{cw:Q,ch:Z,cols:$,maxLines:V,maxChars:$*V}}var oQ=(()=>{let J=new Uint8Array(128);for(let Q=0;Q<128;Q++){let Z=o(Q);J[Q]=Z>=0&&u(Z)?2:1}return J})();function jJ(J){if(J<128)return oQ[J];let Q=o(J);return Q>=0&&u(Q)?2:1}function iQ(J){let Q=0;for(let Z=0;Z<J.length;Z++){let $=J.charCodeAt(Z);if($>=55296&&$<56320&&Z+1<J.length){let V=J.charCodeAt(Z+1);if(V>=56320&&V<57344)Z++}Q++}return Q}function NJ(J){let Q=J.split(`
32
- `);for(let Z=0;Z<Q.length;Z++){let $=Q[Z],V=$.length;while(V>0){let G=$.charCodeAt(V-1);if(G!==32&&G!==9)break;V--}if(V!==$.length)Q[Z]=$.slice(0,V)}return Q.join(`
33
- `).replace(cQ,`
41
+ var i=4,$J=4,cQ=1568,oQ=728,GJ="↵",iQ="⏎",VJ="→",rQ="⇢",jJ="⇥",aQ="⇨",tQ=9647,xJ=4,sQ=3,kJ="0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz",eQ=/\n{4,}/g;function g(J){return J.length===4&&J.replace(/[A-Z]/g,(Q)=>Q.toLowerCase())==="tiny"?"tiny":"normal"}function gJ(J){let Q=J==="tiny"?4:v,Z=J==="tiny"?6:c,$=Math.floor((cQ-2*i)/Q),G=Math.floor((oQ-2*$J)/Z);return{cw:Q,ch:Z,cols:$,maxLines:G,maxChars:$*G}}var JZ=(()=>{let J=new Uint8Array(128);for(let Q=0;Q<128;Q++){let Z=o(Q);J[Q]=Z>=0&&u(Z)?2:1}return J})();function NJ(J){if(J<128)return JZ[J];let Q=o(J);return Q>=0&&u(Q)?2:1}function QZ(J){let Q=0;for(let Z=0;Z<J.length;Z++){let $=J.charCodeAt(Z);if($>=55296&&$<56320&&Z+1<J.length){let G=J.charCodeAt(Z+1);if(G>=56320&&G<57344)Z++}Q++}return Q}function IJ(J){let Q=J.split(`
42
+ `);for(let Z=0;Z<Q.length;Z++){let $=Q[Z],G=$.length;while(G>0){let V=$.charCodeAt(G-1);if(V!==32&&V!==9)break;G--}if(G!==$.length)Q[Z]=$.slice(0,G)}return Q.join(`
43
+ `).replace(eQ,`
34
44
 
35
45
 
36
- `)}function mJ(J){if(!J.includes("\t"))return J;let Q="",Z=0;for(let $ of J)if($==="\t"){let V=bJ-Z%bJ;Q+=$J;for(let G=1;G<V;G++)Q+=" ";Z+=V}else Q+=$,Z+=jJ($.codePointAt(0));return Q}function aQ(J){let Q=J.includes("\t")?J.replaceAll("\t",$J):J,Z=0;while(Z<Q.length&&Q.charCodeAt(Z)===32)Z++;if(Z>=nQ&&Z<vJ.length)return WJ+vJ[Z]+Q.slice(Z);return Q}function uJ(J){return J.includes(ZJ)?J.replaceAll(ZJ,gQ):J}function rQ(J){let Q=uJ(J);if(Q.includes($J))Q=Q.replaceAll($J,dQ);if(Q.includes(WJ))Q=Q.replaceAll(WJ,lQ);return Q}function tQ(J){let Q=NJ(J).split(`
37
- `);for(let Z=0;Z<Q.length;Z++)Q[Z]=mJ(Q[Z]);return Q.join(ZJ)}function sQ(J){let Q=NJ(J).split(`
38
- `);for(let Z=0;Z<Q.length;Z++)Q[Z]=aQ(Q[Z]);return Q.join(ZJ)}function eQ(J,Q){let Z=[],$=NJ(J);for(let V of $.split(`
39
- `)){let G=mJ(V);if(G.length===0){Z.push("");continue}let Y="",H=0;for(let z of G){let K=jJ(z.codePointAt(0));if(H+K>Q)Z.push(Y),Y=z,H=K;else Y+=z,H+=K}if(Y.length!==0)Z.push(Y)}return Z}function JZ(J,Q,Z){let $=[],V=[],G=0;for(let Y of J){let H=iQ(Y),z=H+(V.length!==0?1:0);if(V.length!==0&&(V.length>=Q||G+z>Z))$.push(V),V=[],G=0;G+=H+(V.length!==0?1:0),V.push(Y)}if(V.length!==0)$.push(V);return $}function gJ(J){if(J<32)return!0;if(J>=127&&J<=159)return!0;if(J>=768&&J<=879)return!0;if(J===8203||J===8204||J===8205||J===8288||J===65279)return!0;if(J>=65024&&J<=65039)return!0;if(J>=917760&&J<=917999)return!0;return!1}function QZ(J){let Q=null,Z=0;for(let $ of J){let V=$.codePointAt(0);if(o(V)<0&&!gJ(V)){if(Q===null)Q=J.slice(0,Z);Q+=`[U+${V.toString(16).toUpperCase()}]`}else if(Q!==null)Q+=$;Z+=$.length}return Q??J}function dJ(J,Q,Z,$){let V=Q?Z?sQ(rQ(J)):tQ(uJ(J)):J;return JZ(eQ(QZ(V),$.cols),$.maxLines,$.maxChars)}function lJ(J,Q,Z){if(!Z)return 2*i+Q.cols*Q.cw;let $=0;for(let Y of J){let H=0;for(let z of Y)H+=jJ(z.codePointAt(0));if(H>Q.cols)H=Q.cols;if(H>$)$=H}let V=2*i+$*Q.cw,G=2*i+Q.cw;return V>G?V:G}var xJ=new Map;function kJ(J,Q,Z,$,V,G,Y){let H=o(V);if(H<0)return 0;let z=u(H),K=z?2*G.cw:G.cw,O;if(Y==="normal")O=MJ(H);else{let B=xJ.get(H);if(B===void 0)B=yJ(H,K,G.ch),xJ.set(H,B);O=B}for(let B=0;B<G.ch;B++){let X=($+B)*Q+Z,q=B*K;for(let D=0;D<K;D++){let M=O[q+D];if(M>0){let R=X+D;if(M>J[R])J[R]=M}}}return z?2:1}function ZZ(J,Q,Z,$){let V=lJ(J,Q,Z),G=2*QJ+J.length*Q.ch,Y=new Uint8Array(V*G),H=0;for(let z=0;z<J.length;z++){let K=QJ+z*Q.ch,O=0;for(let B of J[z]){if(O>=Q.cols)break;let X=i+O*Q.cw,q=kJ(Y,V,X,K,B.codePointAt(0),Q,$);if(q===0){if(q=1,gJ(B.codePointAt(0)));else if(H++,B!==" ")kJ(Y,V,X,K,pQ,Q,$)}O+=q}}for(let z=0;z<Y.length;z++)Y[z]=255-Y[z];return{png:wJ(Y,V,G),width:V,height:G,dropped:H}}function VJ(J,Q,Z,$){let V=hJ($),G=dJ(J,Q,Z,V).map((K)=>ZZ(K,V,Z,$)),Y=0,H=0,z=0;for(let K of G)Y+=K.width*K.height,H+=pJ(K.width,K.height),z+=K.dropped;return{pages:G,pixels:Y,tokens:H,dropped:z}}function GJ(J,Q,Z,$){let V=hJ($),G=dJ(J,Q,Z,V),Y=0,H=0;for(let z of G){let K=lJ(z,V,Z),O=2*QJ+z.length*V.ch;Y+=K*O,H+=pJ(K,O)}return{pages:G.length,pixels:Y,tokens:H}}var fJ=28;function pJ(J,Q){return Math.ceil(J/fJ)*Math.ceil(Q/fJ)}import{readFileSync as $Z}from"node:fs";import{join as VZ}from"node:path";//! pxpipe measurement-log summary (~/.pxpipe/events.jsonl), same math as the
46
+ `)}function dJ(J){if(!J.includes("\t"))return J;let Q="",Z=0;for(let $ of J)if($==="\t"){let G=xJ-Z%xJ;Q+=VJ;for(let V=1;V<G;V++)Q+=" ";Z+=G}else Q+=$,Z+=NJ($.codePointAt(0));return Q}function ZZ(J){let Q=J.includes("\t")?J.replaceAll("\t",VJ):J,Z=0;while(Z<Q.length&&Q.charCodeAt(Z)===32)Z++;if(Z>=sQ&&Z<kJ.length)return jJ+kJ[Z]+Q.slice(Z);return Q}function lJ(J){return J.includes(GJ)?J.replaceAll(GJ,iQ):J}function $Z(J){let Q=lJ(J);if(Q.includes(VJ))Q=Q.replaceAll(VJ,rQ);if(Q.includes(jJ))Q=Q.replaceAll(jJ,aQ);return Q}function GZ(J){let Q=IJ(J).split(`
47
+ `);for(let Z=0;Z<Q.length;Z++)Q[Z]=dJ(Q[Z]);return Q.join(GJ)}function VZ(J){let Q=IJ(J).split(`
48
+ `);for(let Z=0;Z<Q.length;Z++)Q[Z]=ZZ(Q[Z]);return Q.join(GJ)}function YZ(J,Q){let Z=[],$=IJ(J);for(let G of $.split(`
49
+ `)){let V=dJ(G);if(V.length===0){Z.push("");continue}let Y="",H=0;for(let K of V){let z=NJ(K.codePointAt(0));if(H+z>Q)Z.push(Y),Y=K,H=z;else Y+=K,H+=z}if(Y.length!==0)Z.push(Y)}return Z}function HZ(J,Q,Z){let $=[],G=[],V=0;for(let Y of J){let H=QZ(Y),K=H+(G.length!==0?1:0);if(G.length!==0&&(G.length>=Q||V+K>Z))$.push(G),G=[],V=0;V+=H+(G.length!==0?1:0),G.push(Y)}if(G.length!==0)$.push(G);return $}function pJ(J){if(J<32)return!0;if(J>=127&&J<=159)return!0;if(J>=768&&J<=879)return!0;if(J===8203||J===8204||J===8205||J===8288||J===65279)return!0;if(J>=65024&&J<=65039)return!0;if(J>=917760&&J<=917999)return!0;return!1}function KZ(J){let Q=null,Z=0;for(let $ of J){let G=$.codePointAt(0);if(o(G)<0&&!pJ(G)){if(Q===null)Q=J.slice(0,Z);Q+=`[U+${G.toString(16).toUpperCase()}]`}else if(Q!==null)Q+=$;Z+=$.length}return Q??J}function nJ(J,Q,Z,$){let G=Q?Z?VZ($Z(J)):GZ(lJ(J)):J;return HZ(YZ(KZ(G),$.cols),$.maxLines,$.maxChars)}function cJ(J,Q,Z){if(!Z)return 2*i+Q.cols*Q.cw;let $=0;for(let Y of J){let H=0;for(let K of Y)H+=NJ(K.codePointAt(0));if(H>Q.cols)H=Q.cols;if(H>$)$=H}let G=2*i+$*Q.cw,V=2*i+Q.cw;return G>V?G:V}var hJ=new Map;function mJ(J,Q,Z,$,G,V,Y){let H=o(G);if(H<0)return 0;let K=u(H),z=K?2*V.cw:V.cw,O;if(Y==="normal")O=WJ(H);else{let X=hJ.get(H);if(X===void 0)X=vJ(H,z,V.ch),hJ.set(H,X);O=X}for(let X=0;X<V.ch;X++){let B=($+X)*Q+Z,q=X*z;for(let M=0;M<z;M++){let U=O[q+M];if(U>0){let P=B+M;if(U>J[P])J[P]=U}}}return K?2:1}function zZ(J,Q,Z,$){let G=cJ(J,Q,Z),V=2*$J+J.length*Q.ch,Y=new Uint8Array(G*V),H=0;for(let K=0;K<J.length;K++){let z=$J+K*Q.ch,O=0;for(let X of J[K]){if(O>=Q.cols)break;let B=i+O*Q.cw,q=mJ(Y,G,B,z,X.codePointAt(0),Q,$);if(q===0){if(q=1,pJ(X.codePointAt(0)));else if(H++,X!==" ")mJ(Y,G,B,z,tQ,Q,$)}O+=q}}for(let K=0;K<Y.length;K++)Y[K]=255-Y[K];return{png:fJ(Y,G,V),width:G,height:V,dropped:H}}function YJ(J,Q,Z,$){let G=gJ($),V=nJ(J,Q,Z,G).map((z)=>zZ(z,G,Z,$)),Y=0,H=0,K=0;for(let z of V)Y+=z.width*z.height,H+=oJ(z.width,z.height),K+=z.dropped;return{pages:V,pixels:Y,tokens:H,dropped:K}}function HJ(J,Q,Z,$){let G=gJ($),V=nJ(J,Q,Z,G),Y=0,H=0;for(let K of V){let z=cJ(K,G,Z),O=2*$J+K.length*G.ch;Y+=z*O,H+=oJ(z,O)}return{pages:V.length,pixels:Y,tokens:H}}var uJ=28;function oJ(J,Q){return Math.ceil(J/uJ)*Math.ceil(Q/uJ)}import{readFileSync as XZ}from"node:fs";import{join as BZ}from"node:path";//! pxpipe measurement-log summary (~/.pxpipe/events.jsonl), same math as the
40
50
  //! node MCP: actual = every way input bytes get billed (input + cache reads +
41
51
  //! cache creates) — ignoring cache_read would fake the savings.
42
- class YJ{value;constructor(J){this.value=J}}function nJ(){let J=process.env.TANUKI_EVENTS;if(J!==void 0)return J;let Q=process.env.HOME??"";return VZ(Q,".pxpipe","events.jsonl")}function d(J){return typeof J==="number"&&Number.isSafeInteger(J)&&J>=0?J:0}function GZ(J){return J<0?-Math.round(-J):Math.round(J)}function IJ(){let J=nJ(),Q;try{Q=$Z(J,"utf8")}catch{return{available:!1,note:`no ${J} yet`}}let Z=0,$=0,V=0,G=0,Y=0,H=0;for(let K of Q.split(`
43
- `)){if(K.trim().length===0)continue;let O;try{O=JSON.parse(K)}catch{continue}Z+=1;let B=O!==null&&typeof O==="object"&&!Array.isArray(O)?O:{};if(B.compressed===!0)$+=1,V+=d(B.orig_chars),G+=d(B.image_count);Y+=d(B.baseline_tokens),H+=d(B.input_tokens)+d(B.cache_read_tokens)+d(B.cache_create_tokens)}let z=Y>0&&H>0?new YJ(GZ((1-H/Y)*1000)/10):null;return{available:!0,requests:Z,compressedRequests:$,imagedChars:V,imagesEmitted:G,baselineTokens:Y,actualInputTokens:H,estInputSavedPct:z}}//! Implicit mode: a local Anthropic middlebox, the pxpipe deployment shape
52
+ class KJ{value;constructor(J){this.value=J}}function iJ(){let J=process.env.TANUKI_EVENTS;if(J!==void 0)return J;let Q=process.env.HOME??"";return BZ(Q,".pxpipe","events.jsonl")}function d(J){return typeof J==="number"&&Number.isSafeInteger(J)&&J>=0?J:0}function OZ(J){return J<0?-Math.round(-J):Math.round(J)}function PJ(){let J=iJ(),Q;try{Q=XZ(J,"utf8")}catch{return{available:!1,note:`no ${J} yet`}}let Z=0,$=0,G=0,V=0,Y=0,H=0;for(let z of Q.split(`
53
+ `)){if(z.trim().length===0)continue;let O;try{O=JSON.parse(z)}catch{continue}Z+=1;let X=O!==null&&typeof O==="object"&&!Array.isArray(O)?O:{};if(X.compressed===!0)$+=1,G+=d(X.orig_chars),V+=d(X.image_count);Y+=d(X.baseline_tokens),H+=d(X.input_tokens)+d(X.cache_read_tokens)+d(X.cache_create_tokens)}let K=Y>0&&H>0?new KJ(OZ((1-H/Y)*1000)/10):null;return{available:!0,requests:Z,compressedRequests:$,imagedChars:G,imagesEmitted:V,baselineTokens:Y,actualInputTokens:H,estInputSavedPct:K}}//! Implicit mode: a local Anthropic middlebox, the pxpipe deployment shape
44
54
  //! without pxpipe's structural flaw. Rules that keep it injection-shaped-free:
45
55
  //!
46
56
  //! 1. The system prompt and tool definitions are NEVER touched.
@@ -56,7 +66,7 @@ class YJ{value;constructor(J){this.value=J}}function nJ(){let J=process.env.TANU
56
66
  //!
57
67
  //! Responses stream through untouched; usage is scraped from the stream for
58
68
  //! the ~/.pxpipe/events.jsonl savings log (same format tanuki_stats reads).
59
- import{createHash as YZ}from"node:crypto";import{mkdirSync as HZ,readFileSync as zZ,writeFileSync as KZ}from"node:fs";import cJ from"node:process";//! Stash mode: context-mode's shape (content parked outside the context
69
+ import{createHash as DZ}from"node:crypto";import{mkdirSync as qZ,readFileSync as MZ,writeFileSync as UZ}from"node:fs";import rJ from"node:process";//! Stash mode: context-mode's shape (content parked outside the context
60
70
  //! window, queried on demand) fused with tanuki's pricing (big answers come
61
71
  //! back as dense pages).
62
72
  //!
@@ -65,10 +75,10 @@ import{createHash as YZ}from"node:crypto";import{mkdirSync as HZ,readFileSync as
65
75
  //! repeats, first/last lines, the id). fetch = pull a slice by regex query
66
76
  //! (distill-powered) or line range; the caller images it only when pages
67
77
  //! clearly win. Contract is byte-identical with the Rust engine.
68
- function oJ(){let J=cJ.env.TANUKI_STASH;if(J!==void 0&&J!=="")return J;return`${cJ.env.HOME??""}/.tanuki/stash`}function iJ(J){let Q=YZ("sha256").update(J,"utf8").digest("hex").slice(0,12),Z=oJ();HZ(Z,{recursive:!0}),KZ(`${Z}/${Q}`,J);let $=Buffer.byteLength(J,"utf8"),V=J.split(`
69
- `),G=b(J,null,2).stats,Y=[`stashed ${Q} · ${$} bytes · ${V.length} lines`,`distill map: ${G.origLines} -> ${G.outLines} lines · ${G.savedPct}% of chars removable · ${G.importantKept} error/warn lines`];if(G.topRepeats.length>0){Y.push("top repeats:");for(let z of G.topRepeats.slice(0,5)){let K=z.kind==="template"?" (template)":"";Y.push(` ×${z.count}${K} ${z.exemplar}`)}}let H="";for(let z=V.length-1;z>=0;z--)if(V[z]!==""){H=V[z];break}return Y.push(`first: ${n(p(V[0]),160)}`),Y.push(`last: ${n(p(H),160)}`),Y.push(`fetch: tanuki_fetch {"id":"${Q}","query":"<regex>"} or {"id":"${Q}","lines":"a-b"}`),{id:Q,overview:Y.join(`
70
- `)}}function aJ(J,Q,Z){if(Q===null===(Z===null))throw Error("give exactly one of query or lines");let $;try{$=zZ(`${oJ()}/${J}`,"utf8")}catch{throw Error(`unknown stash id: ${J}`)}if(Z!==null){let V=/^(\d+)-(\d+)$/.exec(Z);if(V===null)throw Error("bad lines range");let G=$.split(`
71
- `),Y=Math.max(1,Number(V[1])),H=Math.min(G.length,Number(V[2]));if(Number(V[1])>Number(V[2]))throw Error("bad lines range");return G.slice(Y-1,H).join(`
78
+ function aJ(){let J=rJ.env.TANUKI_STASH;if(J!==void 0&&J!=="")return J;return`${rJ.env.HOME??""}/.tanuki/stash`}function tJ(J){let Q=DZ("sha256").update(J,"utf8").digest("hex").slice(0,12),Z=aJ();qZ(Z,{recursive:!0}),UZ(`${Z}/${Q}`,J);let $=Buffer.byteLength(J,"utf8"),G=J.split(`
79
+ `),V=b(J,null,2).stats,Y=[`stashed ${Q} · ${$} bytes · ${G.length} lines`,`distill map: ${V.origLines} -> ${V.outLines} lines · ${V.savedPct}% of chars removable · ${V.importantKept} error/warn lines`];if(V.topRepeats.length>0){Y.push("top repeats:");for(let K of V.topRepeats.slice(0,5)){let z=K.kind==="template"?" (template)":"";Y.push(` ×${K.count}${z} ${K.exemplar}`)}}let H="";for(let K=G.length-1;K>=0;K--)if(G[K]!==""){H=G[K];break}return Y.push(`first: ${n(p(G[0]),160)}`),Y.push(`last: ${n(p(H),160)}`),Y.push(`fetch: tanuki_fetch {"id":"${Q}","query":"<regex>"} or {"id":"${Q}","lines":"a-b"}`),{id:Q,overview:Y.join(`
80
+ `)}}function sJ(J,Q,Z){if(Q===null===(Z===null))throw Error("give exactly one of query or lines");let $;try{$=MZ(`${aJ()}/${J}`,"utf8")}catch{throw Error(`unknown stash id: ${J}`)}if(Z!==null){let G=/^(\d+)-(\d+)$/.exec(Z);if(G===null)throw Error("bad lines range");let V=$.split(`
81
+ `),Y=Math.max(1,Number(G[1])),H=Math.min(V.length,Number(G[2]));if(Number(G[1])>Number(G[2]))throw Error("bad lines range");return V.slice(Y-1,H).join(`
72
82
  `)}return b($,Q,2).distilled}//! tanuki-context — token-cutting context pipeline.
73
83
  //! pipeline: text -> distill (stage 0, logs) -> ladder level 0-4 (stage 1)
74
84
  //! -> pxpipe imaging (stage 2, name kept from the original mechanic)
@@ -78,15 +88,15 @@ function oJ(){let J=cJ.env.TANUKI_STASH;if(J!==void 0&&J!=="")return J;return`${
78
88
  //! tanuki-context estimate <file> [level] [--distill]
79
89
  //! tanuki-context render <file> [level] [outdir]
80
90
  //! tanuki-context proxy [--port N] [--upstream URL] [knobs] (implicit mode)
81
- var rJ="0.4.1",RJ=6;function BZ(J,Q){let Z=Math.min(J.length,Q.length),$=0;while($<Z&&J.charCodeAt($)===Q.charCodeAt($))$++;if($>=Z)return J.length-Q.length;return J.codePointAt($)-Q.codePointAt($)}function L(J,Q,Z=""){if(J===null||J===void 0)return"null";if(J instanceof YJ){let z=J.value;return Number.isFinite(z)&&Number.isInteger(z)?z.toFixed(1):String(z)}let $=typeof J;if($==="string")return JSON.stringify(J);if($==="number"||$==="boolean")return String(J);if(Array.isArray(J)){if(J.length===0)return"[]";if(!Q){let O="[";for(let B=0;B<J.length;B++){if(B>0)O+=",";O+=L(J[B],!1)}return O+"]"}let z=Z+" ",K=`[
82
- `;for(let O=0;O<J.length;O++){if(O>0)K+=`,
83
- `;K+=z+L(J[O],!0,z)}return K+`
84
- `+Z+"]"}let V=J,G=Object.keys(V).sort(BZ);if(G.length===0)return"{}";if(!Q){let z="{";for(let K=0;K<G.length;K++){if(K>0)z+=",";z+=JSON.stringify(G[K])+":"+L(V[G[K]],!1)}return z+"}"}let Y=Z+" ",H=`{
85
- `;for(let z=0;z<G.length;z++){if(z>0)H+=`,
86
- `;H+=Y+JSON.stringify(G[z])+": "+L(V[G[z]],!0,Y)}return H+`
87
- `+Z+"}"}function I(J,Q){return J!==null&&typeof J==="object"&&!Array.isArray(J)?J[Q]:void 0}function S(J){return typeof J==="string"?J:null}function HJ(J){return typeof J==="boolean"?J:null}function tJ(J){return typeof J==="number"&&Number.isSafeInteger(J)&&J>=0?J:null}function x(J){let Q=0;for(let Z=0;Z<J.length;Z++){Q++;let $=J.charCodeAt(Z);if($>=55296&&$<=56319&&Z+1<J.length){let V=J.charCodeAt(Z+1);if(V>=56320&&V<=57343)Z++}}return Q}function sJ(J,Q,Z,$,V){let G,Y=null;if(Z||$!==null){let K=b(J,$,2);G=K.distilled,Y=K.stats}else G=J;let H=0;if(V){let K=t(G);G=K.text,H=K.entries}let z=e(G,Q);return{stage0:Y,compressed:z.compressed,protectedLines:z.protectedLines,level:z.level,cbEntries:H}}function a(J){return Math.round(J/4)}function r(J,Q){if(J===0)return 0;let Z=(1-Q/J)*100;return Z<0?-Math.round(-Z):Math.round(Z)}function eJ(J){return{text:S(I(J,"text"))??"",level:(tJ(I(J,"level"))??0)%256,distill:HJ(I(J,"distill"))??!1,query:S(I(J,"query")),reflow:HJ(I(J,"reflow"))??!0,pack:HJ(I(J,"pack"))??!0,font:S(I(J,"font"))??"normal",codebook:HJ(I(J,"codebook"))??!1}}function XZ(J){let Q=(G)=>{let Y={codebook:!1,tokens:1/0,pages:0,text:G};for(let H of[!1,!0]){let z=H?t(G).text:G,K=GJ(z,!0,!0,g("normal"));if(K.tokens<Y.tokens)Y={codebook:H,tokens:K.tokens,pages:K.pages,text:z}}return Y},Z=Q(J),$=Q(b(J,null,2).distilled),V=GJ(Z.text,!0,!0,g("tiny"));return{codebook:Z.codebook,imageTokens:Z.tokens,pages:Z.pages,tinyImageTokens:V.tokens,withDistill:{codebook:$.codebook,imageTokens:$.tokens}}}function JQ(J){let Q=eJ(J),Z=sJ(Q.text,Q.level,Q.distill,Q.query,Q.codebook),$=g(Q.font),V=GJ(Z.compressed,Q.reflow,Q.pack,$),G=V.tokens,Y=x(Q.text),H=x(Z.compressed),z=a(Y),[K,O]=s[Z.level];return{engine:"pxpipe",level:`${Z.level} ${K}`,loss:O,distill:Z.stage0,origChars:Y,stage1Chars:H,stage1SavedPct:r(Y,H),pages:V.pages,imageTokens:G,rawTextTokens:z,totalSavedPct:r(z,G),protectedLines:Z.protectedLines,pack:Q.pack,font:$==="tiny"?"tiny":"normal",codebook:Q.codebook?Z.cbEntries:!1,verdict:G<z?"PIPELINE cheaper":"TEXT cheaper",recommend:XZ(Q.text)}}function QQ(J){let Q=eJ(J),Z=sJ(Q.text,Q.level,Q.distill,Q.query,Q.codebook),$=g(Q.font),V=VJ(Z.compressed,Q.reflow,Q.pack,$),G=V.tokens,Y=x(Q.text),H=x(Z.compressed),z=a(Y),[K,O]=s[Z.level],B="";if(Z.stage0!==null){let D=Z.stage0;B+=`distill: ${D.origLines} -> ${D.outLines} lines (-${D.savedPct}% chars, ${D.collapsedRuns} runs, ${D.suppressedLines} exact + ${D.templateSuppressed} template suppressed, ${D.importantKept} error/warn kept)
88
- `}if(B+=`L${Z.level} ${K} (${O}): ${Y} chars -> ${H} chars (stage1 -${r(Y,H)}%) -> ${V.pages.length} page(s), ~${G} image-tokens
89
- vs ~${z} text-tokens raw = TOTAL -${r(z,G)}%`,Z.protectedLines>0)B+=` · ${Z.protectedLines} lines kept verbatim`;if(V.dropped>0)B+=` · ${V.dropped} unmapped glyphs -> ▯`;if(Z.cbEntries>0)B+=` · codebook: ${Z.cbEntries} sigils (see ·legend·)`;if($==="tiny")B+=" · font: tiny 4x6";if(Q.pack)B+=" · packed (⇥N indent, → tab)";if(Q.reflow)B+=" · ↵ = newline · engine: pxpipe";let X=[{type:"text",text:B}],q=Math.min(V.pages.length,RJ);for(let D=0;D<q;D++){let M=V.pages[D].png;X.push({type:"image",data:Buffer.from(M.buffer,M.byteOffset,M.byteLength).toString("base64"),mimeType:"image/png"})}if(V.pages.length>RJ)X.push({type:"text",text:`(+${V.pages.length-RJ} more page(s))`});return X}function ZQ(J){let Q=S(I(J,"text"))??"",Z=b(Q,S(I(J,"query")),2);return[{type:"text",text:L(Z.stats,!0)},{type:"text",text:Z.distilled}]}function $Q(J){let Q=S(I(J,"text"))??"",Z=(tJ(I(J,"level"))??1)%256,$=e(Q,Z),[V,G,Y]=s[$.level],H=x(Q),z=x($.compressed),K=a(H),O=a(z),B={level:`${$.level} ${V}`,loss:G,note:Y,origChars:H,outChars:z,approxOrigTokens:K,approxOutTokens:O,savedPct:r(K,O),protectedLines:$.protectedLines};return[{type:"text",text:L(B,!0)},{type:"text",text:$.compressed}]}function VQ(J){let Q=S(I(J,"text"))??"";return[{type:"text",text:iJ(Q).overview}]}function GQ(J){let Q=S(I(J,"id"))??"",Z=aJ(Q,S(I(J,"query"))??null,S(I(J,"lines"))??null),$=a(x(Z)),V=VJ(Z,!0,!0,g("normal"));if(!(V.tokens<=$*0.75&&$-V.tokens>=300&&V.pages.length<=6))return[{type:"text",text:Z}];let H=[{type:"text",text:`[tanuki-context stash ${Q}: slice of ${x(Z)} chars imaged as ${V.pages.length} PNG page(s), ~${V.tokens} vs ~${$} text tokens. ↵=newline →=tab ⇥N=indent]`}];for(let z of V.pages){let K=z.png;H.push({type:"image",data:Buffer.from(K.buffer,K.byteOffset,K.byteLength).toString("base64"),mimeType:"image/png"})}return H}//! Claude Agent SDK integration (`tanuki-context/agent`).
91
+ var eJ="0.5.0",RJ=6;function WZ(J,Q){let Z=Math.min(J.length,Q.length),$=0;while($<Z&&J.charCodeAt($)===Q.charCodeAt($))$++;if($>=Z)return J.length-Q.length;return J.codePointAt($)-Q.codePointAt($)}function L(J,Q,Z=""){if(J===null||J===void 0)return"null";if(J instanceof KJ){let K=J.value;return Number.isFinite(K)&&Number.isInteger(K)?K.toFixed(1):String(K)}let $=typeof J;if($==="string")return JSON.stringify(J);if($==="number"||$==="boolean")return String(J);if(Array.isArray(J)){if(J.length===0)return"[]";if(!Q){let O="[";for(let X=0;X<J.length;X++){if(X>0)O+=",";O+=L(J[X],!1)}return O+"]"}let K=Z+" ",z=`[
92
+ `;for(let O=0;O<J.length;O++){if(O>0)z+=`,
93
+ `;z+=K+L(J[O],!0,K)}return z+`
94
+ `+Z+"]"}let G=J,V=Object.keys(G).sort(WZ);if(V.length===0)return"{}";if(!Q){let K="{";for(let z=0;z<V.length;z++){if(z>0)K+=",";K+=JSON.stringify(V[z])+":"+L(G[V[z]],!1)}return K+"}"}let Y=Z+" ",H=`{
95
+ `;for(let K=0;K<V.length;K++){if(K>0)H+=`,
96
+ `;H+=Y+JSON.stringify(V[K])+": "+L(G[V[K]],!0,Y)}return H+`
97
+ `+Z+"}"}function I(J,Q){return J!==null&&typeof J==="object"&&!Array.isArray(J)?J[Q]:void 0}function S(J){return typeof J==="string"?J:null}function r(J){return typeof J==="boolean"?J:null}function JQ(J){return typeof J==="number"&&Number.isSafeInteger(J)&&J>=0?J:null}function f(J){let Q=0;for(let Z=0;Z<J.length;Z++){Q++;let $=J.charCodeAt(Z);if($>=55296&&$<=56319&&Z+1<J.length){let G=J.charCodeAt(Z+1);if(G>=56320&&G<=57343)Z++}}return Q}function QQ(J,Q,Z,$,G){let V,Y=null;if(Z||$!==null){let z=b(J,$,2);V=z.distilled,Y=z.stats}else V=J;let H=0;if(G){let z=s(V);V=z.text,H=z.entries}let K=QJ(V,Q);return{stage0:Y,compressed:K.compressed,protectedLines:K.protectedLines,level:K.level,cbEntries:H}}function a(J){return Math.round(J/4)}function t(J,Q){if(J===0)return 0;let Z=(1-Q/J)*100;return Z<0?-Math.round(-Z):Math.round(Z)}function ZQ(J){return{text:S(I(J,"text"))??"",level:(JQ(I(J,"level"))??0)%256,distill:r(I(J,"distill"))??!1,query:S(I(J,"query")),reflow:r(I(J,"reflow"))??!0,pack:r(I(J,"pack"))??!0,font:S(I(J,"font"))??"normal",codebook:r(I(J,"codebook"))??!1}}function FZ(J){let Q=(V)=>{let Y={codebook:!1,tokens:1/0,pages:0,text:V};for(let H of[!1,!0]){let K=H?s(V).text:V,z=HJ(K,!0,!0,g("normal"));if(z.tokens<Y.tokens)Y={codebook:H,tokens:z.tokens,pages:z.pages,text:K}}return Y},Z=Q(J),$=Q(b(J,null,2).distilled),G=HJ(Z.text,!0,!0,g("tiny"));return{codebook:Z.codebook,imageTokens:Z.tokens,pages:Z.pages,tinyImageTokens:G.tokens,withDistill:{codebook:$.codebook,imageTokens:$.tokens}}}function $Q(J){let Q=ZQ(J),Z=QQ(Q.text,Q.level,Q.distill,Q.query,Q.codebook),$=g(Q.font),G=HJ(Z.compressed,Q.reflow,Q.pack,$),V=G.tokens,Y=f(Q.text),H=f(Z.compressed),K=a(Y),[z,O]=JJ[Z.level],X=S(I(J,"model")),B=r(I(J,"cached"))??!1,q={engine:"pxpipe",level:`${Z.level} ${z}`,loss:O,distill:Z.stage0,origChars:Y,stage1Chars:H,stage1SavedPct:t(Y,H),pages:G.pages,imageTokens:V,rawTextTokens:K,totalSavedPct:t(K,V),protectedLines:Z.protectedLines,pack:Q.pack,font:$==="tiny"?"tiny":"normal",codebook:Q.codebook?Z.cbEntries:!1,verdict:V<K?"PIPELINE cheaper":"TEXT cheaper",recommend:FZ(Q.text)};if(X!==null||B)q.cost=LJ(K,V,{model:X,cached:B});return q}function GQ(J){let Q=ZQ(J),Z=QQ(Q.text,Q.level,Q.distill,Q.query,Q.codebook),$=g(Q.font),G=YJ(Z.compressed,Q.reflow,Q.pack,$),V=G.tokens,Y=f(Q.text),H=f(Z.compressed),K=a(Y),[z,O]=JJ[Z.level],X="";if(Z.stage0!==null){let M=Z.stage0;X+=`distill: ${M.origLines} -> ${M.outLines} lines (-${M.savedPct}% chars, ${M.collapsedRuns} runs, ${M.suppressedLines} exact + ${M.templateSuppressed} template suppressed, ${M.importantKept} error/warn kept)
98
+ `}if(X+=`L${Z.level} ${z} (${O}): ${Y} chars -> ${H} chars (stage1 -${t(Y,H)}%) -> ${G.pages.length} page(s), ~${V} image-tokens
99
+ vs ~${K} text-tokens raw = TOTAL -${t(K,V)}%`,Z.protectedLines>0)X+=` · ${Z.protectedLines} lines kept verbatim`;if(G.dropped>0)X+=` · ${G.dropped} unmapped glyphs -> ▯`;if(Z.cbEntries>0)X+=` · codebook: ${Z.cbEntries} sigils (see ·legend·)`;if($==="tiny")X+=" · font: tiny 4x6";if(Q.pack)X+=" · packed (⇥N indent, → tab)";if(Q.reflow)X+=" · ↵ = newline · engine: pxpipe";let B=[{type:"text",text:X}],q=Math.min(G.pages.length,RJ);for(let M=0;M<q;M++){let U=G.pages[M].png;B.push({type:"image",data:Buffer.from(U.buffer,U.byteOffset,U.byteLength).toString("base64"),mimeType:"image/png"})}if(G.pages.length>RJ)B.push({type:"text",text:`(+${G.pages.length-RJ} more page(s))`});return B}function VQ(J){let Q=S(I(J,"text"))??"",Z=b(Q,S(I(J,"query")),2);return[{type:"text",text:L(Z.stats,!0)},{type:"text",text:Z.distilled}]}function YQ(J){let Q=S(I(J,"text"))??"",Z=(JQ(I(J,"level"))??1)%256,$=QJ(Q,Z),[G,V,Y]=JJ[$.level],H=f(Q),K=f($.compressed),z=a(H),O=a(K),X={level:`${$.level} ${G}`,loss:V,note:Y,origChars:H,outChars:K,approxOrigTokens:z,approxOutTokens:O,savedPct:t(z,O),protectedLines:$.protectedLines};return[{type:"text",text:L(X,!0)},{type:"text",text:$.compressed}]}function HQ(J){let Q=S(I(J,"text"))??"";return[{type:"text",text:tJ(Q).overview}]}function KQ(J){let Q=S(I(J,"id"))??"",Z=sJ(Q,S(I(J,"query"))??null,S(I(J,"lines"))??null),$=a(f(Z)),G=YJ(Z,!0,!0,g("normal"));if(!(G.tokens<=$*0.75&&$-G.tokens>=300&&G.pages.length<=6))return[{type:"text",text:Z}];let H=[{type:"text",text:`[tanuki-context stash ${Q}: slice of ${f(Z)} chars imaged as ${G.pages.length} PNG page(s), ~${G.tokens} vs ~${$} text tokens. ↵=newline →=tab ⇥N=indent]`}];for(let K of G.pages){let z=K.png;H.push({type:"image",data:Buffer.from(z.buffer,z.byteOffset,z.byteLength).toString("base64"),mimeType:"image/png"})}return H}//! Claude Agent SDK integration (`tanuki-context/agent`).
90
100
  //!
91
101
  //! Two flavours, both one-liners from an agent's point of view:
92
102
  //!
@@ -103,8 +113,8 @@ vs ~${z} text-tokens raw = TOTAL -${r(z,G)}%`,Z.protectedLines>0)B+=` · ${Z.pro
103
113
  //! The core package stays zero-dependency: the SDK and zod are touched only
104
114
  //! inside `tanukiSdkServer()` via dynamic import, and both are already present
105
115
  //! in any Agent SDK project (zod is the SDK's own peer dependency).
106
- var DZ=["tanuki_render","tanuki_estimate","tanuki_distill","tanuki_compress","tanuki_stats","tanuki_stash","tanuki_fetch"],qZ=`tanuki-context turns bulky text (logs, command output, docs) into dense PNG pages that cost a fraction of the text tokens.
107
- Workflow: call tanuki_estimate first (instant, exact, never renders pixels). Its "recommend" field prices the reversible route; for logs, recommend.withDistill prices the distill route - do not probe combos by hand. If the verdict says "PIPELINE cheaper", call tanuki_render with the recommended knobs and use the returned pages instead of pasting the text.
116
+ var IZ=["tanuki_render","tanuki_estimate","tanuki_distill","tanuki_compress","tanuki_stats","tanuki_stash","tanuki_fetch"],PZ=`tanuki-context turns bulky text (logs, command output, docs) into dense PNG pages that cost a fraction of the text tokens.
117
+ Workflow: call tanuki_estimate first (instant, exact, never renders pixels). Its "recommend" field prices the reversible route; for logs, recommend.withDistill prices the distill route - do not probe combos by hand. If the verdict says "PIPELINE cheaper", call tanuki_render with the recommended knobs and use the returned pages instead of pasting the text. Pass model:"<your model>" and cached:true when the text is already in the prompt cache - the returned "cost" field prices it in real dollars, and cached content is usually cheaper left as text (a cache-read token is ~0.1x a fresh one), so do not image it.
108
118
  For logs, pass distill:true (repeats collapse, error/warn lines stay verbatim; add query:"regex" to slice). For prose you will not quote verbatim, level 2-3 shrinks it further. codebook:true helps path-heavy logs. Never image content you must quote byte-exact at level 4 or font tiny.
109
119
  For huge references you will only consult occasionally: tanuki_stash parks the text outside context for a few hundred tokens of map; tanuki_fetch pulls slices later, auto-imaged when pages win.
110
- Pages decode as: ↵ = newline, → = tab, ⇥N = N leading spaces, a trailing ·legend· line maps sigils back to full tokens.`;function MZ(){let J=new URL("./cli.js",import.meta.url);if(J.protocol==="file:"){let Q=UZ(J);if(OZ(Q))return{type:"stdio",command:process.execPath,args:[Q]}}return{type:"stdio",command:"npx",args:["-y","tanuki-context"]}}function FZ(J="tanuki"){return DZ.map((Q)=>`mcp__${J}__${Q}`)}function H$(J,Q={}){let Z=J??{},$=Q.key??"tanuki";return{...Z,mcpServers:{...Z.mcpServers??{},[$]:Q.server??MZ()},allowedTools:[...Z.allowedTools??[],...FZ($)]}}function WZ(J){let Q=J.string().describe("the bulky text to process"),Z=J.number().int().min(0).max(4).optional().describe("ladder level 0-4 (default 0)"),$={text:Q,level:Z,distill:J.boolean().optional().describe("stage 0 log distiller"),query:J.string().optional().describe("distill: keep matching lines +context"),reflow:J.boolean().optional().describe("pack short lines into full rows (default true)"),pack:J.boolean().optional().describe("indent RLE + width trim, lossless (default true)"),font:J.enum(["normal","tiny"]).optional().describe("tiny = 4x6 cells, ~40% fewer tokens, gated"),codebook:J.boolean().optional().describe("repeated tokens/paths -> sigils + legend")},V=(Y)=>({content:Y}),G=async(Y)=>{try{return V(Y())}catch(H){return{content:[{type:"text",text:`tanuki-context error: ${H instanceof Error?H.message:String(H)}`}],isError:!0}}};return[{name:"tanuki_render",description:"Render text through the pipeline (optional distill/level/codebook) into dense PNG pages. Call after tanuki_estimate says PIPELINE cheaper.",inputSchema:$,handler:(Y)=>G(()=>QQ(Y))},{name:"tanuki_estimate",description:"Exact page/token math for the same arguments as tanuki_render, without touching pixels. Instant; call this first.",inputSchema:$,handler:(Y)=>G(()=>[{type:"text",text:L(JQ(Y),!0)}])},{name:"tanuki_distill",description:"Stage 0 alone: collapse repeated log lines/blocks and template near-dupes; error/warn lines kept verbatim. Output stays greppable text.",inputSchema:{text:Q,query:$.query},handler:(Y)=>G(()=>ZQ(Y))},{name:"tanuki_compress",description:"Stage 1 alone: graded text compression, levels 0-4, code/paths/hashes protected from level 2 up.",inputSchema:{text:Q,level:Z},handler:(Y)=>G(()=>$Q(Y))},{name:"tanuki_stats",description:"Session savings summary from the events log (honest denominator: input + cache reads + cache creates).",inputSchema:{},handler:()=>G(()=>[{type:"text",text:L(IJ(),!0)}])},{name:"tanuki_stash",description:"Park bulky text outside the context window; returns a compact map (distill stats, top repeats, id). Retrieval pattern, tanuki pricing on the way back.",inputSchema:{text:Q},handler:(Y)=>G(()=>VQ(Y))},{name:"tanuki_fetch",description:"Pull a slice of stashed text by id + query regex or lines 'a-b'. Big slices return as dense PNG pages automatically.",inputSchema:{id:$.query,query:$.query,lines:$.query},handler:(Y)=>G(()=>GQ(Y))}]}async function z$(){let J,Q;try{J=await import("@anthropic-ai/claude-agent-sdk");let $=await import("zod");Q=$.z??$}catch($){throw Error(`tanukiSdkServer() needs the host project's @anthropic-ai/claude-agent-sdk and zod (npm i @anthropic-ai/claude-agent-sdk zod). Import failed: ${$ instanceof Error?$.message:String($)}`)}let Z=WZ(Q).map(($)=>J.tool($.name,$.description,$.inputSchema,(V)=>$.handler(V)));return J.createSdkMcpServer({name:"tanuki-context",version:rJ,instructions:qZ,tools:Z})}export{H$ as withTanuki,WZ as tanukiSdkToolSpecs,z$ as tanukiSdkServer,MZ as tanukiMcpServer,FZ as tanukiAllowedTools,DZ as TANUKI_TOOL_NAMES,qZ as TANUKI_INSTRUCTIONS};
120
+ Pages decode as: ↵ = newline, → = tab, ⇥N = N leading spaces, a trailing ·legend· line maps sigils back to full tokens.`;function RZ(){let J=new URL("./cli.js",import.meta.url);if(J.protocol==="file:"){let Q=NZ(J);if(jZ(Q))return{type:"stdio",command:process.execPath,args:[Q]}}return{type:"stdio",command:"npx",args:["-y","tanuki-context"]}}function AZ(J="tanuki"){return IZ.map((Q)=>`mcp__${J}__${Q}`)}function U$(J,Q={}){let Z=J??{},$=Q.key??"tanuki";return{...Z,mcpServers:{...Z.mcpServers??{},[$]:Q.server??RZ()},allowedTools:[...Z.allowedTools??[],...AZ($)]}}function _Z(J){let Q=J.string().describe("the bulky text to process"),Z=J.number().int().min(0).max(4).optional().describe("ladder level 0-4 (default 0)"),$={text:Q,level:Z,distill:J.boolean().optional().describe("stage 0 log distiller"),query:J.string().optional().describe("distill: keep matching lines +context"),reflow:J.boolean().optional().describe("pack short lines into full rows (default true)"),pack:J.boolean().optional().describe("indent RLE + width trim, lossless (default true)"),font:J.enum(["normal","tiny"]).optional().describe("tiny = 4x6 cells, ~40% fewer tokens, gated"),codebook:J.boolean().optional().describe("repeated tokens/paths -> sigils + legend"),model:J.string().optional().describe("estimate: price the decision for this model (opus/sonnet/haiku/gpt/gemini)"),cached:J.boolean().optional().describe("estimate: text already prompt-cached this turn? imaging it usually loses")},G=(Y)=>({content:Y}),V=async(Y)=>{try{return G(Y())}catch(H){return{content:[{type:"text",text:`tanuki-context error: ${H instanceof Error?H.message:String(H)}`}],isError:!0}}};return[{name:"tanuki_render",description:"Render text through the pipeline (optional distill/level/codebook) into dense PNG pages. Call after tanuki_estimate says PIPELINE cheaper.",inputSchema:$,handler:(Y)=>V(()=>GQ(Y))},{name:"tanuki_estimate",description:"Exact page/token math for the same arguments as tanuki_render, without touching pixels. Pass model and/or cached:true for a real-dollar 'cost' verdict (cached content usually should not be imaged). Instant; call this first.",inputSchema:$,handler:(Y)=>V(()=>[{type:"text",text:L($Q(Y),!0)}])},{name:"tanuki_distill",description:"Stage 0 alone: collapse repeated log lines/blocks and template near-dupes; error/warn lines kept verbatim. Output stays greppable text.",inputSchema:{text:Q,query:$.query},handler:(Y)=>V(()=>VQ(Y))},{name:"tanuki_compress",description:"Stage 1 alone: graded text compression, levels 0-4, code/paths/hashes protected from level 2 up.",inputSchema:{text:Q,level:Z},handler:(Y)=>V(()=>YQ(Y))},{name:"tanuki_stats",description:"Session savings summary from the events log (honest denominator: input + cache reads + cache creates).",inputSchema:{},handler:()=>V(()=>[{type:"text",text:L(PJ(),!0)}])},{name:"tanuki_stash",description:"Park bulky text outside the context window; returns a compact map (distill stats, top repeats, id). Retrieval pattern, tanuki pricing on the way back.",inputSchema:{text:Q},handler:(Y)=>V(()=>HQ(Y))},{name:"tanuki_fetch",description:"Pull a slice of stashed text by id + query regex or lines 'a-b'. Big slices return as dense PNG pages automatically.",inputSchema:{id:$.query,query:$.query,lines:$.query},handler:(Y)=>V(()=>KQ(Y))}]}async function W$(){let J,Q;try{J=await import("@anthropic-ai/claude-agent-sdk");let $=await import("zod");Q=$.z??$}catch($){throw Error(`tanukiSdkServer() needs the host project's @anthropic-ai/claude-agent-sdk and zod (npm i @anthropic-ai/claude-agent-sdk zod). Import failed: ${$ instanceof Error?$.message:String($)}`)}let Z=_Z(Q).map(($)=>J.tool($.name,$.description,$.inputSchema,(G)=>$.handler(G)));return J.createSdkMcpServer({name:"tanuki-context",version:eJ,instructions:PZ,tools:Z})}export{U$ as withTanuki,_Z as tanukiSdkToolSpecs,W$ as tanukiSdkServer,RZ as tanukiMcpServer,AZ as tanukiAllowedTools,IZ as TANUKI_TOOL_NAMES,PZ as TANUKI_INSTRUCTIONS};
package/dist/cli.js CHANGED
@@ -1,20 +1,30 @@
1
1
  #!/usr/bin/env node
2
- import{spawnSync as SZ}from"node:child_process";import{readFileSync as CZ,mkdirSync as GQ,writeFileSync as YQ}from"node:fs";import R from"node:process";function WQ(J){if(J===32||J>=9&&J<=13)return!0;if(J<133)return!1;return J===133||J===160||J===5760||J>=8192&&J<=8202||J===8232||J===8233||J===8239||J===8287||J===12288}function FJ(J){let Q=0;for(let Z=0;Z<J.length;Z++){let $=J.charCodeAt(Z);if($>=55296&&$<=56319&&Z+1<J.length){let V=J.charCodeAt(Z+1);if(V>=56320&&V<=57343)Z++}Q++}return Q}function jQ(J,Q){let Z=0,$=0;while(Z<J.length&&$<Q.length){let V=J.codePointAt(Z),z=Q.codePointAt($);if(V!==z)return V-z;Z+=V>65535?2:1,$+=z>65535?2:1}return J.length-Z-(Q.length-$)}function a(J){let Q=new Map,Z=(O)=>{Q.set(O,(Q.get(O)??0)+1)},$=(O)=>{if(FJ(O)>=12)Z(O);if(O.includes("/")){let X=O.split("/"),D="";for(let M=0;M<X.length;M++){if(M>0)D+="/";if(D+=X[M],M>=2){let E=D+"/";if(FJ(E)>=12)Z(E)}}}},V=-1;for(let O=0;O<J.length;){let X=J.codePointAt(O),D=X>65535?2:1;if(WQ(X)){if(V>=0)$(J.slice(V,O)),V=-1}else if(V<0)V=O;O+=D}if(V>=0)$(J.slice(V));let z=[];for(let[O,X]of Q)if(X>=3){let D=FJ(O);z.push({k:O,c:X,len:D,saved:(D-1)*X})}z.sort((O,X)=>X.saved-O.saved||jQ(O.k,X.k));let G=[];for(let O of"§¤¢£¥µ¶ª°±¬×÷ØÞßæðøþ¡¿")if(!J.includes(O))G.push(O);let Y=[],H=[];for(let{k:O,c:X,len:D}of z){if(Y.length>=G.length)break;if((D-1)*X<=D+3)continue;let M=!1;for(let S=0;S<H.length;S++){let k=H[S];if(k.startsWith(O)||O.startsWith(k)){M=!0;break}}if(M)continue;let E=G[Y.length];H.push(O),Y.push({sig:E,val:O,len:D})}if(Y.length===0)return{text:J,entries:0};let K=Y.map((O,X)=>X);K.sort((O,X)=>Y[X].len-Y[O].len);let B=J;for(let O=0;O<K.length;O++){let{sig:X,val:D}=Y[K[O]];B=B.replaceAll(D,X)}let U=`
3
- ·legend· `;for(let O=0;O<Y.length;O++)U+=Y[O].sig+"="+Y[O].val+" ";return B+=U.slice(0,-1),{text:B,entries:Y.length}}import{Buffer as fJ}from"node:buffer";var NQ=/\x1b\[[0-9;]*[A-Za-z]/g,WJ=/\b([0-9A-Za-z_]*(error|exception)s?|err|warn(ing)?s?|fail(s|ed|ure|ures)?|panic(s|ked)?|fatal|critical|traceback|denied|refused|timeouts?|timed.?out|assert(s|ed|ion|ions)?|segfault(s|ed)?)\b/i,IQ=/[0-9]{4}-[0-9]{2}-[0-9]{2}[T ][0-9]{2}:[0-9]{2}:[0-9]{2}([.,][0-9]+)?(Z|[+-][0-9]{2}:?[0-9]{2})?/g,RQ=/\b[0-9]{2}:[0-9]{2}:[0-9]{2}([.,][0-9]+)?\b/g,AQ=/\b[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}\b/gi,PQ=/\b[0-9a-f]{7,64}\b/gi,_Q=/\b[0-9]+(\.[0-9]+)?[ \t\u00a0]?(ms|us|µs|ns|s|m|h|%|[KMGT]i?B)?\b/gi,EQ=/[0-9a-f]/i,SQ=3,CQ=8,jJ=2,hJ=40;function TQ(J){if(!EQ.test(J))return J;let Q=J.replace(IQ,"<ts>");return Q=Q.replace(RQ,"<time>"),Q=Q.replace(AQ,"<uuid>"),Q=Q.replace(PQ,"<hex>"),Q.replace(_Q,"<n>")}function p(J){if(J===32)return!0;if(J<9)return!1;if(J<=13)return!0;if(J<133)return!1;return J===133||J===160||J===5760||J>=8192&&J<=8202||J===8232||J===8233||J===8239||J===8287||J===12288}function r(J){let Q=0,Z=J.length;while(Q<Z&&p(J.charCodeAt(Q)))Q++;while(Z>Q&&p(J.charCodeAt(Z-1)))Z--;return Q===0&&Z===J.length?J:J.slice(Q,Z)}function LQ(J,Q){let Z=0,$=J.length;while(Z<$&&p(J.charCodeAt(Z)))Z++;while($>Z&&p(J.charCodeAt($-1)))$--;let V=0;for(let z=Z;z<$&&V<Q;V++){let G=J.charCodeAt(z);z+=G>=55296&&G<=56319&&z+1<$?2:1}return V<Q}function yQ(J){let Q=0,Z=J.length;while(Q<Z&&p(J.charCodeAt(Q)))Q++;return J.charCodeAt(Q)===91&&J.charCodeAt(Q+1)===215}function wQ(J){let Q=[],Z=-1,$=!0,V=!1,z=!1,G=!0;for(let Y=0;Y<J.length;){let H=J.codePointAt(Y),K=H>65535?2:1,B=p(H);if(G){if(G=!1,B)Q.push("<v>")}if(B){if(Z>=0)Q.push($?J.slice(Z,Y):"<v>"),Z=-1;z=!0}else{if(V=!0,z=!1,Z<0)Z=Y,$=!0;if($){let U=H|32;if(U<97||U>122||H>127)$=!1}}Y+=K}if(Z>=0)Q.push($?J.slice(Z):"<v>");if(V&&z)Q.push("<v>");return Q.join(" ")}function t(J,Q){let Z=0,$=0,V=J.length;while(Z<V&&$<Q){let z=J.charCodeAt(Z);Z+=z>=55296&&z<=56319&&Z+1<V?2:1,$++}return Z>=V?J:J.slice(0,Z)}var bQ=/[.*+?^${}()|[\]\\]/g;function w(J,Q=null,Z=2){let $=Z,z=J.replace(NQ,"").split(`
4
- `).map((q)=>{let F=q.endsWith("\r")?q.slice(0,-1):q,W=F.lastIndexOf("\r");return W===-1?F:F.slice(W+1)}),G=z.length,Y=G,H=Array(G),K=Array(G),B=0;for(let q=0;q<G;q++){H[q]=TQ(z[q]);let F=WJ.test(z[q]);if(K[q]=F,F)B++}let U=[],O=[],X=[],D=0,M=0;while(M<G){let q=0,F=0;for(let W=1;W<=CQ&&M+2*W<=G;W++){if(K[M+W-1])break;let I=1;J:for(;;){let N=M+I*W;if(N+W>G)break;for(let T=0;T<W;T++)if(K[N+T]||H[N+T]!==H[M+T])break J;I++}if(I>=SQ&&W*(I-1)>q*(F>0?F-1:0))q=W,F=I}if(q>0){for(let W=M;W<M+q;W++)U.push(z[W]),O.push(K[W]),X.push(H[W]);U.push(q===1?` [×${F} similar]`:` [×${F} similar ${q}-line blocks]`),O.push(!1),X.push(null),D++,M+=q*F}else U.push(z[M]),O.push(K[M]),X.push(H[M]),M++}let E=new Map,S=new Map,k=jJ+1,y=[],C=[],x=0,f=0;for(let q=0;q<U.length;q++){let F=U[q],W=O[q];if(W||yQ(F)||LQ(F,4)){y.push(F),C.push(W);continue}let I=X[q],N=E.get(I);if(N!==void 0){if(N.count++,N.count<=jJ)y.push(F),C.push(!1);else x++;continue}let T=wQ(I);E.set(I,{count:1,exemplar:F});let i=S.get(T);if(i!==void 0)if(i.count++,i.count<=k)y.push(F),C.push(!1);else f++;else S.set(T,{count:1,exemplar:F}),y.push(F),C.push(!1)}let u=[];for(let q of E.values())if(q.count>jJ)u.push([q.count,"exact",q.exemplar]);for(let q of S.values())if(q.count>k)u.push([q.count,"template",q.exemplar]);if(u.sort((q,F)=>F[0]-q[0]),u.length>hJ)u.length=hJ;if(x+f>0){let q=`── ${x+f} repeated lines suppressed (${x} exact ×N, ${f} same-template; first occurrences kept above) ──`;y.push(q),C.push(WJ.test(q));for(let[F,W,I]of u){let T=` ×${F}${W==="template"?" (template)":""} ${t(r(I),160)}`;y.push(T),C.push(WJ.test(T))}}let g;if(Q!=null){let q;try{q=new RegExp(Q,"i")}catch{q=new RegExp(Q.replace(bQ,"\\$&"),"i")}let F=y.length,W=new Uint8Array(F);for(let N=0;N<F;N++)if(C[N]||q.test(y[N])){let T=N>$?N-$:0,i=Math.min(N+$,F-1);W.fill(1,T,i+1)}g=[];let I=0;for(let N=0;N<F;N++)if(W[N]){if(I>0)g.push(`… ${I} lines omitted`),I=0;g.push(y[N])}else I++;if(I>0)g.push(`… ${I} lines omitted`)}else g=y;let vJ=g.join(`
5
- `),kJ=fJ.byteLength(J),xJ=fJ.byteLength(vJ),MJ=(1-xJ/kJ)*100,qQ=J.length===0?0:MJ<0?-Math.round(-MJ):Math.round(MJ),MQ=u.map(([q,F,W])=>({count:q,exemplar:t(r(W),160),kind:F})),FQ={collapsedRuns:D,importantKept:B,origChars:kJ,origLines:Y,outChars:xJ,outLines:g.length,query:Q??null,savedPct:qQ,suppressedLines:x,templateSuppressed:f,topRepeats:MQ};return{distilled:vJ,stats:FQ}}var GJ=[["none","none","passthrough (baseline)"],["whitespace","lossless","trailing whitespace + blank-line runs collapsed; safe for code"],["prose","light","L1 + prose lines: collapse spaces, cut redundant filler phrases (code/IDs protected)"],["dense","medium","L2 + prose: drop articles & intensifiers"],["caveman","heavy","L3 + prose: telegraphic — drop function words; gist only, NOT verbatim"]];var b=(J)=>new RegExp(`(?<![\\p{Alphabetic}\\p{Mark}\\p{Decimal_Number}\\p{Connector_Punctuation}\\p{Join_Control}])(?:${J})(?![\\p{Alphabetic}\\p{Mark}\\p{Decimal_Number}\\p{Connector_Punctuation}\\p{Join_Control}])`,"giu"),NJ=[[b("in order to"),"to"],[b("due to the fact that"),"because"],[b("at this point in time"),"now"],[b("in the event that"),"if"],[b("for the purpose of"),"for"],[b("with regard to"),"about"],[b("a large number of"),"many"],[b("it is important to note that"),""],[b("please note that"),""],[b("as a matter of fact"),""],[b("in terms of"),"for"],[b("the fact that"),"that"]],vQ=new RegExp("(?<![\\p{Alphabetic}\\p{Mark}\\p{Decimal_Number}\\p{Connector_Punctuation}\\p{Join_Control}])(?:the|an|a)[\\t\\n\\x0B\\f\\r \\u0085\\u00A0\\u1680\\u2000-\\u200A\\u2028\\u2029\\u202F\\u205F\\u3000]+","giu"),kQ=new RegExp("(?<![\\p{Alphabetic}\\p{Mark}\\p{Decimal_Number}\\p{Connector_Punctuation}\\p{Join_Control}])(?:very|really|just|actually|basically|simply|quite|rather|essentially|literally)[\\t\\n\\x0B\\f\\r \\u0085\\u00A0\\u1680\\u2000-\\u200A\\u2028\\u2029\\u202F\\u205F\\u3000]+","giu"),xQ=new RegExp("(?<![\\p{Alphabetic}\\p{Mark}\\p{Decimal_Number}\\p{Connector_Punctuation}\\p{Join_Control}])(?:is|are|was|were|am|be|been|being|do|does|did|have|has|had|will|would|shall|should|can|could|may|might|of|to|in|on|at|for|with|that|this|these|those|it|its|there|here)(?![\\p{Alphabetic}\\p{Mark}\\p{Decimal_Number}\\p{Connector_Punctuation}\\p{Join_Control}])[\\t\\n\\x0B\\f\\r \\u0085\\u00A0\\u1680\\u2000-\\u200A\\u2028\\u2029\\u202F\\u205F\\u3000]*","giu"),mJ=/ {2,}/g,fQ=new RegExp("[\\t\\n\\x0B\\f\\r \\u0085\\u00A0\\u1680\\u2000-\\u200A\\u2028\\u2029\\u202F\\u205F\\u3000]+([.,;:!?])","gu"),hQ=/\n{3,}/g;function IJ(J){if(J===32||J>=9&&J<=13)return!0;if(J<133)return!1;return J===133||J===160||J===5760||J>=8192&&J<=8202||J===8232||J===8233||J===8239||J===8287||J===12288}function mQ(J){let Q=0,Z=J.length;while(Q<Z){let $=J.codePointAt(Q);if(!IJ($))break;Q+=$>65535?2:1}while(Z>Q){let $=J.charCodeAt(Z-1);if(!IJ($))break;Z--}return Q===0&&Z===J.length?J:J.slice(Q,Z)}function uQ(J){if(J.length===0)return!1;let Q=J.charCodeAt(0);if(Q===32||Q===9)return!0;let Z=0,$=0,V=0,z=!1;for(let G=0;G<J.length;){let Y=J.codePointAt(G);if(G+=Y>65535?2:1,Z++,IJ(Y)){V=0;continue}if(V++,V>=24)z=!0;if(Y>=48&&Y<=57||Y>=65&&Y<=90||Y>=97&&Y<=122)continue;switch(Y){case 46:case 44:case 59:case 58:case 39:case 34:case 33:case 63:case 40:case 41:case 45:continue}$++}if($/Z>0.3)return!0;return z}function gQ(J,Q){let Z=J.replace(mJ," ");for(let V=0;V<NJ.length;V++)Z=Z.replace(NJ[V][0],NJ[V][1]);if(Q>=3)Z=Z.replace(vQ,""),Z=Z.replace(kQ,"");if(Q>=4)Z=Z.replace(xQ,"");Z=Z.replace(mJ," "),Z=mQ(Z.replace(fQ,"$1"));let $=Z.charCodeAt(0);if($>=97&&$<=122)Z=String.fromCharCode($-32)+Z.slice(1);return Z}function s(J,Q){let Z=Math.min(Q,4);if(Z===0)return{compressed:J,protectedLines:0,level:Z};let $=0,V=J.split(`
6
- `),z=Array(V.length);for(let Y=0;Y<V.length;Y++){let H=V[Y],K=H.length;while(K>0){let U=H.charCodeAt(K-1);if(U!==32&&U!==9)break;K--}let B=K===H.length?H:H.slice(0,K);if(Z===1){z[Y]=B;continue}if(uQ(B)){$++,z[Y]=B;continue}z[Y]=gQ(B,Z)}return{compressed:z.join(`
7
- `).replace(hQ,`
2
+ import{spawnSync as vZ}from"node:child_process";import{readFileSync as fZ,mkdirSync as KQ,writeFileSync as XQ}from"node:fs";import R from"node:process";function IQ(J){if(J===32||J>=9&&J<=13)return!0;if(J<133)return!1;return J===133||J===160||J===5760||J>=8192&&J<=8202||J===8232||J===8233||J===8239||J===8287||J===12288}function WJ(J){let Q=0;for(let Z=0;Z<J.length;Z++){let $=J.charCodeAt(Z);if($>=55296&&$<=56319&&Z+1<J.length){let z=J.charCodeAt(Z+1);if(z>=56320&&z<=57343)Z++}Q++}return Q}function RQ(J,Q){let Z=0,$=0;while(Z<J.length&&$<Q.length){let z=J.codePointAt(Z),G=Q.codePointAt($);if(z!==G)return z-G;Z+=z>65535?2:1,$+=G>65535?2:1}return J.length-Z-(Q.length-$)}function r(J){let Q=new Map,Z=(O)=>{Q.set(O,(Q.get(O)??0)+1)},$=(O)=>{if(WJ(O)>=12)Z(O);if(O.includes("/")){let D=O.split("/"),U="";for(let M=0;M<D.length;M++){if(M>0)U+="/";if(U+=D[M],M>=2){let S=U+"/";if(WJ(S)>=12)Z(S)}}}},z=-1;for(let O=0;O<J.length;){let D=J.codePointAt(O),U=D>65535?2:1;if(IQ(D)){if(z>=0)$(J.slice(z,O)),z=-1}else if(z<0)z=O;O+=U}if(z>=0)$(J.slice(z));let G=[];for(let[O,D]of Q)if(D>=3){let U=WJ(O);G.push({k:O,c:D,len:U,saved:(U-1)*D})}G.sort((O,D)=>D.saved-O.saved||RQ(O.k,D.k));let V=[];for(let O of"§¤¢£¥µ¶ª°±¬×÷ØÞßæðøþ¡¿")if(!J.includes(O))V.push(O);let Y=[],H=[];for(let{k:O,c:D,len:U}of G){if(Y.length>=V.length)break;if((U-1)*D<=U+3)continue;let M=!1;for(let C=0;C<H.length;C++){let f=H[C];if(f.startsWith(O)||O.startsWith(f)){M=!0;break}}if(M)continue;let S=V[Y.length];H.push(O),Y.push({sig:S,val:O,len:U})}if(Y.length===0)return{text:J,entries:0};let K=Y.map((O,D)=>D);K.sort((O,D)=>Y[D].len-Y[O].len);let X=J;for(let O=0;O<K.length;O++){let{sig:D,val:U}=Y[K[O]];X=X.replaceAll(U,D)}let B=`
3
+ ·legend· `;for(let O=0;O<Y.length;O++)B+=Y[O].sig+"="+Y[O].val+" ";return X+=B.slice(0,-1),{text:X,entries:Y.length}}//! Situation-aware cost model the "codeburn calculation." tanuki's verdict
4
+ //! compares token COUNTS, which equals real cost only when both sides bill at
5
+ //! the same per-token rate. They do not: on Anthropic a cache-read costs ~0.1×
6
+ //! a fresh input token, while image (visual) tokens bill AT the input rate. So
7
+ //! the cheapest technique depends on the SITUATION — is the text already cached
8
+ //! this turn, and which provider prices it. Only the RATIOS drive the verdict;
9
+ //! absolute $/Mtok (list prices, overridable via TANUKI_RATES) drive the
10
+ //! optional dollar figure. Image-token COUNTS here are Anthropic's 28px patch
11
+ //! grid, so the dollars are calibrated for Anthropic; other providers count
12
+ //! image tokens on a different (tile) model — flagged in `note`, never hidden.
13
+ function PQ(J){return J<0?-Math.round(-J):Math.round(J)}function hJ(J){return Math.round(J*1e6)/1e6}var AQ="2026-07",YJ={opus:{input:15,output:75,cacheReadMult:0.1,imageMult:1,anthropicGrid:!0},sonnet:{input:3,output:15,cacheReadMult:0.1,imageMult:1,anthropicGrid:!0},haiku:{input:1,output:5,cacheReadMult:0.1,imageMult:1,anthropicGrid:!0},gpt:{input:1.25,output:10,cacheReadMult:0.5,imageMult:1,anthropicGrid:!1},gemini:{input:1.25,output:10,cacheReadMult:0.25,imageMult:1,anthropicGrid:!1},default:{input:3,output:15,cacheReadMult:0.1,imageMult:1,anthropicGrid:!0}};function _Q(){let J=process.env.TANUKI_RATES;if(J===void 0||J.length===0)return YJ;try{let Q=JSON.parse(J),Z={...YJ};for(let[$,z]of Object.entries(Q))Z[$]={...Z[$]??YJ.default,...z};return Z}catch{return YJ}}function EQ(J){let Q=_Q(),Z=(J??"").toLowerCase();for(let $ of["opus","sonnet","haiku","gpt","gemini"])if(Z.includes($)&&Q[$]!==void 0)return{key:$,rate:Q[$]};return{key:"default",rate:Q.default}}function mJ(J,Q,Z){let{key:$,rate:z}=EQ(Z.model),G=Z.cached===!0,V=z.input/1e6,Y=V*(G?z.cacheReadMult:1),H=V*z.imageMult,K=J*Y,X=Q*H,B=H>0?Math.floor(J*Y/H):1/0,O=X<K?"PIPELINE":"TEXT",D=K>0?PQ((1-X/K)*100):0,U;if(!z.anthropicGrid)U=`image-token counts use Anthropic's 28px patch grid; ${$} prices images on a different (tile) model — treat dollars as approximate`;else if(G)U=`text priced at cache-read rate (${z.cacheReadMult}× input); imaging already-cached content usually loses`;return{model:$,cached:G,ratesAsOf:AQ,textUsd:hJ(K),imageUsd:hJ(X),cheaper:O,savedPct:D,breakevenImageTokens:B,note:U}}import{Buffer as uJ}from"node:buffer";var SQ=/\x1b\[[0-9;]*[A-Za-z]/g,jJ=/\b([0-9A-Za-z_]*(error|exception)s?|err|warn(ing)?s?|fail(s|ed|ure|ures)?|panic(s|ked)?|fatal|critical|traceback|denied|refused|timeouts?|timed.?out|assert(s|ed|ion|ions)?|segfault(s|ed)?)\b/i,CQ=/[0-9]{4}-[0-9]{2}-[0-9]{2}[T ][0-9]{2}:[0-9]{2}:[0-9]{2}([.,][0-9]+)?(Z|[+-][0-9]{2}:?[0-9]{2})?/g,LQ=/\b[0-9]{2}:[0-9]{2}:[0-9]{2}([.,][0-9]+)?\b/g,TQ=/\b[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}\b/gi,yQ=/\b[0-9a-f]{7,64}\b/gi,wQ=/\b[0-9]+(\.[0-9]+)?[ \t\u00a0]?(ms|us|µs|ns|s|m|h|%|[KMGT]i?B)?\b/gi,bQ=/[0-9a-f]/i,vQ=3,fQ=8,NJ=2,gJ=40;function kQ(J){if(!bQ.test(J))return J;let Q=J.replace(CQ,"<ts>");return Q=Q.replace(LQ,"<time>"),Q=Q.replace(TQ,"<uuid>"),Q=Q.replace(yQ,"<hex>"),Q.replace(wQ,"<n>")}function p(J){if(J===32)return!0;if(J<9)return!1;if(J<=13)return!0;if(J<133)return!1;return J===133||J===160||J===5760||J>=8192&&J<=8202||J===8232||J===8233||J===8239||J===8287||J===12288}function a(J){let Q=0,Z=J.length;while(Q<Z&&p(J.charCodeAt(Q)))Q++;while(Z>Q&&p(J.charCodeAt(Z-1)))Z--;return Q===0&&Z===J.length?J:J.slice(Q,Z)}function xQ(J,Q){let Z=0,$=J.length;while(Z<$&&p(J.charCodeAt(Z)))Z++;while($>Z&&p(J.charCodeAt($-1)))$--;let z=0;for(let G=Z;G<$&&z<Q;z++){let V=J.charCodeAt(G);G+=V>=55296&&V<=56319&&G+1<$?2:1}return z<Q}function hQ(J){let Q=0,Z=J.length;while(Q<Z&&p(J.charCodeAt(Q)))Q++;return J.charCodeAt(Q)===91&&J.charCodeAt(Q+1)===215}function mQ(J){let Q=[],Z=-1,$=!0,z=!1,G=!1,V=!0;for(let Y=0;Y<J.length;){let H=J.codePointAt(Y),K=H>65535?2:1,X=p(H);if(V){if(V=!1,X)Q.push("<v>")}if(X){if(Z>=0)Q.push($?J.slice(Z,Y):"<v>"),Z=-1;G=!0}else{if(z=!0,G=!1,Z<0)Z=Y,$=!0;if($){let B=H|32;if(B<97||B>122||H>127)$=!1}}Y+=K}if(Z>=0)Q.push($?J.slice(Z):"<v>");if(z&&G)Q.push("<v>");return Q.join(" ")}function t(J,Q){let Z=0,$=0,z=J.length;while(Z<z&&$<Q){let G=J.charCodeAt(Z);Z+=G>=55296&&G<=56319&&Z+1<z?2:1,$++}return Z>=z?J:J.slice(0,Z)}var uQ=/[.*+?^${}()|[\]\\]/g;function w(J,Q=null,Z=2){let $=Z,G=J.replace(SQ,"").split(`
14
+ `).map((q)=>{let F=q.endsWith("\r")?q.slice(0,-1):q,W=F.lastIndexOf("\r");return W===-1?F:F.slice(W+1)}),V=G.length,Y=V,H=Array(V),K=Array(V),X=0;for(let q=0;q<V;q++){H[q]=kQ(G[q]);let F=jJ.test(G[q]);if(K[q]=F,F)X++}let B=[],O=[],D=[],U=0,M=0;while(M<V){let q=0,F=0;for(let W=1;W<=fQ&&M+2*W<=V;W++){if(K[M+W-1])break;let I=1;J:for(;;){let N=M+I*W;if(N+W>V)break;for(let T=0;T<W;T++)if(K[N+T]||H[N+T]!==H[M+T])break J;I++}if(I>=vQ&&W*(I-1)>q*(F>0?F-1:0))q=W,F=I}if(q>0){for(let W=M;W<M+q;W++)B.push(G[W]),O.push(K[W]),D.push(H[W]);B.push(q===1?` [×${F} similar]`:` [×${F} similar ${q}-line blocks]`),O.push(!1),D.push(null),U++,M+=q*F}else B.push(G[M]),O.push(K[M]),D.push(H[M]),M++}let S=new Map,C=new Map,f=NJ+1,y=[],L=[],k=0,x=0;for(let q=0;q<B.length;q++){let F=B[q],W=O[q];if(W||hQ(F)||xQ(F,4)){y.push(F),L.push(W);continue}let I=D[q],N=S.get(I);if(N!==void 0){if(N.count++,N.count<=NJ)y.push(F),L.push(!1);else k++;continue}let T=mQ(I);S.set(I,{count:1,exemplar:F});let i=C.get(T);if(i!==void 0)if(i.count++,i.count<=f)y.push(F),L.push(!1);else x++;else C.set(T,{count:1,exemplar:F}),y.push(F),L.push(!1)}let u=[];for(let q of S.values())if(q.count>NJ)u.push([q.count,"exact",q.exemplar]);for(let q of C.values())if(q.count>f)u.push([q.count,"template",q.exemplar]);if(u.sort((q,F)=>F[0]-q[0]),u.length>gJ)u.length=gJ;if(k+x>0){let q=`── ${k+x} repeated lines suppressed (${k} exact ×N, ${x} same-template; first occurrences kept above) ──`;y.push(q),L.push(jJ.test(q));for(let[F,W,I]of u){let T=` ×${F}${W==="template"?" (template)":""} ${t(a(I),160)}`;y.push(T),L.push(jJ.test(T))}}let g;if(Q!=null){let q;try{q=new RegExp(Q,"i")}catch{q=new RegExp(Q.replace(uQ,"\\$&"),"i")}let F=y.length,W=new Uint8Array(F);for(let N=0;N<F;N++)if(L[N]||q.test(y[N])){let T=N>$?N-$:0,i=Math.min(N+$,F-1);W.fill(1,T,i+1)}g=[];let I=0;for(let N=0;N<F;N++)if(W[N]){if(I>0)g.push(`… ${I} lines omitted`),I=0;g.push(y[N])}else I++;if(I>0)g.push(`… ${I} lines omitted`)}else g=y;let fJ=g.join(`
15
+ `),kJ=uJ.byteLength(J),xJ=uJ.byteLength(fJ),FJ=(1-xJ/kJ)*100,WQ=J.length===0?0:FJ<0?-Math.round(-FJ):Math.round(FJ),jQ=u.map(([q,F,W])=>({count:q,exemplar:t(a(W),160),kind:F})),NQ={collapsedRuns:U,importantKept:X,origChars:kJ,origLines:Y,outChars:xJ,outLines:g.length,query:Q??null,savedPct:WQ,suppressedLines:k,templateSuppressed:x,topRepeats:jQ};return{distilled:fJ,stats:NQ}}var HJ=[["none","none","passthrough (baseline)"],["whitespace","lossless","trailing whitespace + blank-line runs collapsed; safe for code"],["prose","light","L1 + prose lines: collapse spaces, cut redundant filler phrases (code/IDs protected)"],["dense","medium","L2 + prose: drop articles & intensifiers"],["caveman","heavy","L3 + prose: telegraphic — drop function words; gist only, NOT verbatim"]];var b=(J)=>new RegExp(`(?<![\\p{Alphabetic}\\p{Mark}\\p{Decimal_Number}\\p{Connector_Punctuation}\\p{Join_Control}])(?:${J})(?![\\p{Alphabetic}\\p{Mark}\\p{Decimal_Number}\\p{Connector_Punctuation}\\p{Join_Control}])`,"giu"),IJ=[[b("in order to"),"to"],[b("due to the fact that"),"because"],[b("at this point in time"),"now"],[b("in the event that"),"if"],[b("for the purpose of"),"for"],[b("with regard to"),"about"],[b("a large number of"),"many"],[b("it is important to note that"),""],[b("please note that"),""],[b("as a matter of fact"),""],[b("in terms of"),"for"],[b("the fact that"),"that"]],gQ=new RegExp("(?<![\\p{Alphabetic}\\p{Mark}\\p{Decimal_Number}\\p{Connector_Punctuation}\\p{Join_Control}])(?:the|an|a)[\\t\\n\\x0B\\f\\r \\u0085\\u00A0\\u1680\\u2000-\\u200A\\u2028\\u2029\\u202F\\u205F\\u3000]+","giu"),dQ=new RegExp("(?<![\\p{Alphabetic}\\p{Mark}\\p{Decimal_Number}\\p{Connector_Punctuation}\\p{Join_Control}])(?:very|really|just|actually|basically|simply|quite|rather|essentially|literally)[\\t\\n\\x0B\\f\\r \\u0085\\u00A0\\u1680\\u2000-\\u200A\\u2028\\u2029\\u202F\\u205F\\u3000]+","giu"),lQ=new RegExp("(?<![\\p{Alphabetic}\\p{Mark}\\p{Decimal_Number}\\p{Connector_Punctuation}\\p{Join_Control}])(?:is|are|was|were|am|be|been|being|do|does|did|have|has|had|will|would|shall|should|can|could|may|might|of|to|in|on|at|for|with|that|this|these|those|it|its|there|here)(?![\\p{Alphabetic}\\p{Mark}\\p{Decimal_Number}\\p{Connector_Punctuation}\\p{Join_Control}])[\\t\\n\\x0B\\f\\r \\u0085\\u00A0\\u1680\\u2000-\\u200A\\u2028\\u2029\\u202F\\u205F\\u3000]*","giu"),dJ=/ {2,}/g,pQ=new RegExp("[\\t\\n\\x0B\\f\\r \\u0085\\u00A0\\u1680\\u2000-\\u200A\\u2028\\u2029\\u202F\\u205F\\u3000]+([.,;:!?])","gu"),nQ=/\n{3,}/g;function RJ(J){if(J===32||J>=9&&J<=13)return!0;if(J<133)return!1;return J===133||J===160||J===5760||J>=8192&&J<=8202||J===8232||J===8233||J===8239||J===8287||J===12288}function cQ(J){let Q=0,Z=J.length;while(Q<Z){let $=J.codePointAt(Q);if(!RJ($))break;Q+=$>65535?2:1}while(Z>Q){let $=J.charCodeAt(Z-1);if(!RJ($))break;Z--}return Q===0&&Z===J.length?J:J.slice(Q,Z)}function oQ(J){if(J.length===0)return!1;let Q=J.charCodeAt(0);if(Q===32||Q===9)return!0;let Z=0,$=0,z=0,G=!1;for(let V=0;V<J.length;){let Y=J.codePointAt(V);if(V+=Y>65535?2:1,Z++,RJ(Y)){z=0;continue}if(z++,z>=24)G=!0;if(Y>=48&&Y<=57||Y>=65&&Y<=90||Y>=97&&Y<=122)continue;switch(Y){case 46:case 44:case 59:case 58:case 39:case 34:case 33:case 63:case 40:case 41:case 45:continue}$++}if($/Z>0.3)return!0;return G}function iQ(J,Q){let Z=J.replace(dJ," ");for(let z=0;z<IJ.length;z++)Z=Z.replace(IJ[z][0],IJ[z][1]);if(Q>=3)Z=Z.replace(gQ,""),Z=Z.replace(dQ,"");if(Q>=4)Z=Z.replace(lQ,"");Z=Z.replace(dJ," "),Z=cQ(Z.replace(pQ,"$1"));let $=Z.charCodeAt(0);if($>=97&&$<=122)Z=String.fromCharCode($-32)+Z.slice(1);return Z}function s(J,Q){let Z=Math.min(Q,4);if(Z===0)return{compressed:J,protectedLines:0,level:Z};let $=0,z=J.split(`
16
+ `),G=Array(z.length);for(let Y=0;Y<z.length;Y++){let H=z[Y],K=H.length;while(K>0){let B=H.charCodeAt(K-1);if(B!==32&&B!==9)break;K--}let X=K===H.length?H:H.slice(0,K);if(Z===1){G[Y]=X;continue}if(oQ(X)){$++,G[Y]=X;continue}G[Y]=iQ(X,Z)}return{compressed:G.join(`
17
+ `).replace(nQ,`
8
18
 
9
- `),protectedLines:$,level:Z}}import{appendFileSync as DZ,mkdirSync as qZ}from"node:fs";import{dirname as MZ}from"node:path";import ZQ from"node:http";import FZ from"node:https";import{URL as WZ}from"node:url";import{readFileSync as AJ}from"node:fs";import{inflateSync as dQ}from"node:zlib";//! Full-BMP glyph atlas (Spleen 5x8 for ASCII/code + Unifont fallback),
19
+ `),protectedLines:$,level:Z}}import{appendFileSync as IZ,mkdirSync as RZ}from"node:fs";import{dirname as PZ}from"node:path";import GQ from"node:http";import AZ from"node:https";import{URL as _Z}from"node:url";import{readFileSync as AJ}from"node:fs";import{inflateSync as rQ}from"node:zlib";//! Full-BMP glyph atlas (Spleen 5x8 for ASCII/code + Unifont fallback),
10
20
  //! extracted from pxpipe's generated gray atlas by `tools/gen-glyphs.mjs`.
11
21
  //!
12
22
  //! Codepoints + wide flags load eagerly (~175 KB, needed for wrap math);
13
23
  //! coverage pixels stay zlib-packed on disk and decompress lazily on the
14
24
  //! first blit, so `estimate` never pays for them.
15
- var h=5,e=8,d=AJ(new URL("../assets/glyphs.cps",import.meta.url)),YJ=AJ(new URL("../assets/glyphs.wide",import.meta.url)),uJ=(()=>{let J=d.byteLength>>>2;if((d.byteOffset&3)===0)return new Uint32Array(d.buffer,d.byteOffset,J);return new Uint32Array(d.buffer.slice(d.byteOffset,d.byteOffset+(J<<2)))})(),lQ=(()=>{let J=new Uint32Array(YJ.length),Q=0;for(let Z=0;Z<YJ.length;Z++)J[Z]=Q,Q+=(YJ[Z]===1?2*h:h)*e;return J})(),RJ=null;function JJ(J){let Q=0,Z=uJ.length-1;while(Q<=Z){let $=Q+Z>>>1,V=uJ[$];if(V<J)Q=$+1;else if(V>J)Z=$-1;else return $}return-1}function n(J){return YJ[J]===1}function PJ(J){if(RJ===null)RJ=dQ(AJ(new URL("../assets/glyphs.pix.z",import.meta.url)));let Q=lQ[J],Z=n(J)?2*h:h;return RJ.subarray(Q,Q+Z*e)}function gJ(J,Q,Z){let $=PJ(J),V=n(J)?2*h:h;return pQ($,V,e,Q,Z)}function pQ(J,Q,Z,$,V){let z=new Uint8Array($*V),G=Q/$,Y=Z/V;for(let H=0;H<V;H++){let K=H*Y,B=(H+1)*Y;for(let U=0;U<$;U++){let O=U*G,X=(U+1)*G,D=0,M=0,E=Math.min(Math.ceil(B),Z);for(let S=Math.floor(K);S<E;S++){let k=Math.min(S+1,B)-Math.max(S,K);if(k<=0)continue;let y=Math.min(Math.ceil(X),Q);for(let C=Math.floor(O);C<y;C++){let x=Math.min(C+1,X)-Math.max(C,O);if(x<=0)continue;let f=x*k;D+=f*J[S*Q+C],M+=f}}z[H*$+U]=M>0?Math.min(255,Math.max(0,Math.round(D/M))):0}}return z}import{deflateSync as nQ}from"node:zlib";//! Minimal grayscale PNG encoder (bit depth 8, color type 0), mirroring
25
+ var h=5,e=8,d=AJ(new URL("../assets/glyphs.cps",import.meta.url)),KJ=AJ(new URL("../assets/glyphs.wide",import.meta.url)),lJ=(()=>{let J=d.byteLength>>>2;if((d.byteOffset&3)===0)return new Uint32Array(d.buffer,d.byteOffset,J);return new Uint32Array(d.buffer.slice(d.byteOffset,d.byteOffset+(J<<2)))})(),aQ=(()=>{let J=new Uint32Array(KJ.length),Q=0;for(let Z=0;Z<KJ.length;Z++)J[Z]=Q,Q+=(KJ[Z]===1?2*h:h)*e;return J})(),PJ=null;function JJ(J){let Q=0,Z=lJ.length-1;while(Q<=Z){let $=Q+Z>>>1,z=lJ[$];if(z<J)Q=$+1;else if(z>J)Z=$-1;else return $}return-1}function n(J){return KJ[J]===1}function _J(J){if(PJ===null)PJ=rQ(AJ(new URL("../assets/glyphs.pix.z",import.meta.url)));let Q=aQ[J],Z=n(J)?2*h:h;return PJ.subarray(Q,Q+Z*e)}function pJ(J,Q,Z){let $=_J(J),z=n(J)?2*h:h;return tQ($,z,e,Q,Z)}function tQ(J,Q,Z,$,z){let G=new Uint8Array($*z),V=Q/$,Y=Z/z;for(let H=0;H<z;H++){let K=H*Y,X=(H+1)*Y;for(let B=0;B<$;B++){let O=B*V,D=(B+1)*V,U=0,M=0,S=Math.min(Math.ceil(X),Z);for(let C=Math.floor(K);C<S;C++){let f=Math.min(C+1,X)-Math.max(C,K);if(f<=0)continue;let y=Math.min(Math.ceil(D),Q);for(let L=Math.floor(O);L<y;L++){let k=Math.min(L+1,D)-Math.max(L,O);if(k<=0)continue;let x=k*f;U+=x*J[C*Q+L],M+=x}}G[H*$+B]=M>0?Math.min(255,Math.max(0,Math.round(U/M))):0}}return G}import{deflateSync as sQ}from"node:zlib";//! Minimal grayscale PNG encoder (bit depth 8, color type 0), mirroring
16
26
  //! pxpipe's png.ts: IHDR + one IDAT (zlib) + IEND, filter byte 0 per row.
17
- var cQ=(()=>{let J=new Uint32Array(256);for(let Q=0;Q<256;Q++){let Z=Q;for(let $=0;$<8;$++)Z=(Z&1)!==0?3988292384^Z>>>1:Z>>>1;J[Q]=Z>>>0}return J})();function _J(J,Q,Z,$){let V=$.length;J[Q]=V>>>24&255,J[Q+1]=V>>>16&255,J[Q+2]=V>>>8&255,J[Q+3]=V&255;let z=Q+4;for(let H=0;H<4;H++)J[z+H]=Z.charCodeAt(H);J.set($,z+4);let G=4294967295;for(let H=z;H<z+4+V;H++)G=cQ[(G^J[H])&255]^G>>>8;G=~G>>>0;let Y=z+4+V;return J[Y]=G>>>24&255,J[Y+1]=G>>>16&255,J[Y+2]=G>>>8&255,J[Y+3]=G&255,Y+4}function dJ(J,Q,Z){let $=new Uint8Array(Z*(Q+1));for(let H=0,K=0,B=0;H<Z;H++)$[K++]=0,$.set(J.subarray(B,B+Q),K),K+=Q,B+=Q;let V=nQ($,{level:6}),z=new Uint8Array(33+(12+V.length)+12);z[0]=137,z[1]=80,z[2]=78,z[3]=71,z[4]=13,z[5]=10,z[6]=26,z[7]=10;let G=new Uint8Array(13);G[0]=Q>>>24&255,G[1]=Q>>>16&255,G[2]=Q>>>8&255,G[3]=Q&255,G[4]=Z>>>24&255,G[5]=Z>>>16&255,G[6]=Z>>>8&255,G[7]=Z&255,G[8]=8,G[9]=0;let Y=_J(z,8,"IHDR",G);return Y=_J(z,Y,"IDAT",V),_J(z,Y,"IEND",new Uint8Array(0)),z}//! Stage 2: the `pxpipe` imaging engine, ported from pxpipe's render.ts
27
+ var eQ=(()=>{let J=new Uint32Array(256);for(let Q=0;Q<256;Q++){let Z=Q;for(let $=0;$<8;$++)Z=(Z&1)!==0?3988292384^Z>>>1:Z>>>1;J[Q]=Z>>>0}return J})();function EJ(J,Q,Z,$){let z=$.length;J[Q]=z>>>24&255,J[Q+1]=z>>>16&255,J[Q+2]=z>>>8&255,J[Q+3]=z&255;let G=Q+4;for(let H=0;H<4;H++)J[G+H]=Z.charCodeAt(H);J.set($,G+4);let V=4294967295;for(let H=G;H<G+4+z;H++)V=eQ[(V^J[H])&255]^V>>>8;V=~V>>>0;let Y=G+4+z;return J[Y]=V>>>24&255,J[Y+1]=V>>>16&255,J[Y+2]=V>>>8&255,J[Y+3]=V&255,Y+4}function nJ(J,Q,Z){let $=new Uint8Array(Z*(Q+1));for(let H=0,K=0,X=0;H<Z;H++)$[K++]=0,$.set(J.subarray(X,X+Q),K),K+=Q,X+=Q;let z=sQ($,{level:6}),G=new Uint8Array(33+(12+z.length)+12);G[0]=137,G[1]=80,G[2]=78,G[3]=71,G[4]=13,G[5]=10,G[6]=26,G[7]=10;let V=new Uint8Array(13);V[0]=Q>>>24&255,V[1]=Q>>>16&255,V[2]=Q>>>8&255,V[3]=Q&255,V[4]=Z>>>24&255,V[5]=Z>>>16&255,V[6]=Z>>>8&255,V[7]=Z&255,V[8]=8,V[9]=0;let Y=EJ(G,8,"IHDR",V);return Y=EJ(G,Y,"IDAT",z),EJ(G,Y,"IEND",new Uint8Array(0)),G}//! Stage 2: the `pxpipe` imaging engine, ported from pxpipe's render.ts
18
28
  //! production dense path (bare 5x8 AA cell, 312 cols, 1568x728 pages).
19
29
  //! Glyphs cover BMP (pxpipe's atlas: Spleen for ASCII/code, Unifont fallback)
20
30
  //! PLUS the astral planes (unifont_upper, incl. emoji) — beyond pxpipe, which
@@ -29,19 +39,19 @@ var cQ=(()=>{let J=new Uint32Array(256);for(let Q=0;Q<256;Q++){let Z=Q;for(let $
29
39
  //! * `font` — `Tiny` renders the same atlas box-filtered into a 4x6 cell
30
40
  //! (390 cols x 120 rows/page), ~40% fewer image-tokens; opt-in,
31
41
  //! transcription-accuracy gated.
32
- var QJ=4,HJ=4,oQ=1568,iQ=728,KJ="↵",aQ="⏎",BJ="→",rQ="⇢",EJ="⇥",tQ="⇨",sQ=9647,lJ=4,eQ=3,pJ="0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz",JZ=/\n{4,}/g;function v(J){return J.length===4&&J.replace(/[A-Z]/g,(Q)=>Q.toLowerCase())==="tiny"?"tiny":"normal"}function iJ(J){let Q=J==="tiny"?4:h,Z=J==="tiny"?6:e,$=Math.floor((oQ-2*QJ)/Q),V=Math.floor((iQ-2*HJ)/Z);return{cw:Q,ch:Z,cols:$,maxLines:V,maxChars:$*V}}var QZ=(()=>{let J=new Uint8Array(128);for(let Q=0;Q<128;Q++){let Z=JJ(Q);J[Q]=Z>=0&&n(Z)?2:1}return J})();function SJ(J){if(J<128)return QZ[J];let Q=JJ(J);return Q>=0&&n(Q)?2:1}function ZZ(J){let Q=0;for(let Z=0;Z<J.length;Z++){let $=J.charCodeAt(Z);if($>=55296&&$<56320&&Z+1<J.length){let V=J.charCodeAt(Z+1);if(V>=56320&&V<57344)Z++}Q++}return Q}function CJ(J){let Q=J.split(`
33
- `);for(let Z=0;Z<Q.length;Z++){let $=Q[Z],V=$.length;while(V>0){let z=$.charCodeAt(V-1);if(z!==32&&z!==9)break;V--}if(V!==$.length)Q[Z]=$.slice(0,V)}return Q.join(`
34
- `).replace(JZ,`
42
+ var QJ=4,XJ=4,JZ=1568,QZ=728,OJ="↵",ZZ="⏎",BJ="→",$Z="⇢",SJ="⇥",zZ="⇨",GZ=9647,cJ=4,VZ=3,oJ="0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz",YZ=/\n{4,}/g;function v(J){return J.length===4&&J.replace(/[A-Z]/g,(Q)=>Q.toLowerCase())==="tiny"?"tiny":"normal"}function tJ(J){let Q=J==="tiny"?4:h,Z=J==="tiny"?6:e,$=Math.floor((JZ-2*QJ)/Q),z=Math.floor((QZ-2*XJ)/Z);return{cw:Q,ch:Z,cols:$,maxLines:z,maxChars:$*z}}var HZ=(()=>{let J=new Uint8Array(128);for(let Q=0;Q<128;Q++){let Z=JJ(Q);J[Q]=Z>=0&&n(Z)?2:1}return J})();function CJ(J){if(J<128)return HZ[J];let Q=JJ(J);return Q>=0&&n(Q)?2:1}function KZ(J){let Q=0;for(let Z=0;Z<J.length;Z++){let $=J.charCodeAt(Z);if($>=55296&&$<56320&&Z+1<J.length){let z=J.charCodeAt(Z+1);if(z>=56320&&z<57344)Z++}Q++}return Q}function LJ(J){let Q=J.split(`
43
+ `);for(let Z=0;Z<Q.length;Z++){let $=Q[Z],z=$.length;while(z>0){let G=$.charCodeAt(z-1);if(G!==32&&G!==9)break;z--}if(z!==$.length)Q[Z]=$.slice(0,z)}return Q.join(`
44
+ `).replace(YZ,`
35
45
 
36
46
 
37
- `)}function aJ(J){if(!J.includes("\t"))return J;let Q="",Z=0;for(let $ of J)if($==="\t"){let V=lJ-Z%lJ;Q+=BJ;for(let z=1;z<V;z++)Q+=" ";Z+=V}else Q+=$,Z+=SJ($.codePointAt(0));return Q}function $Z(J){let Q=J.includes("\t")?J.replaceAll("\t",BJ):J,Z=0;while(Z<Q.length&&Q.charCodeAt(Z)===32)Z++;if(Z>=eQ&&Z<pJ.length)return EJ+pJ[Z]+Q.slice(Z);return Q}function rJ(J){return J.includes(KJ)?J.replaceAll(KJ,aQ):J}function VZ(J){let Q=rJ(J);if(Q.includes(BJ))Q=Q.replaceAll(BJ,rQ);if(Q.includes(EJ))Q=Q.replaceAll(EJ,tQ);return Q}function zZ(J){let Q=CJ(J).split(`
38
- `);for(let Z=0;Z<Q.length;Z++)Q[Z]=aJ(Q[Z]);return Q.join(KJ)}function GZ(J){let Q=CJ(J).split(`
39
- `);for(let Z=0;Z<Q.length;Z++)Q[Z]=$Z(Q[Z]);return Q.join(KJ)}function YZ(J,Q){let Z=[],$=CJ(J);for(let V of $.split(`
40
- `)){let z=aJ(V);if(z.length===0){Z.push("");continue}let G="",Y=0;for(let H of z){let K=SJ(H.codePointAt(0));if(Y+K>Q)Z.push(G),G=H,Y=K;else G+=H,Y+=K}if(G.length!==0)Z.push(G)}return Z}function HZ(J,Q,Z){let $=[],V=[],z=0;for(let G of J){let Y=ZZ(G),H=Y+(V.length!==0?1:0);if(V.length!==0&&(V.length>=Q||z+H>Z))$.push(V),V=[],z=0;z+=Y+(V.length!==0?1:0),V.push(G)}if(V.length!==0)$.push(V);return $}function tJ(J){if(J<32)return!0;if(J>=127&&J<=159)return!0;if(J>=768&&J<=879)return!0;if(J===8203||J===8204||J===8205||J===8288||J===65279)return!0;if(J>=65024&&J<=65039)return!0;if(J>=917760&&J<=917999)return!0;return!1}function KZ(J){let Q=null,Z=0;for(let $ of J){let V=$.codePointAt(0);if(JJ(V)<0&&!tJ(V)){if(Q===null)Q=J.slice(0,Z);Q+=`[U+${V.toString(16).toUpperCase()}]`}else if(Q!==null)Q+=$;Z+=$.length}return Q??J}function sJ(J,Q,Z,$){let V=Q?Z?GZ(VZ(J)):zZ(rJ(J)):J;return HZ(YZ(KZ(V),$.cols),$.maxLines,$.maxChars)}function eJ(J,Q,Z){if(!Z)return 2*QJ+Q.cols*Q.cw;let $=0;for(let G of J){let Y=0;for(let H of G)Y+=SJ(H.codePointAt(0));if(Y>Q.cols)Y=Q.cols;if(Y>$)$=Y}let V=2*QJ+$*Q.cw,z=2*QJ+Q.cw;return V>z?V:z}var nJ=new Map;function cJ(J,Q,Z,$,V,z,G){let Y=JJ(V);if(Y<0)return 0;let H=n(Y),K=H?2*z.cw:z.cw,B;if(G==="normal")B=PJ(Y);else{let U=nJ.get(Y);if(U===void 0)U=gJ(Y,K,z.ch),nJ.set(Y,U);B=U}for(let U=0;U<z.ch;U++){let O=($+U)*Q+Z,X=U*K;for(let D=0;D<K;D++){let M=B[X+D];if(M>0){let E=O+D;if(M>J[E])J[E]=M}}}return H?2:1}function BZ(J,Q,Z,$){let V=eJ(J,Q,Z),z=2*HJ+J.length*Q.ch,G=new Uint8Array(V*z),Y=0;for(let H=0;H<J.length;H++){let K=HJ+H*Q.ch,B=0;for(let U of J[H]){if(B>=Q.cols)break;let O=QJ+B*Q.cw,X=cJ(G,V,O,K,U.codePointAt(0),Q,$);if(X===0){if(X=1,tJ(U.codePointAt(0)));else if(Y++,U!==" ")cJ(G,V,O,K,sQ,Q,$)}B+=X}}for(let H=0;H<G.length;H++)G[H]=255-G[H];return{png:dJ(G,V,z),width:V,height:z,dropped:Y}}function m(J,Q,Z,$){let V=iJ($),z=sJ(J,Q,Z,V).map((K)=>BZ(K,V,Z,$)),G=0,Y=0,H=0;for(let K of z)G+=K.width*K.height,Y+=JQ(K.width,K.height),H+=K.dropped;return{pages:z,pixels:G,tokens:Y,dropped:H}}function OJ(J,Q,Z,$){let V=iJ($),z=sJ(J,Q,Z,V),G=0,Y=0;for(let H of z){let K=eJ(H,V,Z),B=2*HJ+H.length*V.ch;G+=K*B,Y+=JQ(K,B)}return{pages:z.length,pixels:G,tokens:Y}}var oJ=28;function JQ(J,Q){return Math.ceil(J/oJ)*Math.ceil(Q/oJ)}import{readFileSync as OZ}from"node:fs";import{join as UZ}from"node:path";//! pxpipe measurement-log summary (~/.pxpipe/events.jsonl), same math as the
47
+ `)}function sJ(J){if(!J.includes("\t"))return J;let Q="",Z=0;for(let $ of J)if($==="\t"){let z=cJ-Z%cJ;Q+=BJ;for(let G=1;G<z;G++)Q+=" ";Z+=z}else Q+=$,Z+=CJ($.codePointAt(0));return Q}function XZ(J){let Q=J.includes("\t")?J.replaceAll("\t",BJ):J,Z=0;while(Z<Q.length&&Q.charCodeAt(Z)===32)Z++;if(Z>=VZ&&Z<oJ.length)return SJ+oJ[Z]+Q.slice(Z);return Q}function eJ(J){return J.includes(OJ)?J.replaceAll(OJ,ZZ):J}function OZ(J){let Q=eJ(J);if(Q.includes(BJ))Q=Q.replaceAll(BJ,$Z);if(Q.includes(SJ))Q=Q.replaceAll(SJ,zZ);return Q}function BZ(J){let Q=LJ(J).split(`
48
+ `);for(let Z=0;Z<Q.length;Z++)Q[Z]=sJ(Q[Z]);return Q.join(OJ)}function DZ(J){let Q=LJ(J).split(`
49
+ `);for(let Z=0;Z<Q.length;Z++)Q[Z]=XZ(Q[Z]);return Q.join(OJ)}function UZ(J,Q){let Z=[],$=LJ(J);for(let z of $.split(`
50
+ `)){let G=sJ(z);if(G.length===0){Z.push("");continue}let V="",Y=0;for(let H of G){let K=CJ(H.codePointAt(0));if(Y+K>Q)Z.push(V),V=H,Y=K;else V+=H,Y+=K}if(V.length!==0)Z.push(V)}return Z}function qZ(J,Q,Z){let $=[],z=[],G=0;for(let V of J){let Y=KZ(V),H=Y+(z.length!==0?1:0);if(z.length!==0&&(z.length>=Q||G+H>Z))$.push(z),z=[],G=0;G+=Y+(z.length!==0?1:0),z.push(V)}if(z.length!==0)$.push(z);return $}function JQ(J){if(J<32)return!0;if(J>=127&&J<=159)return!0;if(J>=768&&J<=879)return!0;if(J===8203||J===8204||J===8205||J===8288||J===65279)return!0;if(J>=65024&&J<=65039)return!0;if(J>=917760&&J<=917999)return!0;return!1}function MZ(J){let Q=null,Z=0;for(let $ of J){let z=$.codePointAt(0);if(JJ(z)<0&&!JQ(z)){if(Q===null)Q=J.slice(0,Z);Q+=`[U+${z.toString(16).toUpperCase()}]`}else if(Q!==null)Q+=$;Z+=$.length}return Q??J}function QQ(J,Q,Z,$){let z=Q?Z?DZ(OZ(J)):BZ(eJ(J)):J;return qZ(UZ(MZ(z),$.cols),$.maxLines,$.maxChars)}function ZQ(J,Q,Z){if(!Z)return 2*QJ+Q.cols*Q.cw;let $=0;for(let V of J){let Y=0;for(let H of V)Y+=CJ(H.codePointAt(0));if(Y>Q.cols)Y=Q.cols;if(Y>$)$=Y}let z=2*QJ+$*Q.cw,G=2*QJ+Q.cw;return z>G?z:G}var iJ=new Map;function rJ(J,Q,Z,$,z,G,V){let Y=JJ(z);if(Y<0)return 0;let H=n(Y),K=H?2*G.cw:G.cw,X;if(V==="normal")X=_J(Y);else{let B=iJ.get(Y);if(B===void 0)B=pJ(Y,K,G.ch),iJ.set(Y,B);X=B}for(let B=0;B<G.ch;B++){let O=($+B)*Q+Z,D=B*K;for(let U=0;U<K;U++){let M=X[D+U];if(M>0){let S=O+U;if(M>J[S])J[S]=M}}}return H?2:1}function FZ(J,Q,Z,$){let z=ZQ(J,Q,Z),G=2*XJ+J.length*Q.ch,V=new Uint8Array(z*G),Y=0;for(let H=0;H<J.length;H++){let K=XJ+H*Q.ch,X=0;for(let B of J[H]){if(X>=Q.cols)break;let O=QJ+X*Q.cw,D=rJ(V,z,O,K,B.codePointAt(0),Q,$);if(D===0){if(D=1,JQ(B.codePointAt(0)));else if(Y++,B!==" ")rJ(V,z,O,K,GZ,Q,$)}X+=D}}for(let H=0;H<V.length;H++)V[H]=255-V[H];return{png:nJ(V,z,G),width:z,height:G,dropped:Y}}function m(J,Q,Z,$){let z=tJ($),G=QQ(J,Q,Z,z).map((K)=>FZ(K,z,Z,$)),V=0,Y=0,H=0;for(let K of G)V+=K.width*K.height,Y+=$Q(K.width,K.height),H+=K.dropped;return{pages:G,pixels:V,tokens:Y,dropped:H}}function DJ(J,Q,Z,$){let z=tJ($),G=QQ(J,Q,Z,z),V=0,Y=0;for(let H of G){let K=ZQ(H,z,Z),X=2*XJ+H.length*z.ch;V+=K*X,Y+=$Q(K,X)}return{pages:G.length,pixels:V,tokens:Y}}var aJ=28;function $Q(J,Q){return Math.ceil(J/aJ)*Math.ceil(Q/aJ)}import{readFileSync as WZ}from"node:fs";import{join as jZ}from"node:path";//! pxpipe measurement-log summary (~/.pxpipe/events.jsonl), same math as the
41
51
  //! node MCP: actual = every way input bytes get billed (input + cache reads +
42
52
  //! cache creates) — ignoring cache_read would fake the savings.
43
- class ZJ{value;constructor(J){this.value=J}}function TJ(){let J=process.env.TANUKI_EVENTS;if(J!==void 0)return J;let Q=process.env.HOME??"";return UZ(Q,".pxpipe","events.jsonl")}function c(J){return typeof J==="number"&&Number.isSafeInteger(J)&&J>=0?J:0}function XZ(J){return J<0?-Math.round(-J):Math.round(J)}function QQ(){let J=TJ(),Q;try{Q=OZ(J,"utf8")}catch{return{available:!1,note:`no ${J} yet`}}let Z=0,$=0,V=0,z=0,G=0,Y=0;for(let K of Q.split(`
44
- `)){if(K.trim().length===0)continue;let B;try{B=JSON.parse(K)}catch{continue}Z+=1;let U=B!==null&&typeof B==="object"&&!Array.isArray(B)?B:{};if(U.compressed===!0)$+=1,V+=c(U.orig_chars),z+=c(U.image_count);G+=c(U.baseline_tokens),Y+=c(U.input_tokens)+c(U.cache_read_tokens)+c(U.cache_create_tokens)}let H=G>0&&Y>0?new ZJ(XZ((1-Y/G)*1000)/10):null;return{available:!0,requests:Z,compressedRequests:$,imagedChars:V,imagesEmitted:z,baselineTokens:G,actualInputTokens:Y,estInputSavedPct:H}}//! Implicit mode: a local Anthropic middlebox, the pxpipe deployment shape
53
+ class ZJ{value;constructor(J){this.value=J}}function TJ(){let J=process.env.TANUKI_EVENTS;if(J!==void 0)return J;let Q=process.env.HOME??"";return jZ(Q,".pxpipe","events.jsonl")}function c(J){return typeof J==="number"&&Number.isSafeInteger(J)&&J>=0?J:0}function NZ(J){return J<0?-Math.round(-J):Math.round(J)}function zQ(){let J=TJ(),Q;try{Q=WZ(J,"utf8")}catch{return{available:!1,note:`no ${J} yet`}}let Z=0,$=0,z=0,G=0,V=0,Y=0;for(let K of Q.split(`
54
+ `)){if(K.trim().length===0)continue;let X;try{X=JSON.parse(K)}catch{continue}Z+=1;let B=X!==null&&typeof X==="object"&&!Array.isArray(X)?X:{};if(B.compressed===!0)$+=1,z+=c(B.orig_chars),G+=c(B.image_count);V+=c(B.baseline_tokens),Y+=c(B.input_tokens)+c(B.cache_read_tokens)+c(B.cache_create_tokens)}let H=V>0&&Y>0?new ZJ(NZ((1-Y/V)*1000)/10):null;return{available:!0,requests:Z,compressedRequests:$,imagedChars:z,imagesEmitted:G,baselineTokens:V,actualInputTokens:Y,estInputSavedPct:H}}//! Implicit mode: a local Anthropic middlebox, the pxpipe deployment shape
45
55
  //! without pxpipe's structural flaw. Rules that keep it injection-shaped-free:
46
56
  //!
47
57
  //! 1. The system prompt and tool definitions are NEVER touched.
@@ -57,12 +67,12 @@ class ZJ{value;constructor(J){this.value=J}}function TJ(){let J=process.env.TANU
57
67
  //!
58
68
  //! Responses stream through untouched; usage is scraped from the stream for
59
69
  //! the ~/.pxpipe/events.jsonl savings log (same format tanuki_stats reads).
60
- var o={level:0,distill:!1,codebook:!1,font:"normal",minChars:4000,ratio:0.75,minSave:300,maxPages:20};function LJ(J){let Q=0;for(let Z=0;Z<J.length;Z++){let $=J.charCodeAt(Z);if($<55296||$>56319)Q++}return Q}function jZ(J,Q){let Z=LJ(J);if(Z<Q.minChars)return null;let $=J;if(Q.distill)$=w($,null,2).distilled;let V=0;if(Q.codebook){let K=a($);$=K.text,V=K.entries}if(Q.level>0)$=s($,Q.level).compressed;let z=Math.round(Z/4),G=m($,!0,!0,Q.font);if(G.pages.length>Q.maxPages)return null;if(G.tokens>z*Q.ratio||z-G.tokens<Q.minSave)return null;let H=[{type:"text",text:`[tanuki-context: ${Z} chars imaged in place as ${G.pages.length} PNG page(s), ~${G.tokens} vs ~${z} text tokens. ↵=newline →=tab ⇥N=indent`+(V>0?`; ·legend· line maps ${V} sigils`:"")+"]"}];for(let K of G.pages)H.push({type:"image",source:{type:"base64",media_type:"image/png",data:Buffer.from(K.png.buffer,K.png.byteOffset,K.png.byteLength).toString("base64")}});return{blocks:H,origChars:Z,pages:G.pages.length,savedTokens:z-G.tokens}}function UJ(J){return J!==null&&typeof J==="object"&&!Array.isArray(J)}function NZ(J,Q){let Z;try{Z=JSON.parse(J)}catch{return null}if(!UJ(Z)||!Array.isArray(Z.messages))return null;let $=0,V=0,z=0,G=0,Y=new Map,H=(K)=>{let B=Y.get(K),U;if(B!==void 0){let O=LJ(K),X=`[tanuki-context: ${O} chars, byte-identical to a block imaged above (${B} PNG page(s)); not repeated]`;U={blocks:[{type:"text",text:X}],origChars:O,pages:0,savedTokens:Math.round(O/4)-Math.round(LJ(X)/4)}}else if(U=jZ(K,Q),U)Y.set(K,U.pages);if(U)$++,V+=U.origChars,z+=U.pages,G+=U.savedTokens;return U};for(let K=0;K<Z.messages.length-1;K++){let B=Z.messages[K];if(!UJ(B)||B.role!=="user")continue;if(typeof B.content==="string"){let O=H(B.content);if(O)B.content=O.blocks;continue}if(!Array.isArray(B.content))continue;let U=[];for(let O of B.content){if(!UJ(O)||O.cache_control!==void 0){U.push(O);continue}if(O.type==="text"&&typeof O.text==="string"){let X=H(O.text);if(X)U.push(...X.blocks);else U.push(O);continue}if(O.type==="tool_result"){if(typeof O.content==="string"){let X=H(O.content);if(X)O.content=X.blocks}else if(Array.isArray(O.content)){let X=[];for(let D of O.content){if(UJ(D)&&D.type==="text"&&typeof D.text==="string"&&D.cache_control===void 0){let M=H(D.text);if(M){X.push(...M.blocks);continue}}X.push(D)}O.content=X}}U.push(O)}B.content=U}if($===0)return null;return{body:JSON.stringify(Z),imagedBlocks:$,origChars:V,imageCount:z,savedTokens:G}}function IZ(J){let Q=(Z)=>{let $=Z.exec(J);return $?Number($[1]):0};return{input:Q(/"input_tokens"\s*:\s*(\d+)/),cacheRead:Q(/"cache_read_input_tokens"\s*:\s*(\d+)/),cacheCreate:Q(/"cache_creation_input_tokens"\s*:\s*(\d+)/)}}function RZ(J){try{let Q=TJ();qZ(MZ(Q),{recursive:!0}),DZ(Q,JSON.stringify(J)+`
61
- `)}catch{}}function $Q(J){let Q=new WZ(J.upstream),Z=Q.protocol==="https:"?FZ:ZQ,$=ZQ.createServer((V,z)=>{let G=[];V.on("data",(Y)=>G.push(Y)),V.on("end",()=>{let Y=Buffer.concat(G),H=V.method==="POST"&&(V.url??"").startsWith("/v1/messages")&&!(V.url??"").includes("count_tokens")&&V.headers["content-encoding"]===void 0,K=null;if(H){if(K=NZ(Y.toString("utf8"),J),K)Y=Buffer.from(K.body,"utf8")}let B={...V.headers};if(delete B.host,delete B.connection,B["content-length"]=String(Y.length),H)delete B["accept-encoding"];let U=Z.request({protocol:Q.protocol,hostname:Q.hostname,port:Q.port||(Q.protocol==="https:"?443:80),path:V.url,method:V.method,headers:B},(O)=>{if(z.writeHead(O.statusCode??502,O.headers),H){let X=[];O.on("data",(D)=>{X.push(D),z.write(D)}),O.on("end",()=>{z.end();let D=IZ(Buffer.concat(X).toString("utf8")),M=D.input+D.cacheRead+D.cacheCreate;RZ({ts:Date.now(),tool:"proxy",compressed:K!==null,orig_chars:K?.origChars??0,image_count:K?.imageCount??0,baseline_tokens:M+(K?.savedTokens??0),input_tokens:D.input,cache_read_tokens:D.cacheRead,cache_create_tokens:D.cacheCreate})})}else O.pipe(z)});U.on("error",(O)=>{z.writeHead(502,{"content-type":"application/json"}),z.end(JSON.stringify({type:"error",error:{type:"api_error",message:`tanuki proxy: upstream unreachable (${O.message})`}}))}),U.end(Y)})});return $.listen(J.port,"127.0.0.1",()=>{let V=$.address(),z=V!==null&&typeof V==="object"?V.port:J.port,G=`level=${J.level} distill=${J.distill} codebook=${J.codebook} font=${J.font} minChars=${J.minChars} ratio=${J.ratio} minSave=${J.minSave}`;process.stderr.write(`tanuki-context proxy on http://127.0.0.1:${z} -> ${J.upstream}
62
- ${G}
70
+ var o={level:0,distill:!1,codebook:!1,font:"normal",minChars:4000,ratio:0.75,minSave:300,maxPages:20};function yJ(J){let Q=0;for(let Z=0;Z<J.length;Z++){let $=J.charCodeAt(Z);if($<55296||$>56319)Q++}return Q}function EZ(J,Q){let Z=yJ(J);if(Z<Q.minChars)return null;let $=J;if(Q.distill)$=w($,null,2).distilled;let z=0;if(Q.codebook){let K=r($);$=K.text,z=K.entries}if(Q.level>0)$=s($,Q.level).compressed;let G=Math.round(Z/4),V=m($,!0,!0,Q.font);if(V.pages.length>Q.maxPages)return null;if(V.tokens>G*Q.ratio||G-V.tokens<Q.minSave)return null;let H=[{type:"text",text:`[tanuki-context: ${Z} chars imaged in place as ${V.pages.length} PNG page(s), ~${V.tokens} vs ~${G} text tokens. ↵=newline →=tab ⇥N=indent`+(z>0?`; ·legend· line maps ${z} sigils`:"")+"]"}];for(let K of V.pages)H.push({type:"image",source:{type:"base64",media_type:"image/png",data:Buffer.from(K.png.buffer,K.png.byteOffset,K.png.byteLength).toString("base64")}});return{blocks:H,origChars:Z,pages:V.pages.length,savedTokens:G-V.tokens}}function UJ(J){return J!==null&&typeof J==="object"&&!Array.isArray(J)}function SZ(J,Q){let Z;try{Z=JSON.parse(J)}catch{return null}if(!UJ(Z)||!Array.isArray(Z.messages))return null;let $=0,z=0,G=0,V=0,Y=new Map,H=(K)=>{let X=Y.get(K),B;if(X!==void 0){let O=yJ(K),D=`[tanuki-context: ${O} chars, byte-identical to a block imaged above (${X} PNG page(s)); not repeated]`;B={blocks:[{type:"text",text:D}],origChars:O,pages:0,savedTokens:Math.round(O/4)-Math.round(yJ(D)/4)}}else if(B=EZ(K,Q),B)Y.set(K,B.pages);if(B)$++,z+=B.origChars,G+=B.pages,V+=B.savedTokens;return B};for(let K=0;K<Z.messages.length-1;K++){let X=Z.messages[K];if(!UJ(X)||X.role!=="user")continue;if(typeof X.content==="string"){let O=H(X.content);if(O)X.content=O.blocks;continue}if(!Array.isArray(X.content))continue;let B=[];for(let O of X.content){if(!UJ(O)||O.cache_control!==void 0){B.push(O);continue}if(O.type==="text"&&typeof O.text==="string"){let D=H(O.text);if(D)B.push(...D.blocks);else B.push(O);continue}if(O.type==="tool_result"){if(typeof O.content==="string"){let D=H(O.content);if(D)O.content=D.blocks}else if(Array.isArray(O.content)){let D=[];for(let U of O.content){if(UJ(U)&&U.type==="text"&&typeof U.text==="string"&&U.cache_control===void 0){let M=H(U.text);if(M){D.push(...M.blocks);continue}}D.push(U)}O.content=D}}B.push(O)}X.content=B}if($===0)return null;return{body:JSON.stringify(Z),imagedBlocks:$,origChars:z,imageCount:G,savedTokens:V}}function CZ(J){let Q=(Z)=>{let $=Z.exec(J);return $?Number($[1]):0};return{input:Q(/"input_tokens"\s*:\s*(\d+)/),cacheRead:Q(/"cache_read_input_tokens"\s*:\s*(\d+)/),cacheCreate:Q(/"cache_creation_input_tokens"\s*:\s*(\d+)/)}}function LZ(J){try{let Q=TJ();RZ(PZ(Q),{recursive:!0}),IZ(Q,JSON.stringify(J)+`
71
+ `)}catch{}}function VQ(J){let Q=new _Z(J.upstream),Z=Q.protocol==="https:"?AZ:GQ,$=GQ.createServer((z,G)=>{let V=[];z.on("data",(Y)=>V.push(Y)),z.on("end",()=>{let Y=Buffer.concat(V),H=z.method==="POST"&&(z.url??"").startsWith("/v1/messages")&&!(z.url??"").includes("count_tokens")&&z.headers["content-encoding"]===void 0,K=null;if(H){if(K=SZ(Y.toString("utf8"),J),K)Y=Buffer.from(K.body,"utf8")}let X={...z.headers};if(delete X.host,delete X.connection,X["content-length"]=String(Y.length),H)delete X["accept-encoding"];let B=Z.request({protocol:Q.protocol,hostname:Q.hostname,port:Q.port||(Q.protocol==="https:"?443:80),path:z.url,method:z.method,headers:X},(O)=>{if(G.writeHead(O.statusCode??502,O.headers),H){let D=[];O.on("data",(U)=>{D.push(U),G.write(U)}),O.on("end",()=>{G.end();let U=CZ(Buffer.concat(D).toString("utf8")),M=U.input+U.cacheRead+U.cacheCreate;LZ({ts:Date.now(),tool:"proxy",compressed:K!==null,orig_chars:K?.origChars??0,image_count:K?.imageCount??0,baseline_tokens:M+(K?.savedTokens??0),input_tokens:U.input,cache_read_tokens:U.cacheRead,cache_create_tokens:U.cacheCreate})})}else O.pipe(G)});B.on("error",(O)=>{G.writeHead(502,{"content-type":"application/json"}),G.end(JSON.stringify({type:"error",error:{type:"api_error",message:`tanuki proxy: upstream unreachable (${O.message})`}}))}),B.end(Y)})});return $.listen(J.port,"127.0.0.1",()=>{let z=$.address(),G=z!==null&&typeof z==="object"?z.port:J.port,V=`level=${J.level} distill=${J.distill} codebook=${J.codebook} font=${J.font} minChars=${J.minChars} ratio=${J.ratio} minSave=${J.minSave}`;process.stderr.write(`tanuki-context proxy on http://127.0.0.1:${G} -> ${J.upstream}
72
+ ${V}
63
73
  `+` rules: system prompt & tools untouched · in-place blocks only · latest message never imaged · cache_control skipped · identical blocks imaged once
64
- `+` point your client at it: export ANTHROPIC_BASE_URL=http://127.0.0.1:${z}
65
- `)}),$}import{createHash as AZ}from"node:crypto";import{mkdirSync as PZ,readFileSync as _Z,writeFileSync as EZ}from"node:fs";import VQ from"node:process";//! Stash mode: context-mode's shape (content parked outside the context
74
+ `+` point your client at it: export ANTHROPIC_BASE_URL=http://127.0.0.1:${G}
75
+ `)}),$}import{createHash as TZ}from"node:crypto";import{mkdirSync as yZ,readFileSync as wZ,writeFileSync as bZ}from"node:fs";import YQ from"node:process";//! Stash mode: context-mode's shape (content parked outside the context
66
76
  //! window, queried on demand) fused with tanuki's pricing (big answers come
67
77
  //! back as dense pages).
68
78
  //!
@@ -71,10 +81,10 @@ var o={level:0,distill:!1,codebook:!1,font:"normal",minChars:4000,ratio:0.75,min
71
81
  //! repeats, first/last lines, the id). fetch = pull a slice by regex query
72
82
  //! (distill-powered) or line range; the caller images it only when pages
73
83
  //! clearly win. Contract is byte-identical with the Rust engine.
74
- function zQ(){let J=VQ.env.TANUKI_STASH;if(J!==void 0&&J!=="")return J;return`${VQ.env.HOME??""}/.tanuki/stash`}function $J(J){let Q=AZ("sha256").update(J,"utf8").digest("hex").slice(0,12),Z=zQ();PZ(Z,{recursive:!0}),EZ(`${Z}/${Q}`,J);let $=Buffer.byteLength(J,"utf8"),V=J.split(`
75
- `),z=w(J,null,2).stats,G=[`stashed ${Q} · ${$} bytes · ${V.length} lines`,`distill map: ${z.origLines} -> ${z.outLines} lines · ${z.savedPct}% of chars removable · ${z.importantKept} error/warn lines`];if(z.topRepeats.length>0){G.push("top repeats:");for(let H of z.topRepeats.slice(0,5)){let K=H.kind==="template"?" (template)":"";G.push(` ×${H.count}${K} ${H.exemplar}`)}}let Y="";for(let H=V.length-1;H>=0;H--)if(V[H]!==""){Y=V[H];break}return G.push(`first: ${t(r(V[0]),160)}`),G.push(`last: ${t(r(Y),160)}`),G.push(`fetch: tanuki_fetch {"id":"${Q}","query":"<regex>"} or {"id":"${Q}","lines":"a-b"}`),{id:Q,overview:G.join(`
76
- `)}}function yJ(J,Q,Z){if(Q===null===(Z===null))throw Error("give exactly one of query or lines");let $;try{$=_Z(`${zQ()}/${J}`,"utf8")}catch{throw Error(`unknown stash id: ${J}`)}if(Z!==null){let V=/^(\d+)-(\d+)$/.exec(Z);if(V===null)throw Error("bad lines range");let z=$.split(`
77
- `),G=Math.max(1,Number(V[1])),Y=Math.min(z.length,Number(V[2]));if(Number(V[1])>Number(V[2]))throw Error("bad lines range");return z.slice(G-1,Y).join(`
84
+ function HQ(){let J=YQ.env.TANUKI_STASH;if(J!==void 0&&J!=="")return J;return`${YQ.env.HOME??""}/.tanuki/stash`}function $J(J){let Q=TZ("sha256").update(J,"utf8").digest("hex").slice(0,12),Z=HQ();yZ(Z,{recursive:!0}),bZ(`${Z}/${Q}`,J);let $=Buffer.byteLength(J,"utf8"),z=J.split(`
85
+ `),G=w(J,null,2).stats,V=[`stashed ${Q} · ${$} bytes · ${z.length} lines`,`distill map: ${G.origLines} -> ${G.outLines} lines · ${G.savedPct}% of chars removable · ${G.importantKept} error/warn lines`];if(G.topRepeats.length>0){V.push("top repeats:");for(let H of G.topRepeats.slice(0,5)){let K=H.kind==="template"?" (template)":"";V.push(` ×${H.count}${K} ${H.exemplar}`)}}let Y="";for(let H=z.length-1;H>=0;H--)if(z[H]!==""){Y=z[H];break}return V.push(`first: ${t(a(z[0]),160)}`),V.push(`last: ${t(a(Y),160)}`),V.push(`fetch: tanuki_fetch {"id":"${Q}","query":"<regex>"} or {"id":"${Q}","lines":"a-b"}`),{id:Q,overview:V.join(`
86
+ `)}}function wJ(J,Q,Z){if(Q===null===(Z===null))throw Error("give exactly one of query or lines");let $;try{$=wZ(`${HQ()}/${J}`,"utf8")}catch{throw Error(`unknown stash id: ${J}`)}if(Z!==null){let z=/^(\d+)-(\d+)$/.exec(Z);if(z===null)throw Error("bad lines range");let G=$.split(`
87
+ `),V=Math.max(1,Number(z[1])),Y=Math.min(G.length,Number(z[2]));if(Number(z[1])>Number(z[2]))throw Error("bad lines range");return G.slice(V-1,Y).join(`
78
88
  `)}return w($,Q,2).distilled}//! tanuki-context — token-cutting context pipeline.
79
89
  //! pipeline: text -> distill (stage 0, logs) -> ladder level 0-4 (stage 1)
80
90
  //! -> pxpipe imaging (stage 2, name kept from the original mechanic)
@@ -84,30 +94,30 @@ function zQ(){let J=VQ.env.TANUKI_STASH;if(J!==void 0&&J!=="")return J;return`${
84
94
  //! tanuki-context estimate <file> [level] [--distill]
85
95
  //! tanuki-context render <file> [level] [outdir]
86
96
  //! tanuki-context proxy [--port N] [--upstream URL] [knobs] (implicit mode)
87
- var TZ="0.4.1",wJ=6,bJ=8000;function LZ(J,Q){let Z=Math.min(J.length,Q.length),$=0;while($<Z&&J.charCodeAt($)===Q.charCodeAt($))$++;if($>=Z)return J.length-Q.length;return J.codePointAt($)-Q.codePointAt($)}function P(J,Q,Z=""){if(J===null||J===void 0)return"null";if(J instanceof ZJ){let H=J.value;return Number.isFinite(H)&&Number.isInteger(H)?H.toFixed(1):String(H)}let $=typeof J;if($==="string")return JSON.stringify(J);if($==="number"||$==="boolean")return String(J);if(Array.isArray(J)){if(J.length===0)return"[]";if(!Q){let B="[";for(let U=0;U<J.length;U++){if(U>0)B+=",";B+=P(J[U],!1)}return B+"]"}let H=Z+" ",K=`[
88
- `;for(let B=0;B<J.length;B++){if(B>0)K+=`,
89
- `;K+=H+P(J[B],!0,H)}return K+`
90
- `+Z+"]"}let V=J,z=Object.keys(V).sort(LZ);if(z.length===0)return"{}";if(!Q){let H="{";for(let K=0;K<z.length;K++){if(K>0)H+=",";H+=JSON.stringify(z[K])+":"+P(V[z[K]],!1)}return H+"}"}let G=Z+" ",Y=`{
91
- `;for(let H=0;H<z.length;H++){if(H>0)Y+=`,
92
- `;Y+=G+JSON.stringify(z[H])+": "+P(V[z[H]],!0,G)}return Y+`
93
- `+Z+"}"}function j(J,Q){return J!==null&&typeof J==="object"&&!Array.isArray(J)?J[Q]:void 0}function L(J){return typeof J==="string"?J:null}function XJ(J){return typeof J==="boolean"?J:null}function OQ(J){return typeof J==="number"&&Number.isSafeInteger(J)&&J>=0?J:null}function _(J){let Q=0;for(let Z=0;Z<J.length;Z++){Q++;let $=J.charCodeAt(Z);if($>=55296&&$<=56319&&Z+1<J.length){let V=J.charCodeAt(Z+1);if(V>=56320&&V<=57343)Z++}}return Q}function qJ(J,Q,Z,$,V){let z,G=null;if(Z||$!==null){let K=w(J,$,2);z=K.distilled,G=K.stats}else z=J;let Y=0;if(V){let K=a(z);z=K.text,Y=K.entries}let H=s(z,Q);return{stage0:G,compressed:H.compressed,protectedLines:H.protectedLines,level:H.level,cbEntries:Y}}function l(J){return Math.round(J/4)}function zJ(J,Q){if(J===0)return 0;let Z=(1-Q/J)*100;return Z<0?-Math.round(-Z):Math.round(Z)}function UQ(J){return{text:L(j(J,"text"))??"",level:(OQ(j(J,"level"))??0)%256,distill:XJ(j(J,"distill"))??!1,query:L(j(J,"query")),reflow:XJ(j(J,"reflow"))??!0,pack:XJ(j(J,"pack"))??!0,font:L(j(J,"font"))??"normal",codebook:XJ(j(J,"codebook"))??!1}}function yZ(J){let Q=(z)=>{let G={codebook:!1,tokens:1/0,pages:0,text:z};for(let Y of[!1,!0]){let H=Y?a(z).text:z,K=OJ(H,!0,!0,v("normal"));if(K.tokens<G.tokens)G={codebook:Y,tokens:K.tokens,pages:K.pages,text:H}}return G},Z=Q(J),$=Q(w(J,null,2).distilled),V=OJ(Z.text,!0,!0,v("tiny"));return{codebook:Z.codebook,imageTokens:Z.tokens,pages:Z.pages,tinyImageTokens:V.tokens,withDistill:{codebook:$.codebook,imageTokens:$.tokens}}}function XQ(J){let Q=UQ(J),Z=qJ(Q.text,Q.level,Q.distill,Q.query,Q.codebook),$=v(Q.font),V=OJ(Z.compressed,Q.reflow,Q.pack,$),z=V.tokens,G=_(Q.text),Y=_(Z.compressed),H=l(G),[K,B]=GJ[Z.level];return{engine:"pxpipe",level:`${Z.level} ${K}`,loss:B,distill:Z.stage0,origChars:G,stage1Chars:Y,stage1SavedPct:zJ(G,Y),pages:V.pages,imageTokens:z,rawTextTokens:H,totalSavedPct:zJ(H,z),protectedLines:Z.protectedLines,pack:Q.pack,font:$==="tiny"?"tiny":"normal",codebook:Q.codebook?Z.cbEntries:!1,verdict:z<H?"PIPELINE cheaper":"TEXT cheaper",recommend:yZ(Q.text)}}function wZ(J){let Q=UQ(J),Z=qJ(Q.text,Q.level,Q.distill,Q.query,Q.codebook),$=v(Q.font),V=m(Z.compressed,Q.reflow,Q.pack,$),z=V.tokens,G=_(Q.text),Y=_(Z.compressed),H=l(G),[K,B]=GJ[Z.level],U="";if(Z.stage0!==null){let D=Z.stage0;U+=`distill: ${D.origLines} -> ${D.outLines} lines (-${D.savedPct}% chars, ${D.collapsedRuns} runs, ${D.suppressedLines} exact + ${D.templateSuppressed} template suppressed, ${D.importantKept} error/warn kept)
94
- `}if(U+=`L${Z.level} ${K} (${B}): ${G} chars -> ${Y} chars (stage1 -${zJ(G,Y)}%) -> ${V.pages.length} page(s), ~${z} image-tokens
95
- vs ~${H} text-tokens raw = TOTAL -${zJ(H,z)}%`,Z.protectedLines>0)U+=` · ${Z.protectedLines} lines kept verbatim`;if(V.dropped>0)U+=` · ${V.dropped} unmapped glyphs -> ▯`;if(Z.cbEntries>0)U+=` · codebook: ${Z.cbEntries} sigils (see ·legend·)`;if($==="tiny")U+=" · font: tiny 4x6";if(Q.pack)U+=" · packed (⇥N indent, → tab)";if(Q.reflow)U+=" · ↵ = newline · engine: pxpipe";let O=[{type:"text",text:U}],X=Math.min(V.pages.length,wJ);for(let D=0;D<X;D++){let M=V.pages[D].png;O.push({type:"image",data:Buffer.from(M.buffer,M.byteOffset,M.byteLength).toString("base64"),mimeType:"image/png"})}if(V.pages.length>wJ)O.push({type:"text",text:`(+${V.pages.length-wJ} more page(s))`});return O}function bZ(J){let Q=L(j(J,"text"))??"",Z=w(Q,L(j(J,"query")),2);return[{type:"text",text:P(Z.stats,!0)},{type:"text",text:Z.distilled}]}function vZ(J){let Q=L(j(J,"text"))??"",Z=(OQ(j(J,"level"))??1)%256,$=s(Q,Z),[V,z,G]=GJ[$.level],Y=_(Q),H=_($.compressed),K=l(Y),B=l(H),U={level:`${$.level} ${V}`,loss:z,note:G,origChars:Y,outChars:H,approxOrigTokens:K,approxOutTokens:B,savedPct:zJ(K,B),protectedLines:$.protectedLines};return[{type:"text",text:P(U,!0)},{type:"text",text:$.compressed}]}function kZ(J){let Q=L(j(J,"text"))??"";return[{type:"text",text:$J(Q).overview}]}function xZ(J){let Q=L(j(J,"id"))??"",Z=yJ(Q,L(j(J,"query"))??null,L(j(J,"lines"))??null),$=l(_(Z)),V=m(Z,!0,!0,v("normal"));if(!(V.tokens<=$*0.75&&$-V.tokens>=300&&V.pages.length<=6))return[{type:"text",text:Z}];let Y=[{type:"text",text:`[tanuki-context stash ${Q}: slice of ${_(Z)} chars imaged as ${V.pages.length} PNG page(s), ~${V.tokens} vs ~${$} text tokens. ↵=newline →=tab ⇥N=indent]`}];for(let H of V.pages){let K=H.png;Y.push({type:"image",data:Buffer.from(K.buffer,K.byteOffset,K.byteLength).toString("base64"),mimeType:"image/png"})}return Y}function fZ(){let J={type:"string"},Q={type:"integer",minimum:0,maximum:4};return{tools:[{name:"tanuki_render",description:"Token-cut pipeline: optional log distillation (dedupe noise, keep errors verbatim, optional query filter), optional codebook (repeated long tokens/path prefixes -> 1-cell sigils + a ·legend· line), then a ladder level, then dense PNG page(s) via the pxpipe imaging engine. level 0 raw · 1 whitespace (lossless) · 2 prose · 3 dense · 4 caveman (gist only). From level 2 up code/IDs/hashes/paths stay verbatim. pack (default true) = lossless tight reflow (single-cell tabs, ⇥N indent runs, width-trimmed pages). font 'tiny' = 4x6 cell, ~40% fewer image-tokens (opt-in). Image tokens are pixel-priced, so every earlier cut compounds. Returns image blocks + a breakdown.",inputSchema:{type:"object",properties:{text:J,level:Q,distill:{type:"boolean"},query:{type:"string"},reflow:{type:"boolean"},pack:{type:"boolean"},font:{type:"string",enum:["normal","tiny"]},codebook:{type:"boolean"}},required:["text"]}},{name:"tanuki_estimate",description:"Estimate tokens for the pipeline (distill -> codebook -> level -> pxpipe imaging) vs sending the raw text as text. Exact page geometry, no image data returned. Compare levels/pack/font/codebook to pick a loss/size tradeoff. The result's 'recommend' field prices the reversible knobs (pack/codebook, level 0) and, separately under 'withDistill', the lossy-but-counted log route - one call replaces manual knob probing.",inputSchema:{type:"object",properties:{text:J,level:Q,distill:{type:"boolean"},query:{type:"string"},reflow:{type:"boolean"},pack:{type:"boolean"},font:{type:"string",enum:["normal","tiny"]},codebook:{type:"boolean"}},required:["text"]}},{name:"tanuki_distill",description:"Stage 0 alone: make noisy logs/output small and readable WITHOUT imaging. Strips ANSI, collapses runs of near-identical lines/blocks into '[×N similar]', suppresses global near-dupes (exact + same-template) with exact counts, always keeps error/warn/fail lines verbatim, optional query (regex) returns only the relevant slice. Deterministic, order-preserving.",inputSchema:{type:"object",properties:{text:J,query:{type:"string"}},required:["text"]}},{name:"tanuki_compress",description:"Stage 1 alone: graded text compression for content that stays TEXT. level 0 none · 1 whitespace (lossless, safe for code) · 2 prose · 3 dense · 4 caveman (gist only). From level 2 up code/IDs/hashes/paths are preserved verbatim.",inputSchema:{type:"object",properties:{text:J,level:Q},required:["text"]}},{name:"tanuki_stats",description:"Summarize the pxpipe measurement log (~/.pxpipe/events.jsonl): requests, compression counts, honest input-token savings (input + cache reads + cache creates).",inputSchema:{type:"object",properties:{}}},{name:"tanuki_stash",description:"Park bulky text outside the context window (content-addressed file under TANUKI_STASH or ~/.tanuki/stash) and get back a compact map: distill stats, top repeats, first/last lines, and the stash id. Pay a few hundred tokens now, fetch slices later - the retrieval pattern, with tanuki pricing on the way back.",inputSchema:{type:"object",properties:{text:J},required:["text"]}},{name:"tanuki_fetch",description:"Pull a slice of stashed text by id: query (regex, distill-powered: matches + error/warn lines + context) or lines 'a-b'. Big slices come back as dense PNG pages automatically when they clearly win (>=25% and >=300 tokens cheaper, <=6 pages); small ones stay text.",inputSchema:{type:"object",properties:{id:{type:"string"},query:{type:"string"},lines:{type:"string"}},required:["id"]}}]}}function hZ(J){let Q=L(j(J,"name"))??"",Z=j(J,"arguments"),$;switch(Q){case"tanuki_render":$=wZ(Z);break;case"tanuki_estimate":$=[{type:"text",text:P(XQ(Z),!0)}];break;case"tanuki_distill":$=bZ(Z);break;case"tanuki_compress":$=vZ(Z);break;case"tanuki_stats":$=[{type:"text",text:P(QQ(),!0)}];break;case"tanuki_stash":$=kZ(Z);break;case"tanuki_fetch":try{$=xZ(Z)}catch(V){return{ok:!1,error:V instanceof Error?V.message:String(V)}}break;default:return{ok:!1,error:`unknown tool: ${Q}`}}return{ok:!0,value:{content:$}}}function HQ(J){let Q=J.endsWith("\r")?J.slice(0,-1):J;if(Q.trim().length===0)return;let Z;try{Z=JSON.parse(Q)}catch{return}let $=Z!==null&&typeof Z==="object"&&!Array.isArray(Z)&&Object.prototype.hasOwnProperty.call(Z,"id"),V=$?Z.id??null:null,z=L(j(Z,"method")),G;switch(z){case"initialize":{let Y=L(j(j(Z,"params"),"protocolVersion"))??"2025-06-18";G={jsonrpc:"2.0",id:V,result:{protocolVersion:Y,capabilities:{tools:{}},serverInfo:{name:"tanuki-context",version:TZ}}};break}case"notifications/initialized":case"notifications/cancelled":G=void 0;break;case"ping":G={jsonrpc:"2.0",id:V,result:{}};break;case"tools/list":G={jsonrpc:"2.0",id:V,result:fZ()};break;case"tools/call":{let Y=hZ(j(Z,"params"));G=Y.ok?{jsonrpc:"2.0",id:V,result:Y.value}:{jsonrpc:"2.0",id:V,error:{code:-32602,message:Y.error}};break}default:G=$?{jsonrpc:"2.0",id:V,error:{code:-32601,message:"method not found"}}:void 0}if(G!==void 0)R.stdout.write(P(G,!1)+`
96
- `)}function mZ(){let J=Buffer.alloc(0);R.stdin.on("data",(Q)=>{let Z=J.length>0?Buffer.concat([J,Q]):Q,$=0,V;while((V=Z.indexOf(10,$))!==-1)HQ(Z.toString("utf8",$,V)),$=V+1;J=Z.subarray($)}),R.stdin.on("end",()=>{if(J.length>0)HQ(J.toString("utf8")),J=Buffer.alloc(0)})}function A(J){R.stderr.write(J+`
97
- `),R.exit(101)}function VJ(J){try{return CZ(J,"utf8")}catch{A("read file")}}function DJ(J,Q){if(!/^\+?[0-9]+$/.test(J))return null;let Z=BigInt(J.startsWith("+")?J.slice(1):J);return Z>Q?null:Number(Z)}var KQ=255n,BQ=0xffffffffffffffffn;function DQ(){let J=R.argv.slice(1);switch(J[1]){case"distill":{let Q=J[2]??A("usage: tanuki-context distill <file> [query]"),Z=VJ(Q),$=w(Z,J[3]??null,2);R.stdout.write(P($.stats,!1)+`
98
- `);break}case"estimate":{let Q=J[2]??A("usage: tanuki-context estimate <file> [level] [--distill] [--no-pack] [--font tiny] [--codebook]"),Z=VJ(Q),$=J.slice(3).filter((H)=>!H.startsWith("--")),V=$.length>0?DJ($[0],BQ)??0:0,z=J.indexOf("--font"),G=z!==-1&&J[z+1]!==void 0?J[z+1]:"normal",Y=XQ({text:Z,level:V,distill:J.includes("--distill"),pack:!J.includes("--no-pack"),font:G,codebook:J.includes("--codebook")});R.stdout.write(P(Y,!1)+`
99
- `);break}case"render":{let Q=J[2]??A("usage: tanuki-context render <file> [level] [outdir] [--distill] [--no-pack] [--font tiny] [--codebook]"),Z=VJ(Q),$=J.slice(3).filter((X)=>!X.startsWith("--")),V=$.length>0?DJ($[0],KQ)??0:0,z=!J.includes("--no-pack"),G=J.includes("--codebook"),Y=J.indexOf("--font"),H=v(Y!==-1&&J[Y+1]!==void 0?J[Y+1]:"normal"),K=qJ(Z,V,J.includes("--distill"),null,G),B=m(K.compressed,!0,z,H),U=B.tokens;R.stdout.write(P({pages:B.pages.length,imageTokens:U,dropped:B.dropped,rawTextTokens:l(_(Z))},!1)+`
100
- `);let O=$[1];if(O!==void 0){try{GQ(O,{recursive:!0})}catch{A("mkdir")}for(let X=0;X<B.pages.length;X++)try{YQ(`${O}/page${X}.png`,B.pages[X].png)}catch{A("write png")}}break}case"bench":{let Q=J[2]??A("usage: tanuki-context bench <file> <op> [level] [runs] [--distill]"),Z=J[3]??"pipeline",$=J[4]!==void 0?DJ(J[4],KQ)??0:0,V=J[5]!==void 0?DJ(J[5],BQ)??3:3,z=J.includes("--distill"),G=VJ(Q),Y=[],H=null;for(let K=0;K<=V;K++){let B=performance.now();if(Z==="distill")H=w(G,null,2).stats;else{let U=qJ(G,$,z,null,!1),O=m(U.compressed,!0,!1,"normal");H={pages:O.pages.length,imageTokens:O.tokens,stage1Chars:_(U.compressed),dropped:O.dropped}}if(K>0)Y.push(performance.now()-B)}if(Y.sort((K,B)=>K-B),Y.length===0)A("index out of bounds: the len is 0 but the index is 0");R.stdout.write(P({medianMs:new ZJ(Y[Math.floor(Y.length/2)]),runs:V,result:H},!1)+`
101
- `);break}case"proxy":{let Q=(V,z)=>{let G=J.indexOf(V);if(G===-1||J[G+1]===void 0)return z;let Y=Number(J[G+1]);return Number.isFinite(Y)?Y:z},Z=J.indexOf("--upstream"),$=J.indexOf("--font");$Q({port:Q("--port",8484),upstream:Z!==-1&&J[Z+1]!==void 0?J[Z+1]:R.env.TANUKI_UPSTREAM??"https://api.anthropic.com",level:Q("--level",o.level),distill:J.includes("--distill"),codebook:J.includes("--codebook"),font:v($!==-1&&J[$+1]!==void 0?J[$+1]:"normal"),minChars:Q("--min-chars",o.minChars),ratio:Q("--ratio",o.ratio),minSave:Q("--min-save",o.minSave),maxPages:Q("--max-pages",o.maxPages)});break}case"stash":{let Q=J[2]??A("usage: tanuki-context stash <file>"),Z=$J(VJ(Q));R.stdout.write(Z.overview+`
102
- `);break}case"fetch":{let Q=J[2]??A("usage: tanuki-context fetch <id> [outdir] [--query re] [--lines a-b]"),Z=J.indexOf("--query"),$=J.indexOf("--lines"),V="";try{V=yJ(Q,Z!==-1?J[Z+1]??null:null,$!==-1?J[$+1]??null:null)}catch(B){A(B instanceof Error?B.message:String(B))}let z=l(_(V)),G=m(V,!0,!0,v("normal"));if(!(G.tokens<=z*0.75&&z-G.tokens>=300&&G.pages.length<=6)){R.stdout.write(P({mode:"text"},!1)+`
103
- `+V+`
104
- `);break}R.stdout.write(P({imageTokens:G.tokens,mode:"pages",pages:G.pages.length,rawTextTokens:z},!1)+`
105
- `);let H=new Set([Z+1,$+1]),K;for(let B=3;B<J.length;B++)if(!J[B].startsWith("--")&&!H.has(B)){K=J[B];break}if(K!==void 0){try{GQ(K,{recursive:!0})}catch{A("mkdir")}for(let B=0;B<G.pages.length;B++)try{YQ(`${K}/page${B}.png`,G.pages[B].png)}catch{A("write png")}}break}case"run":{let Q=J.indexOf("--"),Z=Q!==-1?J.slice(Q+1):[];if(Z.length===0)A("usage: tanuki-context run [--query re] -- <command> [args...]");let $=J.indexOf("--query"),V=$!==-1&&$<Q?J[$+1]??null:null,z=SZ(Z[0],Z.slice(1),{encoding:"utf8",maxBuffer:268435456});if(z.error!==void 0)A(`spawn failed: ${z.error.message}`);let G=(z.stdout??"")+((z.stderr??"")!==""?`
97
+ var kZ="0.5.0",bJ=6,vJ=8000;function xZ(J,Q){let Z=Math.min(J.length,Q.length),$=0;while($<Z&&J.charCodeAt($)===Q.charCodeAt($))$++;if($>=Z)return J.length-Q.length;return J.codePointAt($)-Q.codePointAt($)}function A(J,Q,Z=""){if(J===null||J===void 0)return"null";if(J instanceof ZJ){let H=J.value;return Number.isFinite(H)&&Number.isInteger(H)?H.toFixed(1):String(H)}let $=typeof J;if($==="string")return JSON.stringify(J);if($==="number"||$==="boolean")return String(J);if(Array.isArray(J)){if(J.length===0)return"[]";if(!Q){let X="[";for(let B=0;B<J.length;B++){if(B>0)X+=",";X+=A(J[B],!1)}return X+"]"}let H=Z+" ",K=`[
98
+ `;for(let X=0;X<J.length;X++){if(X>0)K+=`,
99
+ `;K+=H+A(J[X],!0,H)}return K+`
100
+ `+Z+"]"}let z=J,G=Object.keys(z).sort(xZ);if(G.length===0)return"{}";if(!Q){let H="{";for(let K=0;K<G.length;K++){if(K>0)H+=",";H+=JSON.stringify(G[K])+":"+A(z[G[K]],!1)}return H+"}"}let V=Z+" ",Y=`{
101
+ `;for(let H=0;H<G.length;H++){if(H>0)Y+=`,
102
+ `;Y+=V+JSON.stringify(G[H])+": "+A(z[G[H]],!0,V)}return Y+`
103
+ `+Z+"}"}function j(J,Q){return J!==null&&typeof J==="object"&&!Array.isArray(J)?J[Q]:void 0}function E(J){return typeof J==="string"?J:null}function GJ(J){return typeof J==="boolean"?J:null}function UQ(J){return typeof J==="number"&&Number.isSafeInteger(J)&&J>=0?J:null}function _(J){let Q=0;for(let Z=0;Z<J.length;Z++){Q++;let $=J.charCodeAt(Z);if($>=55296&&$<=56319&&Z+1<J.length){let z=J.charCodeAt(Z+1);if(z>=56320&&z<=57343)Z++}}return Q}function MJ(J,Q,Z,$,z){let G,V=null;if(Z||$!==null){let K=w(J,$,2);G=K.distilled,V=K.stats}else G=J;let Y=0;if(z){let K=r(G);G=K.text,Y=K.entries}let H=s(G,Q);return{stage0:V,compressed:H.compressed,protectedLines:H.protectedLines,level:H.level,cbEntries:Y}}function l(J){return Math.round(J/4)}function VJ(J,Q){if(J===0)return 0;let Z=(1-Q/J)*100;return Z<0?-Math.round(-Z):Math.round(Z)}function qQ(J){return{text:E(j(J,"text"))??"",level:(UQ(j(J,"level"))??0)%256,distill:GJ(j(J,"distill"))??!1,query:E(j(J,"query")),reflow:GJ(j(J,"reflow"))??!0,pack:GJ(j(J,"pack"))??!0,font:E(j(J,"font"))??"normal",codebook:GJ(j(J,"codebook"))??!1}}function hZ(J){let Q=(G)=>{let V={codebook:!1,tokens:1/0,pages:0,text:G};for(let Y of[!1,!0]){let H=Y?r(G).text:G,K=DJ(H,!0,!0,v("normal"));if(K.tokens<V.tokens)V={codebook:Y,tokens:K.tokens,pages:K.pages,text:H}}return V},Z=Q(J),$=Q(w(J,null,2).distilled),z=DJ(Z.text,!0,!0,v("tiny"));return{codebook:Z.codebook,imageTokens:Z.tokens,pages:Z.pages,tinyImageTokens:z.tokens,withDistill:{codebook:$.codebook,imageTokens:$.tokens}}}function MQ(J){let Q=qQ(J),Z=MJ(Q.text,Q.level,Q.distill,Q.query,Q.codebook),$=v(Q.font),z=DJ(Z.compressed,Q.reflow,Q.pack,$),G=z.tokens,V=_(Q.text),Y=_(Z.compressed),H=l(V),[K,X]=HJ[Z.level],B=E(j(J,"model")),O=GJ(j(J,"cached"))??!1,D={engine:"pxpipe",level:`${Z.level} ${K}`,loss:X,distill:Z.stage0,origChars:V,stage1Chars:Y,stage1SavedPct:VJ(V,Y),pages:z.pages,imageTokens:G,rawTextTokens:H,totalSavedPct:VJ(H,G),protectedLines:Z.protectedLines,pack:Q.pack,font:$==="tiny"?"tiny":"normal",codebook:Q.codebook?Z.cbEntries:!1,verdict:G<H?"PIPELINE cheaper":"TEXT cheaper",recommend:hZ(Q.text)};if(B!==null||O)D.cost=mJ(H,G,{model:B,cached:O});return D}function mZ(J){let Q=qQ(J),Z=MJ(Q.text,Q.level,Q.distill,Q.query,Q.codebook),$=v(Q.font),z=m(Z.compressed,Q.reflow,Q.pack,$),G=z.tokens,V=_(Q.text),Y=_(Z.compressed),H=l(V),[K,X]=HJ[Z.level],B="";if(Z.stage0!==null){let U=Z.stage0;B+=`distill: ${U.origLines} -> ${U.outLines} lines (-${U.savedPct}% chars, ${U.collapsedRuns} runs, ${U.suppressedLines} exact + ${U.templateSuppressed} template suppressed, ${U.importantKept} error/warn kept)
104
+ `}if(B+=`L${Z.level} ${K} (${X}): ${V} chars -> ${Y} chars (stage1 -${VJ(V,Y)}%) -> ${z.pages.length} page(s), ~${G} image-tokens
105
+ vs ~${H} text-tokens raw = TOTAL -${VJ(H,G)}%`,Z.protectedLines>0)B+=` · ${Z.protectedLines} lines kept verbatim`;if(z.dropped>0)B+=` · ${z.dropped} unmapped glyphs -> ▯`;if(Z.cbEntries>0)B+=` · codebook: ${Z.cbEntries} sigils (see ·legend·)`;if($==="tiny")B+=" · font: tiny 4x6";if(Q.pack)B+=" · packed (⇥N indent, → tab)";if(Q.reflow)B+=" · ↵ = newline · engine: pxpipe";let O=[{type:"text",text:B}],D=Math.min(z.pages.length,bJ);for(let U=0;U<D;U++){let M=z.pages[U].png;O.push({type:"image",data:Buffer.from(M.buffer,M.byteOffset,M.byteLength).toString("base64"),mimeType:"image/png"})}if(z.pages.length>bJ)O.push({type:"text",text:`(+${z.pages.length-bJ} more page(s))`});return O}function uZ(J){let Q=E(j(J,"text"))??"",Z=w(Q,E(j(J,"query")),2);return[{type:"text",text:A(Z.stats,!0)},{type:"text",text:Z.distilled}]}function gZ(J){let Q=E(j(J,"text"))??"",Z=(UQ(j(J,"level"))??1)%256,$=s(Q,Z),[z,G,V]=HJ[$.level],Y=_(Q),H=_($.compressed),K=l(Y),X=l(H),B={level:`${$.level} ${z}`,loss:G,note:V,origChars:Y,outChars:H,approxOrigTokens:K,approxOutTokens:X,savedPct:VJ(K,X),protectedLines:$.protectedLines};return[{type:"text",text:A(B,!0)},{type:"text",text:$.compressed}]}function dZ(J){let Q=E(j(J,"text"))??"";return[{type:"text",text:$J(Q).overview}]}function lZ(J){let Q=E(j(J,"id"))??"",Z=wJ(Q,E(j(J,"query"))??null,E(j(J,"lines"))??null),$=l(_(Z)),z=m(Z,!0,!0,v("normal"));if(!(z.tokens<=$*0.75&&$-z.tokens>=300&&z.pages.length<=6))return[{type:"text",text:Z}];let Y=[{type:"text",text:`[tanuki-context stash ${Q}: slice of ${_(Z)} chars imaged as ${z.pages.length} PNG page(s), ~${z.tokens} vs ~${$} text tokens. ↵=newline →=tab ⇥N=indent]`}];for(let H of z.pages){let K=H.png;Y.push({type:"image",data:Buffer.from(K.buffer,K.byteOffset,K.byteLength).toString("base64"),mimeType:"image/png"})}return Y}function pZ(){let J={type:"string"},Q={type:"integer",minimum:0,maximum:4};return{tools:[{name:"tanuki_render",description:"Token-cut pipeline: optional log distillation (dedupe noise, keep errors verbatim, optional query filter), optional codebook (repeated long tokens/path prefixes -> 1-cell sigils + a ·legend· line), then a ladder level, then dense PNG page(s) via the pxpipe imaging engine. level 0 raw · 1 whitespace (lossless) · 2 prose · 3 dense · 4 caveman (gist only). From level 2 up code/IDs/hashes/paths stay verbatim. pack (default true) = lossless tight reflow (single-cell tabs, ⇥N indent runs, width-trimmed pages). font 'tiny' = 4x6 cell, ~40% fewer image-tokens (opt-in). Image tokens are pixel-priced, so every earlier cut compounds. Returns image blocks + a breakdown.",inputSchema:{type:"object",properties:{text:J,level:Q,distill:{type:"boolean"},query:{type:"string"},reflow:{type:"boolean"},pack:{type:"boolean"},font:{type:"string",enum:["normal","tiny"]},codebook:{type:"boolean"}},required:["text"]}},{name:"tanuki_estimate",description:"Estimate tokens for the pipeline (distill -> codebook -> level -> pxpipe imaging) vs sending the raw text as text. Exact page geometry, no image data returned. Compare levels/pack/font/codebook to pick a loss/size tradeoff. The result's 'recommend' field prices the reversible knobs (pack/codebook, level 0) and, separately under 'withDistill', the lossy-but-counted log route. Pass 'model' (e.g. claude-opus-4) and/or cached:true to add a 'cost' field that prices the decision in real dollars: a cached text token costs ~0.1x a fresh one on Anthropic, so imaging already-cached content usually loses even when it has fewer tokens. One call replaces manual knob probing.",inputSchema:{type:"object",properties:{text:J,level:Q,distill:{type:"boolean"},query:{type:"string"},reflow:{type:"boolean"},pack:{type:"boolean"},font:{type:"string",enum:["normal","tiny"]},codebook:{type:"boolean"},model:{type:"string"},cached:{type:"boolean"}},required:["text"]}},{name:"tanuki_distill",description:"Stage 0 alone: make noisy logs/output small and readable WITHOUT imaging. Strips ANSI, collapses runs of near-identical lines/blocks into '[×N similar]', suppresses global near-dupes (exact + same-template) with exact counts, always keeps error/warn/fail lines verbatim, optional query (regex) returns only the relevant slice. Deterministic, order-preserving.",inputSchema:{type:"object",properties:{text:J,query:{type:"string"}},required:["text"]}},{name:"tanuki_compress",description:"Stage 1 alone: graded text compression for content that stays TEXT. level 0 none · 1 whitespace (lossless, safe for code) · 2 prose · 3 dense · 4 caveman (gist only). From level 2 up code/IDs/hashes/paths are preserved verbatim.",inputSchema:{type:"object",properties:{text:J,level:Q},required:["text"]}},{name:"tanuki_stats",description:"Summarize the pxpipe measurement log (~/.pxpipe/events.jsonl): requests, compression counts, honest input-token savings (input + cache reads + cache creates).",inputSchema:{type:"object",properties:{}}},{name:"tanuki_stash",description:"Park bulky text outside the context window (content-addressed file under TANUKI_STASH or ~/.tanuki/stash) and get back a compact map: distill stats, top repeats, first/last lines, and the stash id. Pay a few hundred tokens now, fetch slices later - the retrieval pattern, with tanuki pricing on the way back.",inputSchema:{type:"object",properties:{text:J},required:["text"]}},{name:"tanuki_fetch",description:"Pull a slice of stashed text by id: query (regex, distill-powered: matches + error/warn lines + context) or lines 'a-b'. Big slices come back as dense PNG pages automatically when they clearly win (>=25% and >=300 tokens cheaper, <=6 pages); small ones stay text.",inputSchema:{type:"object",properties:{id:{type:"string"},query:{type:"string"},lines:{type:"string"}},required:["id"]}}]}}function nZ(J){let Q=E(j(J,"name"))??"",Z=j(J,"arguments"),$;switch(Q){case"tanuki_render":$=mZ(Z);break;case"tanuki_estimate":$=[{type:"text",text:A(MQ(Z),!0)}];break;case"tanuki_distill":$=uZ(Z);break;case"tanuki_compress":$=gZ(Z);break;case"tanuki_stats":$=[{type:"text",text:A(zQ(),!0)}];break;case"tanuki_stash":$=dZ(Z);break;case"tanuki_fetch":try{$=lZ(Z)}catch(z){return{ok:!1,error:z instanceof Error?z.message:String(z)}}break;default:return{ok:!1,error:`unknown tool: ${Q}`}}return{ok:!0,value:{content:$}}}function OQ(J){let Q=J.endsWith("\r")?J.slice(0,-1):J;if(Q.trim().length===0)return;let Z;try{Z=JSON.parse(Q)}catch{return}let $=Z!==null&&typeof Z==="object"&&!Array.isArray(Z)&&Object.prototype.hasOwnProperty.call(Z,"id"),z=$?Z.id??null:null,G=E(j(Z,"method")),V;switch(G){case"initialize":{let Y=E(j(j(Z,"params"),"protocolVersion"))??"2025-06-18";V={jsonrpc:"2.0",id:z,result:{protocolVersion:Y,capabilities:{tools:{}},serverInfo:{name:"tanuki-context",version:kZ}}};break}case"notifications/initialized":case"notifications/cancelled":V=void 0;break;case"ping":V={jsonrpc:"2.0",id:z,result:{}};break;case"tools/list":V={jsonrpc:"2.0",id:z,result:pZ()};break;case"tools/call":{let Y=nZ(j(Z,"params"));V=Y.ok?{jsonrpc:"2.0",id:z,result:Y.value}:{jsonrpc:"2.0",id:z,error:{code:-32602,message:Y.error}};break}default:V=$?{jsonrpc:"2.0",id:z,error:{code:-32601,message:"method not found"}}:void 0}if(V!==void 0)R.stdout.write(A(V,!1)+`
106
+ `)}function cZ(){let J=Buffer.alloc(0);R.stdin.on("data",(Q)=>{let Z=J.length>0?Buffer.concat([J,Q]):Q,$=0,z;while((z=Z.indexOf(10,$))!==-1)OQ(Z.toString("utf8",$,z)),$=z+1;J=Z.subarray($)}),R.stdin.on("end",()=>{if(J.length>0)OQ(J.toString("utf8")),J=Buffer.alloc(0)})}function P(J){R.stderr.write(J+`
107
+ `),R.exit(101)}function zJ(J){try{return fZ(J,"utf8")}catch{P("read file")}}function qJ(J,Q){if(!/^\+?[0-9]+$/.test(J))return null;let Z=BigInt(J.startsWith("+")?J.slice(1):J);return Z>Q?null:Number(Z)}var BQ=255n,DQ=0xffffffffffffffffn;function FQ(){let J=R.argv.slice(1);switch(J[1]){case"distill":{let Q=J[2]??P("usage: tanuki-context distill <file> [query]"),Z=zJ(Q),$=w(Z,J[3]??null,2);R.stdout.write(A($.stats,!1)+`
108
+ `);break}case"estimate":{let Q=J[2]??P("usage: tanuki-context estimate <file> [level] [--distill] [--no-pack] [--font tiny] [--codebook] [--model <id>] [--cached]"),Z=zJ(Q),$=J.slice(3).filter((X)=>!X.startsWith("--")),z=$.length>0?qJ($[0],DQ)??0:0,G=J.indexOf("--font"),V=G!==-1&&J[G+1]!==void 0?J[G+1]:"normal",Y=J.indexOf("--model"),H=Y!==-1&&J[Y+1]!==void 0?J[Y+1]:null,K=MQ({text:Z,level:z,distill:J.includes("--distill"),pack:!J.includes("--no-pack"),font:V,codebook:J.includes("--codebook"),model:H,cached:J.includes("--cached")});R.stdout.write(A(K,!1)+`
109
+ `);break}case"render":{let Q=J[2]??P("usage: tanuki-context render <file> [level] [outdir] [--distill] [--no-pack] [--font tiny] [--codebook]"),Z=zJ(Q),$=J.slice(3).filter((D)=>!D.startsWith("--")),z=$.length>0?qJ($[0],BQ)??0:0,G=!J.includes("--no-pack"),V=J.includes("--codebook"),Y=J.indexOf("--font"),H=v(Y!==-1&&J[Y+1]!==void 0?J[Y+1]:"normal"),K=MJ(Z,z,J.includes("--distill"),null,V),X=m(K.compressed,!0,G,H),B=X.tokens;R.stdout.write(A({pages:X.pages.length,imageTokens:B,dropped:X.dropped,rawTextTokens:l(_(Z))},!1)+`
110
+ `);let O=$[1];if(O!==void 0){try{KQ(O,{recursive:!0})}catch{P("mkdir")}for(let D=0;D<X.pages.length;D++)try{XQ(`${O}/page${D}.png`,X.pages[D].png)}catch{P("write png")}}break}case"bench":{let Q=J[2]??P("usage: tanuki-context bench <file> <op> [level] [runs] [--distill]"),Z=J[3]??"pipeline",$=J[4]!==void 0?qJ(J[4],BQ)??0:0,z=J[5]!==void 0?qJ(J[5],DQ)??3:3,G=J.includes("--distill"),V=zJ(Q),Y=[],H=null;for(let K=0;K<=z;K++){let X=performance.now();if(Z==="distill")H=w(V,null,2).stats;else{let B=MJ(V,$,G,null,!1),O=m(B.compressed,!0,!1,"normal");H={pages:O.pages.length,imageTokens:O.tokens,stage1Chars:_(B.compressed),dropped:O.dropped}}if(K>0)Y.push(performance.now()-X)}if(Y.sort((K,X)=>K-X),Y.length===0)P("index out of bounds: the len is 0 but the index is 0");R.stdout.write(A({medianMs:new ZJ(Y[Math.floor(Y.length/2)]),runs:z,result:H},!1)+`
111
+ `);break}case"proxy":{let Q=(z,G)=>{let V=J.indexOf(z);if(V===-1||J[V+1]===void 0)return G;let Y=Number(J[V+1]);return Number.isFinite(Y)?Y:G},Z=J.indexOf("--upstream"),$=J.indexOf("--font");VQ({port:Q("--port",8484),upstream:Z!==-1&&J[Z+1]!==void 0?J[Z+1]:R.env.TANUKI_UPSTREAM??"https://api.anthropic.com",level:Q("--level",o.level),distill:J.includes("--distill"),codebook:J.includes("--codebook"),font:v($!==-1&&J[$+1]!==void 0?J[$+1]:"normal"),minChars:Q("--min-chars",o.minChars),ratio:Q("--ratio",o.ratio),minSave:Q("--min-save",o.minSave),maxPages:Q("--max-pages",o.maxPages)});break}case"stash":{let Q=J[2]??P("usage: tanuki-context stash <file>"),Z=$J(zJ(Q));R.stdout.write(Z.overview+`
112
+ `);break}case"fetch":{let Q=J[2]??P("usage: tanuki-context fetch <id> [outdir] [--query re] [--lines a-b]"),Z=J.indexOf("--query"),$=J.indexOf("--lines"),z="";try{z=wJ(Q,Z!==-1?J[Z+1]??null:null,$!==-1?J[$+1]??null:null)}catch(X){P(X instanceof Error?X.message:String(X))}let G=l(_(z)),V=m(z,!0,!0,v("normal"));if(!(V.tokens<=G*0.75&&G-V.tokens>=300&&V.pages.length<=6)){R.stdout.write(A({mode:"text"},!1)+`
113
+ `+z+`
114
+ `);break}R.stdout.write(A({imageTokens:V.tokens,mode:"pages",pages:V.pages.length,rawTextTokens:G},!1)+`
115
+ `);let H=new Set([Z+1,$+1]),K;for(let X=3;X<J.length;X++)if(!J[X].startsWith("--")&&!H.has(X)){K=J[X];break}if(K!==void 0){try{KQ(K,{recursive:!0})}catch{P("mkdir")}for(let X=0;X<V.pages.length;X++)try{XQ(`${K}/page${X}.png`,V.pages[X].png)}catch{P("write png")}}break}case"run":{let Q=J.indexOf("--"),Z=Q!==-1?J.slice(Q+1):[];if(Z.length===0)P("usage: tanuki-context run [--query re] -- <command> [args...]");let $=J.indexOf("--query"),z=$!==-1&&$<Q?J[$+1]??null:null,G=vZ(Z[0],Z.slice(1),{encoding:"utf8",maxBuffer:268435456});if(G.error!==void 0)P(`spawn failed: ${G.error.message}`);let V=(G.stdout??"")+((G.stderr??"")!==""?`
106
116
  --- stderr ---
107
- ${z.stderr}`:""),Y=z.status??0,H=w(G,V,2),K=H.stats,B=[`[tanuki run] exit ${Y} · ${K.origLines} -> ${K.outLines} lines · ${K.savedPct}% of chars removed`];if(_(H.distilled)<=bJ||_(G)<=bJ){if(B.push(H.distilled),_(G)>bJ){let U=$J(G);B.push(`full output stashed: tanuki-context fetch ${U.id} [--query re] [--lines a-b]`)}}else{let U=$J(G);B.push(U.overview)}R.stdout.write(B.join(`
117
+ ${G.stderr}`:""),Y=G.status??0,H=w(V,z,2),K=H.stats,X=[`[tanuki run] exit ${Y} · ${K.origLines} -> ${K.outLines} lines · ${K.savedPct}% of chars removed`];if(_(H.distilled)<=vJ||_(V)<=vJ){if(X.push(H.distilled),_(V)>vJ){let B=$J(V);X.push(`full output stashed: tanuki-context fetch ${B.id} [--query re] [--lines a-b]`)}}else{let B=$J(V);X.push(B.overview)}R.stdout.write(X.join(`
108
118
  `)+`
109
- `),R.exit(Y)}case"serve":case void 0:mZ();break;default:R.stderr.write(`unknown command: ${J[1]}
119
+ `),R.exit(Y)}case"serve":case void 0:cZ();break;default:R.stderr.write(`unknown command: ${J[1]}
110
120
  usage: tanuki-context [serve|proxy|distill|estimate|render|bench|stash|fetch|run] ...
111
121
  `),R.exit(1)}}//! Bin entry: keeps src/main.ts importable as a library (src/agent.ts) without
112
122
  //! starting the MCP server as an import side effect.
113
- DQ();
123
+ FQ();
package/dist/pi.js CHANGED
@@ -11,5 +11,5 @@ import{spawn as W}from"node:child_process";import{fileURLToPath as X}from"node:u
11
11
  //! ToolResult content shape, so results pass through untouched.
12
12
  function Y(){let F=process.env.TANUKI_BIN;if(F)return{cmd:F,args:[]};return{cmd:process.execPath,args:[X(new URL("./cli.js",import.meta.url))]}}class Q{proc;buf="";nextId=1;pending=new Map;ready;constructor(){let{cmd:F,args:B}=Y();this.proc=W(F,B,{stdio:["pipe","pipe","inherit"]}),this.proc.stdout.setEncoding("utf8"),this.proc.stdout.on("data",(G)=>{this.buf+=G;let z;while((z=this.buf.indexOf(`
13
13
  `))!==-1){let H=this.buf.slice(0,z).trim();if(this.buf=this.buf.slice(z+1),!H)continue;let D;try{D=JSON.parse(H)}catch{continue}let J=D.id!==void 0?this.pending.get(D.id):void 0;if(!J)continue;if(this.pending.delete(D.id),D.error)J.reject(Error(D.error.message??"tanuki-context error"));else J.resolve(D.result)}}),this.proc.on("exit",(G)=>{let z=Error(`tanuki-context server exited (code ${G})`);for(let H of this.pending.values())H.reject(z);this.pending.clear()}),this.ready=this.request("initialize",{})}request(F,B){let G=this.nextId++,{promise:z,resolve:H,reject:D}=Promise.withResolvers();if(!this.proc.stdin?.writable)return D(Error("tanuki-context server is gone")),z;return this.pending.set(G,{resolve:H,reject:D}),this.proc.stdin.write(JSON.stringify({jsonrpc:"2.0",id:G,method:F,params:B})+`
14
- `),z}async call(F,B){return await this.ready,this.request("tools/call",{name:F,arguments:B})}kill(){this.proc.kill()}get alive(){return this.proc.exitCode===null&&!this.proc.killed}}var K=q.String({description:"The text to process"}),V=q.Optional(q.Integer({minimum:0,maximum:4,description:"0 raw · 1 whitespace · 2 prose · 3 dense · 4 caveman"})),N=q.Object({text:K,level:V,distill:q.Optional(q.Boolean()),query:q.Optional(q.String()),reflow:q.Optional(q.Boolean()),pack:q.Optional(q.Boolean()),font:q.Optional(q.String({enum:["normal","tiny"]})),codebook:q.Optional(q.Boolean())}),Z=[{name:"tanuki_render",label:"Tanuki Render",description:"Token-cut pipeline: optional log distillation (dedupe noise, keep errors verbatim, optional query filter), optional codebook (repeated long tokens/path prefixes -> 1-cell sigils + a ·legend· line), then a ladder level, then dense PNG page(s) via the pxpipe imaging engine. level 0 raw · 1 whitespace (lossless) · 2 prose · 3 dense · 4 caveman (gist only). From level 2 up code/IDs/hashes/paths stay verbatim. pack (default true) = lossless tight reflow. font 'tiny' = 4x6 cell, ~40% fewer image-tokens (opt-in). Image tokens are pixel-priced, so every earlier cut compounds. Returns image blocks + a breakdown.",parameters:N,snippet:"Render bulky text/logs as dense PNG pages that cost a fraction of the tokens"},{name:"tanuki_estimate",label:"Tanuki Estimate",description:"Estimate tokens for the pipeline (distill -> codebook -> level -> pxpipe imaging) vs sending the raw text as text. Exact page geometry, no image data returned. Compare levels/pack/font/codebook to pick a loss/size tradeoff. The result's 'recommend' field prices the reversible knobs (pack/codebook, level 0) and, separately under 'withDistill', the lossy-but-counted log route - one call replaces manual knob probing.",parameters:N,snippet:"Instant token verdict: would imaging this text beat sending it as text?"},{name:"tanuki_distill",label:"Tanuki Distill",description:"Stage 0 alone: make noisy logs/output small and readable WITHOUT imaging. Strips ANSI, collapses runs of near-identical lines/blocks into '[×N similar]', suppresses global near-dupes with exact counts, always keeps error/warn/fail lines verbatim, optional query (regex) returns only the relevant slice. Deterministic, order-preserving.",parameters:q.Object({text:K,query:q.Optional(q.String())}),snippet:"Deterministically dedupe noisy logs, keeping every error line verbatim"},{name:"tanuki_compress",label:"Tanuki Compress",description:"Stage 1 alone: graded text compression for content that stays TEXT. level 0 none · 1 whitespace (lossless, safe for code) · 2 prose · 3 dense · 4 caveman (gist only). From level 2 up code/IDs/hashes/paths are preserved verbatim.",parameters:q.Object({text:K,level:V}),snippet:"Graded text compression (lossless whitespace up to gist-only)"},{name:"tanuki_stats",label:"Tanuki Stats",description:"Summarize the pxpipe measurement log (~/.pxpipe/events.jsonl): requests, compression counts, honest input-token savings (input + cache reads + cache creates).",parameters:q.Object({}),snippet:"Session savings summary from the tanuki/pxpipe event log"},{name:"tanuki_stash",label:"Tanuki Stash",description:"Park bulky text outside the context window (content-addressed file under TANUKI_STASH or ~/.tanuki/stash) and get back a compact map: distill stats, top repeats, first/last lines, and the stash id. Pay a few hundred tokens now, fetch slices later - the retrieval pattern, with tanuki pricing on the way back.",parameters:q.Object({text:K}),snippet:"Park huge text on disk for a few hundred tokens of map; fetch slices later"},{name:"tanuki_fetch",label:"Tanuki Fetch",description:"Pull a slice of stashed text by id: query (regex, distill-powered: matches + error/warn lines + context) or lines 'a-b'. Big slices come back as dense PNG pages automatically when they clearly win (>=25% and >=300 tokens cheaper, <=6 pages); small ones stay text.",parameters:q.Object({id:q.String(),query:q.Optional(q.String()),lines:q.Optional(q.String())}),snippet:"Pull a stashed slice; big answers arrive as cheap dense pages"}];function $(F){let B=null,G=()=>{if(!B||!B.alive)B=new Q;return B};F.on("session_shutdown",async()=>{B?.kill(),B=null});for(let z of Z)F.registerTool({name:z.name,label:z.label,description:z.description,promptSnippet:z.snippet,parameters:z.parameters,async execute(H,D){let J=await G().call(z.name,D??{}),M=(J.content??[]).map((I)=>I.type==="image"?{type:"image",data:I.data??"",mimeType:I.mimeType??"image/png"}:{type:"text",text:I.text??""});if(J.isError)throw Error(M.map((I)=>("text"in I)?I.text:"").join(`
14
+ `),z}async call(F,B){return await this.ready,this.request("tools/call",{name:F,arguments:B})}kill(){this.proc.kill()}get alive(){return this.proc.exitCode===null&&!this.proc.killed}}var K=q.String({description:"The text to process"}),V=q.Optional(q.Integer({minimum:0,maximum:4,description:"0 raw · 1 whitespace · 2 prose · 3 dense · 4 caveman"})),N=q.Object({text:K,level:V,distill:q.Optional(q.Boolean()),query:q.Optional(q.String()),reflow:q.Optional(q.Boolean()),pack:q.Optional(q.Boolean()),font:q.Optional(q.String({enum:["normal","tiny"]})),codebook:q.Optional(q.Boolean()),model:q.Optional(q.String({description:"price the decision for this model (opus/sonnet/haiku/gpt/gemini)"})),cached:q.Optional(q.Boolean({description:"text already prompt-cached this turn? imaging it usually loses"}))}),Z=[{name:"tanuki_render",label:"Tanuki Render",description:"Token-cut pipeline: optional log distillation (dedupe noise, keep errors verbatim, optional query filter), optional codebook (repeated long tokens/path prefixes -> 1-cell sigils + a ·legend· line), then a ladder level, then dense PNG page(s) via the pxpipe imaging engine. level 0 raw · 1 whitespace (lossless) · 2 prose · 3 dense · 4 caveman (gist only). From level 2 up code/IDs/hashes/paths stay verbatim. pack (default true) = lossless tight reflow. font 'tiny' = 4x6 cell, ~40% fewer image-tokens (opt-in). Image tokens are pixel-priced, so every earlier cut compounds. Returns image blocks + a breakdown.",parameters:N,snippet:"Render bulky text/logs as dense PNG pages that cost a fraction of the tokens"},{name:"tanuki_estimate",label:"Tanuki Estimate",description:"Estimate tokens for the pipeline (distill -> codebook -> level -> pxpipe imaging) vs sending the raw text as text. Exact page geometry, no image data returned. Compare levels/pack/font/codebook to pick a loss/size tradeoff. The result's 'recommend' field prices the reversible knobs (pack/codebook, level 0) and, separately under 'withDistill', the lossy-but-counted log route. Pass 'model' and/or cached:true for a 'cost' field in real dollars - a cached text token costs ~0.1x a fresh one on Anthropic, so imaging already-cached content usually loses even with fewer tokens. One call replaces manual knob probing.",parameters:N,snippet:"Instant token verdict: would imaging this text beat sending it as text?"},{name:"tanuki_distill",label:"Tanuki Distill",description:"Stage 0 alone: make noisy logs/output small and readable WITHOUT imaging. Strips ANSI, collapses runs of near-identical lines/blocks into '[×N similar]', suppresses global near-dupes with exact counts, always keeps error/warn/fail lines verbatim, optional query (regex) returns only the relevant slice. Deterministic, order-preserving.",parameters:q.Object({text:K,query:q.Optional(q.String())}),snippet:"Deterministically dedupe noisy logs, keeping every error line verbatim"},{name:"tanuki_compress",label:"Tanuki Compress",description:"Stage 1 alone: graded text compression for content that stays TEXT. level 0 none · 1 whitespace (lossless, safe for code) · 2 prose · 3 dense · 4 caveman (gist only). From level 2 up code/IDs/hashes/paths are preserved verbatim.",parameters:q.Object({text:K,level:V}),snippet:"Graded text compression (lossless whitespace up to gist-only)"},{name:"tanuki_stats",label:"Tanuki Stats",description:"Summarize the pxpipe measurement log (~/.pxpipe/events.jsonl): requests, compression counts, honest input-token savings (input + cache reads + cache creates).",parameters:q.Object({}),snippet:"Session savings summary from the tanuki/pxpipe event log"},{name:"tanuki_stash",label:"Tanuki Stash",description:"Park bulky text outside the context window (content-addressed file under TANUKI_STASH or ~/.tanuki/stash) and get back a compact map: distill stats, top repeats, first/last lines, and the stash id. Pay a few hundred tokens now, fetch slices later - the retrieval pattern, with tanuki pricing on the way back.",parameters:q.Object({text:K}),snippet:"Park huge text on disk for a few hundred tokens of map; fetch slices later"},{name:"tanuki_fetch",label:"Tanuki Fetch",description:"Pull a slice of stashed text by id: query (regex, distill-powered: matches + error/warn lines + context) or lines 'a-b'. Big slices come back as dense PNG pages automatically when they clearly win (>=25% and >=300 tokens cheaper, <=6 pages); small ones stay text.",parameters:q.Object({id:q.String(),query:q.Optional(q.String()),lines:q.Optional(q.String())}),snippet:"Pull a stashed slice; big answers arrive as cheap dense pages"}];function $(F){let B=null,G=()=>{if(!B||!B.alive)B=new Q;return B};F.on("session_shutdown",async()=>{B?.kill(),B=null});for(let z of Z)F.registerTool({name:z.name,label:z.label,description:z.description,promptSnippet:z.snippet,parameters:z.parameters,async execute(H,D){let J=await G().call(z.name,D??{}),M=(J.content??[]).map((I)=>I.type==="image"?{type:"image",data:I.data??"",mimeType:I.mimeType??"image/png"}:{type:"text",text:I.text??""});if(J.isError)throw Error(M.map((I)=>("text"in I)?I.text:"").join(`
15
15
  `)||z.name+" failed");return{content:M,details:{}}}})}export{$ as default};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tanuki-context",
3
- "version": "0.4.1",
3
+ "version": "0.5.0",
4
4
  "description": "Token-cutting context pipeline as an MCP server: distill logs, compress text, render dense PNG pages (pxpipe imaging engine). Zero dependencies.",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: tanuki-context
3
- version: 0.4.1
3
+ version: 0.5.0
4
4
  description: |
5
5
  Cut input-token cost by rendering bulky text (logs, command output, long
6
6
  docs) as dense PNG pages the model reads at a fraction of the price, or by
@@ -34,6 +34,12 @@ verbatim, and every drop is counted.
34
34
  `{ id, lines: "a-b" }`. Big slices arrive as pages automatically.
35
35
  - `"TEXT cheaper"` -> just use the text. Small inputs are not worth an
36
36
  image even when the math technically favors one.
37
+ - **Already cached?** If the text is already in the prompt cache (a file
38
+ the harness re-sends every turn), pass `{ model: "<your model>",
39
+ cached: true }`. `tanuki_estimate` adds a `cost` block in real dollars:
40
+ a cache-read token costs ~0.1x a fresh one, so imaging cached content
41
+ usually *loses* even with fewer tokens - `cost.cheaper` says "TEXT" and
42
+ you leave it alone. Pass `model` alone to price a one-shot decision.
37
43
  3. **For noisy logs**, add `distill: true` (and `query: "regex"` for a
38
44
  slice). Error/warn/fail lines survive verbatim; repeats become one
39
45
  exemplar plus an exact xN count.