news 2026/9/24 15:51:24

CodeBurn 集成 ZCode 深度指南:SQLite 用量解析与 z.ai 套餐额度实时监控

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
CodeBurn 集成 ZCode 深度指南:SQLite 用量解析与 z.ai 套餐额度实时监控

【免费下载链接】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

项目地址:https://gitcode.com/gh_mirrors/co/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.tslazyProviderNames列表包含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.tscreateZcodeDb构建的就是上述 schema 的最小可行子集(仅保留 Provider 实际读取的列),与真实库结构一一对应。

会话发现与解析流水线

Provider 的读取分两个阶段,接口定义在src/providers/types.ts

1. 会话发现(discoverSessions)

discover()src/providers/zcode.ts)以只读方式打开数据库,先通过validateSchema探测model_usagesession两张表是否存在(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/projUsers-me-proj,对应测试中的断言)。解析时再从右侧切分该 path 还原 session id,这样 Windows 盘符里的冒号不会破坏 id。

2. 逐会话解析(createSessionParser)

解析器(parse()异步生成器)按started_at升序读取model_usage行,同时预先按 turn 聚合tool_usage,逐行产出ParsedProviderCall。字段映射关系如下:

codeburn 字段ZCode 来源说明
inputTokensmodel_usage.input_tokens减去 cached/created 部分见下文缓存拆分
outputTokensmodel_usage.output_tokens
reasoningTokensmodel_usage.reasoning_tokens
cacheCreationInputTokensmodel_usage.cache_creation_input_tokens
cacheReadInputTokensmodel_usage.cache_read_input_tokens
costUSDcalculateCost计算ZCode 不存任何成本
modelmodel_usage.model_id(如GLM-5.2
timestampmodel_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 = 9125cache_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.idmodel_usage表主键、对每次请求唯一。解析器与seenKeys集合协作,已出现过的 key 直接跳过(tests/providers/zcode.test.tsdoes 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_tokenscache_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_ALIASESsrc/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_ALIASESglm-5.2GLM-5.2glm-5.3GLM-5.3全部指向z-ai/glm-5.2/z-ai/glm-5.3。报表会以“定价目标”的名字展示模型,与所有走别名的模型行为一致。若后续 LiteLLM 收录 GLM-5.2,可去掉该别名。

时间戳是毫秒

与某些 Provider(如 Crush 用秒)不同,ZCode 存的是 epoch毫秒,解析器将其直接交给DateepochMsToIso还会对null/非有限值兜底为new Date(0)

工具按 turn 而非按请求挂载

tool_usage只关联turn_id,不关联具体model_usage行,所以每个 turn 的工具列表会挂到该 turn 的第一条请求上,避免跨多次请求重复计数(源码用turnsWithToolsEmitted集合保证每个 turn 只挂一次)。另外 Bash 命令文本不被存储,因此bashCommands恒为空数组。测试种子数据中turn-1的两个工具调用(BashRead)最终以['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.tsapp/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唯一的过期信号:解码器(decodeZcodeUsagedecodeZaiPlanUsage)将其判为'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 55-hour窗口;
  • unit 6 × number 1Weekly窗口;
  • 用量百分比优先取percentage字段,缺失时用currentValue / usage推算(源码对 JSON number 与字符串两种类型都做了兼容,num()统一处理);
  • data.level为套餐标签,"pro"→ "Pro"、"coding_pro"→ "Coding Pro"(planLabel做下划线展开与标题化);
  • 重置时间nextResetTime兼容 ISO-8601、epoch 秒与 epoch 毫秒三种形态。

响应解码只接受CREDIT_LIMITTOKENS_LIMIT类型的窗口项,无法识别的 payload 返回nulltransientFailure,并提示 “Z.ai returned an unrecognized quota response”。

修复本模块 Bug 的操作手册

文档与源码共同给出如下排障清单:

  1. 先确认 schema,再动真库:对真实 ZCode 安装验证 schema;查询前把~/.zcode/cli/db/db.sqlite复制到临时文件,避免锁住正在使用的活库(openDatabase全程只读打开)。
  2. 成本全是 $0:检查GLM-5.2(或当前模型 id)是否仍能通过BUILTIN_ALIASESsrc/models.ts)解析到已定价模型。
  3. token 看起来约 8 倍偏高:多半是有人删掉了输入归一化中的缓存减法——行的input_tokens已经包含缓存 token,必须按“新鲜输入 + 缓存读”拆分计费。
  4. 新增 fixture:放在tests/providers/zcode.test.ts内联 schema 之下(createZcodeDb+seed模式)。
  5. 额度 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

项目地址:https://gitcode.com/gh_mirrors/co/codeburn
点击查看免费下载

相关推荐

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/24 15:51:20

YOLOv8模型导出TensorRT算子不兼容问题全解析:从算子识别、自定义插件开发到模型转换与性能优化的完整实战指南

🎪 摸鱼匠:个人主页 🎒 个人专栏:《YOLOv8 入门到精通:全栈实战》 🥇 没有好的理念,只有脚踏实地! 文章目录 一、YOLOv8模型导出基础与算子支持问题 1.1 YOLOv8模型导出流程概述 1.2 常见不支持的算子类型分析 1.3 算子兼容性检测方法 二、TensorRT插件开发基础 …

作者头像 李华
网站建设 2026/9/24 15:47:23

从ET1100到AX58100:EtherCAT从站硬件改版实战记录

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华