アーキテクチャ

Tokfuel はサーバーを持たない SwiftUI 製のメニューバーアプリ。表示する 数字はすべて、Claude Code・Cursor・Codex CLI が Mac にすでに残している ファイルを読み取って作られる。

SPM レイヤー

アプリ本体は App/ 配下の複数 SPM target に分かれる。依存の向きは UI → Store → sources。executable(Tokfuel)が具象を組み立てる。

Tokfuel SPM layer architecture Dependency flow UI to Store to sources. The Tokfuel executable wires concrete types. Settings, Analytics, and Core sit beside the main stack. Tokfuel executable · DI / wiring TokfuelUI Popover · Settings · About · presentation depends on TokfuelStore UsageStore · shape / aggregate for UI depends on TokfuelClaude retok · transcripts TokfuelCursor dashboard · pricing TokfuelCodex CLI sessions TokfuelBudget thresholds · alerts Shared · settings · diagnostics TokfuelSettings AppSettings · UserDefaults TokfuelAnalytics opt-in · Crashlytics (dist) TokfuelCore shared types only Local data on disk ? sources fetch ? Store shapes ? UI presents. Prompts never leave the Mac. Arrow direction = import / depends-on (UI ? Store ? sources).
  • TokfuelUI — ポップオーバー・設定・About など表示

  • TokfuelStore — 合算と UI 向け整形(UsageStore

  • TokfuelClaude / TokfuelCursor / TokfuelCodex / TokfuelBudget — 取得・判定などの sources

  • TokfuelSettings / TokfuelAnalytics / TokfuelCore — 設定、任意の Analytics、横断型

データの流れは取得 → 整形・合算 → 表示。決定の正本は ADR-0002。リポジトリ README にも同じ依存図がある。

UsageStore:唯一の情報源

UsageStore(TokfuelStore)は全ビューが参照する唯一の @MainActor オブジェクト。 現在のコスト合計・チャート・モデル別内訳を保持し、タイマーで更新する(待機中は 10 分ごと、コストが動くと 5 分間だけ 1 分ごとに切り替わる)。 PopoverView など UI 側は純粋な表示層のままで、設定は AppSettings (UserDefaults ベース)に分離している。

RetokService:Claude Code 自身のトランスクリプトを読む

RetokService(TokfuelClaude)は同梱の retok(© Daiki Matsudate、MIT、無改変で同梱)を呼び出し、Claude Code が 自分で書き出す ~/.claude/projects/ のトランスクリプトを解析する。フックも追加インストールも設定も不要。python3 は任意の依存で、無くてもコスト分析だけが縮退し、他の機能は動き続ける。

BudgetMonitor

BudgetMonitor(TokfuelBudget)は UsageStore の合計値を AppSettings の月次・日次の 上限と突き合わせ、しきい値を超えるたびに一度だけ知らせる。アラートウィンドウの 表示は App / UI 側が組み立てる。

ソース別の Service

  • CursorDashboardService — Cursor がインストール済みでサインインもされていれば、Cursor が state.vscdb に保持済みのセッショントークンを使って Cursor 自身のダッシュボード使用量 API を呼ぶ。サインアウトや オフライン時はローカル SQLite のトークンスナップショットへ フォールバックする。

  • CursorPricingService — Cursor 自身が公開する価格表を 1 日 1 回取得し、フォールバック経路の利用を補正する。価格を引けないモデルは 当て推量のレートではなく $0 として計上する。

  • ExchangeRateService — JPY 表示を有効にしたときだけ、Frankfurter から USD→JPY レートを 1 日 1 回取得する。

  • UpdateChecker — 起動時と以後 24 時間ごとに GitHub Releases をポーリングし、新しいバージョンを検知する。リリースアセットのダウンロードは アップデートボタンを押したときだけ。

  • CSVExportService — retok レポートにすでにある当該期間のデータを、端末上だけで日次・月次 CSV に変換する。

  • AnalyticsService — オプトイン・配布ビルド限定の Firebase Analytics イベント送信を一元化する窓口。それ以外のビルドでは何もしない。

各ソースは独立に扱い、ラベル付きで区別する。Cursor や Codex のコストが ラベルなしで Claude の合計に混ざることはない。

App/ の木

ADR-0001 により、アプリ関連は App/ 配下に集約する。Site・Docs・Scripts は 対象外。検証物は App/Tests/ にまとめ、本体の SPM レイヤー(App/Tokfuel*)と 並べる。

  • App/Tokfuel* — executable と各 library(UI / Store / sources)

  • App/Tests/UnitTestsswift test の対象

  • App/Tests/{IntegrationTests,E2E,TestDocs} — 結合・通し・シナリオ設計(役割はテストページを参照)

関連ドキュメント