@ciandt-flow/cli 2.11.0-beta.53 → 2.11.1-beta.54
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/dist/index.js +132 -132
- package/package.json +1 -8
- package/dist/ctxa.js +0 -160
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ciandt-flow/cli",
|
|
3
|
-
"version": "2.11.
|
|
3
|
+
"version": "2.11.1-beta.54",
|
|
4
4
|
"description": "TUI for browsing and installing Claude Code plugins from the Flow ecosystem",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -51,13 +51,6 @@
|
|
|
51
51
|
"email": "flow@ciandt.com"
|
|
52
52
|
},
|
|
53
53
|
"dependencies": {
|
|
54
|
-
"@inquirer/core": "^10.1.1",
|
|
55
|
-
"@inquirer/prompts": "^7.2.1",
|
|
56
|
-
"@opentelemetry/api": "^1.9.1",
|
|
57
|
-
"@opentelemetry/exporter-metrics-otlp-http": "^0.221.0",
|
|
58
|
-
"@opentelemetry/resources": "^2.10.0",
|
|
59
|
-
"@opentelemetry/sdk-metrics": "^2.10.0",
|
|
60
|
-
"@opentelemetry/semantic-conventions": "^1.43.0",
|
|
61
54
|
"@tanstack/react-query": "5.104.1",
|
|
62
55
|
"boxen": "8.0.1",
|
|
63
56
|
"chalk": "6.0.1",
|
package/dist/ctxa.js
DELETED
|
@@ -1,160 +0,0 @@
|
|
|
1
|
-
import {Command}from'commander';import v from'chalk';import {checkbox,confirm}from'@inquirer/prompts';import {ExitPromptError}from'@inquirer/core';import {execFile,spawn}from'child_process';import {mkdtemp,rm,mkdir,writeFile,readFile,readlink,symlink,copyFile,appendFile,lstat,readdir,rename,stat}from'fs/promises';import wr,{homedir,tmpdir}from'os';import E,{dirname,join,sep,basename}from'path';import {promises}from'fs';import {randomUUID,createHash}from'crypto';import {promisify}from'util';var vn=15e3,Ks="2024-11-05";function _t(e){return `${JSON.stringify(e)}
|
|
2
|
-
`}async function Ys(e){let t=r=>({name:e.name,toolCount:0,schemaBytes:0,toolNames:[],error:r});if(e.transport!=="stdio"||!e.command)return t("apenas servidores stdio podem ser sondados localmente");let n=e.command,o=e.args??e.command.split(/\s+/).slice(1),s=e.args?n:n.split(/\s+/)[0]??n;return new Promise(r=>{let i=false,c=l=>{i||(i=true,clearTimeout(u),a.kill("SIGKILL"),r(l));},a=spawn(s,o,{stdio:["pipe","pipe","ignore"],env:{...process.env,...e.env}}),u=setTimeout(()=>c(t(`sem resposta em ${vn/1e3}s`)),vn);a.on("error",l=>c(t(`falha ao executar: ${l.message}`))),a.on("exit",l=>c(t(`processo encerrou (c\xF3digo ${l}) antes de responder`)));let d="";a.stdout.on("data",l=>{d+=l.toString("utf8");let p;for(;(p=d.indexOf(`
|
|
3
|
-
`))!==-1;){let g=d.slice(0,p).trim();if(d=d.slice(p+1),!g)continue;let h;try{h=JSON.parse(g);}catch{continue}if(h.id===1&&h.result){a.stdin.write(_t({jsonrpc:"2.0",method:"notifications/initialized"})),a.stdin.write(_t({jsonrpc:"2.0",id:2,method:"tools/list",params:{}}));continue}if(h.id===2){if(h.error){c(t(`tools/list falhou: ${h.error.message??"erro desconhecido"}`));return}c(Xs(e.name,h.result));return}}}),a.stdin.on("error",()=>c(t("stdin fechado pelo servidor"))),a.stdin.write(_t({jsonrpc:"2.0",id:1,method:"initialize",params:{protocolVersion:Ks,capabilities:{},clientInfo:{name:"ctxa",version:"0.1.0"}}}));})}function Xs(e,t){let n=typeof t=="object"&&t!==null&&"tools"in t?t.tools:void 0;if(!Array.isArray(n))return {name:e,toolCount:0,schemaBytes:0,toolNames:[],error:"resposta sem lista de tools"};let o=0,s=[];for(let r of n)if(o+=JSON.stringify(r).length,typeof r=="object"&&r!==null&&"name"in r){let i=r.name;typeof i=="string"&&s.push(i);}return {name:e,toolCount:n.length,schemaBytes:o,toolNames:s}}async function bn(e,t=4){let n=e.filter(s=>s.transport==="stdio"&&s.command),o=new Map;for(let s=0;s<n.length;s+=t){let r=n.slice(s,s+t),i=await Promise.all(r.map(c=>Ys(c)));for(let c of i)o.set(c.name,c);}return o}function k(e){return typeof e=="object"&&e!==null&&!Array.isArray(e)}function M(e){return typeof e=="number"&&Number.isFinite(e)?e:void 0}function P(e){return typeof e=="string"?e:void 0}function Qs(e){let t=k(e)?e:{},n={inputTokens:M(t.inputTokens)??0,outputTokens:M(t.outputTokens)??0,cacheReadInputTokens:M(t.cacheReadInputTokens)??0,cacheCreationInputTokens:M(t.cacheCreationInputTokens)??0,costUSD:M(t.costUSD)??0},o=M(t.contextWindow);return o!==void 0&&(n.contextWindow=o),n}function Qe(e){if(!k(e))return {};let t={};for(let[n,o]of Object.entries(e))t[n]=Qs(o);return t}function kn(e){return e??homedir()}function xe(e){return E.join(kn(e),".claude")}function De(e){return E.join(kn(e),".claude.json")}function q(e){return E.join(xe(e),"settings.json")}function He(e){return E.join(xe(e),"settings.local.json")}function Sn(e){return E.join(xe(e),"stats-cache.json")}function Ze(e){return E.join(xe(e),"plugins","cache")}function et(e){return E.join(xe(e),"plugins","installed_plugins.json")}async function K(e){let t;try{t=await readFile(e,"utf8");}catch{return}try{return JSON.parse(t)}catch{return}}function tr(e){if(!k(e))return {usageCount:0};let t=M(e.usageCount)??0,n=M(e.lastUsedAt);return n===void 0?{usageCount:t}:{usageCount:t,lastUsedAt:n}}function $t(e){if(!k(e))return {};let t={};for(let[n,o]of Object.entries(e))t[n]=tr(o);return t}function nr(e){return Array.isArray(e)?e.filter(t=>typeof t=="string"):[]}function or(e){return typeof e.command=="string"?"stdio":typeof e.url=="string"&&e.url.startsWith("http")?"http":e.type==="sse"?"sse":"unknown"}function Tn(e,t,n,o){if(!k(t))return;let s={name:e,scope:n,transport:or(t)},r=P(t.command);if(r!==void 0&&(s.command=r),Array.isArray(t.args)){let c=t.args.filter(a=>typeof a=="string");c.length>0&&(s.args=c);}if(k(t.env)){let c={};for(let[a,u]of Object.entries(t.env))typeof u=="string"&&(c[a]=u);Object.keys(c).length>0&&(s.env=c);}let i=P(t.url);return i!==void 0&&(s.url=i),o!==void 0&&(s.projectPath=o),s}function sr(e,t,n){let o=k(t)?t:{},s={path:e,mcpServers:[]},r=M(o.lastCost);r!==void 0&&(s.lastCost=r);let i=M(o.lastTotalInputTokens);i!==void 0&&(s.lastTotalInputTokens=i);let c=M(o.lastTotalOutputTokens);c!==void 0&&(s.lastTotalOutputTokens=c);let a=M(o.lastTotalCacheCreationInputTokens);a!==void 0&&(s.lastTotalCacheCreationInputTokens=a);let u=M(o.lastTotalCacheReadInputTokens);u!==void 0&&(s.lastTotalCacheReadInputTokens=u),k(o.lastModelUsage)&&(s.lastModelUsage=Qe(o.lastModelUsage));let d=P(o.lastSessionId);if(d!==void 0&&(s.lastSessionId=d),k(o.mcpServers)){let l=[];for(let[p,g]of Object.entries(o.mcpServers)){l.push(p);let h=Tn(p,g,"project",e);h!==void 0&&n.push(h);}s.mcpServers=l;}return s}async function xn(e){let t=De(e),n=await K(t),o=k(n)?n:{},s=[];if(k(o.mcpServers))for(let[i,c]of Object.entries(o.mcpServers)){let a=Tn(i,c,"user");a!==void 0&&s.push(a);}let r=[];if(k(o.projects))for(let[i,c]of Object.entries(o.projects))r.push(sr(i,c,s));return {path:t,toolUsage:$t(o.toolUsage),skillUsage:$t(o.skillUsage),pluginUsage:$t(o.pluginUsage),mcpServers:s,connectors:nr(o.claudeAiMcpEverConnected),projects:r}}var ar=new Set(["CLAUDE_CODE_EFFORT_LEVEL","CLAUDE_CODE_DISABLE_EXPERIMENTAL_BETAS"]),cr=new Set(["low","medium","high","xhigh","max"]),dr=new Set(["on","name-only","user-invocable-only","off"]);function Pn(e){if(!k(e))return {};let t={};for(let[n,o]of Object.entries(e)){let s=P(o);s!==void 0&&dr.has(s)&&(t[n]=s);}return t}function wn(e){return k(e)?Object.keys(e):[]}function tt(e,t){if(!(!ar.has(t)||!k(e)))return P(e[t])}function Cn(e){if(!k(e))return {};let t={};for(let[n,o]of Object.entries(e))typeof o=="boolean"&&(t[n]=o);return t}function It(e){return Array.isArray(e)?e.length:0}function An(e){let t=k(e)?e:{};return {allow:It(t.allow),deny:It(t.deny),ask:It(t.ask)}}function Lt(e){return Array.isArray(e)?e.filter(t=>typeof t=="string"):[]}function En(e){let t=k(e)?e:{};return {allow:Lt(t.allow),deny:Lt(t.deny),ask:Lt(t.ask)}}function Bt(e,t,n){if(!k(e))return [];let o=[];for(let[s,r]of Object.entries(e))if(Array.isArray(r))for(let i of r){if(!k(i))continue;let c=P(i.matcher)??"",a=Array.isArray(i.hooks)?i.hooks:[];for(let u of a){if(!k(u))continue;let d=P(u.command);if(d===void 0)continue;let l={event:s,matcher:c,command:d,source:t};n!==void 0&&(l.plugin=n),o.push(l);}}return o}function ur(e){let t=e.lastIndexOf("@");if(!(t<=0||t===e.length-1))return {plugin:e.slice(0,t),marketplace:e.slice(t+1)}}async function lr(e){try{return (await readdir(e,{withFileTypes:!0})).filter(n=>n.isDirectory()).map(n=>n.name)}catch{return []}}async function pr(e){try{return (await stat(e)).mtimeMs}catch{return}}async function mr(e){let t=await lr(e),n,o=-1/0;for(let s of t){let r=E.join(e,s,"hooks","hooks.json"),i=await pr(r);i!==void 0&&i>o&&(o=i,n=r);}return n}async function fr(e,t){let n=ur(e);if(n===void 0)return [];let o=E.join(Ze(t),n.marketplace,n.plugin),s=await mr(o);if(s===void 0)return [];let r=await K(s),i=k(r)?r.hooks:void 0;return Bt(i,"plugin",e)}async function Rn(e){let t=await K(q(e)),n=await K(He(e)),o=k(t)?t:{},s=k(n)?n:{},r=P(s.model)??P(o.model),i=P(s.outputStyle)??P(o.outputStyle),c={...Cn(o.enabledPlugins),...Cn(s.enabledPlugins)},a=[...Bt(o.hooks,"user-settings"),...Bt(s.hooks,"local-settings")];for(let[T,A]of Object.entries(c))A&&a.push(...await fr(T,e));let u=An(o.permissions),d=An(s.permissions),l={allow:u.allow+d.allow,deny:u.deny+d.deny,ask:u.ask+d.ask},p=En(o.permissions),g=En(s.permissions),h={allow:[...p.allow,...g.allow],deny:[...p.deny,...g.deny],ask:[...p.ask,...g.ask]},m=[...new Set([...wn(o.env),...wn(s.env)])],f=tt(s.env,"CLAUDE_CODE_EFFORT_LEVEL")??tt(o.env,"CLAUDE_CODE_EFFORT_LEVEL"),y=tt(s.env,"CLAUDE_CODE_DISABLE_EXPERIMENTAL_BETAS")??tt(o.env,"CLAUDE_CODE_DISABLE_EXPERIMENTAL_BETAS"),S={...Pn(o.skillOverrides),...Pn(s.skillOverrides)},b={enabledPlugins:c,hooks:a,permissionCounts:l,permissionRules:h,envKeys:m,skillOverrides:S};f!==void 0&&cr.has(f)&&(b.envEffortLevel=f),y!==void 0&&(b.envDisableExperimentalBetas=y),r!==void 0&&(b.model=r),i!==void 0&&(b.outputStyle=i);let x=s.disableClaudeAiConnectors??o.disableClaudeAiConnectors;typeof x=="boolean"&&(b.disableClaudeAiConnectors=x);let O=P(s.effortLevel)??P(o.effortLevel);O!==void 0&&(b.effortLevel=O);let V=P(s.otelHeadersHelper)??P(o.otelHeadersHelper);V!==void 0&&(b.otelHeadersHelper=V);let X=s.autoCompactEnabled??o.autoCompactEnabled;return typeof X=="boolean"&&(b.autoCompactEnabled=X),b}function gr(e){if(!Array.isArray(e))return [];let t=[];for(let n of e){if(!k(n))continue;let o=P(n.date);o!==void 0&&t.push({date:o,messageCount:M(n.messageCount)??0,sessionCount:M(n.sessionCount)??0,toolCallCount:M(n.toolCallCount)??0});}return t}async function On(e){let t=await K(Sn(e)),n=k(t)?t:{},o={totalSessions:M(n.totalSessions)??0,totalMessages:M(n.totalMessages)??0,modelUsage:Qe(n.modelUsage),dailyActivity:gr(n.dailyActivity)},s=P(n.firstSessionDate);return s!==void 0&&(o.firstSessionDate=s),o}var hr=/^---\r?\n([\s\S]*?)\r?\n---[ \t]*\r?\n?/,yr=/^([A-Za-z0-9_-]+):[ \t]?(.*)$/,vr=/^([>|])([+-]?)\d*$/;function Ut(e){let t=hr.exec(e);if(!t)return {fields:{},body:e};let n=t[1]??"",o=e.slice(t[0].length);return {fields:br(n),body:o}}function Nt(e){let t=/^[ \t]*/.exec(e);return t?t[0].length:0}function br(e){let t=e.split(/\r?\n/),n={},o=0;for(;o<t.length;){let s=t[o]??"";if(o++,s.trim()===""||Nt(s)>0)continue;let r=yr.exec(s);if(!r)continue;let i=r[1]??"",c=(r[2]??"").trim();if(c===""){for(;o<t.length&&(t[o]===""||Nt(t[o]??"")>0);)o++;n[i]="";continue}let a=vr.exec(c);if(a){let u=a[1]??">",d=a[2]??"",l=[],p=null;for(;o<t.length;){let g=t[o]??"";if(g.trim()===""){l.push(""),o++;continue}let h=Nt(g);if(p===null&&(p=h),h<p)break;l.push(g.slice(p)),o++;}n[i]=kr(l,u,d);continue}if(c.startsWith('"')){n[i]=Sr(c);continue}if(c.startsWith("'")){n[i]=xr(c);continue}n[i]=c;}return n}function kr(e,t,n){let o=[...e];for(;o.length>0&&o[o.length-1]==="";)o.pop();let s;if(t==="|")s=o.join(`
|
|
4
|
-
`);else {let r=[],i=[];for(let c of o)c===""?i.length>0&&(r.push(i.join(" ")),i=[]):i.push(c);i.length>0&&r.push(i.join(" ")),s=r.join(`
|
|
5
|
-
`);}return n!=="-"&&s.length>0&&(s+=`
|
|
6
|
-
`),s}function Sr(e){let t=Tr(e);return (t===-1?e.slice(1):e.slice(1,t)).replace(/\\(.)/g,"$1")}function Tr(e){for(let t=1;t<e.length;t++)if(e[t]==='"'&&e[t-1]!=="\\")return t;return -1}function xr(e){return (e.endsWith("'")&&e.length>1?e.slice(1,-1):e.slice(1)).replace(/''/g,"'")}async function ee(e){try{return await promises.stat(e),!0}catch{return false}}async function Dn(e){try{return await promises.readdir(e,{withFileTypes:!0})}catch{return []}}async function Je(e){return (await Dn(e)).filter(n=>n.isDirectory()&&!n.name.startsWith(".")).map(n=>n.name).sort()}async function nt(e){let t=await Dn(e),n=Fe(16);return (await Promise.all(t.map(s=>n(async()=>{let r=E.join(e,s.name);if(s.isSymbolicLink())try{return (await promises.lstat(r)).size}catch{return 0}if(s.isDirectory())return nt(r);try{return (await promises.stat(r)).size}catch{return 0}})))).reduce((s,r)=>s+r,0)}async function Fn(e){try{let t=await promises.readFile(e,"utf8");return JSON.parse(t)}catch{return}}function Fe(e){let t=0,n=[],o=()=>{if(t>=e)return;let s=n.shift();s&&(t++,s());};return function(r){return new Promise((i,c)=>{n.push(()=>{r().then(a=>{t--,i(a),o();}).catch(a=>{t--,c(a instanceof Error?a:new Error(String(a))),o();});}),o();})}}var Cr=3,Ar=300;async function $n(e){let t=e??wr.homedir(),n=E.join(t,".claude"),o=[];o.push(...await In(E.join(n,"skills"),"user")),o.push(...await ot(E.join(n,"agents"),"agent","user")),o.push(...await ot(E.join(n,"commands"),"command","user"));let{pluginArtifacts:s,plugins:r}=await Rr(n);return o.push(...s),{artifacts:o,plugins:r}}async function In(e,t,n){if(!await ee(e))return [];let o;try{o=await promises.readdir(e,{withFileTypes:!0});}catch{return []}let s=Fe(16);return (await Promise.all(o.map(i=>s(async()=>{if(!i.isDirectory()&&!i.isSymbolicLink())return null;let c=E.join(e,i.name);return Er(c,i.name,t,n)})))).filter(i=>i!==null)}async function Er(e,t,n,o){let r={kind:"skill",name:n==="plugin"&&o?`${o}:${t}`:t,scope:n,plugin:o},i=e;if(await Mr(e)){let p=await promises.readlink(e),g=E.resolve(E.dirname(e),p);if(!await ee(g))return {...r,path:e,descriptionBytes:0,bodyBytes:0,dirBytes:0,broken:`symlink quebrado -> ${p}`};i=g;}let c=E.join(i,"SKILL.md");if(!await ee(c)){let p=await nt(i);return {...r,path:i,descriptionBytes:0,bodyBytes:0,dirBytes:p,broken:"diret\xF3rio de skill sem SKILL.md"}}let[a,u]=await Promise.all([promises.readFile(c,"utf8"),nt(i)]),{fields:d,body:l}=Ut(a);return {...r,path:c,descriptionBytes:st(d.description),bodyBytes:st(l),dirBytes:u}}async function Mr(e){try{return (await promises.lstat(e)).isSymbolicLink()}catch{return false}}async function ot(e,t,n,o){if(!await ee(e))return [];let s;try{s=await promises.readdir(e,{withFileTypes:!0});}catch{return []}let r=s.filter(c=>c.isFile()&&c.name.endsWith(".md")),i=Fe(16);return Promise.all(r.map(c=>i(async()=>{let a=E.join(e,c.name),u=c.name.slice(0,-3),d=n==="plugin"&&o?`${o}:${u}`:u,[l,p]=await Promise.all([promises.readFile(a,"utf8"),promises.stat(a)]),{fields:g,body:h}=Ut(l),m={kind:t,name:d,path:a,scope:n,plugin:o,descriptionBytes:st(g.description),bodyBytes:st(h),dirBytes:p.size};return t==="agent"&&g.model&&(m.model=g.model),m})))}function st(e){return e?Buffer.byteLength(e,"utf8"):0}async function Rr(e){let t=E.join(e,"plugins","cache"),n=[],o=new Map,s=await Je(t);for(let r of s){let i=E.join(t,r),c=await Je(i);for(let a of c){let u=E.join(i,a),d=await Je(u),l=[],p=[];for(let h of d){let m=E.join(u,h);if(l.push(m),await ee(E.join(m,".orphaned_at"))){p.push(m);continue}let y=await Dr(m),[S,b,x]=await Promise.all([In(E.join(y,"skills"),"plugin",a),ot(E.join(y,"agents"),"agent","plugin",a),ot(E.join(y,"commands"),"command","plugin",a)]);n.push(...S,...b,...x);}let g=`${a}@${r}`;o.set(g,{name:g,enabled:false,installed:false,scope:"",cacheDirs:l,orphanedDirs:p});}}return await jr(E.join(e,"plugins","installed_plugins.json"),o),{pluginArtifacts:n,plugins:Array.from(o.values())}}async function jn(e){if(await ee(E.join(e,".claude-plugin","plugin.json")))return true;let[t,n,o]=await Promise.all([Or(E.join(e,"skills")),_n(E.join(e,"agents")),_n(E.join(e,"commands"))]);return t||n||o}async function _n(e){let t;try{t=await promises.readdir(e,{withFileTypes:!0});}catch{return false}return t.some(n=>n.isFile()&&n.name.endsWith(".md"))}async function Or(e){let t;try{t=await promises.readdir(e,{withFileTypes:!0});}catch{return false}return (await Promise.all(t.filter(o=>o.isDirectory()).map(o=>ee(E.join(e,o.name,"SKILL.md"))))).some(Boolean)}async function Dr(e){if(await jn(e))return e;let t=[e],n=0;for(let o=0;o<Cr&&t.length>0;o++){let s=[];for(let r of t){if(n>=Ar)return e;let i=await Je(r);for(let c of i){n++;let a=E.join(r,c);if(await jn(a))return a;s.push(a);}}t=s;}return e}function Fr(e){return typeof e=="object"&&e!==null}async function jr(e,t){let n=await Fn(e);if(typeof n!="object"||n===null)return;let o=n.plugins;if(!(typeof o!="object"||o===null))for(let[s,r]of Object.entries(o)){if(!Array.isArray(r))continue;let i=r.filter(Fr),c=Array.from(new Set(i.map(d=>d.scope).filter(d=>!!d))).sort(),a=Array.from(new Set(i.map(d=>d.installPath).filter(d=>!!d))),u=t.get(s);if(u){u.installed=true,u.scope=c.join(",");continue}t.set(s,{name:s,installed:true,enabled:false,scope:c.join(","),cacheDirs:a,orphanedDirs:[]});}}function R(e){return Math.round(e/4)}var zt="CLAUDE.md",Ir=6,qt=16,Lr=80,Br=12,Nr=/^[ \t]*`{3,}/,Ur=/^(\||[-*+]\s|\d+[.)]\s)/,Ln=/^(#{1,6})\s+(.*)$/,zr=3,qr=.6,Hr=new Set(["node_modules",".git","dist","build",".next","coverage"]);async function Nn(e){let t=e?.homeDir??wr.homedir(),n=e?.searchRoots??[E.join(t,"git")],o=E.resolve(E.join(t,".claude",zt)),s=E.resolve(t),r=(e?.projectPaths??[]).map(d=>E.resolve(d)),i=new Set;i.add(o),i.add(E.resolve(E.join(t,zt)));let c=Fe(qt),a=await Promise.all(n.map(d=>Jr(d)));for(let d of a)for(let l of d)i.add(E.resolve(l));let u=(await Promise.all(Array.from(i).map(d=>c(()=>Vr(d,o,s,r))))).filter(d=>d!==null);return u.sort((d,l)=>d.path.localeCompare(l.path)),{files:u}}function Bn(e,t){let n=E.relative(e,t);return n===""||!n.startsWith("..")&&!E.isAbsolute(n)}function Wr(e,t,n){let o=E.resolve(E.dirname(e));return Bn(t,o)?n.filter(s=>Bn(o,s)).sort():[]}async function Jr(e){if(!await ee(e))return [];let t=[],n=[{dir:e,depth:0}];for(;n.length>0;){let o=[];for(let s=0;s<n.length;s+=qt){let r=n.slice(s,s+qt),i=await Promise.all(r.map(c=>Gr(c)));for(let c of i)t.push(...c.files),o.push(...c.dirs);}n=o;}return t}async function Gr({dir:e,depth:t}){let n;try{n=await promises.readdir(e,{withFileTypes:!0});}catch{return {files:[],dirs:[]}}let o=[],s=[];for(let r of n)if(!r.isSymbolicLink()){if(r.isFile()){r.name===zt&&o.push(E.join(e,r.name));continue}if(r.isDirectory()){if(Hr.has(r.name)||t>=Ir)continue;s.push({dir:E.join(e,r.name),depth:t+1});}}return {files:o,dirs:s}}async function Vr(e,t,n,o){let s;try{s=await promises.readFile(e,"utf8");}catch{return null}let r=Buffer.byteLength(s,"utf8"),i=E.resolve(e)===t?"global":"project",{imports:c,importedBytes:a}=await Xr(e,s),u=i==="global"?[]:Wr(e,n,o),{codeBlockBytes:d,tableBytes:l}=Qr(s);return {path:e,scope:i,bytes:r,lines:Kr(s),estTokens:R(r),imports:c,importedBytes:a,blockHashes:ni(s),inheritedBy:u,codeBlockBytes:d,tableBytes:l,hasSkillCatalogSection:ti(s)}}function Kr(e){if(e==="")return 0;let t=(e.match(/\n/g)??[]).length;return e.endsWith(`
|
|
7
|
-
`)?t:t+1}var Yr=/^@(\S+)/;function Un(e){let t=[];for(let n of e.split(/\r?\n/)){let o=n.trim(),s=Yr.exec(o);s?.[1]&&t.push(s[1]);}return t}async function Xr(e,t){let n=E.dirname(e),o=[];for(let c of Un(t)){let a=E.resolve(n,c);await ee(a)&&o.push(a);}let s=Array.from(new Set(o)),r=new Set([E.resolve(e)]),i=0;for(let c of s)i+=await zn(c,r);return {imports:s,importedBytes:i}}async function zn(e,t){let n=E.resolve(e);if(t.has(n))return 0;t.add(n);let o;try{o=await promises.readFile(n,"utf8");}catch{return 0}let s=Buffer.byteLength(o,"utf8"),r=E.dirname(n);for(let i of Un(o)){let c=E.resolve(r,i);await ee(c)&&(s+=await zn(c,t));}return s}function Qr(e){let t=e.replace(/\r\n/g,`
|
|
8
|
-
`).split(`
|
|
9
|
-
`),n=false,o=0,s=0;return t.forEach((r,i)=>{if(Nr.test(r)){n=!n;return}let c=Buffer.byteLength(r,"utf8")+(i===t.length-1?0:1);n?o+=c:r.trimStart().startsWith("|")&&(s+=c);}),{codeBlockBytes:o,tableBytes:s}}function Zr(e){return e.replace(/^[^\p{L}\p{N}]+|[^\p{L}\p{N}]+$/gu,"")}function ei(e){let t=e.replace(/\([^)]*\)/g,"").trim().split(/\s+/).filter(r=>r.length>0),n=t[0],o=t[t.length-1];if(n===void 0||o===void 0)return false;let s=r=>{let i=Zr(r).toLowerCase();return i==="skill"||i==="skills"};return s(n)||s(o)}function ti(e){let t=e.replace(/\r\n/g,`
|
|
10
|
-
`).split(`
|
|
11
|
-
`);for(let n=0;n<t.length;n++){let o=t[n];if(o===void 0)continue;let s=Ln.exec(o);if(s===null||!ei(s[2]??""))continue;let r=n+1;for(;r<t.length&&!Ln.test(t[r]??"");)r+=1;let i=0,c=0;for(let a=n+1;a<r;a++){let u=(t[a]??"").trim();u!==""&&(i+=1,Ur.test(u)&&(c+=1));}if(c>=zr&&c/i>=qr)return true}return false}function ni(e){let t=e.replace(/\r\n/g,`
|
|
12
|
-
`).split(/\n[ \t]*\n+/),n=[];for(let o of t){let s=o.trim().replace(/\s+/g," ");if(s.length<Lr)continue;let r=createHash("sha1").update(s,"utf8").digest("hex").slice(0,Br);n.push(r);}return n}var ii={"ralph-loop.local.md":"ralph-loop","ralph-wiggum.local.md":"ralph-wiggum","ralph.local.md":"ralph","loop-state.local.md":"loop"},ai=/^(?:(.+)-loop|loop-(.+))\.local\.md$/;function ci(e){let t=ii[e];if(t!==void 0)return t;let n=ai.exec(e);if(n===null)return;let o=n[1]??n[2];return o===void 0?void 0:`${o}-loop`}function di(e){let t=e.split(`
|
|
13
|
-
`);if(t[0]?.trim()!=="---")return {};let n={};for(let o of t.slice(1)){if(o.trim()==="---")break;let s=o.indexOf(":");if(s<=0)continue;let r=o.slice(0,s).trim(),i=o.slice(s+1).trim().replace(/^"(.*)"$/,"$1");r.length>0&&(n[r]=i);}return n}function ui(e){let t=e.split(`
|
|
14
|
-
`);if(t[0]?.trim()!=="---")return;let n=-1;for(let o=1;o<t.length;o++)if(t[o]?.trim()==="---"){n=o;break}if(n!==-1)for(let o of t.slice(n+1)){let s=o.trim();if(s.length>0)return s}}function rt(e){if(e===void 0)return;let t=e.trim();if(!(t===""||t==="null"||t==="none"))return t}function li(e){let t=rt(e);if(t===void 0)return;let n=Number(t);return Number.isFinite(n)?n:void 0}async function pi(e,t,n){let o;try{o=await readFile(e,"utf8");}catch{return}let s=di(o),r={path:e,project:t,tool:n,active:s.active?.trim().toLowerCase()==="true"},i=li(s.iteration);i!==void 0&&(r.iteration=i);let c=s.max_iterations?.trim();c!==void 0&&c!==""&&Number.isFinite(Number(c))&&(r.maxIterations=Number(c));let a=rt(s.completion_promise);a!==void 0&&(r.completionPromise=a);let u=rt(s.session_id);u!==void 0&&(r.sessionId=u);let d=rt(s.started_at);d!==void 0&&(r.startedAt=d);let l=ui(o);l!==void 0&&(r.prompt=l);try{r.modifiedAt=(await stat(e)).mtime.toISOString();}catch{}return r}async function Hn(e){let t=new Set,n=[];for(let o of e.projectPaths){let s=E.join(o,".claude");if(t.has(s))continue;t.add(s);let r;try{r=await readdir(s,{withFileTypes:!0});}catch{continue}for(let i of r){if(!i.isFile())continue;let c=ci(i.name);if(c===void 0)continue;let a=await pi(E.join(s,i.name),o,c);a!==void 0&&n.push(a);}}return n}var yi="ctxa",vi="manifest.json",bi=5,ki=`summaries-v${bi}`,Pe={};function Si(){let e=process.env.XDG_CACHE_HOME,t=e!==void 0&&e.length>0?e:join(homedir(),".cache");return join(t,yi)}function Wt(){return Si()}function Jt(){return join(Wt(),ki)}function Wn(){return join(Wt(),vi)}function Ti(e){return typeof e=="object"&&e!==null&&!Array.isArray(e)}async function Jn(){try{let e=await readFile(Wn(),"utf8"),t=JSON.parse(e);Pe=Ti(t)?t:{};}catch{Pe={};}return Pe}function Gn(){return Pe}function Vn(e,t){let n=Pe[e];return n===void 0?false:n.mtimeMs===t.mtimeMs&&n.size===t.size}function Kn(e,t){Pe[e]=t;}async function Yn(){await mkdir(Wt(),{recursive:true}),await writeFile(Wn(),JSON.stringify(Pe),"utf8");}function Ai(e){return createHash("sha1").update(e).digest("hex")}function Ei(e){return typeof e=="object"&&e!==null&&"sessionId"in e&&"turns"in e&&"byModel"in e}async function Qn(e){let t=Gn()[e];if(t!==void 0)try{let n=await readFile(join(Jt(),t.summaryFile),"utf8"),o=JSON.parse(n);return Ei(o)?o:void 0}catch{return}}async function Zn(e,t,n){let o=Jt();await mkdir(o,{recursive:true});let s=`${Ai(e)}.json`;await writeFile(join(o,s),JSON.stringify(n),"utf8"),Kn(e,{mtimeMs:t.mtimeMs,size:t.size,summaryFile:s});}function Di(e){return join(e??homedir(),".claude")}function to(e){return join(Di(e),"projects")}async function no(e){let t=[];async function n(o){let s;try{s=await readdir(o,{withFileTypes:!0});}catch{return}for(let r of s){let i=join(o,r.name);r.isDirectory()?await n(i):r.isFile()&&r.name.endsWith(".jsonl")&&t.push(i);}}return await n(e),t}function oo(e){return e.includes(`${sep}subagents${sep}`)}function so(e,t){let n=t.slice(e.length).replace(/^[/\\]/,""),o=n.split(/[/\\]/)[0];return (o!==void 0&&o.length>0?o:n).replace(/-/g,"/")}function ro(e){return basename(e).replace(/\.jsonl$/,"").replace(/\.orphaned-\d+-[0-9a-f]+$/,"")}var _i=20,$i=8,Ii=400,Li=1,Bi=36e5,Ni=3e5,Ui=new Set(["Edit","Write","NotebookEdit","MultiEdit"]);function ie(e){return typeof e=="object"&&e!==null&&!Array.isArray(e)}function B(e,t){let n=e[t];return typeof n=="string"?n:void 0}function le(e,t){let n=e[t];return typeof n=="number"?n:void 0}function io(e,t){let n=e[t];return Array.isArray(n)?n:void 0}function ao(e){if(e===void 0)return 0;let t=JSON.stringify(e);return typeof t=="string"?t.length:0}function zi(e){let t=e?.cache_creation;if(!ie(t))return;if((le(t,"ephemeral_1h_input_tokens")??0)>0)return Bi;if((le(t,"ephemeral_5m_input_tokens")??0)>0)return Ni}function qi(e){let t,n=-1;for(let[o,s]of e)s>n&&(n=s,t=o);return t}function Hi(e,t,n){if(n<=0)return;if(e.length<n){e.push(t),e.sort((s,r)=>s.chars-r.chars);return}let o=e[0];o!==void 0&&t.chars>o.chars&&(e[0]=t,e.sort((s,r)=>s.chars-r.chars));}var Wi=/(^|[/\\])(bench|benchmark)s?(?=[/\\]|$)/i;function Ji(e){return Wi.test(e)}function Gi(e,t){let n=0;for(let i of t.values())n+=i;return n===0||(t.get("cli")??0)>0||!((t.get("sdk-cli")??0)/n>=.5)?"organic":Ji(e)?"synthetic":"organic"}async function Vi(e,t){let o=(await readFile(e,"utf8")).split(`
|
|
15
|
-
`),s,r,i,c,a,u=0,d=0,l=0,p=0,g=0,h=0,m=0,f,y=new Map,S=new Map,b={},x={},O={},V={},X={},T=[],A=[],j=new Map,he=new Map,Q={turns:0,outputTokens:0,cacheRead:0};for(let _ of o){let ye=_.trim();if(ye.length===0)continue;let J;try{J=JSON.parse(ye);}catch{continue}if(ie(J))try{let fn=B(J,"sessionId");fn!==void 0&&s===void 0&&(s=fn);let gn=B(J,"cwd");gn!==void 0&&r===void 0&&(r=gn);let de=B(J,"timestamp");if(de!==void 0&&(i===void 0&&(i=de),c=de),a===void 0){let z=B(J,"attributionAgent");z!==void 0&&(a=z);}let Dt=B(J,"entrypoint");Dt!==void 0&&S.set(Dt,(S.get(Dt)??0)+1);let Ft=B(J,"type");if(Ft==="assistant"){u+=1,l+=1;let z=J.message;if(!ie(z))continue;let ve=B(z,"model"),Me=z.usage,te=ie(Me)?Me:void 0,Xe=te?le(te,"input_tokens")??0:0,ne=te?le(te,"output_tokens")??0:0,ke=te?le(te,"cache_creation_input_tokens")??0:0,Re=te?le(te,"cache_read_input_tokens")??0:0;l>1?p+=ke:g=Re;let be=zi(te);be!==void 0&&y.set(be,(y.get(be)??0)+1);let qe=de!==void 0?Date.parse(de):NaN,hn=!Number.isNaN(qe);if(l>1&&be!==void 0&&hn&&f!==void 0&&qe-f>be&&(h+=ke,m+=1),f=hn?qe:void 0,ve!==void 0){let L=b[ve]??{turns:0,inputTokens:0,outputTokens:0,cacheCreation:0,cacheRead:0};if(L.turns+=1,L.inputTokens+=Xe,L.outputTokens+=ne,L.cacheCreation+=ke,L.cacheRead+=Re,b[ve]=L,de!==void 0){let oe=de.slice(0,7);if(oe.length===7){let Oe=x[oe]??{},se=Oe[ve]??{turns:0,inputTokens:0,outputTokens:0,cacheCreation:0,cacheRead:0};se.turns+=1,se.inputTokens+=Xe,se.outputTokens+=ne,se.cacheCreation+=ke,se.cacheRead+=Re,Oe[ve]=se,x[oe]=Oe;}}}let jt=B(J,"effort");if(jt!==void 0){let L=O[jt]??{turns:0,outputTokens:0};L.turns+=1,L.outputTokens+=ne,O[jt]=L;}let Gs=io(z,"content")??[],yn=0;for(let L of Gs){if(!ie(L)||B(L,"type")!=="tool_use")continue;yn+=1;let oe=B(L,"name");if(oe===void 0)continue;V[oe]=(V[oe]??0)+1,Ui.has(oe)&&(d+=1);let Oe=B(L,"id");Oe!==void 0&&he.set(Oe,oe);let se=L.input;if(oe==="Skill"&&ie(se)){let Se=B(se,"skill");Se!==void 0&&(X[Se]=(X[Se]??0)+1);}if(oe==="Read"&&ie(se)){let Se=B(se,"file_path");Se!==void 0&&j.set(Se,(j.get(Se)??0)+1);}}ve!==void 0&&ve.includes("opus")&&ne<Ii&&yn<=Li&&(Q.turns+=1,Q.outputTokens+=ne,Q.cacheRead+=Re);}else if(Ft==="user"){let z=J.message,Me=(ie(z)?io(z,"content")??[]:[]).filter(ne=>ie(ne)&&B(ne,"type")==="tool_result");if(Me.length===0)continue;let te=J.toolUseResult,Xe=ao(te);for(let ne of Me){let ke=B(ne,"tool_use_id"),Re=ke!==void 0?he.get(ke)??"unknown":"unknown",be=ao(ne.content),qe=Me.length===1?Math.max(be,Xe):be;Hi(A,{tool:Re,chars:qe,sessionId:s??"",project:r??"",timestamp:de},t.maxFatResults);}}else if(Ft==="system"&&B(J,"subtype")==="compact_boundary"){let z=J.compactMetadata;ie(z)&&T.push({sessionId:s??"",project:r??"",trigger:B(z,"trigger")??"unknown",preTokens:le(z,"preTokens")??0,postTokens:le(z,"postTokens")??0,droppedTokens:le(z,"cumulativeDroppedTokens")??0,timestamp:de});}}catch{continue}}let $=s??ro(e),Z=r??so(t.projectsDir,e),ze=Gi(Z,S);for(let _ of A)_.sessionId===""&&(_.sessionId=$),_.project===""&&(_.project=Z);for(let _ of T)_.sessionId===""&&(_.sessionId=$),_.project===""&&(_.project=Z);let Js=[...j.entries()].filter(([,_])=>_>=2).map(([_,ye])=>({file:_,count:ye})).sort((_,ye)=>ye.count-_.count);return A.sort((_,ye)=>ye.chars-_.chars),{sessionId:$,project:Z,file:e,startedAt:i,endedAt:c,turns:u,byModel:b,byEffort:O,toolCalls:V,skillInvocations:X,cacheCreationAfterFirstTurn:p,inheritedCacheRead:g,byMonth:x,cacheCreationAfterExpiry:h,turnsAfterExpiry:m,cacheTtlMs:qi(y),compactions:T,fatResults:A,repeatedReads:Js,origin:ze,editsProduced:d,trivialOpusTurns:Q,isSidechain:t.isSubagent,agentType:a}}async function Ki(e,t,n){let o=0,s=Math.max(1,Math.min(t,e.length)),r=Array.from({length:s},async()=>{for(;;){let i=o;if(o+=1,i>=e.length)return;let c=e[i];if(c===void 0)return;await n(c,i);}});await Promise.all(r);}async function co(e={}){let t=Date.now(),n=e.useCache??true,o=e.maxFatResults??_i,s=to(e.homeDir),r=await no(s);n&&await Jn();let i=new Array(r.length).fill(void 0),c=0,a=0,u=0;await Ki(r,$i,async(g,h)=>{let m;try{m=await stat(g);}catch{u+=1,e.onProgress?.(u,r.length);return}a+=m.size;let f={mtimeMs:m.mtimeMs,size:m.size};if(n&&Vn(g,f)){let b=await Qn(g);if(b!==void 0){i[h]=b,c+=1,u+=1,e.onProgress?.(u,r.length);return}}let y=oo(g),S=await Vi(g,{isSubagent:y,maxFatResults:o,projectsDir:s});i[h]=S,n&&await Zn(g,f,S),u+=1,e.onProgress?.(u,r.length);}),n&&await Yn();let d=i.filter(g=>g!==void 0),l=0,p=0;for(let g of d)g.origin==="synthetic"?l+=1:p+=1;return {sessions:d,scannedFiles:r.length,cachedFiles:c,totalBytes:a,scanMs:Date.now()-t,syntheticSessions:l,organicSessions:p}}var Yi=[{match:e=>e.includes("opus"),inputPerMTok:15,outputPerMTok:75},{match:e=>e.includes("sonnet"),inputPerMTok:3,outputPerMTok:15},{match:e=>e.includes("haiku"),inputPerMTok:1,outputPerMTok:5},{match:e=>e.includes("fable"),inputPerMTok:3,outputPerMTok:15}],uo={inputPerMTok:3,outputPerMTok:15};function Xi(e){return e.toLowerCase().replace(/^anthropic\./,"").replace(/\[1m\]$/,"").replace(/-\d{8}$/,"").trim()}function Vt(e,t,n,o){return {model:e,inputPerMTok:t,outputPerMTok:n,cacheWritePerMTok:t*1.25,cacheReadPerMTok:t*.1,source:o}}function Qi(e){let t=Xi(e),n=Yi.find(o=>o.match(t));return n?Vt(e,n.inputPerMTok,n.outputPerMTok,"table"):Vt(e,uo.inputPerMTok,uo.outputPerMTok,"fallback")}function Zi(e,t){let{inputTokens:n,outputTokens:o,cacheCreationInputTokens:s,cacheReadInputTokens:r,costUSD:i}=t;if(n+o+s+r<1e3||i<.005)return;let a=n/1e6+5*(o/1e6)+1.25*(s/1e6)+.1*(r/1e6);if(a<=0)return;let u=i/a;if(!(!Number.isFinite(u)||u<=0))return Vt(e,u,u*5,"derived")}function lo(e){return e.inputTokens+e.outputTokens+e.cacheCreationInputTokens+e.cacheReadInputTokens}function ea(e){let t=Object.entries(e);if(t.length===0)return "";let o=t.some(([,r])=>r.costUSD>0)?([,r])=>r.costUSD:([,r])=>lo(r),s=t[0];for(let r of t)(s===void 0||o(r)>o(s))&&(s=r);return s?.[0]??""}function ta(e,t){let n=e.filter(u=>u.messageCount>0||u.sessionCount>0).slice().sort((u,d)=>u.date<d.date?1:u.date>d.date?-1:0).slice(0,30);if(n.length===0)return {turnsPerMonth:200,sessionsPerMonth:15,usingDefaults:true};let o=na(t);if(o)return o;let r=n.reduce((u,d)=>u+d.sessionCount,0)/n.length,i=Math.round(r*30),a=n.reduce((u,d)=>u+d.messageCount,0)/n.length;return {turnsPerMonth:Math.round(a/2*30),sessionsPerMonth:i,usingDefaults:false}}function na(e){if(!e)return;let t=e.sessions.filter(s=>!s.isSidechain);if(t.length===0)return;let n=po(e.sessions);if(n===void 0)return;let o=e.sessions.reduce((s,r)=>s+r.turns,0);return {sessionsPerMonth:Math.round(t.length/n*30),turnsPerMonth:Math.round(o/n*30),usingDefaults:false}}function oa(e){if(!e||e.sessions.length===0)return;let t=0;for(let n of e.sessions)for(let o of Object.values(n.byModel))t+=o.inputTokens+o.outputTokens+o.cacheCreation+o.cacheRead;return t>0?t:void 0}function po(e){let t=Number.POSITIVE_INFINITY,n=Number.NEGATIVE_INFINITY;for(let s of e)for(let r of [s.startedAt,s.endedAt]){if(!r)continue;let i=Date.parse(r);Number.isFinite(i)&&(i<t&&(t=i),i>n&&(n=i));}if(!Number.isFinite(t)||!Number.isFinite(n))return;let o=(n-t)/864e5;return o>=1?o:void 0}function sa(e){let t=e.map(r=>r.date).filter(Boolean).sort(),n=t[0],o=t.at(-1);if(!n||!o)return 30;let s=(Date.parse(o)-Date.parse(n))/864e5;return Number.isFinite(s)&&s>=1?Math.round(s)+1:30}var ra=new WeakMap;var ia=2e5;function aa(e,t){return e!==void 0&&e>0?e:t}function mo(e,t){let n=new Map;function o(l){let p=n.get(l);if(p)return p;let g=e.modelUsage[l],h=(g&&Zi(l,g))??Qi(l);return n.set(l,h),h}let s=ta(e.dailyActivity,t),r=ea(e.modelUsage),i=sa(e.dailyActivity),c=oa(t),a=c??Object.values(e.modelUsage).reduce((l,p)=>l+lo(p),0),u=c!==void 0?po(t?.sessions??[])??i:i,d={rateFor:o,turnsPerMonth:s.turnsPerMonth,sessionsPerMonth:s.sessionsPerMonth,primaryModel:r,totalTokensPerMonth:Math.round(a/u*30),contextWindow:aa(e.modelUsage[r]?.contextWindow,ia),observedDays:i};return ra.set(d,s.usingDefaults),d}var ya=promisify(execFile),va=18e4,ba=10*1024*1024,fo="say ok",go=E.join(homedir(),".cache","ctxa"),ho=E.join(go,"baseline.json");function je(e){return typeof e=="object"&&e!==null}function at(e){return typeof e=="number"&&Number.isFinite(e)?e:0}function ka(e){let t=e.split(`
|
|
16
|
-
`);for(let n=t.length-1;n>=0;n--){let o=t[n];if(o===void 0)continue;let s=o.trim();if(!s)continue;let r;try{r=JSON.parse(s);}catch{continue}if(je(r)&&r.type==="result")return r}}function Sa(e,t){let n=ka(t);if(!n)return;let o=je(n.usage)?n.usage:void 0,s=at(o?.input_tokens),r=at(o?.cache_creation_input_tokens),i=at(o?.cache_read_input_tokens),c=je(n.modelUsage)?n.modelUsage:void 0,a=c?Object.keys(c)[0]:void 0;return {label:e,promptTokens:s+r+i,costUSD:at(n.total_cost_usd),model:a??"unknown",measuredAt:new Date().toISOString()}}async function Ta(e,t,n,o){try{let{stdout:s}=await ya(e,t,{cwd:n,env:o,timeout:va,maxBuffer:ba});return s}catch(s){return je(s)&&typeof s.stdout=="string"&&s.stdout.length>0?s.stdout:void 0}}async function ct(e,t,n,o,s){let r=await Ta(t,n,o,s);if(r!==void 0)return Sa(e,r)}function xa(e){return ["-p",fo,"--bare","--model",e,"--output-format","json"]}function Kt(e){return ["-p",fo,"--model",e,"--output-format","json"]}function Pa(e){let t=e.bare?.promptTokens,n=e.bare!==void 0&&e.localOnly!==void 0?e.localOnly.promptTokens-e.bare.promptTokens:void 0,o=e.localOnly!==void 0&&e.full!==void 0?e.full.promptTokens-e.localOnly.promptTokens:void 0,s=e.full!==void 0&&e.project!==void 0?e.project.promptTokens-e.full.promptTokens:void 0;if(!(t===void 0&&n===void 0&&o===void 0&&s===void 0))return {floorTokens:t??0,localConfigTokens:n??0,connectorTokens:o??0,projectTokens:s??0}}async function yo(e={}){let t={};try{let n=e.claudeBin??"claude",o=e.model??"haiku",s=e.onStep??(()=>{}),r;try{r=await mkdtemp(E.join(tmpdir(),"ctxa-baseline-"));}catch{return t}try{if(s("bare"),t.bare=await ct("bare",n,xa(o),r,{...process.env}),s("localOnly"),t.localOnly=await ct("localOnly",n,Kt(o),r,{...process.env}),!e.skipConnectors){let i={...process.env};delete i.ANTHROPIC_API_KEY,s("full"),t.full=await ct("full",n,Kt(o),r,i),e.cwd&&(s("project"),t.project=await ct("project",n,Kt(o),e.cwd,i));}}finally{await rm(r,{recursive:!0,force:!0}).catch(()=>{});}}catch{}return t.derived=Pa(t),t}async function vo(){try{let e=await readFile(ho,"utf-8"),t=JSON.parse(e);return !je(t)||typeof t.cachedAt!="string"||!je(t.data)?void 0:{data:t.data,cachedAt:t.cachedAt}}catch{return}}async function bo(e){await mkdir(go,{recursive:true});let t={data:e,cachedAt:new Date().toISOString()};await writeFile(ho,JSON.stringify(t,null,2),"utf-8");}async function ko(e={}){let{homeDir:t,searchRoots:n,useCache:o=true,skipTranscripts:s=false,probeMcp:r=false,includeSynthetic:i=false,onProgress:c}=e;c?.("Lendo configura\xE7\xE3o");let a=await xn(t),u=a.projects.map(x=>x.path),[d,l,p,g,h]=await Promise.all([Rn(t),On(t),$n(t),Nn({homeDir:t,searchRoots:n,projectPaths:u}),Hn({projectPaths:u})]);c?.(s?"Pulando transcripts":"Varrendo transcripts");let m=s?{sessions:[],scannedFiles:0,cachedFiles:0,totalBytes:0,scanMs:0,syntheticSessions:0,organicSessions:0}:await co({homeDir:t,useCache:o}),f=i?m:{...m,sessions:m.sessions.filter(x=>x.origin==="organic")},y;if(r){c?.("Sondando servidores MCP");let x=a.mcpServers.filter(O=>O.scope==="user");y=Object.fromEntries(await bn(x));}let S=mo(l,f),b=await vo();return {config:a,settings:d,stats:l,inventory:p,claudemd:g,transcripts:f,pricing:S,loopStates:h,baseline:b?.data,...y?{probedServers:y}:{}}}function dt(e,t){let n=e.rateFor(e.primaryModel),{turnsPerMonth:o,sessionsPerMonth:s}=e,r=Math.max(o-s,0),i=s*t*(n.cacheWritePerMTok/1e6),c=r*t*(n.cacheReadPerMTok/1e6);return i+c}function N(e,t,n){let o=e.rateFor(t);return (n.input??0)/1e6*o.inputPerMTok+(n.output??0)/1e6*o.outputPerMTok+(n.cacheRead??0)/1e6*o.cacheReadPerMTok+(n.cacheCreation??0)/1e6*o.cacheWritePerMTok}function I(e,t,n="estimated"){let o=Math.round(t*e.turnsPerMonth);return {tokensPerTurn:t,tokensPerMonth:o,usdPerMonth:dt(e,t),contextWindowPct:ut(t,e.contextWindow),shareOfTotalPct:ut(o,e.totalTokensPerMonth),confidence:n}}function re(e,t,n,o="measured"){let s=(n.input??0)+(n.output??0)+(n.cacheRead??0)+(n.cacheCreation??0),r=e.observedDays>0?30/e.observedDays:1,i=Math.round(s*r),c=N(e,t,n);return {tokensObserved:s,tokensPerMonth:i,usdPerMonth:Xt(c*r),shareOfTotalPct:ut(i,e.totalTokensPerMonth),confidence:o}}function F(e="estimated"){return {tokensPerMonth:0,usdPerMonth:0,shareOfTotalPct:0,confidence:e}}function pe(e,t,n,o="measured"){let s=e.observedDays>0?30/e.observedDays:1,r=Math.round(t*s);return {tokensObserved:t,tokensPerMonth:r,usdPerMonth:Xt(n*s),shareOfTotalPct:ut(r,e.totalTokensPerMonth),confidence:o}}function w(e){let t=e.contextWindowPct??0;return t>=1||e.shareOfTotalPct>=3||e.usdPerMonth>=300?"high":t>=.1||e.shareOfTotalPct>=.5||e.usdPerMonth>=50?"medium":"low"}function ut(e,t){return t<=0?0:Xt(e/t*100,3)}function Xt(e,t=2){let n=10**t;return Math.round(e*n)/n}function lt(e){return e==="connector"?374:182}var Ce=8,_e=90;function ae(e){if(!e.startsWith("mcp__"))return null;let t=e.slice(5),n=t.indexOf("__");return n<=0?null:{server:t.slice(0,n),method:t.slice(n+2)}}function we(e){return e.toLowerCase().replace(/^claude[\s._-]*ai[\s._-]*/,"").replace(/[^a-z0-9]/g,"")}function So(e,t){let n=we(e),o=we(t);return n.length<4||o.length<4?false:n===o||n.includes(o)||o.includes(n)}function Ge(e,t){if(!(e===void 0||e<=0))return Math.floor((t.getTime()-e)/864e5)}function C(e){return e.reduce((t,n)=>t+n,0)}function G(e){let t,n=-1;for(let[o,s]of Object.entries(e)){let r=s.inputTokens+s.outputTokens+s.cacheCreation+s.cacheRead;r>n&&(n=r,t=o);}return t}function Ae(e,t){for(let n of Object.keys(e))if(n.toLowerCase().includes(t))return n;return t}function $e(e,t,n,o){let s=new Map(n.plugins.map(i=>[i.name,i])),r=new Map;for(let[i,c]of Object.entries(t.enabledPlugins)){if(!c)continue;let u=s.get(i)?.installed??false,d=e.pluginUsage[i],l=d?.usageCount??0,p=Ge(d?.lastUsedAt,o),g=l===0||p!==void 0&&p>_e;r.set(i,{installed:u,usageCount:l,idleDays:p,covered:!u||g});}return r}var To=.4,wa=500,xo={id:"claudemd.catalog",group:"fixed",title:"Cat\xE1logo tratado como instru\xE7\xE3o em CLAUDE.md",run(e){let{claudemd:t,transcripts:n,pricing:o}=e.data,s=[],r=new Map;for(let c of n.sessions)r.set(c.project,(r.get(c.project)??0)+1);let i=n.sessions.length||1;for(let c of t.files){let a=c,u=a.codeBlockBytes??0,d=a.tableBytes??0,l=a.hasSkillCatalogSection??false,p=u+d,g=a.bytes>0&&p>=wa&&p/a.bytes>=To;if(!g&&!l)continue;let h=a.scope==="global"?1:a.inheritedBy.length>0?C(a.inheritedBy.map(x=>r.get(x)??0))/i:(r.get(Ca(a.path))??0)/i;if(a.scope==="project"&&h===0)continue;let m=Math.round(R(p)*h),f=I(o,m,"estimated"),y=a.bytes>0?Aa(p/a.bytes*100):0,S=Math.max(a.bytes-p,0),b=[];g&&b.push(`${y}% do arquivo \xE9 bloco de c\xF3digo ou tabela \u2014 acima do limiar de ${Math.round(To*100)}%`),l&&b.push("lista manualmente skills/comandos que o Claude Code j\xE1 injeta automaticamente a partir do invent\xE1rio real"),s.push({id:`claudemd.catalog:${a.path}`,analyzer:"claudemd.catalog",group:"fixed",severity:w(f),title:l?`CLAUDE.md em "${a.path}" duplica listagem que o Claude Code j\xE1 injeta`:`${y}% de "${a.path}" \xE9 cat\xE1logo, n\xE3o instru\xE7\xE3o`,detail:`CLAUDE.md deve conter o que MUDA comportamento \u2014 regras, guardrails, conven\xE7\xF5es. Listar comandos, skills ou diret\xF3rios \xE9 material de consulta que o modelo descobre sob demanda com Glob/Read; pagar por isso em todo turno \xE9 comprar um \xEDndice que ele gera sozinho. ${b.join("; ")}.`,evidence:{path:a.path,scope:a.scope,bytes:a.bytes,codeBlockBytes:u,tableBytes:d,catalogBytes:p,catalogSharePct:y,hasSkillCatalogSection:l,sessionShare:Number(h.toFixed(4)),tokensPerTurn:m},impact:f,fixSpec:{kind:"claudemd-compact",params:{path:a.path,targetBytes:S},describe:`Remover material de cat\xE1logo de "${a.path}" (~${S} bytes restantes)`}});}return s.sort((c,a)=>a.impact.tokensPerMonth-c.impact.tokensPerMonth)}};function Ca(e){let t=e.lastIndexOf("/");return t>0?e.slice(0,t):e}function Aa(e){return Math.round(e*10)/10}var Ea=4e3,Ma=12e3,Po={id:"claudemd.size",group:"fixed",title:"CLAUDE.md grandes ou redundantes",run(e){let{claudemd:t,transcripts:n,pricing:o}=e.data,s=[],r=new Map;for(let a of n.sessions)r.set(a.project,(r.get(a.project)??0)+1);let i=n.sessions.length||1;for(let a of t.files){let u=a.bytes+a.importedBytes,d=a.scope==="global"?Ea:Ma;if(u<=d)continue;let l=R(u-d),p=a.scope==="global"?1:a.inheritedBy.length>0?C(a.inheritedBy.map(f=>r.get(f)??0))/i:(r.get(Ra(a.path))??0)/i,g=Math.round(l*p),h=I(o,g,"estimated");if(a.scope==="project"&&p===0)continue;let m=a.scope==="project"&&a.inheritedBy.length>1;s.push({id:`claudemd.size:${a.path}`,analyzer:"claudemd.size",group:"fixed",severity:w(h),title:a.scope==="global"?`CLAUDE.md global tem ${a.bytes} bytes`:`CLAUDE.md de projeto tem ${a.bytes} bytes`,detail:a.scope==="global"?`Este \xE9 o \xFAnico CLAUDE.md carregado em TODA sess\xE3o, independente do projeto. S\xE3o ${R(u)} tokens fixos por turno`+(a.imports.length>0?`, dos quais ${R(a.importedBytes)} v\xEAm de ${a.imports.length} import(s) via @ \u2014 o custo do import \xE9 somado ao do arquivo.`:"."):m?`Este arquivo n\xE3o \xE9 exclusivo de um projeto: o Claude Code sobe do diret\xF3rio de trabalho at\xE9 a raiz procurando CLAUDE.md, ent\xE3o ele \xE9 herdado por ${a.inheritedBy.length} diret\xF3rios diferentes, mesmo estando fisicamente em apenas um deles. Juntos, esses diret\xF3rios respondem por ${(p*100).toFixed(1)}% das suas sess\xF5es \u2014 da\xED um arquivo aparentemente pequeno e "de um projeto s\xF3" pesar tanto quanto pesa.`:`Carregado apenas em sess\xF5es deste projeto, que representam ${(p*100).toFixed(1)}% do seu hist\xF3rico. O impacto \xE9 ponderado por essa fatia.`,evidence:{path:a.path,scope:a.scope,bytes:a.bytes,lines:a.lines,importedBytes:a.importedBytes,imports:a.imports,estTokens:R(u),budgetBytes:d,inheritedBy:a.inheritedBy,sessionShare:Number(p.toFixed(4))},impact:h,fixSpec:{kind:"claudemd-compact",params:{path:a.path,targetBytes:d},describe:`Compactar ${a.path} para ~${d} bytes`}});}let c=Oa(t.files);return c&&s.push(c),s.sort((a,u)=>u.impact.tokensPerMonth-a.impact.tokensPerMonth)}};function Ra(e){let t=e.lastIndexOf("/");return t>0?e.slice(0,t):e}function Oa(e){let t=new Map;for(let s of e)for(let r of s.blockHashes){let i=t.get(r)??new Set;i.add(s.path),t.set(r,i);}let n=[...t.entries()].filter(([,s])=>s.size>1);if(n.length===0)return null;let o=new Set;for(let[,s]of n)for(let r of s)o.add(r);return {id:"claudemd.duplicate-blocks",analyzer:"claudemd.size",group:"fixed",severity:"low",title:`${n.length} bloco(s) de texto repetidos entre ${o.size} CLAUDE.md`,detail:"Os mesmos par\xE1grafos aparecem em mais de um CLAUDE.md. Instru\xE7\xE3o que vale para todos os projetos pertence ao CLAUDE.md global, onde \xE9 carregada uma vez; repetida por projeto, ela \xE9 mantida em N lugares e diverge com o tempo. C\xF3pias em worktrees do mesmo reposit\xF3rio s\xE3o esperadas e podem ser ignoradas.",guidance:"Abra os arquivos de `evidence.sample` e decida, bloco a bloco, onde a instru\xE7\xE3o pertence. Se ela vale para todo projeto, mova para `~/CLAUDE.md` e apague das c\xF3pias \u2014 o Claude Code carrega o global por auto-discovery ascendente, ent\xE3o o texto continua valendo em todos eles sem estar escrito em cada um. Se vale s\xF3 para alguns, mantenha onde est\xE1: centralizar instru\xE7\xE3o espec\xEDfica no global faz todo projeto pagar por ela. Antes de mover, confira se os caminhos n\xE3o s\xE3o worktrees do mesmo reposit\xF3rio \u2014 nesse caso \xE9 o mesmo arquivo visto duas vezes e n\xE3o h\xE1 nada a fazer.",evidence:{duplicatedBlocks:n.length,affectedFiles:[...o],sample:n.slice(0,5).map(([s,r])=>({hash:s,files:[...r]}))},impact:F("estimated")}}var Da=6960,wo={id:"connectors.unused",group:"fixed",title:"Conectores claude.ai no system prompt",run(e){let{config:t,transcripts:n,settings:o,pricing:s,baseline:r}=e.data,i=t.connectors;if(i.length===0)return [];if(o.disableClaudeAiConnectors===true)return [];let c=new Map;for(let m of n.sessions)for(let[f,y]of Object.entries(m.toolCalls)){let S=ae(f);if(!S?.server.startsWith("claude_ai_"))continue;let b=we(S.server);c.set(b,(c.get(b)??0)+y);}let a=i.map(m=>({connector:m,calls:c.get(we(m))??0})).sort((m,f)=>f.calls-m.calls),u=a.filter(m=>m.calls===0),d=r?.derived?.connectorTokens,l=d&&d>0?d:i.length*Da,p=I(s,l,d?"measured":"estimated"),g=t.mcpServers.filter(m=>m.scope==="user").map(m=>we(m.name)),h=a.filter(m=>g.some(f=>Fa(f,we(m.connector)))).map(m=>m.connector);return [{id:"connectors.unused:all",analyzer:"connectors.unused",group:"fixed",severity:w(p),title:`${i.length} conectores claude.ai custam ${l.toLocaleString("pt-BR")} tokens em todo turno`,detail:"Os conectores conectados \xE0 sua conta claude.ai carregam as defini\xE7\xF5es de todas as tools deles no system prompt de TODA sess\xE3o"+(d?`. Este n\xFAmero \xE9 medido, n\xE3o estimado: ${d.toLocaleString("pt-BR")} tokens obtidos pela diferen\xE7a entre rodar o Claude Code com e sem os conectores.`:'. O n\xFAmero \xE9 estimado \u2014 rode "ctxa baseline --yes" para medir o valor real.')+(u.length>0?` ${u.length} de ${i.length} n\xE3o registram nenhuma chamada no seu hist\xF3rico: ${u.map(m=>m.connector).join(", ")}.`:" Todos registram algum uso no hist\xF3rico.")+(h.length>0?` Al\xE9m disso, ${h.length} duplicam servidores MCP stdio que voc\xEA j\xE1 tem localmente (${h.join(", ")}) \u2014 a mesma capacidade entra no prompt duas vezes.`:"")+' ATEN\xC7\xC3O ao trade-off: "disableClaudeAiConnectors" desliga TODOS de uma vez, incluindo os que voc\xEA usa. N\xE3o h\xE1 como escolher individualmente por essa chave \u2014 para uso pontual, reative, use, e desligue de novo.',evidence:{connectorCount:i.length,idleCount:u.length,connectors:a,duplicatesLocalServers:h,tokensPerTurn:l,measured:d!==void 0,note:"Chamadas contadas a partir dos transcripts; ~/.claude.json \u2192 toolUsage n\xE3o rastreia o namespace mcp__claude_ai_*."},impact:p,fixSpec:{kind:"settings-patch",params:{set:{disableClaudeAiConnectors:true}},describe:`Desligar os ${i.length} conectores claude.ai`}}]}};function Fa(e,t){return e.length<4||t.length<4?false:e===t||e.includes(t)||t.includes(e)}var Ie=600,Qt=10,Co={id:"description.bloat",group:"fixed",title:"Descriptions inchadas no system prompt",run(e){let{config:t,settings:n,inventory:o,pricing:s}=e.data,r=o.artifacts.filter(p=>!p.broken&&p.descriptionBytes>Ie).sort((p,g)=>g.descriptionBytes-p.descriptionBytes);if(r.length===0)return [];let i=r.slice(0,Qt),c=r.slice(Qt),a=i.map(p=>{let g=p.descriptionBytes-Ie,h=R(g),m=I(s,h,"estimated"),f=p.bodyBytes>0?p.descriptionBytes/p.bodyBytes*100:0;return {id:`description.bloat:${p.kind}:${p.name}`,analyzer:"description.bloat",group:"fixed",severity:w(m),title:`Description de "${p.name}" tem ${p.descriptionBytes} bytes`,detail:`A description entra no system prompt de toda sess\xE3o; o corpo (${p.bodyBytes} bytes) s\xF3 \xE9 lido na invoca\xE7\xE3o. Aqui a description representa ${f.toFixed(0)}% do tamanho do corpo, o que costuma indicar uma lista longa de trigger words. Condensar para o essencial (o que a skill faz e quando usar) reduz o custo recorrente sem perder capacidade de acionamento.`,guidance:`Edite o campo \`description\` no frontmatter de \`${p.path}\`. O alvo \xE9 uma frase que responda duas coisas: o que este artefato faz, e quando acion\xE1-lo. Listas de sin\xF4nimos e trigger words costumam ser o grosso do excesso e raramente mudam o acionamento \u2014 o modelo casa por sentido, n\xE3o por palavra exata. Corte tamb\xE9m exemplos de uso e explica\xE7\xF5es de como funciona: isso pertence ao corpo, que s\xF3 \xE9 lido na invoca\xE7\xE3o e n\xE3o custa nada at\xE9 l\xE1. Se o artefato n\xE3o estiver sendo usado, silenci\xE1-lo via \`skillOverrides\` economiza a description inteira em vez de parte dela \u2014 veja os findings de \`skill.unused\`.`,evidence:{artifact:p.name,kind:p.kind,plugin:p.plugin??null,descriptionBytes:p.descriptionBytes,bodyBytes:p.bodyBytes,budgetBytes:Ie,excessBytes:g,path:p.path},impact:m}}),u=$e(t,n,o,e.now),d=new Map,l=[];for(let p of c){if(p.plugin&&u.get(p.plugin)?.covered){d.set(p.plugin,(d.get(p.plugin)??0)+1);continue}l.push(p);}if(l.length>0){let p=C(l.map(f=>f.descriptionBytes-Ie)),g=R(p),h=I(s,g,"estimated"),m=C([...d.values()]);a.push({id:"description.bloat:low-impact",analyzer:"description.bloat",group:"fixed",severity:w(h),title:`${l.length} description(s) inchada(s) de baixo impacto`,detail:`Estes ${l.length} artefatos passam do or\xE7amento de ${Ie} bytes de description, mas n\xE3o entraram no top ${Qt} por excesso \u2014 cada um isolado \xE9 pequeno demais para justificar finding pr\xF3prio. Juntos somam ${p} bytes de excesso carregados no system prompt de toda sess\xE3o. Revise a lista em \`evidence.artifacts\` e condense as descriptions maiores primeiro.`+(m>0?` ${m} outro(s) artefato(s) inchado(s) ficaram de fora deste agregado porque o plugin dono j\xE1 tem finding pr\xF3prio em \`plugin.unused-or-broken\` \u2014 cont\xE1-los aqui de novo dobraria a economia projetada. Veja \`evidence.excludedByPluginFinding\`.`:""),guidance:"Percorra `evidence.artifacts` \u2014 ela vem ordenada por excesso \u2014 e edite o campo `description` no frontmatter de cada um, come\xE7ando pelos maiores. Em cada um, o alvo \xE9 uma frase dizendo o que faz e quando acionar; listas de trigger words e exemplos de uso s\xE3o o grosso do excesso e pertencem ao corpo, que s\xF3 \xE9 lido na invoca\xE7\xE3o. N\xE3o h\xE1 corre\xE7\xE3o autom\xE1tica aqui porque reescrever description \xE9 decis\xE3o de conte\xFAdo: encurtar demais custa acionamento, e s\xF3 quem conhece o artefato sabe onde est\xE1 esse limite.",evidence:{count:l.length,totalExcessBytes:p,artifacts:l.map(f=>({artifact:f.name,kind:f.kind,plugin:f.plugin??null,descriptionBytes:f.descriptionBytes,bodyBytes:f.bodyBytes,excessBytes:f.descriptionBytes-Ie})),...m>0?{excludedByPluginFinding:{count:m,plugins:[...d.keys()].sort()}}:{}},impact:h});}return a.sort((p,g)=>g.impact.tokensPerMonth-p.impact.tokensPerMonth)}};var ja=new Set(["SessionStart","UserPromptSubmit"]),Ao={id:"hook.context-injection",group:"fixed",title:"Hooks que injetam contexto",run(e){let{settings:t}=e.data,n=t.hooks.filter(r=>ja.has(r.event));if(n.length===0)return [];let o=new Map;for(let r of n){let i=o.get(r.event)??[];i.push(r),o.set(r.event,i);}let s=[];for(let[r,i]of o){let c=r==="UserPromptSubmit";s.push({id:`hook.context-injection:${r}`,analyzer:"hook.context-injection",group:"fixed",severity:c?"medium":"low",title:`${i.length} hook(s) em ${r} podem injetar contexto`,detail:(c?"Hooks em UserPromptSubmit rodam a CADA mensagem sua, e o stdout entra no contexto. Um hook que imprime algo vari\xE1vel (timestamp, estado, contador) tamb\xE9m invalida o cache de prompt, fazendo voc\xEA pagar cache_creation (1,25x) em vez de cache_read (0,1x) repetidamente. ":"Hooks em SessionStart rodam uma vez por sess\xE3o e o stdout entra no contexto inicial. ")+'N\xE3o \xE9 poss\xEDvel medir o tamanho da inje\xE7\xE3o sem executar o hook \u2014 rode "ctxa baseline" para ver o efeito no system prompt real.',guidance:c?"Rode cada comando de `evidence.hooks` no terminal e olhe o stdout: \xE9 isso que entra no contexto a cada mensagem sua. Duas perguntas por hook. Primeira: a sa\xEDda muda entre execu\xE7\xF5es? Timestamp, contador ou qualquer estado vari\xE1vel invalida o cache de prompt e faz voc\xEA pagar 1,25x em vez de 0,1x pelo contexto inteiro, todo turno \u2014 se o hook precisa existir, fa\xE7a-o imprimir algo est\xE1vel, ou nada. Segunda: o modelo precisa dessa informa\xE7\xE3o a cada mensagem? Se for contexto do projeto que n\xE3o muda, o lugar dele \xE9 o CLAUDE.md, que ao menos entra uma vez no cache. Hook que s\xF3 registra telemetria n\xE3o deveria imprimir em stdout.":"Rode cada comando de `evidence.hooks` e veja o stdout \u2014 \xE9 o que entra no contexto inicial de toda sess\xE3o. Como roda uma vez por sess\xE3o, n\xE3o invalida cache; o custo \xE9 o tamanho da inje\xE7\xE3o multiplicado pelas sess\xF5es do m\xEAs. Vale conferir se o conte\xFAdo ainda \xE9 necess\xE1rio e se n\xE3o duplica o que o CLAUDE.md j\xE1 diz: inje\xE7\xE3o de hook e CLAUDE.md ocupam o mesmo prompt, e a duplica\xE7\xE3o passa despercebida porque as duas fontes s\xE3o invis\xEDveis na conversa.",evidence:{event:r,hookCount:i.length,hooks:i.map(a=>({command:a.command,matcher:a.matcher,source:a.source,plugin:a.plugin??null})),runsPerTurn:c},impact:F("estimated")});}return s}};var _a=["ralph-loop","ralph-wiggum","ralph-claude","ralph"],$a="Stop";function pt(e){let t=e.lastIndexOf("@");return t>0?e.slice(0,t):e}function Eo(e){let t=e.toLowerCase();return _a.some(n=>t.includes(n))}function Ia(e){let t=[];return e.maxIterations===0&&t.push({code:"no-iteration-cap",text:"max_iterations=0, que nesta conven\xE7\xE3o significa SEM LIMITE de itera\xE7\xF5es"}),e.completionPromise===void 0&&t.push({code:"no-completion-criteria",text:"nenhum completion_promise, ent\xE3o n\xE3o h\xE1 condi\xE7\xE3o que encerre o loop sozinha"}),e.sessionId===void 0&&t.push({code:"any-session-triggers",text:"session_id vazio, ent\xE3o o loop dispara em QUALQUER sess\xE3o aberta neste projeto, n\xE3o s\xF3 na que o iniciou"}),t}function La(e){return e.length>=2?"high":e.length===1?"medium":"low"}function Ba(e,t){if(e===void 0)return;let n=Date.parse(e);if(!Number.isNaN(n))return Math.max(0,Math.round((t.getTime()-n)/864e5))}function Na(e){if(e!==void 0)return e.length<=120?e:`${e.slice(0,117)}...`}function Ua(e){return e.replace(/^\/+/,"").replace(/\//g,"-")||"root"}function za(e,t){let n=Ia(e),o=Ba(e.modifiedAt??e.startedAt,t),s=Na(e.prompt),r=o!==void 0?` O arquivo n\xE3o \xE9 tocado h\xE1 ${o} dia(s), o que indica loop abandonado e n\xE3o em curso.`:"",i=n.length>0?` Agravantes: ${n.map(a=>a.text).join("; ")}.`:" O loop declara teto de itera\xE7\xE3o e crit\xE9rio de parada, ent\xE3o \xE9 limitado \u2014 ainda assim est\xE1 marcado como ativo e voltar\xE1 a rodar sozinho.",c=s!==void 0?`
|
|
17
|
-
|
|
18
|
-
Prompt que seria repetido a cada itera\xE7\xE3o:
|
|
19
|
-
"${s}"`:"";return {id:`loop.autonomous:armed:${Ua(e.project)}`,analyzer:"loop.autonomous",group:"fixed",severity:La(n),title:`Loop aut\xF4nomo (${e.tool}) armado em ${e.project}`,detail:`Existe um state file de loop marcado como ativo em ${e.path}. Ele n\xE3o custa token enquanto est\xE1 parado \u2014 mas n\xE3o \xE9 res\xEDduo inofensivo: o hook Stop da ferramenta l\xEA este arquivo a cada tentativa de encerrar a sess\xE3o e, encontrando "active: true", recusa a sa\xEDda e re-alimenta o prompt. \xC9 assim que o loop funciona.${r}${i}
|
|
20
|
-
|
|
21
|
-
O que segura o loop hoje \xE9 apenas a ferramenta estar desabilitada ou desinstalada. Reabilit\xE1-la \u2014 ou clonar este projeto numa m\xE1quina onde ela esteja ativa \u2014 retoma o loop a partir da itera\xE7\xE3o ${e.iteration??"?"}, sem nenhuma a\xE7\xE3o deliberada de quem abrir a sess\xE3o. Cada itera\xE7\xE3o recome\xE7a com contexto fresco e re-paga cache_creation a 1,25x input, que \xE9 o token mais caro que existe.${c}`,evidence:{path:e.path,project:e.project,tool:e.tool,active:e.active,iteration:e.iteration??null,maxIterations:e.maxIterations??null,completionPromise:e.completionPromise??null,sessionId:e.sessionId??null,startedAt:e.startedAt??null,idleDays:o??null,aggravators:n.map(a=>a.code),prompt:s??null},impact:F("measured"),fixSpec:{kind:"file-delete",params:{path:e.path},describe:`Desarmar o loop ${e.tool} em ${e.project}`}}}function qa(e,t){let n=pt(e);return {id:`loop.autonomous:enabled:${n}`,analyzer:"loop.autonomous",group:"fixed",severity:"high",title:`Ferramenta de loop aut\xF4nomo habilitada: ${n}`,detail:`O plugin "${e}" est\xE1 habilitado e registra ${t} hook(s) no evento Stop \u2014 o mecanismo que impede a sess\xE3o de encerrar e re-alimenta o prompt. Enquanto ele estiver ligado, qualquer projeto com um state file de loop ativo entra em loop assim que uma sess\xE3o for aberta ali, sem a\xE7\xE3o deliberada.
|
|
22
|
-
|
|
23
|
-
O custo de um loop n\xE3o aparece como tokens/turno e por isso este item soma US$ 0 na proje\xE7\xE3o: ele n\xE3o ocupa espa\xE7o no system prompt. O gasto vem do padr\xE3o de execu\xE7\xE3o \u2014 cada itera\xE7\xE3o recome\xE7a com contexto fresco e re-paga cache_creation a 1,25x input. Uma corrida de dezenas de itera\xE7\xF5es num reposit\xF3rio grande produz, em horas, mais consumo que semanas de uso interativo.
|
|
24
|
-
|
|
25
|
-
Isto n\xE3o \xE9 um defeito da ferramenta: para migra\xE7\xE3o, refatora\xE7\xE3o mec\xE2nica ou TDD em lote ela faz o que promete. O aviso \xE9 sobre deix\xE1-la habilitada por padr\xE3o, quando o uso \xE9 pontual \u2014 e sobre o risco de um state file esquecido reativ\xE1-la sem inten\xE7\xE3o.
|
|
26
|
-
|
|
27
|
-
A corre\xE7\xE3o desinstala em vez de apenas desabilitar, pelo mesmo motivo: um plugin desabilitado continua a uma a\xE7\xE3o de dist\xE2ncia de voltar a rodar. Reinstalar quando precisar \xE9 \`/plugin install ${e}\`.`,evidence:{plugin:e,stopHooks:t},impact:F("measured"),fixSpec:{kind:"plugin-uninstall",params:{plugin:e},describe:`Desinstalar o plugin de loop ${n}`}}}function Ha(e){let t=pt(e.name);return {id:`loop.autonomous:installed:${t}`,analyzer:"loop.autonomous",group:"fixed",severity:"medium",title:`Ferramenta de loop aut\xF4nomo instalada: ${t}`,detail:`O plugin "${e.name}" est\xE1 instalado e no momento desabilitado. Nesse estado ele n\xE3o custa token: n\xE3o entra no system prompt e n\xE3o registra hook. O problema n\xE3o \xE9 o custo de hoje \u2014 \xE9 que instalado-e-desligado \xE9 precisamente o estado que precede o acidente.
|
|
28
|
-
|
|
29
|
-
Basta habilit\xE1-lo de novo, por engano ou por um \`/plugin\` distra\xEDdo, para que qualquer state file de loop esquecido em qualquer projeto volte a disparar sozinho, sem a\xE7\xE3o deliberada de quem abrir a sess\xE3o. Loop aut\xF4nomo \xE9 a \xFAnica categoria de ferramenta capaz de consumir sem algu\xE9m estar olhando: cada itera\xE7\xE3o recome\xE7a com contexto fresco e re-paga cache_creation a 1,25x input.
|
|
30
|
-
|
|
31
|
-
A corre\xE7\xE3o desinstala de verdade \u2014 remove a entrada do registry de plugins instalados e a chave de enabledPlugins. Ela N\xC3O apaga diret\xF3rios de ~/.claude/plugins/: sem a entrada no registry o plugin deixa de contar como instalado, e o diret\xF3rio remanescente vira cache \xF3rf\xE3o, que \`plugin.unused-or-broken\` j\xE1 detecta e limpa com o pr\xF3prio fix. Reinstalar depois \xE9 \`/plugin install ${e.name}\`.`,evidence:{plugin:e.name,installed:e.installed,enabled:e.enabled,scope:e.scope,cacheDirs:e.cacheDirs},impact:F("measured"),fixSpec:{kind:"plugin-uninstall",params:{plugin:e.name},describe:`Desinstalar o plugin de loop ${t}`}}}var Mo={id:"loop.autonomous",group:"fixed",title:"Ferramentas de loop aut\xF4nomo",run(e){let{settings:t,inventory:n,loopStates:o}=e.data,s=[];for(let c of o)c.active&&s.push(za(c,e.now));let r=new Map;for(let c of t.hooks)c.event!==$a||c.plugin===void 0||Eo(c.plugin)&&r.set(c.plugin,(r.get(c.plugin)??0)+1);for(let[c,a]of r)s.push(qa(c,a));let i=new Set([...r.keys()].map(pt));for(let c of n.plugins){let a=pt(c.name);!Eo(a)||!c.installed||c.enabled||i.has(a)||s.push(Ha(c));}return s}};var Ro={id:"mcp.duplicate",group:"fixed",title:"Servidores MCP duplicados",run(e){let{config:t,pricing:n}=e.data,o=t.mcpServers.filter(a=>a.scope==="user"),s=[...new Set(t.connectors)],r=new Map;for(let a of Object.keys(t.toolUsage)){let u=ae(a);u&&r.set(u.server,(r.get(u.server)??0)+1);}let i=[],c=new Set;for(let a of o)for(let u of s){if(!So(a.name,u))continue;let d=[a.name,u].sort().join("|");if(c.has(d))continue;c.add(d);let l=r.get(a.name)??Ce,g=Math.min(l,Ce),h=g*lt(a.scope),m=I(n,h,"estimated");i.push({id:`mcp.duplicate:${a.name}`,analyzer:"mcp.duplicate",group:"fixed",severity:w(m),title:`"${a.name}" e o conector "${u}" cobrem a mesma capacidade`,detail:`O servidor local "${a.name}" (${a.transport}) e o conector claude.ai "${u}" exp\xF5em funcionalidade equivalente, e ambos os conjuntos de schemas entram no system prompt. Manter apenas um elimina a duplica\xE7\xE3o. O conector \xE9 desligado ao definir ANTHROPIC_API_KEY no ambiente; o servidor local \xE9 removido de ~/.claude.json.`,evidence:{localServer:a.name,localTransport:a.transport,localToolsObserved:r.get(a.name)??null,connectorServer:u,connectorToolsObserved:null,removableTools:g,tokensPerTurn:h},impact:m,fixSpec:{kind:"mcp-remove",params:{server:a.name,scope:a.scope,duplicateOf:u},describe:`Remover o servidor local "${a.name}" (mantendo o conector)`}});}return i.sort((a,u)=>u.impact.tokensPerMonth-a.impact.tokensPerMonth)}};var Oo={id:"mcp.unused",group:"fixed",title:"Servidores MCP subutilizados",run(e){let{config:t,transcripts:n,pricing:o}=e.data,s=[],r=new Map,i=new Map,c=new Map;for(let[u,d]of Object.entries(t.toolUsage)){let l=ae(u);if(!l)continue;let p=r.get(l.server)??new Set;if(p.add(l.method),r.set(l.server,p),i.set(l.server,(i.get(l.server)??0)+d.usageCount),d.lastUsedAt!==void 0){let g=c.get(l.server)??0;d.lastUsedAt>g&&c.set(l.server,d.lastUsedAt);}}for(let u of n.sessions)for(let[d,l]of Object.entries(u.toolCalls)){let p=ae(d);if(!p)continue;let g=r.get(p.server)??new Set;g.add(p.method),r.set(p.server,g),i.set(p.server,(i.get(p.server)??0)+l);}let a=t.mcpServers.filter(u=>u.scope==="user"||u.scope==="connector");for(let u of a){let d=i.get(u.name)??0,l=r.get(u.name)?.size,p=Ge(c.get(u.name),e.now);if(!(d===0||p!==void 0&&p>_e))continue;let h=e.data.probedServers?.[u.name],m=h&&!h.error?h:void 0,f=m?.toolCount??l??Ce,y=m?R(m.schemaBytes):f*lt(u.scope),S=I(o,y,m?"measured":"estimated");s.push({id:`mcp.unused:${u.name}`,analyzer:"mcp.unused",group:"fixed",severity:w(S),title:`Servidor MCP "${u.name}" sem uso relevante`,detail:(d===0?`Nenhuma chamada registrada para as tools de "${u.name}", mas suas defini\xE7\xF5es entram no system prompt de toda sess\xE3o. `:`\xDAltima chamada h\xE1 ${p} dias (${d} chamadas no total). As ${f} tools continuam sendo carregadas em toda sess\xE3o. `)+(m?`Sondagem via tools/list: ${m.toolCount} tools, ${m.schemaBytes} bytes de schema \u2014 n\xFAmero exato, n\xE3o estimativa.`:l===void 0?`O n\xFAmero real de tools \xE9 desconhecido (o servidor nunca foi usado, ent\xE3o suas tools n\xE3o aparecem nos contadores) \u2014 a estimativa assume ${Ce}. Rode "ctxa scan --probe-mcp" para contar de verdade.`:`Foram observadas ${l} tools em uso; o total pode ser maior. "ctxa scan --probe-mcp" mede exatamente.`),evidence:{server:u.name,scope:u.scope,transport:u.transport,totalCalls:d,probedTools:m?.toolCount??null,probedSchemaBytes:m?.schemaBytes??null,probedToolNames:m?.toolNames??null,probeError:h?.error??null,observedTools:l??null,assumedTools:m||l?null:Ce,idleDays:p??null,tokensPerTurn:y},impact:S,fixSpec:{kind:"mcp-remove",params:{server:u.name,scope:u.scope},describe:`Remover servidor MCP "${u.name}"`}});}return s.sort((u,d)=>d.impact.tokensPerMonth-u.impact.tokensPerMonth)}};var Do={id:"plugin.unused-or-broken",group:"fixed",title:"Plugins sem uso ou quebrados",run(e){let{config:t,settings:n,inventory:o,pricing:s}=e.data,r=[],i=$e(t,n,o,e.now);for(let[a,u]of i){if(!u.installed){r.push({id:`plugin.broken:${a}`,analyzer:"plugin.unused-or-broken",group:"fixed",severity:"medium",title:`Plugin "${a}" est\xE1 habilitado mas n\xE3o instalado`,detail:`settings.json marca "${a}" como habilitado, mas ele n\xE3o aparece em installed_plugins.json nem tem diret\xF3rio em plugins/cache/. O plugin n\xE3o faz nada \u2014 n\xE3o custa tokens, mas a configura\xE7\xE3o est\xE1 inconsistente e pode mascarar a expectativa de que suas skills estejam dispon\xEDveis.`,evidence:{plugin:a,enabled:true,installed:false,usageCount:u.usageCount},impact:F("measured"),fixSpec:{kind:"plugin-disable",params:{plugin:a,reason:"habilitado mas n\xE3o instalado"},describe:`Remover "${a}" de enabledPlugins`}});continue}if(!u.covered)continue;let d=o.artifacts.filter(h=>h.plugin===a&&!h.broken);if(d.length===0)continue;let l=C(d.map(h=>h.descriptionBytes)),p=R(l),g=I(s,p,"estimated");r.push({id:`plugin.unused:${a}`,analyzer:"plugin.unused-or-broken",group:"fixed",severity:w(g),title:u.usageCount===0?`Plugin "${a}" nunca foi usado`:`Plugin "${a}" sem uso h\xE1 ${u.idleDays} dias`,detail:`Este plugin contribui ${d.length} artefato(s) cujas descriptions somam ${l} bytes no system prompt de toda sess\xE3o. Desabilit\xE1-lo remove todos de uma vez, sem desinstalar nada \u2014 basta reabilitar para ter de volta.`,evidence:{plugin:a,usageCount:u.usageCount,idleDays:u.idleDays??null,artifactCount:d.length,artifacts:d.map(h=>`${h.kind}:${h.name}`),descriptionBytes:l},impact:g,fixSpec:{kind:"plugin-disable",params:{plugin:a,reason:u.usageCount===0?"nunca usado":`ocioso h\xE1 ${u.idleDays}d`},describe:`Desabilitar o plugin "${a}"`}});}let c=o.plugins.filter(a=>a.orphanedDirs.length>0);return c.length>0&&r.push({id:"plugin.orphaned-cache",analyzer:"plugin.unused-or-broken",group:"fixed",severity:"low",title:`${c.length} plugin(s) com vers\xF5es \xF3rf\xE3s em cache`,detail:"Vers\xF5es antigas de plugins permanecem em plugins/cache/ marcadas como \xF3rf\xE3s. Isso ocupa espa\xE7o em disco mas n\xE3o entra no system prompt \u2014 nenhuma economia de token, apenas limpeza.",guidance:"N\xE3o h\xE1 ganho de token aqui, ent\xE3o isto \xE9 opcional e de baixa prioridade. Se o espa\xE7o em disco incomodar, apague os diret\xF3rios \xF3rf\xE3os listados em `evidence.plugins` sob `~/.claude/plugins/cache/`. Confira antes que a vers\xE3o que voc\xEA usa n\xE3o est\xE1 entre eles: o Claude Code n\xE3o marca de forma confi\xE1vel qual est\xE1 ativa, e apagar a errada quebra o plugin at\xE9 a reinstala\xE7\xE3o.",evidence:{plugins:c.map(a=>({name:a.name,orphanedDirs:a.orphanedDirs.length}))},impact:F("measured")}),r.sort((a,u)=>u.impact.tokensPerMonth-a.impact.tokensPerMonth)}};var mt=["allow","deny","ask"],Zt=["Task","Bash","Glob","Grep","Read","Edit","Write","NotebookEdit","WebFetch","WebSearch","TodoWrite","BashOutput","KillShell","ExitPlanMode","SlashCommand","AskUserQuestion","Agent","SendMessage","Monitor","TaskCreate","TaskUpdate","TaskList","TaskGet","TaskOutput","TaskStop","Skill","Artifact"],Wa=new Set(Zt);function Ja(e,t){let n=e.length,o=t.length;if(n===0)return o;if(o===0)return n;let s=Array.from({length:o+1},(r,i)=>i);for(let r=1;r<=n;r++){let i=[r];for(let c=1;c<=o;c++){let a=e[r-1]===t[c-1]?0:1,u=(s[c]??0)+1,d=(i[c-1]??0)+1,l=(s[c-1]??0)+a;i.push(Math.min(u,d,l));}s=i;}return s[o]??Math.max(n,o)}function Ga(e){return !e.includes("(")&&!e.startsWith("mcp__")}function Va(e){let t=Zt[0],n=1/0;for(let o of Zt){let s=Ja(e,o);s<n&&(n=s,t=o);}return {tool:t,distance:n}}function Ka(e){let t=[];for(let n of mt)for(let o of e[n]){if(!Ga(o)||Wa.has(o))continue;let s=Va(o);s.distance>=1&&s.distance<=2&&t.push({scope:n,rule:o,suggestedTool:s.tool,distance:s.distance});}return t}function Ya(e,t){let n={};for(let o of mt){let s=t.filter(i=>i.scope===o);if(s.length===0)continue;let r=new Map(s.map(i=>[i.rule,i.suggestedTool]));n[`permissions.${o}`]=e[o].map(i=>r.get(i)??i);}return n}function Xa(e,t){let n=new Map;for(let o of mt)for(let s of e[o]){let r=ae(s);if(!r||t.has(r.server))continue;let i=n.get(r.server)??{server:r.server,count:0,scopes:{}};i.count+=1,i.scopes[o]=(i.scopes[o]??0)+1,n.set(r.server,i);}return {groups:[...n.values()],orphanServers:new Set(n.keys())}}function Qa(e,t){let n={};for(let o of mt){let s=e[o].filter(r=>{let i=ae(r);return !(i&&t.has(i.server))});s.length!==e[o].length&&(n[`permissions.${o}`]=s);}return n}function Za(e){return Math.round(e*10)/10}var Fo={id:"settings.dead-config",group:"fixed",title:"Configura\xE7\xE3o morta ou contradit\xF3ria em settings.json",run(e){let{settings:t,config:n}=e.data,o=[],s=Ka(t.permissionRules);s.length>0&&o.push({id:"settings.dead-config:invalid-tool-names",analyzer:"settings.dead-config",group:"fixed",severity:"medium",title:`${s.length} regra(s) de permiss\xE3o citam tool(s) inexistente(s)`,detail:"Estas regras n\xE3o correspondem a nenhuma tool nativa do Claude Code, mas est\xE3o perto (dist\xE2ncia de edi\xE7\xE3o 1-2) de uma tool real \u2014 provavelmente um typo. A consequ\xEAncia n\xE3o \xE9 cosm\xE9tica: a tool com o nome CORRETO fica sem allow expl\xEDcito, ent\xE3o algo que voc\xEA acha permitido pode n\xE3o estar. Corrigidas apenas as que casam de forma inequ\xEDvoca, para n\xE3o confundir com uma tool nativa que s\xF3 ainda n\xE3o est\xE1 na lista conhecida por esta vers\xE3o.",evidence:{typos:s.map(a=>({scope:a.scope,rule:a.rule,suggestedTool:a.suggestedTool,editDistance:a.distance}))},impact:F("measured"),fixSpec:{kind:"settings-patch",params:{set:Ya(t.permissionRules,s)},describe:`Corrigir ${s.length} nome(s) de tool em permissions`}});let r=new Set(n.mcpServers.map(a=>a.name)),{groups:i,orphanServers:c}=Xa(t.permissionRules,r);if(i.length>0){let a=i.reduce((m,f)=>m+f.count,0),{allow:u,deny:d,ask:l}=t.permissionRules,p=u.length+d.length+l.length,g=p>0?Za(a/p*100):0,h=[...i].sort((m,f)=>f.count-m.count);o.push({id:"settings.dead-config:orphaned-mcp-permissions",analyzer:"settings.dead-config",group:"fixed",severity:"low",title:`${a} regra(s) de permiss\xE3o MCP para servidor(es) ausente(s)`,detail:'Regras "mcp__<servidor>__*" continuam na lista mesmo que o servidor n\xE3o esteja declarado em NENHUM escopo conhecido (user, project, local ou connector) hoje. Elas n\xE3o custam tokens \u2014 permissions n\xE3o entram no system prompt \u2014 mas s\xE3o configura\xE7\xE3o morta: se o servidor for reconectado sob outro nome, ou se voc\xEA acha que j\xE1 tem essas tools liberadas, a realidade \xE9 diferente do que a lista sugere. Todos os escopos de MCP conhecidos foram considerados antes de marcar um servidor como \xF3rf\xE3o, exatamente para n\xE3o confundir "ausente do escopo user" com "ausente de verdade".',evidence:{totalRules:p,totalOrphaned:a,orphanedSharePct:g,servers:h.map(m=>({server:m.server,count:m.count,scopes:m.scopes}))},impact:F("measured"),fixSpec:{kind:"settings-patch",params:{set:Qa(t.permissionRules,c)},describe:`Remover ${a} regra(s) de permiss\xE3o para servidor(es) MCP ausente(s)`}});}return t.effortLevel!==void 0&&t.effortLevel.length>0&&o.push({id:"settings.dead-config:effort-level-conflict",analyzer:"settings.dead-config",group:"fixed",severity:"low",title:`effortLevel="${t.effortLevel}" definido em settings.json`,detail:`O topo de settings.json define effortLevel="${t.effortLevel}", mas o Claude Code prioriza a vari\xE1vel de ambiente CLAUDE_CODE_EFFORT_LEVEL quando ela est\xE1 presente. Este collector deliberadamente n\xE3o l\xEA "env" (pode conter segredos), ent\xE3o n\xE3o h\xE1 como confirmar se existe de fato uma env sobrepondo este valor \u2014 se voc\xEA tiver CLAUDE_CODE_EFFORT_LEVEL definida, este campo provavelmente n\xE3o tem efeito nenhum. Confira manualmente sua env antes de assumir que effortLevel est\xE1 em vigor.`,guidance:"Rode `echo $CLAUDE_CODE_EFFORT_LEVEL` no terminal. Se retornar algo, \xE9 esse o valor em vigor e o `effortLevel` do settings.json n\xE3o tem efeito nenhum \u2014 decida qual dos dois voc\xEA quer e remova o outro, sen\xE3o o arquivo continuar\xE1 dizendo uma coisa enquanto o Claude Code faz outra. Se n\xE3o retornar nada, o settings.json est\xE1 valendo e n\xE3o h\xE1 o que corrigir.",evidence:{effortLevel:t.effortLevel,envInspected:false},impact:F("measured")}),t.otelHeadersHelper!==void 0&&t.otelHeadersHelper.length>0&&o.push({id:"settings.dead-config:otel-headers-unverified",analyzer:"settings.dead-config",group:"fixed",severity:"low",title:`otelHeadersHelper="${t.otelHeadersHelper}" sem confirma\xE7\xE3o de OTEL_* na env`,detail:`settings.json define otelHeadersHelper="${t.otelHeadersHelper}", mas seu efeito depende de vari\xE1veis OTEL_* estarem definidas na env \u2014 que este collector n\xE3o l\xEA, pela mesma raz\xE3o do caso de effortLevel (pode conter segredos). Se essas vari\xE1veis n\xE3o estiverem definidas, este helper n\xE3o faz efeito nenhum. Confira manualmente sua env.`,guidance:"Rode `env | grep OTEL_` no terminal. Sem nenhuma vari\xE1vel OTEL_*, este helper n\xE3o faz efeito e pode sair do settings.json \u2014 configura\xE7\xE3o morta n\xE3o custa tokens, mas faz voc\xEA acreditar que tem telemetria funcionando quando n\xE3o tem. Se as vari\xE1veis existirem, est\xE1 tudo certo e este item \xE9 s\xF3 informativo.",evidence:{otelHeadersHelper:t.otelHeadersHelper,envInspected:false},impact:F("measured")}),o}};var ec=new Set(["0","false","no","off",""]);function tc(e){return !ec.has(e.trim().toLowerCase())}var jo={id:"settings.disabled-capability",group:"fixed",title:"Capacidade do Claude Code desligada por configura\xE7\xE3o",run(e){let{settings:t}=e.data,n=[],o=t.envDisableExperimentalBetas;return o!==void 0&&tc(o)&&n.push({id:"settings.disabled-capability:experimental-betas",analyzer:"settings.disabled-capability",group:"fixed",severity:"high",title:`CLAUDE_CODE_DISABLE_EXPERIMENTAL_BETAS="${o}" desliga os betas do Claude Code`,detail:`settings.json define env.CLAUDE_CODE_DISABLE_EXPERIMENTAL_BETAS="${o}", e qualquer valor que n\xE3o seja falsy desativa os recursos em beta desta vers\xE3o do Claude Code. A vari\xE1vel n\xE3o custa token \u2014 ela n\xE3o entra no system prompt \u2014, ent\xE3o este item n\xE3o aparece no ranking de dinheiro. O que ela custa \xE9 capacidade: os betas s\xE3o onde entram as melhorias de gest\xE3o de contexto, de uso de ferramenta e os recursos novos antes de virarem padr\xE3o. Enquanto ela estiver definida assim, voc\xEA roda uma vers\xE3o do Claude Code deliberadamente mais antiga em comportamento que a que instalou.
|
|
32
|
-
|
|
33
|
-
S\xF3 o valor em settings.json foi inspecionado. Se a mesma vari\xE1vel tamb\xE9m estiver exportada no seu shell (.zshrc, .bashrc, .profile), remov\xEA-la daqui n\xE3o basta \u2014 a do shell continua valendo, e esta ferramenta n\xE3o a enxerga.`,guidance:"Remova a vari\xE1vel (o fix faz isso) e reabra o Claude Code. Depois confirme com `echo $CLAUDE_CODE_DISABLE_EXPERIMENTAL_BETAS` num terminal novo: se ainda retornar algo, a origem \xE9 o seu shell e n\xE3o o settings.json \u2014 procure a linha de export no .zshrc e apague l\xE1 tamb\xE9m.",evidence:{value:o,source:"settings.json \u2192 env",shellEnvInspected:false},impact:F("measured"),fixSpec:{kind:"settings-patch",params:{set:{},unset:["env.CLAUDE_CODE_DISABLE_EXPERIMENTAL_BETAS"]},describe:"Remover CLAUDE_CODE_DISABLE_EXPERIMENTAL_BETAS para reativar os betas"}}),t.autoCompactEnabled===false&&n.push({id:"settings.disabled-capability:auto-compact",analyzer:"settings.disabled-capability",group:"fixed",severity:"high",title:"autoCompactEnabled=false \u2014 a sess\xE3o bate no teto da janela em vez de compactar",detail:'settings.json define "autoCompactEnabled": false, o que desliga a compacta\xE7\xE3o autom\xE1tica ao se aproximar do limite da janela de contexto.\n\nVale ler isto junto com o analisador `compaction.waste`, que mede os tokens pagos e descartados em cada compacta\xE7\xE3o e os trata como desperd\xEDcio \u2014 os dois n\xE3o se contradizem. A alternativa a compactar n\xE3o \xE9 "n\xE3o compactar": \xE9 a sess\xE3o atingir o teto e parar de aceitar contexto novo, obrigando voc\xEA a recome\xE7ar do zero e a repagar a constru\xE7\xE3o inteira do contexto. Compacta\xE7\xE3o \xE9 o custo menor dos dois, e \xE9 por isso que ela deve ficar ligada mesmo custando tokens.\n\nA leitura correta de `compaction.waste` n\xE3o \xE9 "desligue a compacta\xE7\xE3o", e sim "trabalhe em sess\xF5es mais curtas para precisar dela menos vezes".',guidance:"Aplique o fix para voltar ao comportamento padr\xE3o. Se voc\xEA desligou de prop\xF3sito porque compacta\xE7\xE3o estava atrapalhando, o caminho \xE9 encurtar a sess\xE3o \u2014 `/clear` ao trocar de assunto \u2014 em vez de deixar o contexto crescer at\xE9 o limite sem rede de prote\xE7\xE3o.",evidence:{autoCompactEnabled:false},impact:F("measured"),fixSpec:{kind:"settings-patch",params:{set:{autoCompactEnabled:true},unset:[]},describe:"Religar a compacta\xE7\xE3o autom\xE1tica (autoCompactEnabled: true)"}}),n}};var en=10,Ve="name-only";function _o(e,t){let n={...e};for(let o of t)n[o]=Ve;return {skillOverrides:n}}var $o={id:"skill.unused",group:"fixed",title:"Skills instaladas sem uso",run(e){let{config:t,settings:n,inventory:o,transcripts:s,pricing:r}=e.data,i=new Map;for(let f of s.sessions)for(let[y,S]of Object.entries(f.skillInvocations))i.set(y,(i.get(y)??0)+S);let c=f=>{let y=n.skillOverrides[f];return y!==void 0&&y!=="on"},a=o.artifacts.filter(f=>f.kind==="skill"&&!f.broken&&!c(f.name)),u=[];for(let f of a){let y=t.skillUsage[f.name],S=y?.usageCount??0,b=i.get(f.name)??0,x=Math.max(S,b),O=Ge(y?.lastUsedAt,e.now);(x===0||O!==void 0&&O>_e)&&u.push({skill:f,uses:x,idleDays:O});}u.sort((f,y)=>y.skill.descriptionBytes-f.skill.descriptionBytes);let d=u.slice(0,en),l=u.slice(en),p=d.map(({skill:f,uses:y,idleDays:S})=>{let b=R(f.descriptionBytes),x=I(r,b,"estimated");return {id:`skill.unused:${f.name}`,analyzer:"skill.unused",group:"fixed",severity:w(x),title:y===0?`Skill "${f.name}" nunca foi usada`:`Skill "${f.name}" sem uso h\xE1 ${S} dias`,detail:`A description desta skill (${f.descriptionBytes} bytes) \xE9 carregada no system prompt de toda sess\xE3o para que o modelo saiba que ela existe. O corpo (${f.bodyBytes} bytes) s\xF3 \xE9 lido na invoca\xE7\xE3o, ent\xE3o desabilitar economiza apenas a description \u2014 mas em todos os turnos. A corre\xE7\xE3o marca skillOverrides["${f.name}"] = "${Ve}", que remove a description do system prompt mantendo a skill instalada e invoc\xE1vel; \xE9 revers\xEDvel apagando a entrada. Se quiser ir al\xE9m, "user-invocable-only" tira a skill da vis\xE3o do modelo preservando /${f.name}, e "off" a esconde de vez.`+(f.plugin?` Vem do plugin "${f.plugin}"; se as demais skills dele tamb\xE9m estiverem ociosas, desabilitar o plugin inteiro resolve de uma vez.`:""),evidence:{skill:f.name,plugin:f.plugin??null,scope:f.scope,usageCount:y,idleDays:S??null,descriptionBytes:f.descriptionBytes,bodyBytes:f.bodyBytes,path:f.path},impact:x,fixSpec:{kind:"settings-patch",params:{set:_o(n.skillOverrides,[f.name])},describe:`Silenciar a description da skill "${f.name}" (${Ve})`}}}),g=$e(t,n,o,e.now),h=new Map,m=[];for(let f of l){let y=f.skill.plugin;if(y&&g.get(y)?.covered){h.set(y,(h.get(y)??0)+1);continue}m.push(f);}if(m.length>0){let f=C(m.map(({skill:x})=>x.descriptionBytes)),y=R(f),S=I(r,y,"estimated"),b=C([...h.values()]);p.push({id:"skill.unused:low-impact",analyzer:"skill.unused",group:"fixed",severity:w(S),title:`${m.length} skill(s) ociosa(s) de baixo impacto`,detail:`Estas ${m.length} skills est\xE3o ociosas (nunca usadas, ou sem uso h\xE1 mais de ${_e} dias) mas n\xE3o entraram no top ${en} por descriptionBytes \u2014 cada description isolada \xE9 pequena demais para justificar um finding pr\xF3prio. Juntas, por\xE9m, somam ${f} bytes de description carregados no system prompt de toda sess\xE3o \u2014 no acumulado do m\xEAs isso deixa de ser desprez\xEDvel, que \xE9 justamente por que elas aparecem agrupadas em vez de sumirem do relat\xF3rio. A corre\xE7\xE3o marca as ${m.length} de uma vez em skillOverrides como "${Ve}": a description sai do system prompt e a skill continua instalada e invoc\xE1vel, ent\xE3o o custo de errar \xE9 baixo e a revers\xE3o \xE9 apagar as entradas (ou \`ctxa revert\`). Confira a lista em \`evidence.skills\` antes de aplicar.`+(b>0?` ${b} outra(s) skill(s) ociosa(s) ficaram de fora deste agregado porque o plugin dono j\xE1 tem finding pr\xF3prio em \`plugin.unused-or-broken\` \u2014 cont\xE1-las aqui de novo dobraria a economia projetada. Veja \`evidence.excludedByPluginFinding\`.`:""),evidence:{count:m.length,totalDescriptionBytes:f,skills:m.map(({skill:x,uses:O,idleDays:V})=>({skill:x.name,plugin:x.plugin??null,scope:x.scope,usageCount:O,idleDays:V??null,descriptionBytes:x.descriptionBytes})),...b>0?{excludedByPluginFinding:{count:b,plugins:[...h.keys()].sort()}}:{}},impact:S,fixSpec:{kind:"settings-patch",params:{set:_o(n.skillOverrides,m.map(({skill:x})=>x.name))},describe:`Silenciar a description de ${m.length} skill(s) ociosa(s) (${Ve})`}});}return p.sort((f,y)=>y.impact.tokensPerMonth-f.impact.tokensPerMonth)}};var nc=36e5,oc=3e5,sc=5e3,Io=10;function Lo(){return {oneHourSessions:0,fiveMinSessions:0,unknownSessions:0}}function rc(e,t){t===nc?e.oneHourSessions+=1:t===oc?e.fiveMinSessions+=1:e.unknownSessions+=1;}function ic(e,t){return {oneHourSessions:e.oneHourSessions+t.oneHourSessions,fiveMinSessions:e.fiveMinSessions+t.fiveMinSessions,unknownSessions:e.unknownSessions+t.unknownSessions}}function Bo(e,t,n){let o=e[t]??{turns:0,inputTokens:0,outputTokens:0,cacheCreation:0,cacheRead:0};o.cacheCreation+=n,e[t]=o;}var No={id:"cache.thrashing",group:"variable",title:"Cache de prompt expira por ociosidade",run(e){let{transcripts:t,pricing:n}=e.data,o=new Map;for(let m of t.sessions){let f=o.get(m.project)??{expiryTokens:0,turnsAfterExpiry:0,sessionsAffected:0,sessionsTotal:0,savedUsd:0,modelStats:{},ttl:Lo()};if(f.sessionsTotal+=1,m.cacheCreationAfterExpiry>0){let y=G(m.byModel)??n.primaryModel;Bo(f.modelStats,y,m.cacheCreationAfterExpiry);let S=n.rateFor(y),b=Math.max(S.cacheWritePerMTok-S.cacheReadPerMTok,0);f.savedUsd+=m.cacheCreationAfterExpiry/1e6*b,f.expiryTokens+=m.cacheCreationAfterExpiry,f.turnsAfterExpiry+=m.turnsAfterExpiry,f.sessionsAffected+=1,rc(f.ttl,m.cacheTtlMs);}o.set(m.project,f);}let s=[...o].filter(([,m])=>m.expiryTokens>=sc);if(s.length===0)return [];let r=C(s.map(([,m])=>m.expiryTokens)),i=C(s.map(([,m])=>m.savedUsd)),c=C(s.map(([,m])=>m.sessionsAffected)),a=C(s.map(([,m])=>m.turnsAfterExpiry)),u=t.sessions.length,d=s.map(([,m])=>m.ttl).reduce(ic,Lo()),l={};for(let[,m]of s)for(let[f,y]of Object.entries(m.modelStats))Bo(l,f,y.cacheCreation);let p=G(l)??n.primaryModel,g=pe(n,r,i,"measured"),h=s.sort((m,f)=>f[1].expiryTokens-m[1].expiryTokens).slice(0,Io).map(([m,f])=>({project:m,cacheCreationAfterExpiry:f.expiryTokens,sessions:f.sessionsAffected,turnsAfterExpiry:f.turnsAfterExpiry,excessTokens:f.expiryTokens}));return [{id:"cache.thrashing:all",analyzer:"cache.thrashing",group:"variable",severity:w(g),title:`Cache expirou por ociosidade em ${c} sess\xE3o(\xF5es), ${r} tokens reescritos`,detail:`O prompt cache tem TTL \u2014 5min ou 1h, conforme o turno. Enquanto o cache est\xE1 vivo, cada turno grava s\xF3 o incremento de contexto (mensagem nova, resposta anterior, tool results); isso \xE9 normal, n\xE3o desperd\xEDcio. Passado o TTL sem uma nova requisi\xE7\xE3o, o cache expira e o turno seguinte reescreve TODO o contexto do zero, n\xE3o o incremento \u2014 e cada token reescrito custa 1,25x o pre\xE7o de input contra 0,1x para ler, 12,5x de diferen\xE7a. O ponto acion\xE1vel mais importante: o custo de CADA expira\xE7\xE3o \xE9 proporcional ao tamanho do contexto \u2014 um system prompt de 150k tokens torna cada expira\xE7\xE3o 150k tokens mais cara. Por isso reduzir o custo fixo (os findings do grupo \`fixed\`: MCP, CLAUDE.md, skills) barateia toda expira\xE7\xE3o futura, mesmo sem mudar o padr\xE3o de uso. Sess\xF5es com TTL de 5min (tipicamente subagents/SDK) s\xE3o bem mais sens\xEDveis a pausas do que as de 1h, j\xE1 que qualquer gap acima de 5min j\xE1 invalida o cache. Detectamos ${a} turno(s) ap\xF3s expira\xE7\xE3o em ${c} de ${u} sess\xE3o(\xF5es) analisadas, em ${s.length} projeto(s). Veja \`evidence.topProjects\` para os ${Io} piores casos.`,guidance:"N\xE3o h\xE1 patch para isto: o que dispara a expira\xE7\xE3o \xE9 a pausa entre turnos. Na pr\xE1tica, tr\xEAs h\xE1bitos mudam o n\xFAmero. (1) Ao interromper o trabalho por mais de uma hora, encerre a sess\xE3o em vez de deix\xE1-la aberta \u2014 retomar uma sess\xE3o longa depois de uma pausa reescreve TODO o contexto, enquanto come\xE7ar do zero reescreve s\xF3 o system prompt. (2) Evite ficar alternando entre sess\xF5es em paralelo: cada volta a uma sess\xE3o parada h\xE1 mais tempo que o TTL paga a reescrita inteira. (3) Se a pausa for curta e voc\xEA souber que vai voltar, volte antes do TTL \u2014 1h em sess\xF5es interativas, mas s\xF3 5min nas de subagent/SDK. Al\xE9m do h\xE1bito, vale reduzir o custo fixo: como cada expira\xE7\xE3o custa o tamanho do contexto, cortar o system prompt (findings do grupo `fixed`) barateia todas as expira\xE7\xF5es futuras sem exigir disciplina nenhuma.",evidence:{projectsAffected:s.length,totalExpiryCacheCreationTokens:r,totalTurnsAfterExpiry:a,totalSessionsAffected:c,totalSessionsScanned:u,ttlDistribution:d,model:p,topProjects:h},impact:g}]}};function Uo(e){return Math.round(e*100)/100}var ac=5e3,zo=.2,cc=2,dc=5;function qo(e,t,n){let o=e[t]??{turns:0,inputTokens:0,outputTokens:0,cacheCreation:0,cacheRead:0};o.inputTokens+=n,e[t]=o;}var Ho={id:"compaction.waste",group:"variable",title:"Tokens descartados em compaction",run(e){let{transcripts:t,pricing:n}=e.data,o=new Map,s=[],r=n.observedDays>0?30/n.observedDays:1;for(let h of t.sessions){let m=G(h.byModel)??n.primaryModel;for(let f of h.compactions){s.push(f);let y=o.get(f.project)??{droppedTokens:0,events:0,autoEvents:0,manualEvents:0,costUsd:0,modelStats:{}};y.droppedTokens+=f.droppedTokens,y.events+=1,y.costUsd+=N(n,m,{input:f.droppedTokens}),qo(y.modelStats,m,f.droppedTokens),f.trigger==="auto"?y.autoEvents+=1:y.manualEvents+=1,o.set(f.project,y);}}if(s.length===0)return [];let i=C([...o.values()].map(h=>h.droppedTokens)),c=C([...o.values()].map(h=>h.costUsd)),a={};for(let h of o.values())for(let[m,f]of Object.entries(h.modelStats))qo(a,m,f.inputTokens);let u=G(a)??n.primaryModel,d=re(n,u,{input:i},"measured");d.usdPerMonth=Uo(c*r);let l=[...o.entries()].sort((h,m)=>m[1].droppedTokens-h[1].droppedTokens).slice(0,dc).map(([h,m])=>({project:h,droppedTokens:m.droppedTokens,events:m.events})),p=[...o.entries()].filter(([,h])=>h.droppedTokens>=ac&&i>0&&h.droppedTokens/i>zo).sort((h,m)=>m[1].droppedTokens-h[1].droppedTokens).slice(0,cc),g=[];for(let[h,m]of p){let f=G(m.modelStats)??n.primaryModel,y=re(n,f,{input:m.droppedTokens},"measured");y.usdPerMonth=Uo(m.costUsd*r);let S=Math.round(m.droppedTokens/i*100);g.push({id:`compaction.waste:${h}`,analyzer:"compaction.waste",group:"variable",severity:w(y),title:`${m.droppedTokens} tokens descartados em compaction neste projeto (${S}% do total)`,detail:`Este projeto sozinho concentra ${S}% de todo o desperd\xEDcio por compaction observado. ${m.events} compaction(s) descartaram ${m.droppedTokens} tokens que j\xE1 haviam sido pagos para entrar no contexto. ${m.autoEvents} foram autom\xE1ticas \u2014 a sess\xE3o cresceu al\xE9m da janela, sinal de que o trabalho deveria ter sido dividido em subagents ou sess\xF5es menores \u2014 e ${m.manualEvents} foram manuais, uma decis\xE3o consciente e geralmente aceit\xE1vel.`,guidance:m.autoEvents>0?`As ${m.autoEvents} compaction(s) autom\xE1ticas deste projeto s\xE3o o alvo: elas acontecem quando a sess\xE3o estoura a janela, e a\xED o que sai do contexto \xE9 escolhido por heur\xEDstica, n\xE3o por voc\xEA. Comece uma sess\xE3o nova (\`/clear\`) ao trocar de assunto, em vez de emendar tarefas n\xE3o relacionadas na mesma \u2014 o contexto da tarefa anterior n\xE3o ajuda na seguinte e ainda empurra a janela para o limite. Para trabalho de investiga\xE7\xE3o que l\xEA muitos arquivos, delegue a um subagent: ele varre num contexto pr\xF3prio e devolve s\xF3 a conclus\xE3o, em vez de carregar todos os arquivos lidos na sua janela. As ${m.manualEvents} manuais n\xE3o s\xE3o problema \u2014 ali voc\xEA escolheu o momento.`:`Todas as ${m.manualEvents} compaction(s) deste projeto foram manuais, ou seja, voc\xEA escolheu quando compactar. Isso \xE9 uso saud\xE1vel: o n\xFAmero aparece aqui como medida do custo, n\xE3o como erro a corrigir. Se quiser reduzi-lo, o caminho \xE9 \`/clear\` ao trocar de assunto em vez de compactar para seguir na mesma sess\xE3o.`,evidence:{project:h,droppedTokens:m.droppedTokens,events:m.events,autoEvents:m.autoEvents,manualEvents:m.manualEvents,shareOfTotalDroppedPct:S,model:f},impact:y});}return g.push({id:"compaction.waste:summary",analyzer:"compaction.waste",group:"variable",severity:w(d),title:`${i} tokens descartados em compaction no total`,detail:`Somando todos os ${o.size} projeto(s) com compaction, ${s.length} evento(s) descartaram ${i} tokens j\xE1 pagos para entrar no contexto.`+(p.length>0?` ${p.length} projeto(s) concentram sozinhos mais de ${Math.round(zo*100)}% do total e ganharam finding pr\xF3prio \u2014 veja \`evidence.topProjects\` para o resto.`:" Nenhum projeto isolado concentra desperd\xEDcio suficiente para um finding pr\xF3prio; veja `evidence.topProjects` para onde ele se distribui."),guidance:"Compaction descarta contexto que voc\xEA j\xE1 pagou para carregar, ent\xE3o o que a reduz \xE9 a janela nunca chegar perto do limite. Tr\xEAs h\xE1bitos: comece sess\xE3o nova (`/clear`) ao trocar de assunto, em vez de emendar tarefas n\xE3o relacionadas; delegue investiga\xE7\xE3o que l\xEA muitos arquivos a um subagent, que varre num contexto pr\xF3prio e devolve s\xF3 a conclus\xE3o; e prefira apontar trechos (`arquivo.ts:120-180`) a pedir leitura de arquivos inteiros quando voc\xEA j\xE1 sabe onde est\xE1 o ponto. Compaction manual n\xE3o \xE9 problema \u2014 ali o momento foi sua escolha; a autom\xE1tica \xE9 que indica sess\xE3o grande demais para a tarefa.",evidence:{totalEvents:s.length,totalDroppedTokens:i,projects:o.size,topProjects:l},impact:d}),g.sort((h,m)=>m.impact.tokensPerMonth-h.impact.tokensPerMonth)}};var uc=3,Wo=15,lc=2e3;function Jo(e,t,n){let o=e[t]??{turns:0,inputTokens:0,outputTokens:0,cacheCreation:0,cacheRead:0};o.inputTokens+=n,e[t]=o;}var Go={id:"read.repeated",group:"variable",title:"Arquivos relidos repetidamente",run(e){let{transcripts:t,pricing:n}=e.data,o=0,s=0;for(let f of t.sessions)for(let y of f.fatResults)y.tool==="Read"&&(o+=y.chars,s+=1);let r=s>0,i=r?Math.round(o/s):lc,c=R(i),a=new Map;for(let f of t.sessions){let y=G(f.byModel)??n.primaryModel;for(let S of f.repeatedReads){let b=Math.max(S.count-1,0);if(b===0)continue;let x=a.get(S.file)??{redundantReads:0,projects:new Set,modelStats:{}};x.redundantReads+=b,x.projects.add(f.project),Jo(x.modelStats,y,b),a.set(S.file,x);}}let u=[...a].filter(([,f])=>f.redundantReads>=uc);if(u.length===0)return [];let d=C(u.map(([,f])=>f.redundantReads)),l=c*d,p={};for(let[,f]of u)for(let[y,S]of Object.entries(f.modelStats))Jo(p,y,S.inputTokens);let g=G(p)??n.primaryModel,h=re(n,g,{input:l},"estimated"),m=u.sort((f,y)=>y[1].redundantReads-f[1].redundantReads).slice(0,Wo).map(([f,y])=>({file:f,redundantReads:y.redundantReads,projects:[...y.projects].sort()}));return [{id:"read.repeated:all",analyzer:"read.repeated",group:"variable",severity:w(h),title:`${u.length} arquivo(s) relido(s) repetidamente, ${d} releitura(s) redundante(s)`,detail:`A primeira leitura de um arquivo \xE9 leg\xEDtima; as ${d} releituras contadas aqui, espalhadas por ${u.length} arquivo(s), pagam o mesmo conte\xFAdo de novo. N\xE3o temos o tamanho real de cada arquivo, ent\xE3o o custo abaixo \xE9 uma ESTIMATIVA: `+(r?`usa a m\xE9dia observada de ${i} chars por leitura de "Read" nesta m\xE1quina.`:`nenhum tool_result de "Read" foi observado para calibrar, ent\xE3o assume um piso conservador de ${i} chars por leitura.`)+` A\xE7\xE3o concreta: use offset/limit para reler s\xF3 o trecho necess\xE1rio, ou mantenha o conte\xFAdo j\xE1 lido em contexto em vez de reler o arquivo inteiro de novo. O custo usa a taxa de "${g}" (o modelo dominante entre as sess\xF5es com releitura) \u2014 como os tokens aqui j\xE1 s\xE3o estimados (n\xE3o medidos), essa aproxima\xE7\xE3o \xE9 aceit\xE1vel; n\xE3o vale a precis\xE3o de separar por modelo quando o pr\xF3prio volume de tokens j\xE1 \xE9 um palpite. Veja \`evidence.topFiles\` para os ${Wo} arquivos mais custosos.`,guidance:'Releitura quase sempre nasce de contexto perdido: depois de uma compaction, ou numa sess\xE3o longa, o conte\xFAdo saiu da janela e precisa voltar. Por isso o caminho mais eficaz n\xE3o \xE9 "reler menos", \xE9 manter a sess\xE3o curta o bastante para n\xE3o perder o que j\xE1 foi lido \u2014 os findings de `compaction.waste` e este costumam andar juntos. Quando a releitura for inevit\xE1vel, pe\xE7a o trecho (`arquivo.ts:120-180`) em vez do arquivo inteiro. E se um arquivo aparece no topo de `evidence.topFiles` sess\xE3o ap\xF3s sess\xE3o, ele \xE9 candidato a virar contexto permanente: um resumo do que importa nele dentro do CLAUDE.md do projeto custa uma vez por turno em vez de um arquivo inteiro a cada releitura \u2014 mas s\xF3 vale se o resumo for curto, sen\xE3o troca um custo vari\xE1vel por um fixo maior.',evidence:{filesAffected:u.length,totalRedundantReads:d,estimatedCharsPerRead:i,estimatedTokensPerRead:c,estimatedTotalTokens:l,calibratedFromFatResults:r,model:g,topFiles:m},impact:h}]}};var pc=2e5,mc=5,fc={Read:"Pe\xE7a o trecho em vez do arquivo (`arquivo.ts:120-180`) quando j\xE1 souber onde est\xE1 o ponto \u2014 internamente isso vira offset/limit e evita carregar o resto. Para varrer muitos arquivos atr\xE1s de uma resposta, delegue a um subagent: ele l\xEA num contexto pr\xF3prio e devolve a conclus\xE3o, em vez de despejar cada arquivo na sua janela.",WebFetch:'O conte\xFAdo j\xE1 chega resumido por um modelo menor, ent\xE3o um resultado enorme significa p\xE1gina muito grande. Diga no pedido o que extrair ("pegue s\xF3 a tabela de pre\xE7os", "s\xF3 a se\xE7\xE3o de autentica\xE7\xE3o") \u2014 o resumo fica menor porque a instru\xE7\xE3o \xE9 mais estreita.',Grep:"Pe\xE7a a contagem ou a lista de arquivos quando n\xE3o precisar do conte\xFAdo casado; s\xF3 depois abra os arquivos que importarem. Uma busca ampla que devolve o texto de cada casamento paga por linhas que voc\xEA vai descartar.",Write:"Resultados grandes de escrita normalmente s\xE3o arquivos gerados inteiros de uma vez. Quando for editar algo existente, prefira edi\xE7\xE3o pontual a reescrever o arquivo \u2014 o resultado devolvido \xE9 proporcional ao que se escreve.",Edit:"Edi\xE7\xF5es muito grandes indicam blocos reescritos por inteiro. Trocar o menor trecho que identifica a mudan\xE7a reduz tanto o que se envia quanto o que volta como confirma\xE7\xE3o.",Agent:"Um subagent devolvendo muito texto anula parte da vantagem de delegar \u2014 o ponto \xE9 ele gastar contexto pr\xF3prio e te entregar a conclus\xE3o. Pe\xE7a explicitamente um retorno curto (a resposta, os caminhos relevantes) em vez de o relat\xF3rio completo da investiga\xE7\xE3o."},gc="Avalie se o resultado precisa entrar inteiro no contexto. Quando a chamada \xE9 explorat\xF3ria \u2014 voc\xEA ainda n\xE3o sabe o que procura \u2014 delegar a um subagent mant\xE9m o volume fora da sua janela e traz de volta s\xF3 a conclus\xE3o.";function hc(e){return e.hooks.find(n=>n.event==="PreToolUse"&&(n.matcher===""||n.matcher.includes("Bash"))&&/\brtk\b/.test(n.command))?.command}function yc(e){return e!==void 0?`Um filtro de sa\xEDda j\xE1 est\xE1 ativo como hook PreToolUse ("${e}"), ent\xE3o estes caracteres s\xE3o o que sobrou DEPOIS da filtragem \u2014 n\xE3o h\xE1 economia pendente aqui, e o que resta vem sobretudo de comandos para os quais o filtro n\xE3o tem regra dedicada e faz passthrough. Para reduzir mais, limite na origem: head/tail/rg no pr\xF3prio comando.`:"Pipe a sa\xEDda para head/tail/rg em vez de despejar tudo no contexto. Um filtro de sa\xEDda instalado como hook PreToolUse (rtk, por exemplo) faz isso automaticamente para comandos comuns \u2014 git, ls, grep, testes e builds \u2014 sem depender de lembrar do pipe a cada chamada."}var Vo={id:"toolresult.fat",group:"variable",title:"Tool results desproporcionalmente grandes",run(e){let{transcripts:t,pricing:n,settings:o}=e.data,s=hc(o),r=new Map;for(let c of t.sessions)for(let a of c.fatResults){let u=r.get(a.tool)??{totalChars:0,count:0,entries:[]};u.totalChars+=a.chars,u.count+=1,u.entries.push(a),r.set(a.tool,u);}let i=[];for(let[c,a]of r){if(a.totalChars<pc)continue;let u=R(a.totalChars),d=re(n,n.primaryModel,{input:u},"measured"),l=c==="Bash"?yc(s):fc[c]??gc,p=[...a.entries].sort((m,f)=>f.chars-m.chars),g=p[0],h=p.slice(0,mc).map(m=>({chars:m.chars,sessionId:m.sessionId,project:m.project}));i.push({id:`toolresult.fat:${c}`,analyzer:"toolresult.fat",group:"variable",severity:w(d),title:`Tool "${c}" produziu ${a.totalChars} chars em resultados`,detail:`${a.count} chamada(s) de "${c}" somaram ${a.totalChars} caracteres (~${u} tokens) de tool_result j\xE1 lidos como contexto \u2014 tratados como input do modelo principal (${n.primaryModel||"desconhecido"}). O maior caso isolado teve ${g?.chars??0} caracteres.`,guidance:l,evidence:{tool:c,calls:a.count,totalChars:a.totalChars,estimatedTokens:u,maxChars:g?.chars??0,maxSession:g?.sessionId??null,maxProject:g?.project??null,topOccurrences:h,...c==="Bash"?{outputFilterHook:s??null}:{}},impact:d});}return i.sort((c,a)=>a.impact.tokensPerMonth-c.impact.tokensPerMonth)}};var Ko={id:"agent.model-inherit",group:"model",title:"Agents herdando o modelo da sess\xE3o principal",run(e){let{inventory:t,transcripts:n,stats:o,pricing:s}=e.data,r=t.artifacts.filter(u=>u.kind==="agent"&&!u.broken&&(u.model===void 0||u.model==="inherit"));if(r.length===0)return [];let i=new Map;for(let u of n.sessions){if(!u.isSidechain||!u.agentType)continue;let d=i.get(u.agentType)??new Map;for(let[l,p]of Object.entries(u.byModel)){let g=d.get(l)??{turns:0,inputTokens:0,outputTokens:0,cacheCreation:0,cacheRead:0};g.turns+=p.turns,g.inputTokens+=p.inputTokens,g.outputTokens+=p.outputTokens,g.cacheCreation+=p.cacheCreation,g.cacheRead+=p.cacheRead,d.set(l,g);}i.set(u.agentType,d);}let c=Ae(o.modelUsage,"sonnet");return r.map(u=>{let d=i.get(u.name),l=0,p=0,g=0,h=0;if(d)for(let[S,b]of d){let x={input:b.inputTokens,output:b.outputTokens,cacheRead:b.cacheRead,cacheCreation:b.cacheCreation};l+=N(s,S,x),p+=N(s,c,x),g+=b.turns,h+=b.inputTokens+b.outputTokens+b.cacheCreation+b.cacheRead;}let m=Math.max(l-p,0),f=pe(s,h,m,"measured");return {id:`agent.model-inherit:${u.name}`,analyzer:"agent.model-inherit",group:"model",severity:w(f),title:g>0?`Agent "${u.name}" herda modelo e j\xE1 custou $${l.toFixed(2)}`:`Agent "${u.name}" herda modelo (sem execu\xE7\xE3o registrada)`,detail:g>0?`Este agent n\xE3o declara "model:" (ou usa "inherit") no frontmatter, ent\xE3o roda no modelo da sess\xE3o principal. Em ${g} turno(s) sidechain observados, isso custou $${l.toFixed(2)}; rodando em Sonnet custaria $${p.toFixed(2)} \u2014 economia de $${m.toFixed(2)}.`:'Este agent n\xE3o declara "model:" (ou usa "inherit") no frontmatter, mas n\xE3o h\xE1 sess\xE3o sidechain registrada para ele ainda \u2014 n\xE3o h\xE1 como medir o custo real.',evidence:{agent:u.name,path:u.path,declaredModel:u.model??null,turnsObserved:g,tokensObserved:h,realCostUsd:l,sonnetModel:c,sonnetCostUsd:p,savingsUsd:m},impact:f,fixSpec:{kind:"agent-model",params:{path:u.path,agent:u.name,model:"sonnet"},describe:`Fixar "model: sonnet" no frontmatter de "${u.name}"`}}}).sort((u,d)=>d.impact.tokensPerMonth-u.impact.tokensPerMonth)}};var vc="fork";function bc(e,t,n){let o={realCostUsd:0,sonnetCostUsd:0,totalTurns:0,totalTokens:0,inheritedCacheRead:0};for(let s of e){let r=s.inheritedCacheRead;o.inheritedCacheRead+=s.inheritedCacheRead;for(let[i,c]of Object.entries(s.byModel)){let a={input:c.inputTokens,output:c.outputTokens,cacheRead:c.cacheRead,cacheCreation:c.cacheCreation},u=Math.min(r,c.cacheRead);r-=u,o.realCostUsd+=N(n,i,a),o.sonnetCostUsd+=N(n,t,{...a,cacheRead:c.cacheRead-u,cacheCreation:c.cacheCreation+u}),o.totalTurns+=c.turns,o.totalTokens+=c.inputTokens+c.outputTokens+c.cacheCreation+c.cacheRead;}}return o}var Yo={id:"agent.opus-no-edits",group:"model",title:"Subagents Opus sem nenhuma edi\xE7\xE3o produzida",run(e){let{transcripts:t,stats:n,pricing:o,inventory:s}=e.data,r=t.sessions.filter(d=>d.isSidechain&&d.editsProduced===0&&Tc(d.byModel));if(r.length===0)return [];let i=new Map;for(let d of r){let l=d.agentType??`session:${d.sessionId}`,p=i.get(l)??{agentType:d.agentType,sessions:[]};p.sessions.push(d),i.set(l,p);}let c=Ae(n.modelUsage,"sonnet"),a=new Map(s.artifacts.filter(d=>d.kind==="agent").map(d=>[d.name,d])),u=[];for(let[d,l]of i){let p=bc(l.sessions,c,o),g=l.agentType===vc,h=Math.max(p.realCostUsd-p.sonnetCostUsd,0),m=g?F("measured"):pe(o,p.totalTokens,h,"measured"),f=l.agentType!==void 0?a.get(l.agentType):void 0,y={id:`agent.opus-no-edits:${d}`,analyzer:"agent.opus-no-edits",group:"model",severity:w(m),title:g?`${l.sessions.length} tarefa(s) de background (fork) herdaram Opus da sess\xE3o principal`:l.agentType!==void 0?`Agent "${l.agentType}" rodou em Opus ${l.sessions.length}x sem editar nada`:"Sess\xE3o sidechain sem agentType rodou em Opus sem editar nada",detail:g?kc(l.sessions.length,p,h):Sc(l.sessions.length,p,l.agentType,f===void 0),guidance:g?"N\xE3o h\xE1 o que configurar num fork: ele herda o modelo do pai por defini\xE7\xE3o. A \xFAnica alavanca real \xE9 o modelo da sess\xE3o principal \u2014 e troc\xE1-lo arrasta junto todo o trabalho que de fato precisa de Opus, ent\xE3o raramente compensa por causa das tarefas de background. O que efetivamente reduz este custo \xE9 o tamanho do contexto que o fork herda: como ele rel\xEA a conversa inteira, sess\xF5es longas tornam cada tarefa de background cara. Encerrar a sess\xE3o ao trocar de assunto (`/clear`) reduz este item sem abrir m\xE3o de nada.":f===void 0?"Este agent n\xE3o tem arquivo .md localiz\xE1vel no invent\xE1rio, ent\xE3o a corre\xE7\xE3o \xE9 manual: encontre a defini\xE7\xE3o dele (provavelmente sob `.claude/agents/` do projeto ou em um plugin) e declare `model: sonnet` no frontmatter. Se o agent foi removido, n\xE3o h\xE1 nada a fazer \u2014 o custo \xE9 hist\xF3rico.":void 0,evidence:{agentType:l.agentType??null,sessionCount:l.sessions.length,sessionIds:l.sessions.map(S=>S.sessionId),totalTurns:p.totalTurns,totalTokens:p.totalTokens,realCostUsd:p.realCostUsd,sonnetModel:c,sonnetCostUsd:p.sonnetCostUsd,savingsUsd:h,inheritedCacheRead:p.inheritedCacheRead,modelIsConfigurable:!g,artifactPath:f?.path??null},impact:m};f!==void 0&&!g&&(y.fixSpec={kind:"agent-model",params:{path:f.path,agent:f.name,model:"sonnet"},describe:`Fixar "model: sonnet" no frontmatter de "${f.name}"`}),u.push(y);}return u.sort((d,l)=>l.impact.tokensPerMonth-d.impact.tokensPerMonth)}};function kc(e,t,n){return `${e} sess\xE3o(\xF5es) do tipo "fork" \u2014 tarefas de background que o pr\xF3prio Claude Code dispara (consolida\xE7\xE3o de mem\xF3ria, sum\xE1rios, sugest\xF5es) \u2014 rodaram em Opus e custaram US$ ${t.realCostUsd.toFixed(2)} no hist\xF3rico observado, em ${t.totalTurns} turno(s). N\xC3O H\xC1 CORRE\xC7\xC3O DIRETA: um fork sempre herda o modelo da sess\xE3o pai, e o override de modelo \xE9 ignorado para ele. Isso \xE9 consequ\xEAncia de como o fork fica barato \u2014 ele reaproveita o prefixo j\xE1 cacheado da conversa pai (${t.inheritedCacheRead} tokens lidos a 0,1x aqui), e o prompt cache \xE9 por modelo: em outro modelo, esse contexto teria de ser regravado a 1,25x. Mesmo j\xE1 descontando essa regrava\xE7\xE3o, migrar para Sonnet valeria US$ ${n.toFixed(2)} \u2014 mas a \xFAnica alavanca que existiria para isso \xE9 o modelo da SESS\xC3O PRINCIPAL, que arrasta junto todo o trabalho que de fato precisa de Opus. Por isso este item \xE9 informativo: ele mostra o que as tarefas de background custam, n\xE3o uma economia que voc\xEA possa acionar.`}function Sc(e,t,n,o){return `${e} sess\xE3o(\xF5es) sidechain rodaram no modelo Opus e n\xE3o produziram nenhuma edi\xE7\xE3o (Edit/Write/NotebookEdit) \u2014 s\xF3 leitura e racioc\xEDnio, em ${t.totalTurns} turno(s). Isso complementa "agent.model-inherit", que s\xF3 olha o frontmatter e n\xE3o observa execu\xE7\xE3o real: aqui a execu\xE7\xE3o j\xE1 mostrou que o custo de Opus n\xE3o comprou nenhuma mudan\xE7a de c\xF3digo. A economia projetada j\xE1 desconta a regrava\xE7\xE3o do cache herdado do pai (${t.inheritedCacheRead} tokens): o prompt cache \xE9 por modelo, ent\xE3o o que hoje \xE9 lido a 0,1x precisaria ser gravado a 1,25x no primeiro turno sob o novo modelo. O modelo do subagent est\xE1 declarado no frontmatter e troc\xE1-lo por Sonnet \xE9 uma linha, sem afetar a sess\xE3o principal.`+(n!==void 0&&o?" N\xE3o foi encontrado o arquivo .md deste agent no invent\xE1rio (pode ter sido renomeado ou removido) \u2014 a corre\xE7\xE3o precisa ser aplicada manualmente.":"")}function Tc(e){let t=G(e);return t!==void 0&&t.toLowerCase().includes("opus")}var xc=1,Pc=new Set(["high","xhigh"]),Y="high",Xo=100,Qo=100;function wc(e){let t=e.envEffortLevel,n=e.effortLevel;return t!==void 0?{level:t,source:"env",overridden:n!==void 0&&n!==t}:n!==void 0?{level:n,source:"settings",overridden:false}:{level:void 0,source:"default",overridden:false}}function Cc(e){return e.level==="xhigh"&&e.source!=="default"}function Ac(e,t){let n=`Baixar o effort de "xhigh" para "${Y}"`+(t!==void 0?` (~US$ ${t.toFixed(2)}/m\xEAs em output)`:"");if(e.source==="env")return {kind:"settings-patch",params:{set:{"env.CLAUDE_CODE_EFFORT_LEVEL":Y}},describe:n};if(e.source==="settings")return {kind:"settings-patch",params:{set:{effortLevel:Y}},describe:n}}var Zo={id:"effort.spend",group:"model",title:"Gasto por n\xEDvel de effort",run(e){let{transcripts:t,pricing:n,settings:o}=e.data,s=wc(o),r=Cc(s),i=new Map;for(let Q of t.sessions)for(let[$,Z]of Object.entries(Q.byEffort)){let ze=i.get($)??{turns:0,outputTokens:0};ze.turns+=Z.turns,ze.outputTokens+=Z.outputTokens,i.set($,ze);}if(i.size===0&&!r)return [];let c={},a=0,u=0,d=0;for(let[Q,$]of i){let Z=re(n,n.primaryModel,{output:$.outputTokens},"measured").usdPerMonth;c[Q]={turns:$.turns,outputTokens:$.outputTokens,outputPerTurn:$.turns>0?Math.round($.outputTokens/$.turns):0,costUsd:Z},u+=$.outputTokens,Pc.has(Q)&&(a+=Z,d+=$.outputTokens);}if(a<xc&&!r)return [];let l=i.get(Y),p=i.get("xhigh"),g=l!==void 0&&p!==void 0&&l.turns>=Xo&&p.turns>=Qo,h=g?l.outputTokens/l.turns:0,m=g?p.outputTokens/p.turns:0,f=Math.max(m-h,0),y=g?Math.round(f*p.turns):0,S=s.level===Y,b=g&&y>0&&!S,x=b?re(n,n.primaryModel,{output:y},"estimated"):re(n,n.primaryModel,{output:d},"measured"),O=u>0?d/u:0,V=s.source==="env"?`O effort em vigor \xE9 "${s.level}", definido pela env CLAUDE_CODE_EFFORT_LEVEL`+(s.overridden?` \u2014 que tem preced\xEAncia e torna o effortLevel="${o.effortLevel}" do settings.json letra morta. Se voc\xEA achava estar rodando em "${o.effortLevel}", n\xE3o estava.`:"."):s.source==="settings"?`O effort em vigor \xE9 "${s.level}", definido por effortLevel no settings.json.`:"Nenhum effort est\xE1 configurado em settings.json nem na env: o gasto abaixo veio de escolhas por sess\xE3o, ent\xE3o n\xE3o h\xE1 um arquivo para corrigir.",X=i.size>0,T=X?`Juntos custaram $${a.toFixed(2)}, usando a taxa de output do modelo principal (${n.primaryModel||"desconhecido"}) como aproxima\xE7\xE3o \u2014 byEffort n\xE3o amarra o n\xEDvel a um modelo espec\xEDfico. `:"Ainda n\xE3o h\xE1 turno registrado com n\xEDvel de effort no hist\xF3rico analisado, ent\xE3o n\xE3o h\xE1 gasto a medir \u2014 o que segue \xE9 sobre a configura\xE7\xE3o, n\xE3o sobre o que ela j\xE1 custou. ",A=S?` O effort j\xE1 est\xE1 em "${Y}", ent\xE3o n\xE3o h\xE1 corre\xE7\xE3o pendente: o gasto acima \xE9 hist\xF3rico, de quando o n\xEDvel era outro, e some do relat\xF3rio conforme sess\xF5es antigas saem da janela de an\xE1lise.`:b?` Nos dados, "xhigh" produziu ${Math.round(m)} tokens de output por turno contra ${Math.round(h)} de "${Y}" \u2014 ${Math.round(f)} a mais por turno. Projetado sobre os ${p.turns} turnos em xhigh, baixar para "${Y}" pouparia ~${y} tokens de output. ATEN\xC7\xC3O: a compara\xE7\xE3o \xE9 observacional, n\xE3o experimental \u2014 ningu\xE9m sorteou quais tarefas rodariam em cada n\xEDvel. Se xhigh foi usado justamente nas tarefas mais dif\xEDceis, parte dessa diferen\xE7a vem da tarefa e n\xE3o do n\xEDvel, e a economia real \xE9 menor.`:g?` "xhigh" n\xE3o gastou mais output por turno que "${Y}" nestes dados, ent\xE3o n\xE3o h\xE1 economia a projetar.`:` N\xE3o h\xE1 amostra suficiente nos dois n\xEDveis (m\xEDnimo de ${Xo} turnos em "${Y}" e ${Qo} em "xhigh") para estimar economia com honestidade`+(r?` \u2014 mas isso n\xE3o absolve a configura\xE7\xE3o. "xhigh" est\xE1 fixado, \xE9 o n\xEDvel mais caro dispon\xEDvel, e "${Y}" j\xE1 \xE9 o default do Claude Code. A corre\xE7\xE3o \xE9 a mesma com ou sem n\xFAmero para justific\xE1-la; o que falta \xE9 a medi\xE7\xE3o do quanto ela poupa, n\xE3o a certeza de que vale.`:"."),j={id:"effort.spend:summary",analyzer:"effort.spend",group:"model",severity:r?"high":w(x),title:b?`Effort "xhigh" custa ${Math.round(f)} tokens de output a mais por turno`:r?'Effort fixado em "xhigh" \u2014 o n\xEDvel mais caro, em todo turno':`${(O*100).toFixed(0)}% do output vem de effort alto (high/xhigh)`,detail:`N\xEDveis de effort "high" e "xhigh" pedem mais thinking antes de responder, e thinking \xE9 cobrado como output token. ${T}${V}`+A,guidance:b||r?void 0:S?`Nada a fazer: o effort em vigor j\xE1 \xE9 "${Y}". Este item permanece vis\xEDvel porque o gasto hist\xF3rico \xE9 real, mas ele encolhe sozinho conforme as sess\xF5es antigas saem da janela de an\xE1lise.`:'Effort \xE9 escolha por sess\xE3o al\xE9m de configura\xE7\xE3o: `/effort` troca o n\xEDvel no meio do trabalho. Vale subir para "xhigh" em tarefa que exige racioc\xEDnio longo e voltar depois, em vez de deixar fixo no m\xE1ximo \u2014 thinking \xE9 cobrado como output token, ent\xE3o o n\xEDvel alto custa em todo turno, inclusive nos mec\xE2nicos.',evidence:{distribution:c,highEffortCostUsd:a,alreadyAtReference:S,totalOutputTokens:u,highEffortTokens:d,effectiveLevel:s.level??null,effectiveSource:s.source,settingsEffortOverridden:s.overridden,referenceLevel:Y,configuredTooHigh:r,hasSpendData:X,...g?{referenceOutputPerTurn:Math.round(h),xhighOutputPerTurn:Math.round(m),excessOutputPerTurn:Math.round(f),excessOutputTokens:y,comparisonIsObservational:true}:{comparable:false}},impact:x},he=b||r?Ac(s,b?x.usdPerMonth:void 0):void 0;return he!==void 0&&(j.fixSpec=he),[j]}};var Ec=new Set(["Read","Glob","Grep","Bash","WebFetch"]),Mc=10,ft=.5,gt=5;function es(e){return Math.round(e*10)/10}function Rc(e,t){let n=[];for(let[o,s]of e){let r=t.get(o)??s.sessions;if(r===0)continue;let i=s.sessions/r;s.sessions<gt||i<ft||n.push({project:o,mechanicalSessions:s.sessions,totalSessions:r,share:i,savingsUsd:s.savingsUsd});}return n.sort((o,s)=>s.savingsUsd-o.savingsUsd)}function Oc(e){let t=C(Object.values(e.toolCalls));return t===0?false:C(Object.entries(e.toolCalls).filter(([o])=>Ec.has(o)).map(([,o])=>o))/t>=.5}var ts={id:"model.opus-on-trivial",group:"model",title:"Sess\xF5es inteiras em Opus sem produzir edi\xE7\xE3o",run(e){let{transcripts:t,stats:n,pricing:o}=e.data,s=Ae(n.modelUsage,"sonnet"),r=[];for(let T of t.sessions){if(T.editsProduced!==0)continue;let A=G(T.byModel);if(A===void 0||!A.toLowerCase().includes("opus")||!Oc(T))continue;let j=T.byModel[A];if(j===void 0)continue;let he={input:j.inputTokens,output:j.outputTokens,cacheRead:j.cacheRead,cacheCreation:j.cacheCreation},Q=N(o,A,he),$=N(o,s,he),Z=Math.max(Q-$,0);r.push({project:T.project,turns:T.turns,tokensAffected:j.inputTokens+j.outputTokens+j.cacheRead+j.cacheCreation,realCostUsd:Q,sonnetCostUsd:$,savingsUsd:Z});}if(r.length===0)return [];let i=C(r.map(T=>T.turns)),c=C(r.map(T=>T.tokensAffected)),a=C(r.map(T=>T.realCostUsd)),u=C(r.map(T=>T.sonnetCostUsd)),d=C(r.map(T=>T.savingsUsd)),l=d/r.length,p=C(t.sessions.map(T=>T.trivialOpusTurns.turns)),g={output:C(t.sessions.map(T=>T.trivialOpusTurns.outputTokens)),cacheRead:C(t.sessions.map(T=>T.trivialOpusTurns.cacheRead))},h=Ae(n.modelUsage,"opus"),m=N(o,h,g),f=N(o,s,g),y=Math.max(m-f,0),S=pe(o,c,d,"measured"),b=new Map;for(let T of r){let A=b.get(T.project)??{sessions:0,tokensAffected:0,savingsUsd:0};A.sessions+=1,A.tokensAffected+=T.tokensAffected,A.savingsUsd+=T.savingsUsd,b.set(T.project,A);}let x=new Map;for(let T of t.sessions)x.set(T.project,(x.get(T.project)??0)+1);let O=Rc(b,x),V=[...b.entries()].sort((T,A)=>A[1].savingsUsd-T[1].savingsUsd).slice(0,Mc).map(([T,A])=>{let j=x.get(T)??A.sessions;return {project:T,wastedSessions:A.sessions,totalSessions:j,mechanicalSharePct:j>0?es(A.sessions/j*100):0,tokensAffected:A.tokensAffected,savingsUsd:A.savingsUsd}}),X=O.map(T=>{let A=pe(o,b.get(T.project)?.tokensAffected??0,T.savingsUsd,"measured");return {id:`model.opus-on-trivial:default-model:${T.project}`,analyzer:"model.opus-on-trivial",group:"model",severity:w(A),title:`${Math.round(T.share*100)}% das sess\xF5es em "${T.project}" s\xE3o mec\xE2nicas em Opus`,detail:`${T.mechanicalSessions} das ${T.totalSessions} sess\xF5es deste projeto rodaram em Opus sem produzir edi\xE7\xE3o e com maioria de chamadas mec\xE2nicas. Aqui o trabalho mec\xE2nico \xE9 a REGRA, n\xE3o a exce\xE7\xE3o, ent\xE3o vale declarar "model": "${s}" em ${T.project}/.claude/settings.json \u2014 o escopo de projeto n\xE3o afeta suas outras sess\xF5es. Quando uma tarefa espec\xEDfica precisar de Opus, /model troca na hora. Este finding s\xF3 aparece acima de ${Math.round(ft*100)}% de sess\xF5es mec\xE2nicas e ${gt} sess\xF5es: abaixo disso, baixar o default penalizaria a maioria que roda em Opus por um motivo.`,evidence:{project:T.project,mechanicalSessions:T.mechanicalSessions,totalSessions:T.totalSessions,mechanicalSharePct:es(T.share*100),savingsUsd:T.savingsUsd,targetModel:s},impact:A,fixSpec:{kind:"settings-patch",params:{path:`${T.project}/.claude/settings.json`,set:{model:s}},describe:`Definir "model": "${s}" no settings.json de ${T.project}`}}});return X.push({id:"model.opus-on-trivial:all",analyzer:"model.opus-on-trivial",group:"model",severity:w(S),title:`${r.length} sess\xE3o(\xF5es) inteira(s) em Opus sem produzir edi\xE7\xE3o`,detail:`Voc\xEA escolhe o modelo por SESS\xC3O (via /model, ou "model:" no frontmatter de um agent), n\xE3o por turno \u2014 ler arquivos para depois raciocinar sobre eles no mesmo fio de racioc\xEDnio exige o modelo forte durante a sess\xE3o inteira, mesmo que boa parte dos turnos seja s\xF3 leitura mec\xE2nica (Read/Glob/Grep/Bash/WebFetch). As ${r.length} sess\xE3o(\xF5es) abaixo rodaram inteiras em Opus, n\xE3o produziram nenhuma edi\xE7\xE3o (Edit/Write/NotebookEdit) e tiveram maioria de chamadas de tool mec\xE2nicas \u2014 o perfil de algo que Sonnet resolveria igualmente bem. A economia REAL e acion\xE1vel, medida por sess\xE3o, \xE9 de US$ ${d.toFixed(2)}/m\xEAs (US$ ${l.toFixed(2)}/m\xEAs em m\xE9dia por sess\xE3o). Uma heur\xEDstica por TURNO, como uma vers\xE3o anterior deste analisador usava, somaria os ${p} turnos triviais em Opus de TODAS as sess\xF5es \u2014 inclusive as que produziram edi\xE7\xE3o ou onde o turno trivial \xE9 minoria \u2014 e chegaria a US$ ${y.toFixed(2)}/m\xEAs. Esse n\xFAmero por turno N\xC3O \xE9 a economia real: a maioria desses turnos convive, na mesma sess\xE3o, com turnos que continuam exigindo Opus, e n\xE3o d\xE1 para trocar de modelo no meio de uma sess\xE3o.`+(O.length>0?` ${O.length} projeto(s) concentram sess\xF5es mec\xE2nicas o bastante para justificar um "model" pr\xF3prio no settings.json deles \u2014 ver os findings "default-model" logo acima.`:` Nenhum projeto concentra sess\xF5es mec\xE2nicas o bastante (m\xEDnimo de ${Math.round(ft*100)}% das sess\xF5es e ${gt} sess\xF5es) para justificar baixar o "model" default dele em settings.json: elas est\xE3o espalhadas por muitos projetos onde a maioria das sess\xF5es roda em Opus por um motivo, e baixar o default penalizaria essa maioria. Ver "mechanicalSharePct" por projeto em evidence.topProjects.`),guidance:"Como o modelo vale para a sess\xE3o inteira, a decis\xE3o \xE9 no come\xE7o dela: quando a tarefa for reconhecidamente mec\xE2nica \u2014 localizar onde algo est\xE1, ler para entender, rodar comandos e reportar \u2014 abra a sess\xE3o com `/model sonnet` e reserve Opus para quando houver decis\xE3o de arquitetura ou c\xF3digo a escrever. Trocar no meio n\xE3o recupera o que j\xE1 foi gasto, mas vale dali em diante. Uma alternativa que dispensa decidir de antem\xE3o: delegar a parte mec\xE2nica a um subagent com modelo menor e manter a sess\xE3o principal em Opus \u2014 o subagent varre num contexto pr\xF3prio e devolve s\xF3 a conclus\xE3o."+(O.length>0?" Para os projetos listados acima, isso j\xE1 vem como corre\xE7\xE3o autom\xE1tica.":""),evidence:{sessionsAffected:r.length,turnsInWastedSessions:i,tokensAffected:c,sonnetModel:s,realCostUsd:a,sonnetCostUsd:u,savingsUsd:d,perSessionSavingsUsd:l,legacyTrivialOpusTurns:p,legacyPerTurnSavingsUsd:y,topProjects:V,defaultModelCandidates:O.length,defaultModelThresholds:{minSharePct:Math.round(ft*100),minSessions:gt}},impact:S}),X}};var Dc=[wo,Oo,Ro,$o,Do,Co,Po,xo,Ao,Fo,jo,Mo,Vo,Go,Ho,No,ts,Ko,Yo,Zo];function Fc(e,t){return t?!(t.groups&&!t.groups.includes(e.group)||t.ids&&!t.ids.includes(e.id)):true}var ns={high:0,medium:1,low:2};function jc(e,t){let n=ns[e.severity]-ns[t.severity];if(n!==0)return n;let o=t.impact.usdPerMonth-e.impact.usdPerMonth;if(o!==0)return o;let s=t.impact.tokensPerMonth-e.impact.tokensPerMonth;return s!==0?s:e.impact.confidence===t.impact.confidence?0:e.impact.confidence==="measured"?-1:1}async function _c(e,t,n){let o=[];for(let s of e)if(Fc(s,n))try{let r=await s.run(t);o.push(...r);}catch(r){console.error(`[analyzer:${s.id}] falhou:`,r);}return o.sort(jc)}async function os(e,t){return _c(Dc,e,t)}function ss(e){let t=new Map;for(let o of e){let s=o.evidence.plugin;o.analyzer==="plugin.unused-or-broken"&&typeof s=="string"&&t.set(s,o.id);}let n=new Map;for(let o of e){let s=o.evidence.localServer;o.analyzer==="mcp.duplicate"&&typeof s=="string"&&n.set(s,o.id);}return e.map(o=>{let s=o.evidence.plugin;if((o.analyzer==="skill.unused"||o.analyzer==="description.bloat")&&typeof s=="string"){let i=t.get(s);if(i&&i!==o.id)return {...o,subsumedBy:i}}let r=o.evidence.server;if(o.analyzer==="mcp.unused"&&typeof r=="string"){let i=n.get(r);if(i&&i!==o.id)return {...o,subsumedBy:i}}return o})}function rs(e){return e.filter(t=>t.subsumedBy===void 0&&t.resolution===void 0)}function is(e){let t=new Set(e.map(n=>n.id));return e.filter(n=>n.subsumedBy!==void 0&&!t.has(n.subsumedBy)).map(n=>`${n.id} aponta para subsumedBy inexistente: ${n.subsumedBy}`)}function tn(e){if(e!==void 0)return E.join(e,".cache","ctxa");let t=process.env.XDG_CACHE_HOME,n=t!==void 0&&t.trim()!==""?t:E.join(homedir(),".cache");return E.join(n,"ctxa")}var fs=tn;function Lc(e){return E.join(tn(e),"backups")}function yt(e){return E.join(tn(e),"applied.jsonl")}async function gs(e){try{return await lstat(e)}catch{return}}function Bc(e){return e.replace(/^\/+/,"").replace(/\//g,"%2F")}async function H(e,t){let n=new Date().toISOString(),o=E.join(Lc(t),n);await mkdir(o,{recursive:true});let s=[];for(let r of e){let i=E.join(o,Bc(r)),c=await gs(r);if(c!==void 0)if(c.isSymbolicLink()){let a=await readlink(r);await symlink(a,i);}else await copyFile(r,i);s.push({original:r,backup:i});}return {id:n,dir:o,files:s}}function Nc(){return {id:new Date().toISOString(),dir:"",files:[]}}function U(e,t){return {fixId:e,kind:t,backup:Nc(),changed:[],appliedAt:new Date().toISOString()}}async function nn(e){for(let{original:t,backup:n}of e.backup.files){let o=await gs(n);if(o===void 0){await rm(t,{force:true});continue}if(await mkdir(E.dirname(t),{recursive:true}),await rm(t,{force:true}),o.isSymbolicLink()){let s=await readlink(n);await symlink(s,t);}else await copyFile(n,t);}}async function W(e,t){let n=yt(t);await mkdir(E.dirname(n),{recursive:true}),await appendFile(n,`${JSON.stringify(e)}
|
|
34
|
-
`,"utf8");}async function Uc(e,t){let n=yt(t);await mkdir(E.dirname(n),{recursive:true}),await appendFile(n,`${JSON.stringify(e)}
|
|
35
|
-
`,"utf8");}async function on(e,t){await Uc({findingId:e,action:"revert",at:new Date().toISOString()},t);}async function sn(e){let t=yt(e),n;try{n=await readFile(t,"utf8");}catch{return new Map}let o=new Map;for(let s of n.split(`
|
|
36
|
-
`)){let r=s.trim();if(r==="")continue;let i;try{i=JSON.parse(r);}catch{continue}let c=zc(i);c!==void 0&&o.set(c.findingId,c);}return o}function cs(e){return typeof e=="object"&&e!==null&&!Array.isArray(e)}function zc(e){if(!cs(e))return;let t=e.action;if(t==="revert"||t==="dismiss"||t==="apply"){let s=e.findingId;if(typeof s!="string")return;let r=typeof e.at=="string"?e.at:new Date(0).toISOString(),i={findingId:s,action:t,at:r},c=e.impactTokensPerMonth;typeof c=="number"&&(i.impactTokensPerMonth=c);let a=e.applied;return cs(a)&&(i.applied=a),i}let n=e.fixId;if(typeof n!="string")return;let o=typeof e.appliedAt=="string"?e.appliedAt:"";return {findingId:n,action:"apply",at:o,applied:e}}async function vt(e){let t=yt(e),n;try{n=await readFile(t,"utf8");}catch{return []}let o=[];for(let s of n.split(`
|
|
37
|
-
`)){let r=s.trim();if(r!=="")try{o.push(JSON.parse(r));}catch{}}return o}async function rn(e,t){let n=await vt(t);for(let o=n.length-1;o>=0;o--){let s=n[o];if(s!==void 0&&s.fixId===e)return s}}function Wc(e){let t=P(e.path),n=P(e.agent),o=P(e.model);if(t===void 0||n===void 0||o===void 0)throw new Error("agent-model: params inv\xE1lidos \u2014 esperado { path: string, agent: string, model: string }.");return {path:t,agent:n,model:o}}var hs="este agent vem do cache de um plugin \u2014 a mudan\xE7a ser\xE1 perdida na pr\xF3xima atualiza\xE7\xE3o do plugin",Jc=/^([>|])([+-]?)\d*\s*$/;function Gc(e){if((e[0]??"").trim()==="---"){for(let t=1;t<e.length;t++)if((e[t]??"").trim()==="---")return {start:1,end:t}}}function ys(e,t,n,o){let s=new RegExp(`^${o}:[ \\t]?(.*)$`);for(let r=t;r<n;r++){let i=e[r]??"";if(/^[ \t]/.test(i))continue;let c=s.exec(i);if(!c)continue;let a=(c[1]??"").trim();if(Jc.test(a)){let u=r+1;for(;u<n;){let d=e[u]??"";if(d.trim()===""||/^[ \t]/.test(d)){u++;continue}break}return {start:r,end:u}}return {start:r,end:r+1}}}function Vc(e){let t=e.includes(`\r
|
|
38
|
-
`)?`\r
|
|
39
|
-
`:`
|
|
40
|
-
`;return {lines:e.split(/\r\n|\n/),eol:t}}function cn(e,t){let{lines:n,eol:o}=Vc(e),s=Gc(n);if(!s)throw new Error('agent-model: o arquivo n\xE3o tem frontmatter YAML delimitado por "---".');let r=`model: ${t}`,i=ys(n,s.start,s.end,"model");if(i){let d=n.slice(i.start,i.end).join(`
|
|
41
|
-
`);if(i.end-i.start===1&&d===r)return {noop:true,hunkBefore:d,hunkAfter:r,newContent:e};let l=[...n];return l.splice(i.start,i.end-i.start,r),{noop:false,hunkBefore:d,hunkAfter:r,newContent:l.join(o)}}let c=ys(n,s.start,s.end,"description"),a=c?c.end:s.end,u=[...n];return u.splice(a,0,r),{noop:false,hunkBefore:'(sem linha "model:")',hunkAfter:r,newContent:u.join(o)}}var bt=class{kind="agent-model";params;homeDir;findingId;specDescribe;constructor(t,n={}){this.params=Wc(t.params),this.homeDir=n.homeDir,this.findingId=n.findingId,this.specDescribe=t.describe;}describe(){return this.isPluginCache()?`${this.specDescribe} \u2014 aten\xE7\xE3o: ${hs}.`:this.specDescribe}async preview(){let t=await this.readFile(),n=cn(t,this.params.model);if(n.noop)return {hunks:[],summary:`"${this.params.agent}" j\xE1 usa o modelo "${this.params.model}".`};let o=this.isPluginCache()?` Aten\xE7\xE3o: ${hs}.`:"";return {hunks:[{file:this.params.path,before:n.hunkBefore,after:n.hunkAfter}],summary:`Define model: ${this.params.model} para o agent "${this.params.agent}".${o}`}}async apply(t={}){let n=this.findingId??`agent-model:${this.params.path}:${this.params.agent}`,o=await this.readFile(),s=cn(o,this.params.model);if(s.noop||t.dryRun)return U(n,this.kind);let r=await H([this.params.path],this.homeDir);await writeFile(this.params.path,s.newContent,"utf8");let i={fixId:n,kind:this.kind,backup:r,changed:[this.params.path],appliedAt:new Date().toISOString()};return await W(i,this.homeDir),i}async isApplied(){let t=await this.readFile().catch(()=>{});return t===void 0?false:cn(t,this.params.model).noop}isPluginCache(){let t=E.resolve(Ze(this.homeDir)),n=E.resolve(this.params.path);return n===t||n.startsWith(t+E.sep)}async readFile(){try{return await readFile(this.params.path,"utf8")}catch(t){throw new Error(`agent-model: n\xE3o foi poss\xEDvel ler ${this.params.path}: ${t.message}`,{cause:t})}}};function Qc(e){let t=P(e.path),n=M(e.targetBytes);if(t===void 0||n===void 0)throw new Error("claudemd-compact: params inv\xE1lidos \u2014 esperado { path: string, targetBytes: number }.");return {path:t,targetBytes:n}}var vs=18e4,Zc=.3,ed="Condense o CLAUDE.md a seguir preservando TODA diretiva sem\xE2ntica: regras, caminhos, nomes de comandos e prefer\xEAncias. Elimine redund\xE2ncia, verbosidade e exemplos sup\xE9rfluos. Mantenha o formato markdown. Responda APENAS com o conte\xFAdo novo do arquivo, sem pre\xE2mbulo nem cercas de c\xF3digo (```).";function Ke(e){return Buffer.byteLength(e,"utf8")}function td(e,t,n){return new Promise((o,s)=>{let r=spawn(e,["-p","--model","haiku","--output-format","json"],{stdio:["pipe","pipe","pipe"]}),i="",c="",a=false,u=setTimeout(()=>{a||(a=true,r.kill("SIGKILL"),s(new Error(`claudemd-compact: timeout de ${n}ms ao chamar "${e}".`)));},n);r.stdout.on("data",d=>{i+=d.toString("utf8");}),r.stderr.on("data",d=>{c+=d.toString("utf8");}),r.on("error",d=>{a||(a=true,clearTimeout(u),s(new Error(`claudemd-compact: falha ao executar "${e}": ${d.message}`)));}),r.on("close",d=>{if(!a){if(a=true,clearTimeout(u),d!==0){s(new Error(`claudemd-compact: "${e}" saiu com c\xF3digo ${String(d)}. stderr: ${c.slice(0,500)}`));return}o(i);}}),r.stdin.write(t,"utf8"),r.stdin.end();})}function nd(e){let t=e.split(`
|
|
42
|
-
`);for(let n=t.length-1;n>=0;n--){let o=(t[n]??"").trim();if(o!=="")try{let s=JSON.parse(o);if(k(s)&&s.type==="result"&&typeof s.result=="string")return s.result}catch{}}throw new Error('claudemd-compact: n\xE3o encontrei uma linha JSON com type "result" na sa\xEDda do modelo.')}var kt=class{kind="claudemd-compact";params;homeDir;findingId;claudeBin;specDescribe;cachedCompacted;constructor(t,n={}){this.params=Qc(t.params),this.homeDir=n.homeDir,this.findingId=n.findingId,this.claudeBin=n.claudeBin??"claude",this.specDescribe=t.describe;}describe(){return `${this.specDescribe} \u2014 aten\xE7\xE3o: preview() chama um LLM de verdade (custa dinheiro e tempo; timeout de ${vs/1e3}s).`}async preview(){let t=await this.readOriginal();if(this.alreadyWithinTarget(t))return {hunks:[],summary:`${this.params.path} j\xE1 est\xE1 dentro do alvo de ${this.params.targetBytes} bytes.`};let n=await this.compact(t);return {hunks:[{file:this.params.path,before:t,after:n}],summary:`Compacta ${this.params.path} de ${Ke(t)} para ${Ke(n)} bytes (alvo: ${this.params.targetBytes}).`}}async isApplied(){let t=await this.readOriginal().catch(()=>{});return t===void 0?false:this.alreadyWithinTarget(t)}async apply(t={}){let n=this.findingId??`claudemd-compact:${this.params.path}`,o=await this.readOriginal();if(this.alreadyWithinTarget(o))return U(n,this.kind);if(t.dryRun)return await this.compact(o),U(n,this.kind);let s=await this.compact(o),r=await H([this.params.path],this.homeDir);await writeFile(this.params.path,s,"utf8");let i={fixId:n,kind:this.kind,backup:r,changed:[this.params.path],appliedAt:new Date().toISOString()};return await W(i,this.homeDir),i}alreadyWithinTarget(t){return Ke(t)<=this.params.targetBytes}async readOriginal(){try{return await readFile(this.params.path,"utf8")}catch(t){throw new Error(`claudemd-compact: n\xE3o foi poss\xEDvel ler ${this.params.path}: ${t.message}`,{cause:t})}}async compact(t){if(this.cachedCompacted!==void 0)return this.cachedCompacted;let n=await td(this.claudeBin,`${ed}
|
|
43
|
-
|
|
44
|
-
---
|
|
45
|
-
|
|
46
|
-
${t}`,vs),o=nd(n),s=Ke(t),r=Ke(o);if(o.trim()==="")throw new Error("claudemd-compact: o modelo devolveu conte\xFAdo vazio \u2014 recusando aplicar.");if(r>=s)throw new Error(`claudemd-compact: resultado (${r} bytes) n\xE3o ficou menor que o original (${s} bytes) \u2014 recusando aplicar.`);if(r<s*Zc)throw new Error(`claudemd-compact: resultado encolheu mais de 70% (${s} -> ${r} bytes), sinal prov\xE1vel de truncamento em vez de compacta\xE7\xE3o \u2014 recusando aplicar.`);return this.cachedCompacted=o,o}};function rd(e){let t=P(e.path);if(t===void 0)throw new Error('file-delete: params inv\xE1lidos \u2014 "path" (string) \xE9 obrigat\xF3rio.');return {path:t}}var Tt=class{kind="file-delete";params;homeDir;findingId;specDescribe;constructor(t,n={}){this.params=rd(t.params),this.homeDir=n.homeDir,this.findingId=n.findingId,this.specDescribe=t.describe,this.assertAllowedPath();}describe(){return this.specDescribe}async preview(){let t=await this.statTarget();return t===void 0?{hunks:[],summary:`${this.params.path} j\xE1 n\xE3o existe.`}:(this.assertNotDirectory(t),{hunks:[{file:this.params.path,before:"(arquivo presente)",after:"(removido)"}],summary:`Remove ${this.params.path}.`})}async isApplied(){return await this.statTarget()===void 0}async apply(t={}){let n=this.findingId??`file-delete:${this.params.path}`,o=await this.statTarget();if(o===void 0)return U(n,this.kind);if(this.assertNotDirectory(o),t.dryRun)return U(n,this.kind);let s=await H([this.params.path],this.homeDir);await rm(this.params.path,{force:true});let r={fixId:n,kind:this.kind,backup:s,changed:[this.params.path],appliedAt:new Date().toISOString()};return await W(r,this.homeDir),r}async statTarget(){try{return await lstat(this.params.path)}catch{return}}assertNotDirectory(t){if(t.isDirectory())throw new Error(`file-delete: recusado \u2014 "${this.params.path}" \xE9 um diret\xF3rio.`)}assertAllowedPath(){let t=E.resolve(this.params.path);if(!([xe(this.homeDir),fs(this.homeDir)].map(s=>E.resolve(s)).some(s=>t===s||t.startsWith(s+E.sep))||id(t)))throw new Error(`file-delete: recusado \u2014 "${this.params.path}" est\xE1 fora de ~/.claude, ~/.cache/ctxa e de qualquer .claude/ de projeto.`)}};function id(e){return e.split(E.sep).slice(0,-1).includes(".claude")}function ud(e){let t=e.split(`
|
|
47
|
-
`);for(let n of t.slice(1)){let o=/^([ \t]+)\S/.exec(n);if(o)return o[1]??" "}return " "}async function me(e,t){let n;try{n=await readFile(e,"utf8");}catch(g){if(g.code==="ENOENT")n="{}";else throw new Error(`patchJsonFile: n\xE3o foi poss\xEDvel ler ${e}: ${g.message}`,{cause:g})}let o;try{o=JSON.parse(n);}catch(g){throw new Error(`patchJsonFile: ${e} n\xE3o cont\xE9m JSON v\xE1lido: ${g.message}`,{cause:g})}if(!k(o))throw new Error(`patchJsonFile: ${e} precisa ter um objeto no n\xEDvel superior.`);let s=o,r=new Set(Object.keys(s)),i=new Set,c=new Proxy(s,{deleteProperty(g,h){return typeof h=="string"&&i.add(h),Reflect.deleteProperty(g,h)},set(g,h,m){return typeof h=="string"&&m===void 0&&i.add(h),Reflect.set(g,h,m)}});t(c);let a=new Set(Object.keys(s)),u=[...r].filter(g=>!a.has(g)&&!i.has(g));if(u.length>0)throw new Error(`patchJsonFile: chave(s) de topo desaparecida(s) inesperadamente em ${e}: `+u.join(", "));let d=ud(n),l=JSON.stringify(s,null,d);n.endsWith(`
|
|
48
|
-
`)&&(l+=`
|
|
49
|
-
`);try{JSON.parse(l);}catch(g){throw new Error(`patchJsonFile: resultado gerado para ${e} n\xE3o \xE9 JSON v\xE1lido: ${g.message}`,{cause:g})}let p=`${e}.tmp-${process.pid}`;return await writeFile(p,l,"utf8"),await rename(p,e),{before:n,after:l}}function pd(e){let t=P(e.server),n=P(e.scope);if(t===void 0||n===void 0)throw new Error("mcp-remove: params inv\xE1lidos \u2014 esperado { server: string, scope: string }.");return {server:t,scope:n}}var xt=class{kind="mcp-remove";params;homeDir;findingId;specDescribe;constructor(t,n={}){this.params=pd(t.params),this.homeDir=n.homeDir,this.findingId=n.findingId,this.specDescribe=t.describe;}describe(){return this.params.scope==="connector"?`${this.specDescribe} \u2014 conector claude.ai, gerenciado na conta, nada a remover em disco.`:this.specDescribe}async preview(){if(this.params.scope==="connector")return {hunks:[],summary:`Conector claude.ai "${this.params.server}" \xE9 gerenciado na conta, n\xE3o em disco. Para deslig\xE1-lo, defina ANTHROPIC_API_KEY no ambiente (isso desliga todos os conectores claude.ai de uma vez, n\xE3o s\xF3 este).`};this.assertUserScope();let t=De(this.homeDir),n=await this.readServerEntry(t);return n===void 0?{hunks:[],summary:`Servidor MCP "${this.params.server}" j\xE1 n\xE3o existe em ${t}.`}:{hunks:[{file:t,before:JSON.stringify({[this.params.server]:n},null,2),after:"(removido de mcpServers)"}],summary:`Remove o servidor MCP "${this.params.server}" de mcpServers em ${t}.`}}async apply(t={}){let n=this.findingId??`mcp-remove:${this.params.server}`;if(this.params.scope==="connector")return U(n,this.kind);this.assertUserScope();let o=De(this.homeDir);if(await this.readServerEntry(o)===void 0||t.dryRun)return U(n,this.kind);let r=await H([o],this.homeDir);await me(o,c=>{let a=c.mcpServers;k(a)&&delete a[this.params.server];});let i={fixId:n,kind:this.kind,backup:r,changed:[o],appliedAt:new Date().toISOString()};return await W(i,this.homeDir),i}async isApplied(){return this.params.scope==="connector"?false:await this.readServerEntry(De(this.homeDir))===void 0}assertUserScope(){if(this.params.scope!=="user")throw new Error(`mcp-remove: scope "${this.params.scope}" n\xE3o \xE9 suportado (apenas "user" e "connector").`)}async readServerEntry(t){let n=await readFile(t,"utf8").catch(()=>{});if(n===void 0)return;let o;try{o=JSON.parse(n);}catch{return}if(!(!k(o)||!k(o.mcpServers)))return o.mcpServers[this.params.server]}};function fd(e){let t=P(e.plugin);if(t===void 0)throw new Error('plugin-disable: params inv\xE1lidos \u2014 "plugin" (string) \xE9 obrigat\xF3rio.');let n=P(e.reason);return n===void 0?{plugin:t}:{plugin:t,reason:n}}var Pt=class{kind="plugin-disable";params;homeDir;findingId;specDescribe;constructor(t,n={}){this.params=fd(t.params),this.homeDir=n.homeDir,this.findingId=n.findingId,this.specDescribe=t.describe;}describe(){return this.params.reason!==void 0?`${this.specDescribe} (${this.params.reason})`:this.specDescribe}async preview(){let t=q(this.homeDir),n=await this.currentValue(t);return n===false?{hunks:[],summary:`Plugin "${this.params.plugin}" j\xE1 est\xE1 desabilitado.`}:{hunks:[{file:t,before:JSON.stringify({[this.params.plugin]:n??"(ausente)"},null,2),after:JSON.stringify({[this.params.plugin]:false},null,2)}],summary:`Define enabledPlugins["${this.params.plugin}"] = false em ${t}.`}}async apply(t={}){let n=this.findingId??`plugin-disable:${this.params.plugin}`,o=q(this.homeDir);if(await this.currentValue(o)===false||t.dryRun)return U(n,this.kind);let r=await H([o],this.homeDir);await me(o,c=>{let a=k(c.enabledPlugins)?c.enabledPlugins:{};c.enabledPlugins=a,a[this.params.plugin]=false;});let i={fixId:n,kind:this.kind,backup:r,changed:[o],appliedAt:new Date().toISOString()};return await W(i,this.homeDir),i}async isApplied(){return await this.currentValue(q(this.homeDir))===false}async currentValue(t){let n=await readFile(t,"utf8").catch(()=>{});if(n!==void 0)try{let o=JSON.parse(n);return !k(o)||!k(o.enabledPlugins)?void 0:o.enabledPlugins[this.params.plugin]}catch{return}}};function hd(e){let t=P(e.plugin);if(t===void 0)throw new Error('plugin-uninstall: params inv\xE1lidos \u2014 "plugin" (string) \xE9 obrigat\xF3rio.');let n=P(e.reason);return n===void 0?{plugin:t}:{plugin:t,reason:n}}async function bs(e){let t=await readFile(e,"utf8").catch(()=>{});if(t!==void 0)try{let n=JSON.parse(t);return k(n)?n:void 0}catch{return}}var wt=class{kind="plugin-uninstall";params;homeDir;findingId;specDescribe;constructor(t,n={}){this.params=hd(t.params),this.homeDir=n.homeDir,this.findingId=n.findingId,this.specDescribe=t.describe;}describe(){return this.params.reason!==void 0?`${this.specDescribe} (${this.params.reason})`:this.specDescribe}async preview(){let t=et(this.homeDir),n=q(this.homeDir);if(await this.isApplied())return {hunks:[],summary:`Plugin "${this.params.plugin}" j\xE1 n\xE3o est\xE1 instalado.`};let o=[],s=await this.registryEntry();s!==void 0&&o.push({file:t,before:JSON.stringify({[this.params.plugin]:s},null,2),after:"(entrada removida)"});let r=await this.enabledValue();return r!==void 0&&o.push({file:n,before:JSON.stringify({[this.params.plugin]:r},null,2),after:"(chave removida)"}),{hunks:o,summary:`Desinstala "${this.params.plugin}": remove do registry de plugins instalados`+(r!==void 0?" e de enabledPlugins.":".")}}async apply(t={}){let n=this.findingId??`plugin-uninstall:${this.params.plugin}`;if(await this.isApplied()||t.dryRun)return U(n,this.kind);let o=et(this.homeDir),s=q(this.homeDir),r=[],i=await H([o,s],this.homeDir);await this.registryEntry()!==void 0&&(await me(o,a=>{let u=k(a.plugins)?a.plugins:void 0;u!==void 0&&delete u[this.params.plugin];}),r.push(o)),await this.enabledValue()!==void 0&&(await me(s,a=>{let u=k(a.enabledPlugins)?a.enabledPlugins:void 0;u!==void 0&&delete u[this.params.plugin];}),r.push(s));let c={fixId:n,kind:this.kind,backup:i,changed:r,appliedAt:new Date().toISOString()};return await W(c,this.homeDir),c}async isApplied(){return await this.registryEntry()===void 0&&await this.enabledValue()===void 0}async registryEntry(){let t=await bs(et(this.homeDir));return (t!==void 0&&k(t.plugins)?t.plugins:void 0)?.[this.params.plugin]}async enabledValue(){let t=await bs(q(this.homeDir));return (t!==void 0&&k(t.enabledPlugins)?t.enabledPlugins:void 0)?.[this.params.plugin]}};function dn(e){return e.split(".").filter(t=>t.length>0)}function yd(e,t){let n=e[t];if(k(n))return n;let o={};return e[t]=o,o}function Le(e,t){let n=e;for(let o of dn(t)){if(!k(n))return;n=n[o];}return n}function ks(e,t,n){let o=dn(t);if(o.length===0)throw new Error("setByPath: caminho vazio.");let s=e;for(let r=0;r<o.length-1;r++)s=yd(s,o[r]);s[o[o.length-1]]=n;}function Ss(e,t){let n=dn(t);if(n.length===0)return false;let o=e;for(let r=0;r<n.length-1;r++){let i=o[n[r]];if(!k(i))return false;o=i;}let s=n[n.length-1];return s in o?(delete o[s],true):false}function bd(e){let t=P(e.path),n=k(e.set)?e.set:{},o=Array.isArray(e.unset)?e.unset.filter(s=>typeof s=="string"):[];if(Object.keys(n).length===0&&o.length===0)throw new Error('settings-patch: informe ao menos um "set" ou "unset" em params.');return t===void 0?{set:n,unset:o}:{path:t,set:n,unset:o}}var Ct=class{kind="settings-patch";params;homeDir;findingId;specDescribe;constructor(t,n={}){this.params=bd(t.params),this.homeDir=n.homeDir,this.findingId=n.findingId,this.specDescribe=t.describe;}describe(){return this.specDescribe}async preview(){let t=this.filePath();if(await this.isApplied())return {hunks:[],summary:`${t} j\xE1 est\xE1 no estado desejado.`};let n=await this.currentRoot(),o={},s={};for(let r of Object.keys(this.params.set))o[r]=Le(n,r),s[r]=this.params.set[r];for(let r of this.params.unset)o[r]=Le(n,r),s[r]="(removido)";return {hunks:[{file:t,before:JSON.stringify(o,null,2),after:JSON.stringify(s,null,2)}],summary:`Aplica patch em ${t} (${Object.keys(this.params.set).length} set, ${this.params.unset.length} unset).`}}async apply(t={}){let n=this.filePath(),o=this.findingId??`settings-patch:${n}`;if(await this.isApplied()||t.dryRun)return U(o,this.kind);let s=await H([n],this.homeDir);await me(n,i=>{for(let[c,a]of Object.entries(this.params.set)){let u=Le(i,c);ks(i,c,k(u)&&k(a)?{...u,...a}:a);}for(let c of this.params.unset)Ss(i,c);});let r={fixId:o,kind:this.kind,backup:s,changed:[n],appliedAt:new Date().toISOString()};return await W(r,this.homeDir),r}filePath(){return this.params.path??q(this.homeDir)}async currentRoot(){let t=await readFile(this.filePath(),"utf8").catch(()=>"{}");try{let n=JSON.parse(t);return k(n)?n:{}}catch{return {}}}async isApplied(){let t=await this.currentRoot();for(let[n,o]of Object.entries(this.params.set)){let s=Le(t,n);if(k(s)&&k(o)){if(!Object.entries(o).every(([i,c])=>JSON.stringify(s[i])===JSON.stringify(c)))return false}else if(JSON.stringify(s)!==JSON.stringify(o))return false}for(let n of this.params.unset)if(Le(t,n)!==void 0)return false;return true}};function Be(e,t={}){switch(e.kind){case "mcp-remove":return new xt(e,t);case "plugin-disable":return new Pt(e,t);case "plugin-uninstall":return new wt(e,t);case "agent-model":return new bt(e,t);case "settings-patch":return new Ct(e,t);case "claudemd-compact":return new kt(e,t);case "file-delete":return new Tt(e,t);default:{let n=e.kind;throw new Error(`resolveFix: kind de fix desconhecido: ${String(n)}`)}}}var kd=1.5;async function Ts(e,t={}){let n=await sn(t.homeDir);if(n.size===0)return e;let o=[];for(let s of e){let r=n.get(s.id);if(r===void 0){o.push(s);continue}let i=await Sd(s,r,t);o.push(i===void 0?s:{...s,resolution:i});}return o}async function Sd(e,t,n){switch(t.action){case "revert":return;case "dismiss":return Td(e,t);case "apply":return await xd(e,n)?{state:"fixed",at:t.at,...e.fixSpec?{describe:e.fixSpec.describe}:{}}:void 0}}function Td(e,t){let n=t.impactTokensPerMonth,o=e.impact.tokensPerMonth;if(!(n!==void 0&&n>0&&o>=n*kd))return {state:"dismissed",at:t.at,describe:"Dispensado",...n!==void 0?{impactTokensPerMonth:n}:{}}}async function xd(e,t){if(e.fixSpec===void 0)return false;try{return await Be(e.fixSpec,{findingId:e.id,...t.homeDir!==void 0?{homeDir:t.homeDir}:{}}).isApplied()}catch{return false}}function un(e){return e.filter(t=>t.resolution===void 0)}function xs(e){return e.filter(t=>t.resolution!==void 0).sort((t,n)=>(n.resolution?.at??"").localeCompare(t.resolution?.at??""))}var wd=["jan","fev","mar","abr","mai","jun","jul","ago","set","out","nov","dez"];function ws(e,t){return new Date(Date.UTC(e,t+1,0)).getUTCDate()}function Cs(e){let[t,n]=e.split("-"),o=Number(t),s=Number(n);if(!(!Number.isFinite(o)||!Number.isFinite(s)))return {year:o,monthIndex:s-1}}function Ps(e){if(e===void 0)return;let t=new Date(e);return Number.isNaN(t.getTime())?void 0:t}function Cd(e,t,n){let o=Cs(e);if(o===void 0)return 1;let{year:s,monthIndex:r}=o,i=ws(s,r),c=Date.UTC(s,r,1),a=Date.UTC(s,r,i),u=t.getTime()>c?Math.max(t.getUTCDate(),1):1,d=n.getTime()<a?n.getUTCDate():i;return Math.max(d-u+1,1)}function As(e,t){let n=new Map,o,s;for(let d of e.sessions){let l=Ps(d.startedAt);if(l!==void 0){let p=Ps(d.endedAt)??l;(o===void 0||l<o)&&(o=l),(s===void 0||p>s)&&(s=p);}for(let[p,g]of Object.entries(d.byMonth)){let h=n.get(p)??{usd:0,tokens:0,turns:0,sessions:0};h.sessions+=1;for(let[m,f]of Object.entries(g)){let y={input:f.inputTokens,output:f.outputTokens,cacheRead:f.cacheRead,cacheCreation:f.cacheCreation};h.usd+=N(t,m,y),h.tokens+=f.inputTokens+f.outputTokens+f.cacheRead+f.cacheCreation,h.turns+=f.turns;}n.set(p,h);}}if(n.size===0||o===void 0||s===void 0)return;let r=[...n.keys()].sort(),i=r.slice(-6),c=i.map(d=>{let l=n.get(d)??{usd:0,tokens:0,turns:0,sessions:0},p=Cs(d),g=p===void 0?30:ws(p.year,p.monthIndex),h=Cd(d,o,s);return {month:d,label:p===void 0?d:wd[p.monthIndex]??d,usd:At(l.usd),tokens:l.tokens,turns:l.turns,sessions:l.sessions,elapsedDays:h,daysInMonth:g,partial:h<g,usdPerDay:At(l.usd/h)}}),a={months:c,totalUsd:At(c.reduce((d,l)=>d+l.usd,0)),totalTokens:c.reduce((d,l)=>d+l.tokens,0),totalTurns:c.reduce((d,l)=>d+l.turns,0),observedDays:Math.max(Math.round((s.getTime()-o.getTime())/864e5)+1,1),monthsOmitted:r.length-i.length,syntheticSessionsExcluded:e.syntheticSessions},u=Ad(c);return u!==void 0&&(a.paceRatio=u.ratio,a.paceAgainst=u.against),a}function Ad(e){let t=e[e.length-1];if(!(t===void 0||!t.partial))for(let n=e.length-2;n>=0;n--){let o=e[n];if(!(o===void 0||o.partial||o.usdPerDay<=0))return {ratio:At(t.usdPerDay/o.usdPerDay,1),against:o.label}}}function At(e,t=2){let n=10**t;return Math.round(e*n)/n}function Es(e,t,n,o=false,s){let r=rs(e),i=e.filter(y=>y.resolution!==void 0),a=["fixed","variable","model","meta"].map(y=>{let S=r.filter(b=>b.group===y);return {group:y,count:S.length,tokensPerMonth:fe(S,b=>b.impact.tokensPerMonth),usdPerMonth:ge(fe(S,b=>b.impact.usdPerMonth)),tokensPerTurn:fe(S,b=>b.impact.tokensPerTurn??0)}}),u=s?As(s,t):void 0,d=r.filter(y=>y.group==="fixed"),l=r.filter(y=>y.impact.confidence==="measured"),p=fe(r,y=>y.impact.tokensPerMonth),g=fe(l,y=>y.impact.tokensPerMonth),h=fe(d,y=>y.impact.tokensPerTurn??0),m=ge(fe(r,y=>y.impact.usdPerMonth)),f=u&&u.observedDays>0?u.totalUsd/u.observedDays*30:void 0;return {totalFindings:e.length,countableFindings:r.length,byGroup:a,totalTokensPerMonth:p,totalUsdPerMonth:m,fixedTokensPerTurn:h,fixedContextWindowPct:ge(t.contextWindow>0?h/t.contextWindow*100:0,2),shareOfTotalPct:ge(t.totalTokensPerMonth>0?p/t.totalTokensPerMonth*100:0,2),fixableTokensPerMonth:fe(r.filter(y=>y.fixSpec),y=>y.impact.tokensPerMonth),measuredTokensPerMonth:g,estimatedTokensPerMonth:p-g,billing:{mode:o?"metered":"subscription",primaryModel:t.primaryModel,contextWindow:t.contextWindow,turnsPerMonth:t.turnsPerMonth,sessionsPerMonth:t.sessionsPerMonth,totalTokensPerMonth:t.totalTokensPerMonth},baseline:n?Ed(n,h,t):void 0,spendHistory:u,wasteSharePctOfSpend:f!==void 0&&f>0?ge(m/f*100,1):void 0,fixableFindings:r.filter(y=>y.fixSpec).length,resolvedFindings:i.length,resolvedUsdPerMonth:ge(fe(i,y=>y.impact.usdPerMonth)),bySeverity:{high:r.filter(y=>y.severity==="high").length,medium:r.filter(y=>y.severity==="medium").length,low:r.filter(y=>y.severity==="low").length}}}function Ed(e,t,n){let o=e.derived;if(!o)return;let s=e.project?.promptTokens??e.full?.promptTokens??e.localOnly?.promptTokens??0;return {measuredPromptTokens:s,floorTokens:o.floorTokens,localConfigTokens:o.localConfigTokens,connectorTokens:o.connectorTokens,projectTokens:o.projectTokens,promptWindowPct:ge(n.contextWindow>0?s/n.contextWindow*100:0,1),usdPerMonth:ge(dt(n,s)),claimedAvoidableRatio:s>0?ge(t/s,4):0}}function fe(e,t){return e.reduce((n,o)=>n+t(o),0)}function ge(e,t=2){let n=10**t;return Math.round(e*n)/n}function Ms(e,t,n,o=new Date){return {schemaVersion:1,generatedAt:o.toISOString(),summary:n,findings:t,meta:{scannedFiles:e.transcripts.scannedFiles,cachedFiles:e.transcripts.cachedFiles,scanMs:e.transcripts.scanMs,totalBytes:e.transcripts.totalBytes,sessionsAnalyzed:e.transcripts.sessions.length,primaryModel:e.pricing.primaryModel,turnsPerMonth:e.pricing.turnsPerMonth,sessionsPerMonth:e.pricing.sessionsPerMonth,baselineAvailable:e.baseline!==void 0}}}var Rs=randomUUID(),Ne;async function Rd(){if(Ne!==void 0)return Ne;if(!process.env.OTEL_EXPORTER_OTLP_ENDPOINT)return;let{MeterProvider:t,PeriodicExportingMetricReader:n}=await import('@opentelemetry/sdk-metrics'),{OTLPMetricExporter:o}=await import('@opentelemetry/exporter-metrics-otlp-http'),{metrics:s}=await import('@opentelemetry/api'),{resourceFromAttributes:r}=await import('@opentelemetry/resources'),{ATTR_SERVICE_NAME:i}=await import('@opentelemetry/semantic-conventions'),c={},a=process.env.FLOW_API_KEY;a&&(c["x-flow-api-key"]=a);let u=process.env.FLOW_USER_EMAIL;u&&(c["x-flow-user"]=u);let d=new o(Object.keys(c).length>0?{headers:c}:void 0),l=new t({resource:r({[i]:"ctxa",provider:"ctxa","session.id":Rs}),readers:[new n({exporter:d,exportIntervalMillis:2147483647})]});s.setGlobalMeterProvider(l);let p=s.getMeter("ctxa");return Ne={outcome:p.createCounter("ctxa.finding.outcome",{description:"Outcome of each fixable finding per ctxa execution"}),tokensPerMonth:p.createGauge("ctxa.finding.savings.tokens_per_month",{description:"Projected token savings per month for each finding outcome",unit:"token"}),usdPerMonth:p.createGauge("ctxa.finding.savings.usd_per_month",{description:"Projected USD equivalent savings per month for each finding outcome",unit:"USD"}),tokensPerTurn:p.createGauge("ctxa.finding.savings.tokens_per_turn",{description:"Projected fixed-cost token savings per turn for each finding outcome",unit:"token"}),sdk:l},Ne}async function Ee(e,t){let n=await Rd();if(!n)return;let o={status:t,finding_id:e.id,analyzer:e.analyzer,group:e.group,severity:e.severity,"correlation.id":Rs};e.fixSpec&&(o.fix_kind=e.fixSpec.kind),n.outcome.add(1,o),n.tokensPerMonth.record(e.impact.tokensPerMonth,o),n.usdPerMonth.record(e.impact.usdPerMonth,o),n.tokensPerTurn.record(e.impact.tokensPerTurn??0,o);}async function Et(){Ne&&await Ne.sdk.shutdown();}function Fs(e=homedir()){let t=process.env.XDG_CACHE_HOME??join(e,".cache");return join(t,"ctxa","snapshots.jsonl")}function js(e,t,n,o){let s=e.claudemd.files.find(r=>r.scope==="global");return {takenAt:(o?.now??new Date).toISOString(),label:o?.label,baseline:e.baseline,claimedFixedTokensPerTurn:n.fixedTokensPerTurn,totalTokensPerMonth:n.totalTokensPerMonth,totalUsdPerMonth:n.totalUsdPerMonth,findingIds:t.map(r=>r.id),inventory:{mcpServers:e.config.mcpServers.filter(r=>r.scope==="user").length,enabledPlugins:Object.values(e.settings.enabledPlugins).filter(Boolean).length,skills:e.inventory.artifacts.filter(r=>r.kind==="skill").length,agents:e.inventory.artifacts.filter(r=>r.kind==="agent").length,claudeMdGlobalBytes:(s?.bytes??0)+(s?.importedBytes??0),totalDescriptionBytes:e.inventory.artifacts.reduce((r,i)=>r+i.descriptionBytes,0)}}}async function _s(e,t=homedir()){let n=Fs(t);return await mkdir(dirname(n),{recursive:true}),await appendFile(n,`${JSON.stringify(e)}
|
|
50
|
-
`,"utf8"),n}async function $s(e=homedir()){try{let t=await readFile(Fs(e),"utf8"),n=[];for(let o of t.split(`
|
|
51
|
-
`))if(o.trim())try{n.push(JSON.parse(o));}catch{}return n}catch{return []}}function Is(e,t){let n=Ds(e.baseline),o=Ds(t.baseline),s=new Set(e.findingIds),r=new Set(t.findingIds),i={};for(let c of Object.keys(t.inventory)){let a=t.inventory[c]-e.inventory[c];a!==0&&(i[c]=a);}return {from:e.takenAt,to:t.takenAt,promptTokensDelta:n!==void 0&&o!==void 0?o-n:void 0,claimedFixedTokensDelta:t.claimedFixedTokensPerTurn-e.claimedFixedTokensPerTurn,tokensPerMonthDelta:(t.totalTokensPerMonth??0)-(e.totalTokensPerMonth??0),usdPerMonthDelta:Math.round((t.totalUsdPerMonth-e.totalUsdPerMonth)*100)/100,resolvedFindings:[...s].filter(c=>!r.has(c)),newFindings:[...r].filter(c=>!s.has(c)),inventoryDelta:i}}function Ds(e){return e?.project?.promptTokens??e?.full?.promptTokens??e?.localOnly?.promptTokens}var Ns=["CLAUDE_CODE_ENABLE_TELEMETRY","OTEL_EXPORTER_OTLP_PROTOCOL","OTEL_METRICS_EXPORTER","OTEL_LOGS_EXPORTER","OTEL_LOG_TOOL_DETAILS","OTEL_LOG_USER_PROMPTS","OTEL_EXPORTER_OTLP_ENDPOINT","FLOW_API_KEY","FLOW_USER_EMAIL"];function Ls(e){let t=k(e)?e.env:void 0;return new Set(k(t)?Object.keys(t):[])}function Bs(e,t){let n=k(e)?e.env:void 0;if(!k(n)||!(t in n))return;let o=n[t];return typeof o=="string"?o:void 0}async function Us(e){let[t,n]=await Promise.all([K(q(e)),K(He(e))]),o=new Set([...Ls(t),...Ls(n)]),s=[],r=[];for(let i of Ns)(o.has(i)||i in process.env?r:s).push(i);return {missing:s,found:r}}async function zs(e){let[t,n]=await Promise.all([K(q(e)),K(He(e))]);for(let o of Ns){if(o in process.env)continue;let s=Bs(n,o)??Bs(t,o);s!==void 0&&(process.env[o]=s);}}var pn=new Command;pn.name("flow").description("CLI de produtividade \u2014 recursos organizados por subcomando").version("0.1.0");var Ot=pn.command("ctxa").description("Analisa o hist\xF3rico e a configura\xE7\xE3o do Claude Code e sugere economias de token");async function mn(e,t){let n=e.only?e.only.split(",").map(a=>a.trim()):void 0,o=await ko({useCache:e.cache!==false,skipTranscripts:e.fast===true,probeMcp:e.probeMcp===true,includeSynthetic:e.includeSynthetic===true,onProgress:t?void 0:a=>process.stderr.write(v.dim(` ${a}...
|
|
52
|
-
`))}),s=await os({data:o,now:new Date},n?{groups:n}:void 0),r=await Ts(ss(s));for(let a of is(r))process.stderr.write(v.yellow(`aviso: ${a}
|
|
53
|
-
`));let i=Object.values(o.stats.modelUsage).some(a=>a.costUSD>0),c=Es(r,o.pricing,o.baseline,i,o.transcripts);return {data:o,findings:r,summary:c}}Ot.command("scan",{isDefault:true}).description("Escaneia e lista as oportunidades de economia").option("--json","Emite JSON em vez do relat\xF3rio de terminal").option("--only <groups>","Filtra por grupo: fixed,variable,model,meta").option("--no-cache","Ignora o cache e reprocessa todos os transcripts").option("--fast","Pula a varredura de transcripts (s\xF3 analisa configura\xE7\xE3o)").option("--limit <n>","Quantos findings exibir no terminal","15").option("--no-interactive","For\xE7a o relat\xF3rio textual mesmo em terminal interativo").option("--probe-mcp","Sobe cada servidor MCP stdio para contar suas tools exatamente (executa os bin\xE1rios)").option("--include-synthetic","Inclui sess\xF5es de harness automatizado, exclu\xEDdas por padr\xE3o da an\xE1lise").option("--show-fixed","Lista tamb\xE9m o que j\xE1 foi corrigido ou dispensado").action(async e=>{let{data:t,findings:n,summary:o}=await mn(e,e.json===true);if(e.json){process.stdout.write(`${JSON.stringify(Ms(t,n,o),null,2)}
|
|
54
|
-
`);return}let s={organic:t.transcripts.organicSessions,synthetic:t.transcripts.syntheticSessions};if(e.interactive!==false&&process.stdout.isTTY&&process.stdin.isTTY){Hs(o,s),await Ud(n);return}qd(n,o,Number(e.limit??15),s,e.showFixed===true);});Ot.command("baseline").description("Mede o tamanho real do system prompt executando o Claude Code headless").option("--yes","N\xE3o pede confirma\xE7\xE3o (a medi\xE7\xE3o consome cota da API)").option("--model <model>","Modelo usado na medi\xE7\xE3o","haiku").action(async e=>{if(!e.yes){process.stderr.write(v.yellow(`A medi\xE7\xE3o executa o Claude Code at\xE9 4 vezes e consome cota real da API
|
|
55
|
-
(tipicamente < US$ 0,50 no total, usando Haiku).
|
|
56
|
-
Rode novamente com --yes para confirmar.
|
|
57
|
-
`)),process.exitCode=1;return}let t=await yo({cwd:process.cwd(),model:e.model??"haiku",onStep:n=>process.stderr.write(v.dim(` medindo ${n}...
|
|
58
|
-
`))});await bo(t),Jd(t);});Ot.command("fix <id>").description("Aplica (ou reverte) a corre\xE7\xE3o de um finding").option("--dry-run","Mostra o que mudaria sem escrever nada").option("--revert","Desfaz uma corre\xE7\xE3o aplicada anteriormente").action(async(e,t)=>{if(t.revert){let i=await rn(e);if(!i){let c=await vt();if(process.stderr.write(v.red(`Nenhuma corre\xE7\xE3o aplicada encontrada para "${e}".
|
|
59
|
-
`)),c.length>0){process.stderr.write(v.dim(`
|
|
60
|
-
Corre\xE7\xF5es aplicadas dispon\xEDveis para reverter:
|
|
61
|
-
`));for(let a of c)process.stderr.write(v.dim(` ${a.fixId} (${a.appliedAt})
|
|
62
|
-
`));}else process.stderr.write(v.dim(`Nenhuma corre\xE7\xE3o foi aplicada ainda.
|
|
63
|
-
`));process.exitCode=1;return}await nn(i),await on(e),process.stdout.write(v.green(`Revertido: ${e}
|
|
64
|
-
`)),process.stdout.write(v.dim(`Restaurado de ${i.backup.dir}
|
|
65
|
-
`));return}let{findings:n}=await mn({},true),o=n.find(i=>i.id===e);if(!o){process.stderr.write(v.red(`Finding "${e}" n\xE3o encontrado. Rode "flow ctxa scan".
|
|
66
|
-
`)),process.exitCode=1;return}if(!o.fixSpec){process.stderr.write(v.yellow(`"${e}" \xE9 informativo e n\xE3o tem corre\xE7\xE3o autom\xE1tica.
|
|
67
|
-
`)),process.exitCode=1;return}let s=Be(o.fixSpec,{findingId:o.id}),r=await s.preview();Ws(s.describe(),r);try{let i=await s.apply({dryRun:t.dryRun===!0});if(!t.dryRun){await Ee(o,"success");for(let c of n)c.fixSpec&&c.id!==o.id&&await Ee(c,"skipped");}await Et(),process.stdout.write(t.dryRun?v.dim(`
|
|
68
|
-
(dry-run: nada foi escrito)
|
|
69
|
-
`):v.green(`
|
|
70
|
-
Aplicado. Backup em ${i.backup.dir}
|
|
71
|
-
`)+v.dim(`Reverter com: flow ctxa fix ${e} --revert
|
|
72
|
-
`));}catch(i){throw await Ee(o,"error"),await Et(),i}});Ot.command("snapshot").description("Grava o estado atual para comparar depois de aplicar corre\xE7\xF5es").option("--label <label>","R\xF3tulo do snapshot").option("--compare","Compara com o snapshot anterior em vez de gravar um novo").action(async e=>{let{data:t,findings:n,summary:o}=await mn({},true),s=js(t,n,o,{label:e.label});if(e.compare){let c=(await $s()).at(-1);if(!c){process.stderr.write(v.yellow(`Nenhum snapshot anterior. Rode "flow ctxa snapshot".
|
|
73
|
-
`)),process.exitCode=1;return}Gd(Is(c,s));return}let r=await _s(s);process.stdout.write(v.green(`Snapshot gravado em ${r}
|
|
74
|
-
`));});function Bd(e){let t=e.impact,o=`${t.confidence==="measured"?" ":"~"}${Ye(t.tokensPerMonth)}`.padStart(8),s=(t.tokensPerTurn!==void 0&&t.tokensPerTurn>0?`${t.tokensPerTurn.toLocaleString("pt-BR")}/turno`:"").padStart(13),r=`${Rt(t.usdPerMonth)}/m\xEAs`.padStart(14);return `${qs(e)} ${v.bold(o)} ${v.dim(s)} ${v.green(r)} ${e.title}`}function Nd(e){let t=e.impact,n=e.id;return t.contextWindowPct!==void 0&&t.contextWindowPct>0&&(n+=` \xB7 ${Ue(t.contextWindowPct)} da janela`),e.fixSpec?n+=`
|
|
75
|
-
fix: flow ctxa fix ${e.id}`:e.guidance&&(n+=`
|
|
76
|
-
${e.guidance}`),n}async function Ud(e){let t=un(e).filter(o=>o.subsumedBy===void 0),n=t.filter(o=>o.fixSpec!==void 0);if(n.length!==0)try{let o=await checkbox({message:'Selecione o que corrigir ("espa\xE7o" marca, "a" marca todos, "enter" confirma)',pageSize:15,loop:!1,choices:t.map(d=>({name:Bd(d),value:d.id,description:Nd(d),disabled:d.fixSpec?!1:"sem corre\xE7\xE3o autom\xE1tica"}))});if(o.length===0)return;let s=n.filter(d=>o.includes(d.id)),r=[];for(let d of s)if(d.fixSpec)try{let l=await Be(d.fixSpec,{findingId:d.id}).preview();r.push({finding:d,diff:l});}catch(l){r.push({finding:d,diff:{hunks:[],summary:`falha ao gerar preview: ${l instanceof Error?l.message:String(l)}`}});}for(let{finding:d,diff:l}of r)Ws(d.fixSpec?.describe??d.title,l);if(!await confirm({message:`Aplicar ${r.length} corre\xE7\xE3o(\xF5es)? Backup autom\xE1tico antes de cada escrita.`,default:!1}))return;let c=new Set,a=new Set;for(let{finding:d}of r)if(d.fixSpec)try{let l=await Be(d.fixSpec,{findingId:d.id}).apply();c.add(d.id),await Ee(d,"success"),process.stdout.write(v.green(` \u2713 ${d.id}`)+v.dim(` \u2014 backup em ${l.backup.dir} \xB7 reverter: flow ctxa fix ${d.id} --revert
|
|
77
|
-
`));}catch(l){a.add(d.id),await Ee(d,"error"),process.stdout.write(v.red(` \u2717 ${d.id} \u2014 ${l instanceof Error?l.message:String(l)}
|
|
78
|
-
`));}let u=n.filter(d=>!c.has(d.id)&&!a.has(d.id));for(let d of u)await Ee(d,"skipped");await Et(),process.stdout.write(`
|
|
79
|
-
`);}catch(o){if(o instanceof ExitPromptError){process.stdout.write(`
|
|
80
|
-
`);return}throw o}}function Rt(e){return `US$ ${e.toFixed(2)}`}function Ye(e){return e>=1e6?`${(e/1e6).toFixed(1).replace(".",",")}M`:e>=1e3?`${(e/1e3).toFixed(0)}k`:String(e)}function Ue(e){return `${e.toFixed(2).replace(".",",")}%`}function zd(e,t=96){let n=e.search(/\.\s/),o=n>0?e.slice(0,n+1):e;return o.length>t?`${o.slice(0,t-1).trimEnd()}\u2026`:o}function qs(e){let t=e.severity.padEnd(6);return e.severity==="high"?v.red(t):e.severity==="medium"?v.yellow(t):v.dim(t)}function qd(e,t,n,o,s=false){Hs(t,o),Hd(e,n,s);}function Hs(e,t){let n=process.stdout;if(n.write(`
|
|
81
|
-
${v.bold("Desperd\xEDcio identificado")}
|
|
82
|
-
`),n.write(` ${v.bold(Ye(e.totalTokensPerMonth))} tokens/m\xEAs afetados em ${e.countableFindings} itens`+v.dim(` (${Ue(e.shareOfTotalPct)} do seu consumo total)
|
|
83
|
-
`)),n.write(` ${v.bold(e.fixedTokensPerTurn.toLocaleString("pt-BR"))} tokens em ${v.bold("todo turno")}`+v.dim(` \u2014 ${Ue(e.fixedContextWindowPct)} da janela de contexto
|
|
84
|
-
`)),n.write(v.dim(` ${Rt(e.totalUsdPerMonth)}/m\xEAs equivalente \xB7 ${Ye(e.measuredTokensPerMonth)} medido \xB7 ${Ye(e.estimatedTokensPerMonth)} estimado
|
|
85
|
-
`)),t&&t.synthetic>0){let o=t.organic+t.synthetic,s=o>0?t.synthetic/o*100:0;n.write(v.dim(` Analisadas ${t.organic.toLocaleString("pt-BR")} sess\xF5es de trabalho; ${t.synthetic.toLocaleString("pt-BR")} de harness automatizado (${Ue(s)}) foram exclu\xEDdas \u2014 use --include-synthetic para inclu\xED-las.
|
|
86
|
-
`));}if(e.baseline){let o=e.baseline;n.write(`
|
|
87
|
-
${v.bold("System prompt medido")}
|
|
88
|
-
`),n.write(` ${v.bold(o.measuredPromptTokens.toLocaleString("pt-BR"))} tokens em todo turno`+v.dim(` \u2014 ${Ue(o.promptWindowPct)} da janela consumidos antes de voc\xEA digitar
|
|
89
|
-
`)),n.write(v.dim(` piso ${o.floorTokens.toLocaleString("pt-BR")} \xB7 config ${o.localConfigTokens.toLocaleString("pt-BR")} \xB7 conectores ${o.connectorTokens.toLocaleString("pt-BR")} \xB7 projeto ${o.projectTokens.toLocaleString("pt-BR")}
|
|
90
|
-
`)),o.claimedAvoidableRatio>1&&n.write(v.yellow(` aviso: os analisadores alegam evitar ${(o.claimedAvoidableRatio*100).toFixed(0)}% do prompt medido \u2014 h\xE1 superestimativa em algum deles
|
|
91
|
-
`));}else n.write(v.dim(`
|
|
92
|
-
(rode "flow ctxa baseline --yes" para medir o system prompt real)
|
|
93
|
-
`));}function Hd(e,t,n=false){let o=process.stdout,s=un(e),r=s.filter(d=>d.subsumedBy===void 0).slice(0,t),i=r.filter(d=>d.analyzer.startsWith("mcp.")&&d.impact.confidence==="estimated");i.length>0&&o.write(v.yellow(`
|
|
94
|
-
${i.length} finding(s) de MCP acima usam estimativa por heur\xEDstica.
|
|
95
|
-
`)+v.dim(` Rode com --probe-mcp para contar as tools de verdade: a diferen\xE7a chegou a 10x
|
|
96
|
-
em servidores pequenos, e a estimativa erra para cima.
|
|
97
|
-
`)),o.write(`
|
|
98
|
-
${v.bold("Principais oportunidades")}
|
|
99
|
-
`);for(let d of r){let l=d.impact,p=l.confidence==="measured"?" ":v.dim("~"),g=l.tokensPerTurn!==void 0?v.dim(` ${l.tokensPerTurn.toLocaleString("pt-BR")}/turno`):"";o.write(`
|
|
100
|
-
${qs(d)} ${p}${v.bold(Ye(l.tokensPerMonth).padStart(7))}/m\xEAs${g} ${d.title}
|
|
101
|
-
`),o.write(v.dim(` ${d.id} \xB7 ${Rt(l.usdPerMonth)} equiv.`+(l.contextWindowPct!==void 0&&l.contextWindowPct>0?` \xB7 ${Ue(l.contextWindowPct)} da janela`:"")+`
|
|
102
|
-
`)),d.fixSpec?o.write(v.cyan(` fix: flow ctxa fix ${d.id}
|
|
103
|
-
`)):d.guidance&&o.write(v.yellow(` \u2192 ${zd(d.guidance)}
|
|
104
|
-
`));}let c=s.filter(d=>d.subsumedBy===void 0).length-r.length;c>0&&o.write(v.dim(`
|
|
105
|
-
... e mais ${c} (use --limit ou --json)
|
|
106
|
-
`));let a=e.filter(d=>d.subsumedBy!==void 0).length;a>0&&o.write(v.dim(`
|
|
107
|
-
${a} finding(s) omitidos por j\xE1 estarem cobertos por outra corre\xE7\xE3o mais ampla.
|
|
108
|
-
`));let u=xs(e);if(u.length>0)if(n){o.write(`
|
|
109
|
-
${v.bold("J\xE1 corrigidos")}
|
|
110
|
-
`);for(let l of u){let p=l.resolution?.state==="dismissed"?"dispensado":"corrigido";o.write(`
|
|
111
|
-
${v.green("\u2713")} ${v.dim(Wd(l.resolution?.at))} ${p.padEnd(10)} ${l.title}
|
|
112
|
-
`),o.write(v.dim(` ${l.id}
|
|
113
|
-
`));}let d=u.reduce((l,p)=>l+p.impact.usdPerMonth,0);o.write(v.dim(`
|
|
114
|
-
Economia acumulada: ${Rt(d)}/m\xEAs
|
|
115
|
-
`));}else o.write(v.dim(`
|
|
116
|
-
${u.length} j\xE1 corrigido(s) \xB7 --show-fixed para ver
|
|
117
|
-
`));o.write(`
|
|
118
|
-
`);}function Ws(e,t){process.stdout.write(`${v.bold(e)}
|
|
119
|
-
${v.dim(t.summary)}
|
|
120
|
-
|
|
121
|
-
`);for(let n of t.hunks){process.stdout.write(`${v.cyan(n.file)}
|
|
122
|
-
`);for(let o of n.before.split(`
|
|
123
|
-
`))process.stdout.write(v.red(` - ${o}
|
|
124
|
-
`));for(let o of n.after.split(`
|
|
125
|
-
`))process.stdout.write(v.green(` + ${o}
|
|
126
|
-
`));}process.stdout.write(`
|
|
127
|
-
`);}function Wd(e){if(e===void 0)return "\u2014";let t=new Date(e);return Number.isNaN(t.getTime())?"\u2014":`${String(t.getDate()).padStart(2,"0")}/${String(t.getMonth()+1).padStart(2,"0")}`}function Jd(e){let t=process.stdout,n=[["piso (--bare)",e.bare?.promptTokens],["+ config local",e.localOnly?.promptTokens],["+ conectores claude.ai",e.full?.promptTokens],["+ CLAUDE.md do projeto",e.project?.promptTokens]];t.write(`
|
|
128
|
-
${v.bold("System prompt medido")}
|
|
129
|
-
`);for(let[s,r]of n){if(r===void 0){t.write(` ${s.padEnd(26)} ${v.dim("n\xE3o medido")}
|
|
130
|
-
`);continue}t.write(` ${s.padEnd(26)} ${v.bold(r.toLocaleString("pt-BR").padStart(9))} tokens
|
|
131
|
-
`);}let o=e.derived;o&&(t.write(`
|
|
132
|
-
${v.bold("Decomposi\xE7\xE3o")}
|
|
133
|
-
`),t.write(` Claude Code base ${o.floorTokens.toLocaleString("pt-BR").padStart(9)}
|
|
134
|
-
`),t.write(` Sua configura\xE7\xE3o ${o.localConfigTokens.toLocaleString("pt-BR").padStart(9)}
|
|
135
|
-
`),t.write(` Conectores claude.ai ${o.connectorTokens.toLocaleString("pt-BR").padStart(9)}
|
|
136
|
-
`),t.write(` CLAUDE.md do projeto ${o.projectTokens.toLocaleString("pt-BR").padStart(9)}
|
|
137
|
-
`)),t.write(`
|
|
138
|
-
`);}function Gd(e){let t=process.stdout;if(t.write(`
|
|
139
|
-
${v.bold("Compara\xE7\xE3o de snapshots")}
|
|
140
|
-
`),t.write(v.dim(` ${e.from} \u2192 ${e.to}
|
|
141
|
-
|
|
142
|
-
`)),e.promptTokensDelta!==void 0){let n=e.promptTokensDelta<=0?v.green:v.red;t.write(` System prompt medido: ${n(Mt(e.promptTokensDelta))} tokens
|
|
143
|
-
`);let o=-e.claimedFixedTokensDelta;o!==0&&t.write(v.dim(` previsto pelos findings: ${Mt(o)} tokens \u2014 ${Math.abs(e.promptTokensDelta-o)<=Math.abs(o)*.25?"confere":"divergiu"}
|
|
144
|
-
`));}else t.write(v.dim(` System prompt: sem baseline nos dois snapshots para comparar
|
|
145
|
-
`));if(t.write(` Desperd\xEDcio: ${Mt(e.tokensPerMonthDelta)} tokens/m\xEAs
|
|
146
|
-
`),t.write(v.dim(` Equivalente: ${Mt(e.usdPerMonthDelta)} US$/m\xEAs
|
|
147
|
-
`)),e.resolvedFindings.length>0){t.write(v.green(`
|
|
148
|
-
${e.resolvedFindings.length} finding(s) resolvidos
|
|
149
|
-
`));for(let n of e.resolvedFindings.slice(0,10))t.write(v.dim(` ${n}
|
|
150
|
-
`));}if(e.newFindings.length>0){t.write(v.yellow(`
|
|
151
|
-
${e.newFindings.length} finding(s) novos
|
|
152
|
-
`));for(let n of e.newFindings.slice(0,10))t.write(v.dim(` ${n}
|
|
153
|
-
`));}t.write(`
|
|
154
|
-
`);}function Mt(e){return e>0?`+${e.toLocaleString("pt-BR")}`:e.toLocaleString("pt-BR")}async function Vd(){let{missing:e}=await Us();e.length!==0&&process.stderr.write(v.yellow(`Aviso: configura\xE7\xF5es de telemetria n\xE3o encontradas:
|
|
155
|
-
`)+e.map(t=>v.yellow(` - ${t}
|
|
156
|
-
`)).join("")+v.dim(`Fa\xE7a o setup utilizando o flow cli.
|
|
157
|
-
|
|
158
|
-
`));}await zs();await Vd();pn.parseAsync(process.argv).catch(e=>{process.stderr.write(v.red(`
|
|
159
|
-
erro: ${e instanceof Error?e.message:String(e)}
|
|
160
|
-
`)),process.exitCode=1;});
|