8000 feat(release): faster report opening, self-recovering PWA, local OTEL relay and ledger retention for 0.12.1 by InfinityPacer · Pull Request #49 · InfinityPacer/meterleaf · GitHub
[go: up one dir, main page]

Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ jobs:
- uses: actions/checkout@v7
- uses: oven-sh/setup-bun@v2
with:
bun-version: 1.4.2
bun-version: 1.4.4
- run: bun install --frozen-lockfile
- run: bun test tests
- uses: actions/setup-python@v6
Expand All @@ -29,7 +29,7 @@ jobs:
- uses: actions/checkout@v7
- uses: oven-sh/setup-bun@v2
with:
bun-version: 1.4.2
bun-version: 1.4.4
- run: bun install --frozen-lockfile
- run: bun run build
- name: Validate Compose
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ jobs:
fetch-depth: 0
- uses: oven-sh/setup-bun@v2
with:
bun-version: 1.4.2
bun-version: 1.4.4
- name: Validate version and extract notes
id: release
run: bun scripts/release.ts
Expand Down
2 changes: 1 addition & 1 deletion AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ Meterleaf 是独立 AI 用量账本,只读采集上游用量并在本地计价

## 开发与验证命令

使用 Bun 1.4.2 或更新版本,依赖变更提交 `bun.lock`。
使用 Bun 1.4.4 或更新版本,依赖变更提交 `bun.lock`。

- `bun install --frozen-lockfile`:按锁文件安装依赖。
- `bun run dev:demo`:启动可辨识的演示界面。
Expand Down
11 changes: 11 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,17 @@

## [未发布]

## [0.12.1] - 2026-10-23

- 镜像与构建改用 Bun 1.4.4,包含其 fetch 与 TLS 的安全修复。从源码构建采集器同样需要 Bun 1.4.4 或更新版本。
- 网络切换或公网地址变更后打开 PWA 不再长时间白屏。页面等待网络超过 8 秒时显示连不上的提示,提示页自动重试,连上后直接打开账本。
- 服务端不再保留旧价格表的估值和已处理的变更记录,账本体积会明显变小,金额不受影响。旧估值只在维护窗口内删除,不会产生新的报表变更;变更记录只清理报表索引和累计索引都已消费的部分。本版改动数据库结构,升级前先停止服务并备份完整数据目录。需要立即回收磁盘空间时可参考[部署指南](docs/deployment.md#升级与备份恢复)。
- 采集器新增本机 OTEL 中转,Claude Code 的请求归属日志不再需要直接连服务端。Claude Code 把日志发到 `http://127.0.0.1:4319/v1/logs`,常驻进程写入本机待发送队列,再由每分钟的同步和用量一起推送。服务端或网络暂时不可用时记录留在本机,恢复后自动补发。`install-launchd` 会同时注册同步和 OTEL 中继两个后台任务,配置见[本机采集器](docs/collector.md#开启-otel-导出)。
- 直连 `POST /api/otel/v1/logs` 并配置 `otelHeadersHelper` 的旧方式仍然可用。升级采集器后重新执行一次 `install-launchd`,中继任务才会注册。
- 服务端只保留最近 30 天的请求归属记录,OTEL 确定的账户改为写进用量事实本身。采集器因元数据升级、模型映射变化或文件重读而补推旧用量时,账户不会再退回登录时间线推断的那个。服务端账本新增一个迁移修订用来建索引并回填已有归属,升级前先停止服务并备份完整数据目录。
- 服务端接口未变,0.12.0 及以上版本能直接接收本版采集器的数据。服务端版本较早时 OTEL 记录会留在待发送队列,升级服务端后补发。
- 打开页面时报表更快出现。总览和各账户近 7 天微图在同一次打开里发出的报表查询共用账户与额度读取,账本没有新提交时不再重复扫描额度历史。首屏报表已按最新提交计算时,页面也不再重读一遍。

## [0.12.0] - 2026-10-23

- 一台 Mac 上的多个 Claude 订阅账户可以分别记账。采集器新增 `claude-profiles`,登记其他账户的 `CLAUDE_CONFIG_DIR` 并读取各自的账户、套餐与额度;Claude Code 开启 OpenTelemetry 日志导出后,服务端按每次请求的 `request_id` 把用量归到实际账户,不再一律记到默认账户。用法见[本机采集器](docs/collector.md#多个-claude-账户)。
Expand Down
4 changes: 2 additions & 2 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
FROM oven/bun:1.4.2 AS build
FROM oven/bun:1.4.4 AS build
WORKDIR /app
COPY package.json bun.lock ./
RUN bun install --frozen-lockfile
Expand All @@ -10,7 +10,7 @@ COPY tests ./tests
COPY scripts ./scripts
RUN bun run build

FROM oven/bun:1.4.2 AS runtime
FROM oven/bun:1.4.4 AS runtime
WORKDIR /app
COPY LICENSE THIRD_PARTY_NOTICES.md ./
COPY package.json bun.lock ./
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ bun run build:collector
- [贡献指南](AGENTS.md):目录结构、代码规范、测试与提交要求。
- [版本与发布](docs/releasing.md):版本递增、双架构镜像及 Release 流程。

本地演示无需上游凭据,需要 Bun 1.4.2 或更新版本:
本地演示无需上游凭据,需要 Bun 1.4.4 或更新版本:

```sh
bun install --frozen-lockfile
Expand Down
6 changes: 3 additions & 3 deletions bun.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion docs/codex-collector.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ Codex 本地采集器只读扫描 `$CODEX_HOME/sessions` 和 `$CODEX_HOME/archiv

## 安装与连接

从仓库构建,需要 Bun 1.4.2 或更新版本:
从仓库构建,需要 Bun 1.4.4 或更新版本:

```sh
bun install --frozen-lockfile
Expand Down
39 changes: 31 additions & 8 deletions docs/collector.md
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,8 @@ Claude Code 的 OpenTelemetry 日志能补上这个信息。开启导出后,

Token 用量仍由采集器读取会话记录,因为 OTEL 没有 1 小时与 5 分钟缓存写入的拆分、推理 Tokens 和 web search 次数等计价需要的字段。OTEL 只回答这次请求属于哪个账户。归属优先级从高到低是采集器的模型映射、OTEL 给出的请求账户、登录时间线。模型映射是用户明确指定的,服务端不会覆盖。

服务端只保留最近 30 天的请求归属记录。已经被 OTEL 确定的账户会写进用量事实本身,所以采集器之后重发旧用量(元数据升级、模型映射变化或文件重读)不会把账户改回登录时间线。

### 登记额外账户

先为每个额外账户登记配置目录,可以同时指定该账户的状态栏额度缓存。
Expand All @@ -80,7 +82,27 @@ meterleaf-collector claude-profiles \

### 开启 OTEL 导出

在 `~/.claude/settings.json` 中加上下面的设置,地址换成这台电脑访问 Meterleaf 的地址。`otelHeadersHelper` 让 Claude Code 每次导出前向采集器取一次写入密钥,密钥只在本机传递。
推荐让 Claude Code 把日志发给这台电脑上的采集器中转。`install-launchd` 会同时启动一个只监听 `127.0.0.1:4319` 的常驻进程,它把日志写进采集器的本机待发送队列,每分钟的同步再把这些记录和用量一起推送到 Meterleaf。服务端或网络暂时不可用时记录留在本机,恢复后自动补发。队列最多保留最近 5 万条,长期连不上时更早的记录会被丢弃,这些请求退回按登录时间线归属,日志里会有提示。

在 `~/.claude/settings.json` 中加上下面的设置。不需要 `otelHeadersHelper`,中转只接受本机回环地址上的请求,也不再单独传递写入密钥。

```json
{
"env": {
"CLAUDE_CODE_ENABLE_TELEMETRY": "1",
"OTEL_LOGS_EXPORTER": "otlp",
"OTEL_METRICS_EXPORTER": "none",
"OTEL_EXPORTER_OTLP_LOGS_PROTOCOL": "http/json",
"OTEL_EXPORTER_OTLP_LOGS_ENDPOINT": "http://127.0.0.1:4319/v1/logs"
}
}
```

修改设置后重新打开 Claude Code 会话才会生效。`meterleaf-collector status` 的待发送一行会列出 `OTEL` 数量,可以确认记录已经进入队列。后台任务未安装时,也可以手动运行 `meterleaf-collector otel-relay` 启动同一个入口。

端口与其他 OTLP 工具冲突时,在采集器 `config.json` 里加入 `"otelRelay": { "port": 4320 }`,端口范围是 1024 到 65535。保存后重新执行一次 `meterleaf-collector install-launchd`,让后台任务按新端口重启;同时把 `settings.json` 里的地址改成同一个端口。

希望 Claude Code 直接连服务端时,旧配置仍然可用。把地址换成这台电脑访问 Meterleaf 的地址,并保留 `otelHeadersHelper`。

```json
{
Expand All @@ -95,15 +117,15 @@ meterleaf-collector claude-profiles \
}
```

`meterleaf-collector otel-headers` 从采集器配置读取写入密钥,向标准输出打印一行 `{"Authorization":"Bearer ..."}`,不输出其他内容。没有初始化时命令报错并以非 0 退出,Claude Code 的日志导出会失败,但用量仍由采集器正常推送,不受影响。服务端要先升级到支持该入口的版本,见[部署指南](deployment.md#让采集器访问服务)。
`meterleaf-collector otel-headers` 从采集器配置读取写入密钥,向标准输出打印一行 `{"Authorization":"Bearer ..."}`,不输出其他内容。没有初始化时命令报错并以非 0 退出,Claude Code 的日志导出会失败,但用量仍由采集器正常推送,不受影响。直连方式要求服务端先升级到支持该入口的版本,见[部署指南](deployment.md#让采集器访问服务)。

这些日志只发到你自己的 Meterleaf,不发给 Anthropic。Claude Code 默认不导出提示词与回复;Meterleaf 也只保存请求 ID、账户 UUID、组织 UUID、会话 ID、模型和请求时间,其余属性即使到达也不落库。
这些日志只发到你自己的 Meterleaf,不发给 Anthropic。Claude Code 默认不导出提示词与回复;采集器的本机中转与 Meterleaf 服务端都只保留请求 ID、账户 UUID、组织 UUID、会话 ID、模型和请求时间,其余属性即使到达也不落库,也不写进日志。

服务端比采集器先升级时,旧采集器推送的用量还没有 `attribution` 字段。如果配置过 `modelAccounts`,这段时间里 OTEL 会暂时覆盖模型映射的归属;采集器升级后会重发全部已推送用量,归属随之恢复。所以用过模型映射时,请在升级服务端后尽快升级采集器。

## 安装

采集器需要 macOS 13 或更新版本,目前不提供下载,需要在这台 Mac 上从仓库构建。构建需要 Bun 1.4.2 或更新版本,以及 Xcode 命令行工具(没有时执行 `xcode-select --install`)。
采集器需要 macOS 13 或更新版本,目前不提供下载,需要在这台 Mac 上从仓库构建。构建需要 Bun 1.4.4 或更新版本,以及 Xcode 命令行工具(没有时执行 `xcode-select --install`)。

```sh
bun install --frozen-lockfile
Expand Down Expand Up @@ -151,17 +173,17 @@ alias meterleaf-collector="/Applications/Meterleaf.app/Contents/MacOS/meterleaf-
meterleaf-collector install-launchd
```

系统每分钟以低优先级运行一次同步,「系统设置 → 通用 → 登录项与扩展」中会显示带图标的 Meterleaf.app。如果命令提示等待批准,在那里打开 Meterleaf 的开关即可。那里会标注「来自身份不明的开发者」,因为构建使用的是本机临时签名,不影响运行。
系统每分钟以低优先级运行一次同步,同时常驻运行接收 Claude Code OTEL 日志的本机中转。「系统设置 → 通用 → 登录项与扩展」中会显示带图标的 Meterleaf.app。如果命令提示等待批准,在那里打开 Meterleaf 的开关即可。那里会标注「来自身份不明的开发者」,因为构建使用的是本机临时签名,不影响运行。

Claude Code 会删除较早的会话记录,后台任务需要保持运行,才能在删除前把用量记入账本。后台任务的输出写在数据目录的 `logs` 下。
Claude Code 会删除较早的会话记录,后台任务需要保持运行,才能在删除前把用量记入账本。后台任务的输出写在数据目录的 `logs` 下,同步和 OTEL 中转共用这些文件。每个文件超过 1 MB 时改名为 `.1` 并重新开始,只保留这一份旧文件,日志总共不超过约 4 MB。

后台任务随 Meterleaf.app 注册,应用需要留在原位置。如果设置了 `METERLEAF_COLLECTOR_HOME`、`CLAUDE_CONFIG_DIR`、`METERLEAF_CLAUDE_JSON` 或 `--claude-json`,这些路径只能通过环境变量传给后台任务,命令会改为在 `~/Library/LaunchAgents` 安装普通的后台任务,登录项中显示为可执行文件名。

## 升级

先升级 Meterleaf 服务端,再升级采集器。新版采集器可能推送旧服务端不认识的额度类型(例如 Fable 周额度),旧服务端会拒收整批数据;数据留在采集器的待发送队列里,服务端升级后自动补推,不会丢失。

重新构建后,用新的 `dist/Meterleaf.app` 替换「应用程序」中的旧版本,再执行一次 `meterleaf-collector install-launchd`。读取进度、账户归属和写入密钥都在数据目录中,替换应用不会丢失。
重新构建后,用新的 `dist/Meterleaf.app` 替换「应用程序」中的旧版本,再执行一次 `meterleaf-collector install-launchd`。这条命令会按新应用包重新登记同步和 OTEL 中继两个后台任务。读取进度、账户归属和写入密钥都在数据目录中,替换应用不会丢失。

如果 `status` 显示后台任务已启用,但「最近成功」的时间几分钟都不更新,把问题和 `launchctl print gui/$(id -u)/io.meterleaf.collector.background` 的输出反馈给维护者。

Expand Down Expand Up @@ -238,7 +260,8 @@ install -m 755 scripts/paseo-claude-quota.sh ~/.local/bin/meterleaf-paseo-claude

`meterleaf-collector status` 显示同步进度、待发送数量、最近一次成功或失败的原因,以及账户归属情况,不会显示密钥。

- **网络不通或 Meterleaf 暂停**:未送达的数据保存在本机,恢复后自动补发,不会重复计数。
- **网络不通或 Meterleaf 暂停**:未送达的数据保存在本机,恢复后自动补发,不会重复计数。OTEL 请求归属也走同一个队列,等待期间 `status` 的 `OTEL` 数量会逐渐增加。
- **账户归属没有按 OTEL 更新**:先看 `status` 里 OTEL 中继是否显示「已启用」,再确认 `status` 的 `OTEL` 数量在请求后增加。数量长期不变时,检查 `settings.json` 的地址端口与采集器 `config.json` 的 `otelRelay.port` 是否一致,以及该端口是否被其他程序占用。中继只记接收条数,日志在数据目录的 `logs` 下。
- **更换服务地址**:比如从局域网地址改为公网 HTTPS 地址,执行 `meterleaf-collector server https://meterleaf.example.com`。写入密钥不变,服务端不用改。
- **提示密钥无效**:确认 Meterleaf 的 `METERLEAF_INGEST_KEYS` 包含 `init` 输出的那一行并已重启。换电脑或重新生成密钥时,用 `init --force` 并替换服务端对应的行。
- **额度显示为过时**:Claude Code 并不在每次请求后刷新 `~/.claude.json` 里的额度缓存,观察到的刷新发生在打开设置中的用量面板时。采集器不会主动请求额度,可以启用上面的状态栏额度缓存获得更新的数据。
Expand Down
10 changes: 10 additions & 0 deletions docs/deployment.md
Original file line number Diff line number Diff line change
Expand Up @@ -223,6 +223,16 @@ docker compose up -d --no-build --pull never

升级会自动执行数据库迁移;遇到不兼容或无法识别的结构时服务会停止,不要通过清空数据绕过。

本版升级后,服务端会在启动和运行期间自动删除旧价格表版本的估值,以及报表索引和累计索引都已处理的用量变更记录。账本文件会明显变小,已有金额不受影响,价格表本身继续保留。删除腾出的空间由 SQLite 在后续写入中复用,日常不需要额外维护。如果想立即把空间还给磁盘,可以在停服时执行一次:

```sh
docker compose stop meterleaf
sqlite3 app_data/meterleaf.sqlite 'VACUUM'
docker compose up -d --no-build --pull never
```

VACUUM 会临时重写整个文件,需要约等于账本文件大小的可用磁盘空间。不执行 VACUUM 也不影响使用。

## 数据文件与缓存

备份需包含整个 `app_data`,其中保存了账本、账户状态和额度快照。报表缓存可从账本重建,不需要备份,刷新页面也不需要清空数据。
Expand Down
2 changes: 1 addition & 1 deletion docs/reporting.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@

主题、USD 估算口径和账户顺序全局共享。主题可以跟随系统,也可手动选择浅色或深色。配色与明暗相互独立,提供翠绿、靛蓝和黑白三种。

支持 PWA 的浏览器可使用原生安装入口,将 Meterleaf 安装为独立窗口。断网后重新打开时只显示离线提示,不显示旧账本;恢复网络后刷新页面获取当前数据。
支持 PWA 的浏览器可使用原生安装入口,将 Meterleaf 安装为独立窗口。断网后重新打开,或网络卡住 8 秒仍没有响应时,只显示连不上的提示,不显示旧账本;提示页会自动重试,连上后直接打开当前账本,也可以点“重新连接”立即再试。

消耗趋势支持小时、天、周粒度,可切换柱状图、折线图和面积图;饼图展示模型占比,不表示时间变化。USD、Credits 和 Tokens 使用同一份报表结果切换。

Expand Down
8 changes: 4 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
{
"name": "meterleaf",
"version": "0.12.0",
"version": "0.12.1",
"private": true,
"type": "module",
"license": "Apache-2.0",
"packageManager": "bun@1.4.2",
"packageManager": "bun@1.4.4",
"engines": {
"bun": ">=1.4.2"
"bun": ">=1.4.4"
},
"scripts": {
"start": "bun src/server/main.ts",
Expand Down Expand Up @@ -44,7 +44,7 @@
"devDependencies": {
"@playwright/test": "^1.63.0",
"@tailwindcss/vite": "^4.3.3",
"@types/bun": "^1.4.2",
"@types/bun": "^1.4.4",
"@types/pg": "^8.23.1",
"@types/react": "^19.2.18",
"@types/react-dom": "^19.2.7",
Expand Down
Loading
Loading
0