我用 Claude Code 写了一个 macOS 原生 App,来监控 Claude Code 自己的 Token 消耗

起因

最近重度使用 Claude Code 做开发,每天的 token 消耗量非常大。虽然有 npx ccusage@latest 这样的命令行工具可以查看用量,但每次都要跑一遍命令,而且输出是纯文本表格,不够直观。

我想要的是:

  • 一眼看到每天花了多少钱
  • 知道哪个项目最烧钱
  • 了解缓存命中率(这直接影响费用)
  • 不同模型的用量分布

于是决定用 SwiftUI 写一个 macOS 原生 App。整个过程从设计到开发到上架 GitHub,全程用 Claude Code 完成。

先看效果

Dashboard — 一眼掌握全局

顶部四个指标卡片:总费用、总 Token、缓存命中率、会话数。中间是每日用量柱状图(鼠标悬停有 tooltip),右侧是模型分布饼图。

Projects — 哪个项目最烧钱

堆叠面积图展示各项目的 Token 消耗趋势,下方表格可以展开查看每个会话的详情。

Models — 模型用量对比

按模型维度统计费用和 Token 分布。Opus 果然是大头。

Sessions — 会话级明细

所有会话按时间排序,支持搜索和排序,点进去可以看到 Token 时间线、模型切换、工具调用日志。

技术方案

数据从哪来?

Claude Code 会在本地 ~/.claude/projects/ 目录下,为每个项目、每个会话生成 JSONL 文件。每一行是一个 JSON 对象,记录了:

{
  "type": "assistant",
  "message": {
    "model": "claude-opus-4-6",
    "usage": {
      "input_tokens": 3,
      "output_tokens": 9,
      "cache_creation_input_tokens": 44874,
      "cache_read_input_tokens": 0
    }
  },
  "timestamp": "2026-03-19T12:14:17.775Z",
  "sessionId": "7e175846-a0c7-4fcb-9f3f-5aaed25b5f4b",
  "cwd": "/xxx",
  "gitBranch": "xxx/xxx"
}

关键字段:

  • usage — 四种 token 计数:input、output、cache_creation、cache_read
  • model — 使用的模型(opus/sonnet/haiku 等)
  • sessionId + timestamp — 会话关联和时间线
  • cwd + gitBranch — 项目和分支信息

技术栈

组件选择理由
UI 框架SwiftUImacOS 原生,声明式 UI
图表Swift ChartsApple 官方图表库,和 SwiftUI 无缝集成
数据层纯内存模型数据量不大,不需要数据库
项目管理XcodeGenYAML 配置生成 xcodeproj,方便版本控制
最低版本macOS 14Swift Charts 的 SectorMark 需要
第三方依赖零依赖,纯 Apple 框架

核心架构

App
├── AppState (ObservableObject)     # 全局状态 + 时间范围过滤
├── JSONLParser (Actor)             # 异步解析所有 JSONL 文件
├── StatsEngine                     # 按日期/项目/模型聚合统计
├── ModelPricing                    # 可自定义的模型定价
└── L10n                            # 中英文国际化

数据流:App 启动 → JSONLParser 扫描 ~/.claude/projects/ → 解析所有 .jsonl 文件(包括子代理) → 构建 Project/Session 模型 → AppState 持有数据 → 各 View 通过 @EnvironmentObject 消费。

费用计算

费用计算基于 Anthropic 官方定价,四种 token 类型分别计价:

static func cost(for model: String, usage: TokenUsage) -> Double {
    let price = priceFor(model)
    let input = Double(usage.inputTokens) / 1_000_000 * price.inputPerMillion
    let output = Double(usage.outputTokens) / 1_000_000 * price.outputPerMillion
    let cacheWrite = Double(usage.cacheCreationTokens) / 1_000_000 * price.cacheWritePerMillion
    let cacheRead = Double(usage.cacheReadTokens) / 1_000_000 * price.cacheReadPerMillion
    return input + output + cacheWrite + cacheRead
}

当前定价(2026年3月):

模型InputOutputCache WriteCache Read
Opus 4.6$5/MTok$25/MTok$6.25/MTok$0.50/MTok
Sonnet 4.6$3/MTok$15/MTok$3.75/MTok$0.30/MTok
Haiku 4.5$1/MTok$5/MTok$1.25/MTok$0.10/MTok

用户可以在 Settings 里自定义每个模型的单价。

图表交互:鼠标跟随 Tooltip

Swift Charts 本身不提供 hover tooltip,需要用 chartOverlay + onContinuousHover 手动实现:

.chartOverlay { proxy in
    GeometryReader { geo in
        Rectangle().fill(.clear).contentShape(Rectangle())
            .onContinuousHover { phase in
                switch phase {
                case .active(let loc):
                    hoverLocation = loc
                    chartWidth = geo.size.width
                    if let date: Date = proxy.value(atX: loc.x) {
                        selectedDate = Calendar.current.startOfDay(for: date)
                    }
                case .ended:
                    selectedDate = nil
                }
            }
    }
}

Tooltip 位置需要处理边界情况 — 鼠标靠右时 tooltip 要翻转到左侧:

let tooltipW: CGFloat = 170
let xOff: CGFloat = hoverLocation.x + tooltipW + 20 > chartWidth
    ? hoverLocation.x - tooltipW - 12  // 翻转到左侧
    : hoverLocation.x + 16             // 正常在右侧

项目名解析

Claude Code 的项目目录名是把文件路径中的 / 替换成 -,比如:

-Users-devsh-Documents-cnb-code-app-backend

需要解析回可读的项目名。策略是跳过常见路径前缀(Users、Documents 等),取最后有意义的部分:

static func decodeProjectName(_ dirName: String) -> String {
    let components = dirName.components(separatedBy: "-").filter { !$0.isEmpty }
    let skipPrefixes = ["Users", "Documents", "var", "folders", "private", "tmp", "T"]
    // ... 跳过前缀,返回最后 1-2 个有意义的段
}

CI/CD:自动构建 DMG

用 GitHub Actions 实现打 tag 自动构建 DMG 并发布到 Releases:

on:
  push:
    tags: ['v*']

permissions:
  contents: write

jobs:
  build:
    runs-on: macos-15
    steps:
      - uses: actions/checkout@v4
      - run: brew install xcodegen
      - run: xcodegen generate
      - run: xcodebuild -project Tokmon.xcodeproj -scheme Tokmon -configuration Release -derivedDataPath build
      - run: |
          mkdir dmg_contents
          cp -R build/Build/Products/Release/Tokmon.app dmg_contents/
          ln -s /Applications dmg_contents/Applications
          hdiutil create -volname "Tokmon" -srcfolder dmg_contents -ov -format UDZO "Tokmon-${GITHUB_REF_NAME}.dmg"
      - uses: softprops/action-gh-release@v2
        with:
          files: Tokmon-*.dmg

发版只需要:

git tag -a v1.0.0 -m "v1.0.0" && git push origin v1.0.0

一些发现

通过 Tokmon 分析自己的使用数据,发现了几个有意思的点:

  1. 缓存命中率约 46% — 说明将近一半的 input token 是从缓存读取的,省了不少钱
  2. Opus 占了 83% 的费用 — 虽然 Haiku 的会话数更多,但 Opus 单价高太多
  3. 日均消耗 $250+ — 重度使用 Claude Code 的成本确实不低
  4. 不同项目差异很大 — web-management 项目消耗最多,因为代码量大、上下文长

使用方式

直接下载

从 GitHub Releases 下载 DMG,拖到 Applications 即可。

从源码构建

brew install xcodegen
git clone 
cd Tokmon
xcodegen generate
open Tokmon.xcodeproj  # Cmd+R 运行

开源

项目完全开源,MIT 协议:github.com/learningpro…

欢迎 Star、Issue、PR。如果你也在重度使用 Claude Code,希望这个工具能帮你更好地了解自己的用量和费用。


整个项目从设计到开发到发布,全程使用 Claude Code 完成。包括 UI 设计稿(用 Gemini 生成)、SwiftUI 代码、JSONL 解析、图表交互、国际化、CI/CD 配置、App 图标、README,甚至这篇文章。

本站提供的所有下载资源均来自互联网,仅提供学习交流使用,版权归原作者所有。如需商业使用,请联系原作者获得授权。 如您发现有涉嫌侵权的内容,请联系我们 邮箱:alixiixcom@163.com