把 AI 编码助手的积分账单和本机会话记录里的 Token 消耗关联起来,看清每一分积分到底换来了多少 Token。
适用于 WorkBuddy 桌面端与 CodeBuddy CLI。两者内核相同、会话记录格式一致,只是根目录不同,本项目同时扫描两边。
纯本地运行:零服务端部署、零依赖安装(脚本只用 Node 标准库,看板图表库走 CDN),一切数据留在你自己机器上。
和生态里其他工具的区别:WorkBuddy / CodeBuddy 周边的工具已经不少——转 API 的、自动签到的、多账号轮换的、账号池管理的。它们都在帮你多拿积分;这个项目反过来,只回答一个它们都不回答的问题:积分花在哪了、值不值。
差别来自关联:官方账单只知道「这次提问扣了 0.37 积分」,本机留痕只知道「这次请求用了多少 Token」,两份数据本来互不相干。本项目按回合 ID 把它们对上——这件事目前没有别的工具在做。
- 它解决什么问题
- 功能特性
- 快速开始
- 核心设计:积分与 Token 怎么对齐
- 模型响应时间怎么来的
- 自动同步官方账单
- 多端云同步
- 数据来源与隐私
- 命令行参数
- 增量合并
- 相关项目
- 文件说明
- 常见问题
- 实现说明
- License
AI 助手的积分账单只会告诉你「这一次提问扣了 0.37 积分」,但不会告诉你:
- 这 0.37 积分背后实际消耗了多少 Token?
- 缓存命中了多少?缓存到底有没有帮我省钱?
- 哪个工具(读文件 / 执行命令 / 搜索)最烧 Token?
- 哪个模型更划算?
这些信息在本地会话记录里其实都有,只是和账单是两份互不相干的数据。本项目把它们对上。
账号与积分(官方接口自动同步,每账号一张卡片)
- 剩余积分 / 总量 / 已用比例,带进度条;最近到期时间,7 天内到期变红警告
- 今日 / 昨日消耗:按自然日聚合的账单消耗,悬停看口径说明
- 预计可用天数:按最近三周的消耗节奏推算这份余额还够用多久,与「最近到期」取小——到期前用不完时直接提示,不给虚高天数;悬停看日均与样本天数
- 套餐明细按名称聚合——几十个零散赠包会合并成几行,不会刷屏
- 签到日历:签到格子(右端为今天)+ 连续天数 / 累计签到天数 / 累计积分
- 状态 chips(纯图标,悬停看详情):签到、旅行剩余时间、429 限流(带数量角标)、建议优先使用的账号
- 登录徽标与一键切换:卡片右上角三个应用图标(WorkBuddy 桌面端 / CodeBuddy IDE / CodeBuddy CLI),图标即状态——当前登录 ✓、可切换可点、置灰表示不可用(CodeBuddy IDE 的登录态不在本项目读取范围内,恒置灰);点击二次确认后切换账号——桌面端会重启 WorkBuddy 生效,CodeBuddy CLI 写完即生效、无需重启
- 🔄 单账号刷新:每张卡片底部的刷新按钮只重拉该账号的账单与积分余额,其余账号原样保留,比整轮同步快得多
签到与派猫猫(每账号两个按钮,需要本地服务)
| 按钮 | 行为 |
|---|---|
| ✅ 签到 | 每日签到领积分。已签到会自动识别,不会重复提交;点完回显连续天数与累计积分 |
| 🐱 派猫猫 | 按状态机自动判断:空闲就派出去、已到达就领奖励、旅行中提示还要等多久、今日已派则跳过 |
两个动作都会真的调用官方接口改变服务端状态(等同你自己在官网点一下)。
自动任务(账号卡片上方,需要本地服务)
四个独立开关,默认全关:点开哪个哪个开始跑(开启即先执行一次给你反馈),之后按各自周期自动执行。每行显示周期、说明与最近一次结果——开关变绿=最近一次成功、变红=最近一次失败,失败原因与结果摘要直接写在开关下方,悬浮可见绝对时间。
| 任务 | 默认周期 | 行为 |
|---|---|---|
| 自动签到 | 每 6 小时 | 为全部账号签到,已签到的自动跳过(幂等,不会重复提交) |
| 自动猫猫 | 每 30 分钟 | 按状态机照看全部账号的猫猫:空闲自动派出、到点自动领奖。查得勤才不漏领每日积分 |
| 自动切换账号 | 每 1 小时 | 有账号积分将在 14 天内到期(switchHorizonDays 可调)且还没用完时,自动把 WorkBuddy 桌面端与 CodeBuddy CLI 都切到它,优先用掉即将过期的积分。桌面端仅在其正在运行时才重启生效;切换前自动备份登录态,可随时手动切回。自动切换成功后 24 小时内不再切(switchCooldownHours 可调,手动切换不受限) |
| 自动刷新积分 | 每 30 分钟 | 拉取官方账单与各账号余额,增量合并、历史不丢;开启后看板余额自动保鲜,无需手动点「💰 同步积分」 |
开关与参数都存在本地服务的 auto-config.json(不入库),字段如下:
| 字段 | 含义 |
|---|---|
| 四个开关 | checkin / travel / switch / refresh,布尔值,由页面上的 chip 读写 |
intervalMinutes |
各任务的执行周期,单位分钟(如 "checkin": 360 = 6 小时) |
jitterPercent |
触发抖动的随机幅度 ±N%,默认 10 |
switchHorizonDays |
「自动切换账号」的触发阈值:有积分将在 N 天内到期才切,默认 14,下限 1 |
switchCooldownHours |
「自动切换账号」成功后的冷却时长,单位小时,默认 24,下限 1(防数据抖动导致反复切) |
_comment是给单位说明用的自留字段(JSON 不支持注释)——服务端会原样保留它,页面上点开关触发的回写不会把它抹掉,你可以往里加自己的备注。所有_开头的字段都享有这个待遇。
手改后不用重启服务——调度器每秒检查一次文件,变了就重载(页面上「每 X 小时」与「N 天内到期」的文字也跟着变,以服务端配置为准)。填错的值会回退默认(周期下限 1 分钟、抖动上限 ±50%);整份 JSON 写坏时沿用上一份配置,不会把开关静默关掉。失败不会立刻重试——等完整周期后再试,不会刷爆官方接口。各任务的实际触发间隔在标称周期上叠加随机抖动(默认 ±10%,如 30 分钟任务实际 27~33 分钟),避免固定间隔的规律性请求。
这些自动化只是顺手:凭证发现、接口封装、切换能力本来就在项目里,加个调度器而已。项目的主定位仍然是看板——看清楚积分花在哪、值不值。
多端云同步(可选,需要本地服务)
多台电脑各用一份 buddyToken 时,数据本来是互相看不见的。开启后每台机器把自己的数据推到云端一个「传阅箱」,再把别人推的拉回来合进本地,看板于是看到多端汇总:
- 筛选栏多一组**「机器」**,能按机器筛选,也能一眼看出每台贡献了多少
- 后台静默自动同步(默认 30 分钟一轮),看板上不增加任何按钮
- 数据只增不减:合并只做「缺失才加 / 更优才覆盖」,任何一步都不会让历史变少
- 「🗑 一键清空数据」只清本地,云端保留——避免一台机器误删掉别的机器贡献的数据
云端用 Supabase(免费额度足够),建表 SQL 就在仓库根目录的 supabase-cloud-sync.sql。看板不直连云端:密钥只存在本机 sync-config.json(已 gitignore),同步全在 Node 侧完成。详细步骤与注意事项见多端云同步一节。
429 限流台账
扫描本机日志还原每个账号、每个模型的限流记录,给出官方恢复时刻与倒计时;按 sessionId → 模型 归因,避免模型错归。
筛选
日期范围(含今日 / 近 7 / 14 / 30 / 60 / 180 日 / 近 1 年 / 全部快捷键,打开看板默认落在最近 60 天)、模型、客户端、账号四维筛选,可叠加;开启云同步后还有第五维「机器」。模型超过 8 个时自动折叠,已选中的始终可见。
日期范围不随快照保存——每次打开都回到默认窗口,模型与客户端筛选则沿用上次的选择。
KPI
- Token 总量 / 缓存命中率
- 每积分 Token、每 M Token 积分(把积分和 Token 换算起来)
- 免费模型 Token(0 积分但确实消耗了 Token 的记录)
- 积分覆盖(Token 数据覆盖了多少比例的实际花销)
- 单次响应耗时(每次 API 请求,带 P50 / P90)
- 模型耗时占比(用户在回合里等待的时间,有多少花在模型上)
图表
- 每日趋势三轴对比(柱=积分,线=Token / 请求数)
- Token 趋势(逐日堆叠:缓存读 + 未命中输入 + 输出,合计=总 Token)
- 模型 × 时段热力图、各模型每日堆叠
- 各模型响应耗时(横向条形,P50 与 P90 对照,差距即长尾程度)
表格
- Token 消耗 Top 10 回合(按 Token 排序,带步骤数与回合时长)
- 工具 Token 消耗排行
- 模型 / 客户端 / 每日明细,均带 Token 与「Token/积分」列
- 模型数据表额外带「响应 P50」「首字延迟」「输出速度」
- Session 消耗:按会话聚合,带会话标题
报告与导出
- 自动生成分析报告与优化建议
- 导出 Markdown / CSV(CSV 带 BOM,Excel 打开不乱码),可打印或另存为 PDF
- Node.js 18+(脚本用到
util.parseArgs) - Windows(路径与 bat 脚本按
%LOCALAPPDATA%/%USERPROFILE%处理) - 看板需要联网加载 CDN 的
xlsx和chart.js
- 双击
打开看板.bat—— 启动本地服务并自动打开看板(保持那个命令行窗口开着) - 看板顶部点 「⚡ 一键同步」 —— 拉官方账单与账号积分 + 重扫本地会话,完成后自动重载
首次同步会拉取最近 1 年的账单(约 13 个 30 天窗口,并发拉取约 8 秒),之后每次只拉最近 7 天增量(几秒)。要补更早的账单,用 --official-days 1095 跑一次即可。
另外两种情形:
| 想干什么 | 怎么做 |
|---|---|
| 不常驻服务,只同步一次 | 双击 同步Token.bat:一次性全量同步,跑完直接打开看板 |
| 只看已有数据、不更新 | 直接双击 workbuddy-token.html,零进程 |
看板固定用 file:// 打开:双击 workbuddy-token.html,或用 打开看板.bat(它会顺带起本地服务,并打开同一个地址)。
为什么要统一:浏览器的本地存储(IndexedDB / localStorage)按地址隔离,
file://与http://127.0.0.1:8099是两个互不相通的仓库。混着用的话, 「📂 历史」里的快照会分裂成互相看不见的两份,换个入口就"看不到历史"了。 所以服务只当后台接口用(页面会自动探测它的端口),不再由它托管页面。
| 按钮 | 作用 | 需要服务 |
|---|---|---|
| ⚡ 一键同步 | 积分 + Token 一次跑完(串行:先积分后 Token,失败即停) | 积分部分需要 |
| ⋯ 更多 ▸ 💰 同步积分 | 只拉官方账单与各账号积分余额 | 是 |
| ⋯ 更多 ▸ 🔄 同步 Token | 只重扫本地会话记录,约 2 秒 | 否 |
| ⋯ 更多 ▸ 📁 连接本地会话 | 离线时授权会话目录(服务模式下只作状态提示) | 否 |
| ⋯ 更多 ▸ 🗑 一键清空数据 | 删掉项目里的数据文件 + 浏览器本地快照,回到初始状态(连续确认两次) | 删文件需要 |
| ⋯ 更多 ▸ 其余 | 追加 Excel 数据、手动快照、历史、打印 / PDF、导出 Markdown / CSV | — |
「一键清空数据」清的是看板展示的数据,不是你的原始记录:switch-backups/ 账号备份、手工导入的 Excel 账单,以及 ~/.workbuddy / ~/.codebuddy 下的会话 jsonl 都不动。清完重新同步即可再生成。没有本地服务时只能清浏览器这一半,会明确提示。
「同步积分」与「同步 Token」互不覆盖:只同步积分时,本地 Token 数据原样保留;只同步 Token 时,已有的账单与账号余额也不会被抹掉。各自只更新自己那一半。
要用同步按钮,先让服务在跑:双击 打开看板.bat,保持那个命令行窗口开着。关掉即停止服务——看板照常能看,只是同步按钮会提示「本地服务未启动」。
为什么同步必须靠服务:官方接口的跨域预检会被网关返回 401 且不带 CORS 头, 而且浏览器禁止 JS 设置
Origin/Referer,伪装不了官方 Web 端。所以拉数据必须由 Node 侧代劳。
手工导入的通道仍然保留:把积分账单 Excel 拖进去同样有效,两种来源按
RequestID合并,同名记录以官方(更新)为准。
关键点:账单里的 RequestID 对应会话记录里的 providerData.conversationRequestId,不是 messageId。
这是「回合级」ID。一次用户提问 = 一个回合,但 agent 会在其中串行发起多次 API 请求(实测平均 7~8 次,最多上百次)。所以:
一行积分 == 一个回合 == 该回合全部 API 请求的 Token 之和
按 messageId 去匹配是行不通的——那个粒度细 7 倍多,绝大多数都对不上。
total_tokens = input_tokens + output_tokens 恒成立
cache_read_input_tokens <= input_tokens 恒成立
cache_read_input_tokens 是 input_tokens 的子集(命中缓存的那部分),不是额外增量,两者不可相加。正确算法:
- 总输入 =
input_tokens - 未命中缓存 =
input_tokens - cache_read_input_tokens - 缓存命中率 =
cache_read_input_tokens / input_tokens
另外,因为每次请求都要重发全量上下文,同一回合内 input_tokens 会逐次累加——这是 API 的真实计费方式,不是重复计数。
会话记录里没有现成的耗时字段(responseTimeMs 是搜索工具自己的耗时,turn-metrics.durationMs 是整个回合的时长)。但记录是按 agent 循环顺序写入的,可以据此推算:
用户提交 ──(等待起点)──> function_call @ts ← 模型响应完成
└─ 工具执行 ──> function_call_result @ts
└─(等待起点)──> function_call @ts
function_call 的时间戳是模型响应完成时刻,function_call_result 与用户消息是新的等待起点。两者相减,得到的就是纯模型侧耗时——工具执行时间被干净地排除在外。
| 口径 | 含义 | 看哪里 |
|---|---|---|
| 单次响应耗时 | 一次 API 请求的端到端耗时,已排除工具执行,含网络往返与排队 | 模型表的「响应 P50」、响应耗时图表 |
| 回合级等待 | 用户从提交到拿到最终答复的完整时间,其中模型占比由「模型耗时占比」KPI 给出 | 明细表的「时长」列 |
「单次响应 7 秒」不等于「提问 7 秒就答完」。 一次提问(一个回合)平均会触发 7 次以上的 API 请求,中间还夹着工具执行,所以用户实际等待要长得多。两个指标都给了,别拿错。
输出 token 是耗时的主要驱动因素,但直接算「平均耗时 ÷ 平均输出」会把首字延迟也摊进去。所以看板对每个模型做一次分箱回归:
耗时 ≈ 首字延迟 + 输出token ÷ 输出速度
按输出 token 排序分箱、每箱取中位数后再做最小二乘(单次请求波动大,直接对原始点拟合会被离群点带偏)。样本不足 60 条时留空,显示 —。
- 时间戳是记录写入时刻,所以耗时含网络往返与服务端排队,换网络环境数值会变。这既是缺点也是优点——它反映的是真实体验。
- 一个回合内如果换了模型,请求会归到该回合消耗最大的那个模型名下。实测这种混合回合只占千分之几,误差可忽略。
- 单次耗时 <0.5 秒或 >1 小时视为异常(记录不完整或会话中断残留)已剔除,所以样本数会略少于总请求数。
--light模式不产出请求级耗时(明细随步骤一起被省略),此时响应时间列显示—,但回合级的lat合计仍然保留。- 模型耗时占比的分布很宽:纯读文件的回合接近 100%,跑长命令或等外部接口的回合可以低到 30% 以下。看中位数,别当成恒定值。
脚本会自己找到凭证并拉数据,全程不需要你导出任何文件。
WorkBuddy 桌面端把每次登录的凭证写成快照文件,放在:
%LOCALAPPDATA%\CodeBuddyExtension\Data\Public\auth\*.info
这些快照不会被删除,所以你在这台机器上登录过的每个账号都在里面。脚本按 uid 去重、每个账号取最新的一份,就得到了全部账号——不需要 OAuth 扫码,也不需要手动录 token。
| 数据 | 接口 | 用途 |
|---|---|---|
| 积分账单 | /billing/meter/get-user-request-usage |
替代手动导出的 Excel |
| 积分余额 | /billing/meter/get-user-resource-summary |
账号还剩多少积分 |
| 套餐明细 | …-paid-packages / …-free-packages |
每个包的剩余量与到期时间 |
| 签到 | /v2/billing/meter/checkin-activity-status、/daily-checkin |
签到日历与签到动作 |
| 猫猫旅行 | /activity/growth/buddy/travel/* |
旅行状态与领奖 |
账单里的 requestId 就是会话记录里的 providerData.conversationRequestId(回合级 ID),所以两端天然对得上,不需要额外映射。
- 查询窗口超过约 31 天会直接返回空——脚本按 30 天自动切分时间段。
- 单次最多返回 3000 条,且是从窗口起点往新取——天真地拉一次会静默丢掉最新数据。 脚本按「取回本页最新时间 → 作为下一轮起点」推进,直到不再增长。
- 跨日记录的积分会「尾部结算」——同一条记录在当天窗口里取值偏小,窗口延伸到次日才是饱和值。 所以「今日消耗」在当天可能略偏小,之后同步会自动补正;「昨日消耗」已完成结算,是稳定值。
官方同步全程可失败:账号找不到、token 失效、接口变更都只打印警告并继续,本地扫描与看板产出不受影响。失败时看板仍可用手工导入的 Excel。
窗口是并发拉的:切分出来的十几个窗口互不依赖,脚本在同一账号内按 4 路并发拉取(账号之间仍串行,在飞的请求数始终不超过 4)。首次同步拉一年历史从约 18 秒降到约 8 秒。某个窗口失败只跳过它并记进错误列表,不会中断该账号的其余窗口。
多台电脑各用一份 buddyToken 时,数据天然互相看不见。开启云同步后,每台机器把自己的数据推到云端一个「传阅箱」,再把别人推的拉回来合进本地——看板于是看到多端汇总,并且可以按机器筛选(筛选栏多一组「机器」chip,会话表多一列机器)。
云端不是新的数据源,只是机器之间的中转站:本地 token-usage-data.js 仍是唯一数据源,看板读的还是那一个文件、位置和加载方式都不变。
看板不直连云端:file:// 页面里放密钥等于公开,所以 Supabase 的 anonKey 只存在本机 sync-config.json(已 gitignore),同步全在 Node 侧完成。
-
到 supabase.com 注册并建一个项目(建议用独立项目,不要和别的业务共用)。
-
进项目的 SQL Editor,把仓库根目录的
supabase-cloud-sync.sql整段粘贴并执行(可重复执行,不会丢数据)。 执行完在 Table Editor 里应该能看到 6 张bt_开头的表——看不到就是没执行成功,别急着往下走。 -
在 Project Settings → API 里复制
Project URL与anon publickey。 -
启动一次服务(双击
打开看板.bat)。项目目录里会自动出现sync-config.json模板——不用自己新建。 -
打开它,填上
url、anonKey、machineName,把enabled改成true,保存:{ "enabled": true, "url": "https://xxxx.supabase.co", "anonKey": "eyJhbGci...", "proxy": "http://127.0.0.1:10235", "machineName": "台式机" }
把项目拷过去(或 git clone)之后,只需要:
- 删掉
sync-state.json(那是上一台机器的身份文件)。不删也行——程序发现主机名对不上会自动换新身份并打提示。 - 启动服务,同样会自动生成
sync-config.json模板。 - 填上
url与anonKey(和第一台相同)、machineName(取个不同的名字)、proxy(这台机器自己的,拿不准就先留空),enabled改成true。
不需要再执行一遍 SQL——建表是一次性的,所有机器连的是同一个项目。
配置改完保存即可,服务每 30 秒重读一次配置,不必重启。之后按 intervalMinutes(默认 30 分钟)后台自动同步;也可以手动 node cloud-sync.js 跑一轮、--dry-run 只看将要传输的行数。
新机器第一轮同步会把云端已有的数据全部拉回来,所以打开看板立刻就能看到其它机器的记录。
- 只增不减:合并只做「缺失才加 / 更优才覆盖」,任何一步都不会让历史数据变少。
- 上传内容原样、不脱敏:本地回合的 token 统计与每步明细、会话标题、项目路径、会话 UUID、账号 uid/昵称、余额快照都会传上去。介意就不要开。
- 「🗑 一键清空数据」只清本地,云端数据保留——下次同步会把云端数据拉回来,这是有意为之(避免一台机器误删掉其他机器贡献的数据)。
- 网络(最容易卡住的一步):
*.supabase.co走的是 Cloudflare,国内直连常在 TLS 阶段被重置(表现为ECONNRESET/fetch failed)——而api.supabase.com是通的,容易让人误判成 key 或项目有问题。 更迷惑的是:本机的系统代理只有浏览器类应用会走,Node 不会。所以要在proxy字段里显式填代理地址(如http://127.0.0.1:10235,具体端口看你的代理软件),cloud-sync 会带着代理环境变量重跑自己一次。 另外 Node 的NODE_USE_ENV_PROXY只在进程启动时生效,这就是这里非要 re-exec / 起子进程、而不能在运行时设process.env的原因。每台机器的代理端口可能不同,各自填各自的。填了仍不通的话,把url换成自建反代地址也一样可行。 - 同步失败只打警告,本地数据产出与看板一切照常;失败后会等一个完整周期再重试,不会反复刷日志。
- 想关掉:把
enabled改成false,或直接删掉sync-config.json,项目行为与纯本地完全一致。已经传到云端的行要去 Supabase 后台自己删。
脚本扫描本地会话记录(只读;原始 jsonl 始终不外传——即使开了上一节的云同步,传的也只是统计产物,不含 jsonl 正文与凭证):
| 客户端 | 目录 |
|---|---|
| WorkBuddy 桌面端 | %USERPROFILE%\.workbuddy\projects\<工作区>\*.jsonl |
| CodeBuddy CLI | %USERPROFILE%\.codebuddy\projects\<项目>\*.jsonl |
每个 .jsonl 是一个会话,一条带 message.usage 的记录 = 一次 API 请求。
积分账单与账号余额来自官方接口,凭证读自本机登录态:
| 数据 | 来源 |
|---|---|
| 登录凭证 | %LOCALAPPDATA%\CodeBuddyExtension\Data\Public\auth\*.info |
| 积分账单 / 余额 | https://www.workbuddy.cn/billing/meter/* |
| 签到 / 猫猫旅行 | https://www.codebuddy.cn/v2/billing/meter/*、/activity/growth/buddy/travel/* |
| 账号归属 | ~/.workbuddy/workbuddy.db 的 sessions.user_id(只读) |
| 429 台账 | ~/.workbuddy/logs、~/.codebuddy/logs(只读,最近 2 天) |
注意账单在
workbuddy.cn、积分活动在codebuddy.cn,两个域不能混用。
提问正文不会被采集:账单接口的响应里其实带了 input(你提问的原文),脚本按白名单只提取 requestId / credit / model / client / requestTime 五个字段,正文在解析时即被丢弃,不会进入内存结构,更不会写盘。
账号凭证不会写盘:accessToken / refreshToken 只在内存中使用,用完即弃。
token-usage-data.js 里包含真实的会话 UUID、回合 ID 和完整的本机项目路径(例如 C:\Users\<你的用户名>\...),启用官方同步后还包括账号 uid 与昵称(昵称可能是手机号)。这些都属于个人使用痕迹,仓库里的 .gitignore 已默认排除它们。
所以你 clone 下来后打开看板会看到空看板——这是正常的,先同步一次就有数据了:双击 同步Token.bat,或双击 打开看板.bat 后点看板顶部的「⚡ 一键同步」。
日常用不到这一节。 看板上的按钮就是这些命令的封装:「⚡ 一键同步」=
--emit-js、「💰 同步积分」=--only=credits、「🔄 同步 Token」=--only=tokens、账号卡片上的「🔄 刷新」=--only=credits --uid。 只有本地服务起不来要排障、或要写自动化 / 定时任务时,才需要直接敲命令。
# 常用
node token-usage-report.js --emit-js # 本机全量扫描 + 同步官方账单(官方窗口默认 7 天)
node token-usage-report.js --emit-js --official-days 30 # 官方数据取最近 30 天(拉取更慢)
node token-usage-report.js --emit-js --light # 省略每步明细,产物约小一半
node token-usage-report.js --emit-js --no-merge # 关闭增量合并,纯全量覆盖
node token-usage-report.js --emit-js --no-official # 完全跳过官方同步(纯离线)
# 只刷新一半
node token-usage-report.js --emit-js --only=credits # 只刷官方账单与积分余额
node token-usage-report.js --emit-js --only=tokens # 只扫本地会话
# 只刷一个账号(看板卡片上的「🔄 刷新」就是这条)
node token-usage-report.js --emit-js --only=credits --uid <账号uid>
# 时间与输出
node token-usage-report.js --days 7 # 只统计最近 7 天
node token-usage-report.js --since 2026-09-01 # 起始日期
node token-usage-report.js -o D:\out # 指定输出目录
# 清空所有数据(不可撤销,看板上的「🗑 一键清空数据」就是这条 + 清浏览器快照)
node token-usage-report.js --reset
# 云同步(多端汇总,需先在 sync-config.json 里配好 Supabase)
node cloud-sync.js # 同步一轮:先推本机增量,再拉别人的增量合并进本地
node cloud-sync.js --dry-run # 只统计将要推 / 拉的行数,不发写请求、不落盘
node cloud-sync.js --push # 只推不拉(--pull 则只拉不推)--only=credits 是部分更新:它读取已有数据文件,只替换其中的官方字段,本地 Token 部分原样保留(也不会重写 CSV 与汇总报告)。所以第一次必须先跑一次全量,之后才能只刷积分。
再加 --uid <账号uid> 就是只刷该账号:账单按 RequestID 合并、余额按 uid 覆盖,其余账号的账单与余额原样保留。uid 写在账号卡片名字后的标签里(平时只显示前 8 位,鼠标悬停可见完整值);它只能与 --only=credits 一起用。
--reset 是清空而不是重新生成:删掉 token-usage-data.js、明细 CSV、汇总 Markdown 与余额 / 签到历史,回到「从未同步过」的状态。它只按固定文件名白名单删除,不做通配符匹配——账号备份 switch-backups/、云同步配置 sync-config.json 与游标 sync-state.json、手工导入的 Excel 以及 ~/.workbuddy、~/.codebuddy 下的原始 jsonl 都不受影响。浏览器里的本地快照存在页面侧,只能用看板菜单里的「🗑 一键清空数据」一并清掉。
云同步是旁挂的一层,不在
token-usage-report.js里:它只读写脚本已生成好的数据文件,因此--reset、--only=*这些命令的行为都不受它影响。反过来说,--reset清空本地后,下一次云同步会把云端数据拉回来——这是有意为之,避免一台机器误删掉其他机器贡献的数据。
server.js 只提供 API(不托管页面),同一时间只允许一次同步(并发返回 409):
| 端点 | 说明 |
|---|---|
POST /api/sync[/credits|/tokens] |
跑同步脚本;不带后缀为全量。/credits 可带 body {"uid":"…"},只刷该账号 |
POST /api/checkin、POST /api/travel |
签到、派猫猫(可带 {"uid":"…"} 只处理一个账号) |
GET /api/checkin-status |
签到 + 旅行状态(只读) |
GET /api/limits |
429 限流台账(只读) |
POST /api/switch |
切换账号,body 为 {"uid":"…","app":"workbuddy-desktop"|"codebuddy-cli","restart":true} |
GET/POST /api/auto |
自动任务配置:GET 返回完整配置(四个开关 + 周期 + 抖动)与各任务的上次尝试/成功/失败时间及结果摘要;POST 合并开关(如 {"checkin":true}),刚打开的开关会立即执行一次(周期与抖动只从 auto-config.json 读,不接受远程改) |
POST /api/reset |
清空项目里的数据文件(看板「🗑 一键清空数据」走这条)。与同步共用同一把锁,并发返回 409 |
GET /api/status |
同步状态、扫描目录、可切换账号;另含 cloud 字段(云同步是否启用、上次结果、本机标识、周期),排障用 |
服务默认监听 0.0.0.0,同网段任何设备都能调写接口(同步 / 签到 / 切换账号 / 清空),浏览器里的任意网页也能跨域 POST 过来。要给写接口加一道门:
node server.js --auth-token 一串随机字符
# 或:set BUDDYTOKEN_TOKEN=一串随机字符 && node server.js
# 或在项目根目录放 auth-token.txt(一行,适合写进 .bat)设了令牌后,所有 POST /api/* 必须带 X-Auth-Token 头,GET 只读接口不拦(看板首屏要探测 /api/status)。看板里在「⋯ 更多 → 🔑 访问令牌」填同一个值即可——令牌只存在当前浏览器的 localStorage,不写盘、不随快照导出、不出现在 URL 里。不设令牌则维持原行为,升级不会打断现有用法。
端口也可以用 --port 8100 固定(默认从 8099 起自动往后找空位)。注意 Windows 允许 0.0.0.0:8099 与 127.0.0.1:8099 同时监听,起第二个实例时若没注意会出现「请求打到哪个进程全看运气」,固定端口并让冲突直接报错更省事。
token-usage-data.js 的两半都是增量追加写入的,只增不减:
本地 Token 部分:生成前读取已有的数据文件,把历次同步过、但本次本地已扫不到的回合原样保留,这样即使本地会话记录被清理,历史 Token 数据也不会凭空消失。同名回合以本次扫描为准(正在进行的会话会在后续同步里被补齐)。
官方积分部分:账单按 RequestID 去重合并,本次拉到的覆盖同 ID 的旧行,窗口外的历史行原样保留。账号下标表 uids 会一并重排(本次账号在前、历史账号追加在后),否则历史行的账号归属会指错人。余额 acct 是当前快照而非累加量,直接取本次结果。
多端云同步部分(可选):规则同样是只增不减——本地已有的回合一律保留本地(本机扫的是原始 jsonl,比云端副本权威),本地没有的才收下;账单积分取两者较大值、机器归属只补空;账号余额取官方 updatedAt 更新的一条,但 login(本机登录态)永远保留本机值。远端账单行的账号是 uid 文本,合并时会翻译成本机的 uids 下标(本机没有就追加),沿用远端下标会让历史行归属整体错位。另外余额历史合并后要回写 credit-history.json,否则下一轮刷积分会把刚拉回来的远端历史抹掉。
为什么这里必须合并:官方账单接口只能按窗口拉(默认近 7 天)。早先的实现是整体替换
data.bill,于是每同步一次就把窗口外的历史抹掉一次——同步过近 7 天后,更早的账单就永久没了。
想丢弃历史重来,加 --no-merge(对本地回合与官方账单同时生效);想连数据文件一起清掉、回到初始状态,用 --reset。
credit-history.json 记录每次同步时各账号的余额(只在余额变化时追加,同值不重复记),看板据此显示「今日 / 昨日消耗」里的余额对照。
为什么不用它反推「每日获取」:remaining = total − used,而套餐的 used 会周期重置——重置时余额账面回升,看起来就像「获取」(实测出现过 7 分钟内"涨"201 分的情况)。官方又没有「获取」明细接口,无从把重置拆出来。所以看板不展示「每日获取」这个指标。
WorkBuddy / CodeBuddy 生态里的一些互补工具(与本项目不重叠,一并列出方便你按需取用):
| 项目 | 干什么 |
|---|---|
| changexbc/workbuddy-switch | 账号切换桌面 App,带积分到期监控与自动签到 |
| Sliverkiss/workbuddy2api | 把订阅转成 OpenAI 兼容 API,支持多账号轮转 |
| jlcodes99/cockpit-tools | 通用 AI IDE 账号与配额管理 |
它们帮你多拿积分,本项目帮你看清积分花在哪。
| 文件 | 说明 |
|---|---|
workbuddy-token.html |
单文件看板,双击即用 |
打开看板.bat |
推荐入口:起本地服务并打开看板(file://),之后点「⚡ 一键同步」即可拉最新数据 |
server.js |
本地 HTTP 服务:只提供 API,不托管页面 |
token-usage-report.js |
零依赖 Node 脚本,扫描会话记录并生成数据 |
workbuddy-api.js |
官方接口封装:账号发现与切换、账单拉取、积分余额、签到、猫猫旅行、账号归属 |
rate-limits.js |
429 限流台账:扫本机日志还原恢复时刻,按 sessionId → 模型 归因 |
cloud-sync.js |
多端云同步(可选):把本机数据推给云端、把其它机器的拉回来合并;也能当命令行单独跑 |
supabase-cloud-sync.sql |
云同步的建表 SQL,在 Supabase 的 SQL Editor 里整段执行一次 |
同步Token.bat |
一键全量同步:扫本地会话 + 拉官方账单与积分,生成数据后打开看板(不必先起服务) |
以下为脚本产物,不入库(.gitignore 已排除):
| 文件 | 内容 |
|---|---|
token-usage-data.js |
看板数据(含真实会话 UUID、账号 uid) |
token-usage-detail.csv |
逐条请求明细 |
token-usage-summary.md |
汇总报告 |
checkin-history.json |
签到日期本地累积(签到日历用) |
credit-history.json |
余额观察点(仅供余额对照) |
auto-config.json |
自动任务配置:四个开关 + 各任务周期(分钟)+ 抖动幅度,手改无需重启服务 |
sync-config.json |
云同步配置:开关、Supabase 地址与 anonKey、机器名、周期(不在清空白名单内) |
sync-state.json |
云同步游标与本机 machineId(不在清空白名单内) |
switch-backups/ |
账号切换前的凭证备份(含 token) |
「🗑 一键清空数据」/
--reset删的是上表中除switch-backups/、sync-config.json、sync-state.json以外的产物:账号凭证备份与云同步配置都留着(前者删了没法回滚切换,后者是配置不是数据产物),原始会话记录也不碰。
产物落在哪:以上文件一律写在项目目录下,脚本不使用系统临时目录(全文没有
os.tmpdir(),也没有别的临时文件写入)。 唯一一处跨目录写入是「切换账号」——它会覆盖%LOCALAPPDATA%\CodeBuddyExtension\Data\Public\auth\下对应应用的登录文件, 覆盖前先把原文件备份进switch-backups/。另外看板的「本地快照」存在浏览器自己的 IndexedDB 里,跟随浏览器 profile(在系统盘),删浏览器数据即消失。
打开看板是空的?
数据文件不入库,clone 下来自然是空的。先同步一次生成数据:双击 同步Token.bat,或双击 打开看板.bat 后点顶部「⚡ 一键同步」。
点「⚡ 一键同步」提示需要本地服务?
积分部分要调官方接口,而浏览器的跨域预检过不了网关,必须由 Node 侧代劳。用 打开看板.bat 启动服务,并保持命令行窗口开着。离线状态下「一键同步」会退化成只重扫 Token。
为什么积分覆盖不是 100%? 积分账单是账号级计费口径,覆盖所有设备;本地 jsonl 只是本机留痕。同一账号在多台设备或不同入口使用时,账单里会有一部分记录在本机找不到对应会话。这是数据可得性的正常现象,不是错误。
「今日消耗」为什么和官网对不上? 当天数值会略偏小——官方对跨日记录做尾部结算,同一条记录在当天窗口里取值偏小、窗口延伸到次日才饱和。下一次同步会自动补正。「昨日消耗」已完成结算,是稳定值。
「预计可用天数」是怎么算的?准不准? 按最近三周(D-21 ~ D-1,不含今天——今天还在结算,计进去会把日均压低)的账单消耗算日均,再用余额除。两个口径要留意:样本不满三周就按实际天数当分母(新启用的账号只有几天数据,拿 21 天当分母会严重低估日均);积分到期即清零,所以结果再与「最近到期」取小——按节奏算能撑 41 天但 22 天后就过期时,显示的是「到期前用不完」而不是 41 天。
消耗节奏会随账号切换而突变(各账号并非稳定并行使用),所以这是量级估算,别当精确预测。近期几乎没有消耗、或账单样本不足 3 天时显示「样本不足」,不硬算。
为什么「历史」里的快照找不到了?
大概率是打开方式混用了。浏览器存储按地址隔离,file:// 和 http://127.0.0.1:8099 是两套互不相通的仓库。统一用 file:// 打开(两个 bat 现在都这么做)。
缓存命中了是不是就不花钱?
不是。cache_read_input_tokens 是 input_tokens 的子集,命中缓存的 token 计价更低但通常不为零。看板的「缓存命中率」和「每积分 Token」要一起看。
单次响应 7 秒,为什么实际等了一分钟? 那是两个口径。7 秒是一次 API 请求的模型侧耗时;一次提问(一个回合)平均触发 7 次以上请求,还夹着工具执行。回合级等待看明细表的「时长」列。
自动切换账号会不会把我的账号切来切去?
不会乱切。只在有账号积分将在 14 天内到期(默认阈值,switchHorizonDays 可配)且还没用完时才动作,把桌面端与 CLI 切到那个「再不用就浪费」的账号;目标账号已经是当前登录账号、或没有紧急到期的积分时,什么都不做。每次切换前都会备份登录态到 switch-backups/。
会把我本地的代码或提问上传到哪儿吗? 不会。脚本纯本地读写文件,只有拉取官方账单/余额/签到时会访问官方域名;账单响应里的提问正文在解析时即被丢弃。凭证只在内存使用,不写盘。
README 里为什么没有「每日获取多少积分」? 官方没有「获取」明细接口,而套餐额度的周期重置会污染余额差值(见余额快照),所以这个指标做不到可信,看板不提供。
浏览器在 file:// 协议下无法用 fetch 读取同目录文件(会被 CORS 拦),但 <script> 标签可以跨同目录加载。所以脚本产出的是 window.__TOKEN_DATA__ = {...} 形式的 JS 文件,看板用动态注入 <script> 的方式加载,并带时间戳绕开缓存。
这样双击 HTML 就能用,不需要起本地服务器。
token-usage-report.js、server.js、workbuddy-api.js 只用 Node 标准库,npm install 是不需要的。看板里的 xlsx(Excel 导入)和 chart.js(图表)从 CDN 加载。
buddyToken/
├── workbuddy-token.html # 看板(单文件,UI/逻辑/样式全内联)
├── server.js # 本地服务:API only
├── token-usage-report.js # 数据生成主脚本
├── workbuddy-api.js # 官方接口封装
├── rate-limits.js # 429 台账
├── 打开看板.bat / 同步Token.bat
└── (产物,不入库)token-usage-data.js、*.csv、*.md、*-history.json
MIT © 2026 CaoDonald