【免费下载链接】codeburn
Free, 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
CodeBurn 通过内置的 ZCode Provider,以只读方式解析 ZCode CLI(z.ai 推出的编码 Agent,运行 GLM-5.2 模型、基于 z.ai start-plan 订阅)在本机落盘的 SQLite 数据库,将 token 用量与花费按模型、项目、任务维度纳入统一报表;同时通过扫描 ZCode 桌面端 Chromium Local Storage 的 leveldb journal 提取 OAuth 登录态,调用 z.ai 官方额度接口,在 Plans 侧边栏实时展示套餐剩余额度。读完本文,你将掌握 ZCode 数据的存储位置与三张核心表结构、codeburn 的字段映射与缓存/去重处理逻辑、套餐额度的在线抓取机制,以及该模块已知的 quirks 与排障方法。
ZCode 与 CodeBurn 的集成定位
ZCode 是 z.ai 出品的 CLI 编码 Agent,运行 GLM-5.2 模型,走 z.ai 的start-plan订阅。由于套餐模式下 ZCode 自身只记录 token 数量、不落任何美元成本,想要把 ZCode 的消耗并入 CodeBurn 的统一成本核算,就必须由 CodeBurn 侧完成“token 提取 + 价格表计价”。
整个集成由三部分源码构成:
- 用量解析:
src/providers/zcode.ts - 套餐额度(CLI 侧):
src/quota/zcode.ts - 套餐额度(Electron 桌面端):
app/electron/quota/zcode.ts,以及 macOS 原生菜单栏的同构实现mac/Sources/CodeBurnMenubar/Data/ZcodeSubscriptionService.swift
Provider 采用懒加载策略(src/providers/index.ts的lazyProviderNames列表包含zcode),原因是解析器需要借助node:sqlite读取 ZCode 的 SQLite 数据库,只有真正需要扫描 ZCode 时才动态import('./zcode.js'),避免在无关场景拖慢启动。
数据源:为什么只有~/.zcode/cli/db/db.sqlite
ZCode 在磁盘上存在三类可能包含数据的文件,但只有一处可用:
| 来源 | 路径 | 是否使用 |
|---|---|---|
| ZCode CLI 数据库 | ~/.zcode/cli/db/db.sqlite | ✅ 唯一数据源 |
| 桌面端 Electron 运行时目录 | ~/Library/Application Support/ZCode | ❌ 仅存 Electron 运行时状态 |
| JSONL 活动日志 | ~/.zcode/cli/log/*.jsonl | ❌ token 计数已被脱敏 |
源码头部注释(src/providers/zcode.ts)明确记录了取舍原因:JSONL 活动日志会脱敏 token 计数(redact),且任何来源都不存美元成本(GLM-5.2 跑在 z.ai 的 start-plan 订阅上),因此 token 从 SQLite 精确读取,成本由价格表计算。
存储格式:三张核心表的结构与验证
ZCode CLI 用单一全局 SQLite 数据库记录用量,CodeBurn 侧针对 CLI dbv0.14.8做过 schema 校验(src/providers/zcode.ts注释标注了验证日期)。真正被读取的表只有三张:
CREATE TABLE session ( id TEXT PRIMARY KEY, directory TEXT NOT NULL, ... ); CREATE TABLE model_usage ( id TEXT PRIMARY KEY, session_id TEXT NOT NULL, turn_id TEXT, model_id TEXT NOT NULL, input_tokens INTEGER NOT NULL DEFAULT 0, output_tokens INTEGER NOT NULL DEFAULT 0, reasoning_tokens INTEGER NOT NULL DEFAULT 0, cache_creation_input_tokens INTEGER NOT NULL DEFAULT 0, cache_read_input_tokens INTEGER NOT NULL DEFAULT 0, started_at INTEGER NOT NULL, completed_at INTEGER, ... ); CREATE TABLE tool_usage ( session_id TEXT NOT NULL, turn_id TEXT, tool_name TEXT NOT NULL, started_at INTEGER NOT NULL, ... );session表存会话 id 与工作目录(directory),用于按项目归类;model_usage表是核心,一行即一次模型请求,含输入/输出/reasoning token 与缓存读写 token,时间字段为毫秒级 epoch;tool_usage表记录每次 tool 调用,但它只关联到turn_id(回合),并不指向具体的model_usage行。
测试用例tests/providers/zcode.test.ts中createZcodeDb构建的就是上述 schema 的最小可行子集(仅保留 Provider 实际读取的列),与真实库结构一一对应。
会话发现与解析流水线
Provider 的读取分两个阶段,接口定义在src/providers/types.ts:
1. 会话发现(discoverSessions)
discover()(src/providers/zcode.ts)以只读方式打开数据库,先通过validateSchema探测model_usage与session两张表是否存在(SELECT COUNT(*) ... LIMIT 1),再执行一次 JOIN 查询,只挑出至少有一个 token 字段非零的会话:
SELECT DISTINCT s.id as id, s.directory as directory FROM session s JOIN model_usage m ON m.session_id = s.id WHERE m.input_tokens > 0 OR m.output_tokens > 0 OR m.reasoning_tokens > 0 OR m.cache_read_input_tokens > 0 OR m.cache_creation_input_tokens > 0每条 SessionSource 的path被编码为`${dbPath}:${row.id}`,project则由sanitizeProject把目录绝对路径转换为主机无关的扁平 key(去掉开头/、把/替换为-,例如/Users/me/proj→Users-me-proj,对应测试中的断言)。解析时再从右侧切分该 path 还原 session id,这样 Windows 盘符里的冒号不会破坏 id。
2. 逐会话解析(createSessionParser)
解析器(parse()异步生成器)按started_at升序读取model_usage行,同时预先按 turn 聚合tool_usage,逐行产出ParsedProviderCall。字段映射关系如下:
| codeburn 字段 | ZCode 来源 | 说明 |
|---|---|---|
inputTokens | model_usage.input_tokens减去 cached/created 部分 | 见下文缓存拆分 |
outputTokens | model_usage.output_tokens | |
reasoningTokens | model_usage.reasoning_tokens | |
cacheCreationInputTokens | model_usage.cache_creation_input_tokens | |
cacheReadInputTokens | model_usage.cache_read_input_tokens | |
costUSD | 由calculateCost计算 | ZCode 不存任何成本 |
model | model_usage.model_id(如GLM-5.2) | |
timestamp | model_usage.completed_at,为空则用started_at(epoch ms) | epochMsToIso兜底非有限值 |
tools | 该 turn 的tool_usage.tool_name | 每个 turn 只挂到一次请求上 |
缓存拆分:OpenAI 风格 input 折叠的还原
这是本 Provider 最关键的解析逻辑。ZCode 以 OpenAI 风格记录缓存:行的input_tokens已经包含缓存读/写,即provider_total_tokens = input_tokens + output_tokens。而 CodeBurn 的价格表是 Anthropic 语义(新鲜输入按输入价、缓存读按缓存读价分开计费),所以解析器必须把缓存部分从input_tokens里减回去:
const freshInput = Math.max(0, (row.input_tokens ?? 0) - cacheRead - cacheCreation)这一拆分已对照provider_metadata_json里嵌套的 Anthropic usage 做过确认(例如 100 输入 = 36 新鲜 + 64 缓存)。测试用例tests/providers/zcode.test.ts中的splits cached tokens out of input用例验证了完整链路:一行input_tokens = 9125、cache_read_input_tokens = 8064的记录,解析结果为inputTokens = 1061(9125 − 8064)、cacheReadInputTokens = 8064。
成本计算时还有一个容易被忽略的细节:GLM 是“reasoning 独立计桶”的模型,zcode不在REASONING_INCLUDED_IN_OUTPUT集合中,因此解析器通过billableOutputTokens('zcode', output, reasoning)把 reasoning token 按输出等价量加回后再交给calculateCost,否则 reasoning 部分会漏计费(对应测试bills reasoning tokens into the cost)。
去重:以model_usage.id为主键
Provider 层面没有缓存,但每一行产出都会注册去重 key:`zcode:${row.id}`,其中row.id是model_usage表主键、对每次请求唯一。解析器与seenKeys集合协作,已出现过的 key 直接跳过(tests/providers/zcode.test.ts的does not re-emit rows already in the seen set用例验证了重复解析时第二次产出为空)。同时,全零 token 的行会被continue跳过,不产出任何记录。
值得注意的 Quirks
缓存 token 折叠进input_tokens(OpenAI 风格)
如上一节所述,行的input_tokens是完整 prompt 大小(含缓存读/写),provider_total_tokens = input_tokens + output_tokens。解析器减去cache_read_input_tokens与cache_creation_input_tokens后,新鲜输入按输入价、缓存按缓存读价计费,与嵌套的 Anthropic usage 相互印证(例如 100 input = 36 fresh + 64 cached)。
任何地方都不存成本
GLM-5.2 运行在 z.ai 的start-plan订阅上,ZCode 日志里只有 token。CodeBurn 用价格表计算一个名义成本(notional cost),因此报表中的 ZCode 花费是估算值而非官方账单。
GLM-5.2 通过别名定价
LiteLLM 的价格快照没有直接收录某些命名变体,因此模型名需要经过BUILTIN_ALIASES(src/models.ts)归一到已定价行。文档版本说明中曾提到GLM-5.2映射到glm-5p1(GLM-5.1)实现“按目标模型显示”;而当前仓库源码(src/models.ts第 505-512 行)已演进为:ZCode 上报大写的GLM-5.2/GLM-5.3,快照中裸glm-5.2/glm-5.3行是列表价($1.4/$4.4),而 z.ai 自己的z-ai/glm-5.2/z-ai/glm-5.3行才是实际支付的折扣价,因此BUILTIN_ALIASES将glm-5.2、GLM-5.2、glm-5.3、GLM-5.3全部指向z-ai/glm-5.2/z-ai/glm-5.3。报表会以“定价目标”的名字展示模型,与所有走别名的模型行为一致。若后续 LiteLLM 收录 GLM-5.2,可去掉该别名。
时间戳是毫秒
与某些 Provider(如 Crush 用秒)不同,ZCode 存的是 epoch毫秒,解析器将其直接交给Date,epochMsToIso还会对null/非有限值兜底为new Date(0)。
工具按 turn 而非按请求挂载
tool_usage只关联turn_id,不关联具体model_usage行,所以每个 turn 的工具列表会挂到该 turn 的第一条请求上,避免跨多次请求重复计数(源码用turnsWithToolsEmitted集合保证每个 turn 只挂一次)。另外 Bash 命令文本不被存储,因此bashCommands恒为空数组。测试种子数据中turn-1的两个工具调用(Bash、Read)最终以['Bash', 'Read']出现在单条解析结果上。
套餐额度(Live):Plans 侧边栏的数据来源
Plans 侧边栏的用量 gauge 走的是与 ZCode 桌面 App 内嵌 coding-plan 浏览器完全相同的额度接口——它是src/quota/zai.ts(服务 Pi CLI 登录)的姊妹实现,区别只在于这里服务的是 ZCode 桌面 App 自身的登录态。src/quota/zai-plan.ts中的decodeZaiPlanUsage是两者共享的响应解码器。
| 来源 | 路径 / 端点 |
|---|---|
| 登录令牌 | …/ZCode/session/Partitions/zcode-coding-plan/Local Storage/leveldb/*.log,key 为oauth:zai:access_token(可用ZCODE_DATA_DIR环境变量覆盖 App-Data 根目录) |
| 额度查询 | GET https://api.z.ai/api/monitor/usage/quota/limit,请求头Authorization: Bearer <token> |
Journal 扫描而非 leveldb 读取器
令牌是单字节(latin-1)字符串,以key + varint 长度 + 0x01 标记 + value的布局直接存在于 Chromium 的 Local Storage journal 文件中。实现要点(src/quota/zcode.ts与app/electron/quota/zcode.ts两处一致):
- 按
*.log文件名倒序扫描(journal 名是零填充计数器,倒序即最新优先),保留该 key 的最后一次写入; - 由于每个字符串带一个单字节标记(
0x01表示 latin-1、0x00表示 UTF-16LE),整个文件会用 latin1 与 utf16le 两种字节视图各读一遍,保证 key 两种编码都能命中; - 正则
`oauth:zai:access_token[\x00-\x20\x7f-\xff]{0,16}([A-Za-z0-9_\-.=+/]{24,})`跳过 key 与 value 之间的 varint 长度与字符串标记(控制位或高位字节,绝不可能是 token 字符); - 文件大小上限
MAX_JOURNAL_BYTES = 16MB,超出视为非 Local Storage 日志直接跳过; - 明文 capped 读取而非
readSecureFile:Chromium 拥有该文件权限位(组可读是设计使然),readSecureFile会拒绝这种模式。
令牌只用于一次请求,从不持久化、从不打日志(失败分支只打印sanitizeError脱敏后的错误)。
无本地过期:JWT 没有 exp
ZCode 存储的 JWT不携带expclaim,有效性完全由服务端裁决。因此 HTTP 200 响应体内携带业务级code: 401/403是唯一的过期信号:解码器(decodeZcodeUsage→decodeZaiPlanUsage)将其判为'rejected',映射为terminalFailure,footer 提示 “Open the ZCode app and sign in again”(只有 App 本身能铸造新登录)。HTTP 层还有完整的状态分类:401/403 →terminalFailure;429 →transientFailure且按Retry-After计算重试秒数(下限 60 秒);≥500 →transientFailure;找不到令牌 →disconnected。
已知盲区:leveldb 压缩
当 leveldb 把 journal 压缩进.ldb文件后,记录被 snappy 压缩,原始字节扫描不可见,gauge 会回退到disconnected,直到 webview 写入新的 journal 条目才恢复。排查“App 已登录但 gauge 显示 disconnected”时,优先检查是否发生了压缩、key 是否仍是oauth:zai:access_token。
覆盖全部界面
- CLI:
src/quota/zcode.ts - Electron 桌面端:
app/electron/quota/zcode.ts - macOS 原生菜单栏:
mac/Sources/CodeBurnMenubar/Data/ZcodeSubscriptionService.swift(同样的 journal 扫描与端点,catalog idzcode,作为 live Capacity Dock 适配器)
Windows 上的映射与zai.ts一致(windowLabel/resetsAt位于共享解码器src/quota/zai-plan.ts):
unit 3 × number 5→5-hour窗口;unit 6 × number 1→Weekly窗口;- 用量百分比优先取
percentage字段,缺失时用currentValue / usage推算(源码对 JSON number 与字符串两种类型都做了兼容,num()统一处理); data.level为套餐标签,"pro"→ "Pro"、"coding_pro"→ "Coding Pro"(planLabel做下划线展开与标题化);- 重置时间
nextResetTime兼容 ISO-8601、epoch 秒与 epoch 毫秒三种形态。
响应解码只接受CREDIT_LIMIT与TOKENS_LIMIT类型的窗口项,无法识别的 payload 返回null→transientFailure,并提示 “Z.ai returned an unrecognized quota response”。
修复本模块 Bug 的操作手册
文档与源码共同给出如下排障清单:
- 先确认 schema,再动真库:对真实 ZCode 安装验证 schema;查询前把
~/.zcode/cli/db/db.sqlite复制到临时文件,避免锁住正在使用的活库(openDatabase全程只读打开)。 - 成本全是 $0:检查
GLM-5.2(或当前模型 id)是否仍能通过BUILTIN_ALIASES(src/models.ts)解析到已定价模型。 - token 看起来约 8 倍偏高:多半是有人删掉了输入归一化中的缓存减法——行的
input_tokens已经包含缓存 token,必须按“新鲜输入 + 缓存读”拆分计费。 - 新增 fixture:放在
tests/providers/zcode.test.ts内联 schema 之下(createZcodeDb+seed模式)。 - 额度 gauge 在已登录状态下显示
disconnected:检查 journal 是否已被压缩进.ldb(没有可用的*.log条目),以及 key 是否仍为oauth:zai:access_token。
测试保障
集成质量由两层测试兜底:
- 用量解析(fixture 驱动):
tests/providers/zcode.test.ts覆盖会话发现(项目名扁平化)、缓存拆分(9125 → 1061 fresh + 8064 cached)、reasoning 计入成本、seen-set 去重四类场景; - 额度抓取:
tests/quota-zcode.test.ts覆盖登录令牌从最新 journal 读出、key 原地轮换时保留最新写入、存储目录缺失返回 null、额度窗口与套餐等级映射、字符串型数字兼容、body 内鉴权码判为拒绝、HTTP 状态分类(disconnected / terminalFailure / transientFailure)、以及令牌以 Bearer 形式送达额度端点等行为;Electron 侧同名测试位于app/electron/quota/zcode.test.ts。
小结
ZCode Provider 是 CodeBurn 中“离线解析 + 在线额度”双通道集成的代表:离线通道以只读 SQLite 读取精确 token 并还原 OpenAI 风格缓存语义,通过价格表与别名机制计算名义成本;在线通道则利用 leveldb journal 扫描安全地复用 ZCode App 自身的登录态,直连 z.ai 官方额度接口驱动 Plans 侧边栏。理解缓存拆分、别名定价与 journal 压缩盲区这三处细节,是正确使用与维护该集成、以及排查“零成本”和“disconnected”两类高频问题的关键。
【免费下载链接】codeburn
Free, 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
相关推荐
9Router 配额追踪与用量监控深度指南:实时 Token 消耗、额度预警与成本管控
9Router 配额追踪与用量监控深度指南:实时 Token 消耗、额度预警与成本管控 导读 9Router 是一个面向 AI 编程的统一网关,可把 Claud
人工智能LLM 网关AI 应用Antigravity-Manager 集成 z.ai(GLM)实战:Anthropic 兼容透传 + MCP 三件套 + 配额监控
Antigravity Manager 集成 z.ai(GLM)实战:Anthropic 兼容透传 + MCP 三件套 + 配额监控 导读 本文基于 docs/
LLM 网关API网关AI 应用后端CodeBurn 集成 Hermes Agent 深度解析:SQLite 会话级用量解析、计费路由与账本增量核算
CodeBurn 集成 Hermes Agent 深度解析:SQLite 会话级用量解析、计费路由与账本增量核算 CodeBurn 是一款本地运行、免费的开源
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考