【免费下载链接】codeburnFree, local tool to track AI coding token usage and cost across 37 tools and agents (Claude Code, Cursor, Codex, Gemini and more), by model, project, and task. npx codeburn项目地址https://gitcode.com/gh_mirrors/co/codeburn点击查看免费下载CodeBurn 是一个免费的本地工具用于跨 37 个 AI 编码工具与 AgentClaude Code、Cursor、Codex、Gemini 等追踪 Token 用量与成本。本文聚焦 CodeBurn 对 Pi Agent CLI及其姊妹工具 OMP的集成实现它会读取 Pi 存放在~/.pi/agent/sessions/下的 JSONL 会话转录逐条解析出输入/输出 Token、缓存读写、模型、工具调用与成本进而进入统一的按模型、按项目、按任务的聚合报表。读完本文你将掌握 Pi 会话数据的目录结构、JSONL 行格式、去重与回退策略、成本计算路径以及“SKILL.md 读取被识别为技能加载而非普通读取”这一关键分类逻辑的来龙去脉同时了解如何通过源码与测试验证这些行为。集成总览一个解析器两个 ProviderPi 的集成在 CodeBurn 中是一个急加载eagerProvider它在 src/providers/index.ts 中随模块加载即被注册coreProviders数组包含pi与omp而不是像 Cursor、Warp 那样按需动态import()。因此只要安装了 CodeBurnPi/OMP 的发现逻辑每次运行都会参与扫描。更关键的一点是Pi 与 OMP 共用同一份解析代码。src/providers/pi.ts同时导出两个 ProvidercreatePiProvider()→ provider 名为pi显示名Pi数据目录为~/.pi/agent/sessionscreateOmpProvider()→ provider 名为omp显示名OMP数据目录为~/.omp/agent/sessions。两者唯一的区别就是名称、显示名与发现目录见 src/providers/pi.ts 中的getPiSessionsDir/getOmpSessionsDir与createPiProvider/createOmpProvider共享同一个createParser函数与discoverSessionsInDir发现逻辑。这就是 docs/providers/omp.md 中强调“OMP 和 Pi 共享同一个createParser未来若格式分叉不要在文件里复制粘贴解析器而应给createParser加判别参数分支”的原因。数据来源从哪个目录读取Pi 会将会话转录写入~/.pi/agent/sessions/OMP 对应~/.omp/agent/sessions/。CodeBurn 的发现逻辑在 src/providers/pi.ts 的discoverSessionsInDir中实现列出 sessions 目录下的所有一级子目录——Pi 按项目目录组织会话每个子目录代表一个项目目录名形如--Users-test-myproject--在每个项目子目录内扫描以.jsonl结尾的文件作为会话转录仅对 OMP 额外支持嵌套目录OMP 会把每个“crewmate”子 Agent的转录放在父会话目录下的子目录中此时以.jsonl文件名为 Agent 名agentName并携带会话头中的时间戳作为agentStartedAt会话归属的项目名取自会话头部的cwd绝对路径的 basename同时把绝对cwd保留在sourcePath上供后续跨 Provider 合并时以真实路径而非仅 basename作为键对应 issue #1260 的修复。Provider接口还要求实现probeRoots()返回[{ path: dir, label: sessions }]让codeburn doctor能展示并检查探测路径是否存在从而区分“Pi 未安装/无会话”与“目录配置错误”。目录不存在或为空时发现逻辑安全返回空数组不会抛错测试returns empty for non-existent directory覆盖了这一点。有界头部扫描MAX_HEADER_LINES_SCANNED发现阶段只读取每个转录的开头若干行来确认它是否真的是会话文件而不是整个文件OMP 会在type: session记录之前写入一条固定宽度的type: title元数据行issue #845且两个 Provider 都可能在头部夹杂空行因此readSessionEntry最多扫描前 20 行MAX_HEADER_LINES_SCANNED 20src/providers/pi.ts跳过空行与无法 JSON 解析的行直到找到type session的记录扫描是有界而非退化成全文件读取测试does not discover a session record beyond the bounded leading-line scan25 行垃圾后才是 session 头证明第 26 行的 session 不会被发现测试does not read an unreasonable amount of a large message-only file用约 20MB 的无 session 文件验证扫描在毫秒级内结束阈值 500ms保证即使 Pi 目录里堆满超大且无关的转录发现阶段依然廉价只有包含 session 头的文件才会进入解析阶段message-only 文件如被截断的写盘会被直接排除。存储格式逐行 JSONLPi/OMP 的会话转录是JSONL每行一个独立 JSON 对象。解析器按行JSON.parse无法解析的行直接跳过健壮性测试覆盖了“头部 JSON 损坏不抛异常”的情况。从 src/providers/pi.ts 的类型定义与解析循环看行记录主要有三类type作用解析器行为session会话头记录会话 IDentry.id、起始时间戳、cwd用于项目归属与projectPath/workingDirectorymodel_change会话级模型切换OMP 特有更新resolvedModel作为后续消息模型的兜底message用户/助手消息用户消息暂存为待配对文本助手消息携带usage时产出解析调用会话文件可能达到数 GB如压缩后的超大会话因此 src/fs-utils.ts 的readSessionFile设置了 128MB 的整读上限MAX_SESSION_FILE_BYTES超限走readSessionLines流式逐行读取上限 4GBMAX_STREAM_SESSION_FILE_BYTES。被跳过的超大文件会通过notice()明确输出到 stderr避免静默漏算用量。message 记录的字段助手消息的关键字段测试夹具assistantMessage完整展示了真实形状{ type: message, id: msg-asst-1, timestamp: 2026-04-14T10:00:30.000Z, message: { role: assistant, content: [{type: toolCall, id: call-bash, name: bash, arguments: {command: git status}}], api: openai-codex-responses, provider: openai-codex, model: gpt-5.4, responseId: resp-001, usage: { input: 1000, output: 200, cacheRead: 0, cacheWrite: 0, totalTokens: 1200, cost: {input: 0.0025, output: 0.003, cacheRead: 0, cacheWrite: 0, total: 0.0055} }, stopReason: stop } }其中usage.input/usage.output/usage.cacheRead/usage.cacheWrite被映射为ParsedProviderCall定义见 src/providers/types.ts的inputTokens、outputTokens、cacheReadInputTokens、cacheCreationInputTokens。content里的toolCall块会被提取为工具名bash工具的arguments.command还会交给extractBashCommandssrc/bash-utils.ts拆出命令首词如git status bun test得到[git, bun]进入 bash 命令统计。用户消息的两种形态用户消息的content既可能是数组也可能是纯字符串issue #441Pi 对某些注入型用户轮次会直接写字符串。修复前content.filter is not a function会中止整个回填并清空趋势/历史数据现在解析器通过normalizeContentBlockssrc/content-utils.ts统一归一化字符串形态也被安全配对为该助手调用的userMessage。用户消息的时间戳优先级为条目级timestamp→message.attribution.timestamp毫秒时间戳转 ISOOMP 用它在同一次会话内跨天切分记录。解析流水线从转录到 ParsedProviderCallcreateSessionParser返回的SessionParser是一个异步生成器产出ParsedProviderCall。核心流程src/providers/pi.ts 的createParser读取整个转录走readSessionFile按行解析维护会话级状态sessionId、resolvedModel来自model_change、sessionTimestamp、sessionCwd绝对路径来自头部cwd或发现阶段的sourcePath、pendingUserMessage与pendingUserTimestamp最近一条用户消息及其时间用于与下一条助手调用配对只处理role assistant且带usage的消息input与output同时为 0 时跳过空调用不计解析模型名见下节、构造去重键、提取工具/skill/bash 命令、计算成本最终yield一条完整调用。产出后pendingUserMessage被清空等待下一条用户消息。测试yields one call per assistant message in a multi-turn session验证了多轮会话下每条助手消息恰好产出一条调用且分别配对各自的用户消息。模型名解析与显示名Pi 每条消息自带message.model如gpt-5.4OMP 则有会话级model_change与可选的消息级model且消息级值可能是去掉 provider 前缀的裸名如gpt-5.6-terravsopenai-codex/gpt-5.6-terra。resolveMessageModel的优先级消息级模型若含/带前缀直接采用否则与会话级resolvedModel比较若一致或为其后缀采用会话级完整形式否则用消息级值最后兜底gpt-5。显示名方面modelDisplayName对已知前缀做美化映射gpt-5.4→GPT-5.4、gpt-5.4-mini→GPT-5.4 Mini、gpt-5→GPT-5等映射表按键长降序预排序以保证更具体的键先匹配未知模型原样返回toolDisplayName将原始工具名映射为人类可读形式bash→Bash、read→Read、edit→Edit、write→Write、glob→Glob、grep→Grep、task/dispatch_agent→Agent、fetch→WebFetch、search→WebSearch、todo→TodoWrite、patch→Patch未知工具保留原名。去重策略三级回退键跨 Provider 去重是 CodeBurn 防止同一次调用被重复计费的基础设施src/parser.ts维护一个全局seenKeys集合传入每个 Provider 的解析器让“同时出现在两个 Provider 转录中”的同一次调用只计一次docs/architecture.md 的 Pipeline 一节对此有说明。Pi 的去重键格式为provider:path:responseId | entry.id | entry.timestamp | lineIdx即优先使用message.responseIdprovider:path:responseId当 responseId 缺失时依次回退到条目id、条目timestamp最后回退到该行在文件中的行号索引src/providers/pi.ts 中dedupKey的构造。文档特别提示这三个回退键在新旧版 Pi 上的碰撞行为不同——旧版 Pi 的转录缺少 responseId此时条目时间戳/行号成为去重依据排查去重相关 bug 时应通过临时日志确认实际命中了哪一级回退键。测试deduplicates calls seen across multiple parses验证了同一解析器对同一文件跑两遍第二遍不再产出任何调用。成本计算账单成本优先Token 计价兜底每条助手消息的成本按以下规则决定src/providers/pi.ts 中reportedCost与costUSD的逻辑若message.usage.cost.total是非零的有限数值直接采用该账单成本并标记costFromBilling: true——该成本在写入会话缓存后原样保留不会再被重新计价ParsedProviderCall.costFromBilling字段注释说明了这一语义否则调用calculateCost(model, input, output, cacheWrite, cacheRead, 0)src/models.ts按 Token 数与模型单价重算此时costFromBilling不设置缓存的调用会在每次读取时用最新定价重新计价因此价格表更新仍能作用到旧调用。这里有一个精妙的取舍零成本被视为“缺失”。OMP 对xai-oauth调用会写出cost.total 0若直接采纳会导致模型别名表与价格覆盖--model-alias、--price-override永远无法生效因此零成本走重算路径让别名与覆盖介入。而一条真正免费的调用会被重算成很小的非零值——这是修复 OAuth 零成本问题所接受的代价。测试prices a zero reported cost through its alias and price override用xai-oauth/grok-4.6 自定义单价验证了重算结果100 万 input × 2 100 万 output × 4 6 美元。此外cost.total是单条消息的 USD 成本而非会话累计值已对照真实 Pi 转录验证该值等于本条消息 inputoutputcacheReadcacheWrite且不单调递增。NaN 防护未定义字段强制归零Pi/OMP 的会话文件有时会漏写部分 usage 字段。解析器在读取后立即执行const input msg.usage.input ?? 0 const output msg.usage.output ?? 0 const cacheRead msg.usage.cacheRead ?? 0 const cacheWrite msg.usage.cacheWrite ?? 0把undefined/null强制为0src/providers/pi.ts 中// Coerce undefined/null token fields to 0的注释明确写着只把数值传给定价回退逻辑防止 NaN 污染聚合结果。文档特别提醒如果出现 “tokens are NaN” 的 bug先看这里的强制转换——这一处的回归是静默的极易漏查。Quirks 深度解析技能加载识别issue #588Pi/OMP没有像 Claude Code 那样的独立 skill 工具。Pi 的原生技能加载在转录里表现为一次普通的read工具调用其路径指向技能的SKILL.mdPi 从多个根解析技能~/.pi/agent/skills、项目.pi/skills、.agents/skills、包的skills/、--skill path等而新版 OMP 则可能是skill://nameURI。若不处理这些调用会虚增 Read 工具计数且让 “Skills Agents” 维度永远为空issue #588。skillLoadName函数src/providers/pi.ts在解析时拦截仅当工具名是read时继续判断file_path作为path的回退键若路径以skill://开头取 URI 中第一个路径段作为技能名否则只匹配路径最后一个段是否为SKILL.md按目录前缀匹配会因技能根位置众多而失效同时按\\与/两种分隔符切分以兼容 Windows 路径取父目录名作为技能名命中则工具记为Skill并写入skills数组未命中则保持普通Read。这面镜子完全对齐 Claude 解析器的表示方式技能加载后的轮次被共享分类器标记为general且classifyTurnsrc/classifier.ts会把skills[0]写入subCategory从而被会话摘要读取并构建 “Skills Agents” 分解。测试覆盖了全部形态classifies a SKILL.md read as a skill load, not a Read (#588).../.pi/skills/bmad-create-story/SKILL.md→skills: [bmad-create-story]、tools: [Skill, Read, Edit]普通workflow.md读取仍是Readclassifies a skill:// read as a skill load (OMP-style URI)skill://commit-workflow→[commit-workflow]reads the file_path key as a fallback for skill loadsfile_path: /home/u/.agents/skills/deep-research/SKILL.md→[deep-research]leaves a normal read (no SKILL.md) as a Read with no skillssrc/skill-loader.ts保持[Read]端到端测试a pure skill-load turn classifies as general with the skill as subCategory一条纯技能加载轮次经classifyTurn后category general、subCategory systematic-debugging确保技能名最终进入摘要分解。Provider 名不硬编码Pi 解析器产出调用时provider字段取自source.provider即发现阶段传入的pi或omp而不是在解析器内部硬编码。这正是pi.ts能同时服务两个 Provider 的基础docs/providers/omp.md 对共享解析器有同样说明。时间戳回退链每条调用的时间戳按优先级取条目级timestamp→ 暂存的用户消息时间戳 → 会话级sessionTimestamp→文件 mtime作为最后兜底保证即使条目的 entry/user/session 时间戳全部缺失调用仍落在会话时间窗内而不是被丢弃。测试falls back to file mtime when a call has no usable timestamp验证了这条路径真实消费被保留仅时间戳替换为 mtime。测试覆盖与修 Bug 指南Pi 的集成由 tests/providers/pi.test.ts336 行与 tests/providers/omp.test.ts225 行共同守护。测试构造临时目录写入 JSONL 夹具覆盖会话发现多项目、空目录、无 session 头、非 JSONL 文件、title 槽、空行容忍、损坏头部、超大 message-only 文件、JSONL 解析Token 提取、mtime 兜底、字符串 content、工具名收集、bash 命令提取、skill 分类、零 Token 跳过、去重、多轮、缺失文件、显示名映射。当你需要在此处修 bug 时docs/providers/pi.md 给出了三条硬性规则改动解析逻辑后必须同时跑tests/providers/omp.test.ts——OMP 共享这份代码任何 Pi 解析改动都可能波及 OMP“tokens 是 NaN” 先看强制归零处pi.ts中msg.usage.input ?? 0等四行——该回归静默且极易漏查去重行为相关 bug先加临时日志确认本次命中了三级回退键中的哪一级——旧版与新版 Pi 的键碰撞方式不同。若要深入了解 Provider 接口契约与整个解析聚合流水线可继续阅读 src/providers/types.ts 与 docs/architecture.mdProvider 文档索引见 docs/providers/README.md。赞分享【免费下载链接】codeburnFree, local tool to track AI coding token usage and cost across 37 tools and agents (Claude Code, Cursor, Codex, Gemini and more), by model, project, and task. npx codeburn项目地址https://gitcode.com/gh_mirrors/co/codeburn点击查看免费下载相关推荐codeburn 源码级解析CodebuffManicodeCLI Agent 本地会话的用量与成本追踪实现codeburn 源码级解析CodebuffManicodeCLI Agent 本地会话的用量与成本追踪实现 本篇技术指南围绕 codeburn 开源仓库CodeBurn 的 Qwen Code CLI 集成JSONL 会话解析、Token 成本核算与去重机制全解析CodeBurn 的 Qwen Code CLI 集成JSONL 会话解析、Token 成本核算与去重机制全解析 CodeBurn 是一款本地运行、无需账号的codeburn 集成指南KiloCode VS Code 扩展的用量追踪实现与解析原理codeburn 集成指南KiloCode VS Code 扩展的用量追踪实现与解析原理 本指南聚焦 codeburn 如何接入 KiloCodeVS Co创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考