# 帳票設計書 3-Stats Report (CLI出力)

## 概要

本ドキュメントは、opencode CLIの `stats` コマンドによるトークン使用量とコスト統計レポートの設計書である。

### 本帳票の処理概要

本帳票は、opencodeの全セッションにわたるトークン使用量、コスト、ツール使用状況、モデル別統計を集計し、ターミナル上に整形されたテーブル形式で表示するCLIレポート機能を提供する。

**業務上の目的・背景**：AIアシスタントの利用状況を把握し、コスト管理と予算計画を行うために必要である。開発者やチームリーダーが日々のAI使用量を監視し、コスト最適化の判断材料とすることができる。また、どのモデルやツールが頻繁に使用されているかを分析することで、ワークフローの改善にも役立つ。

**帳票の利用シーン**：定期的なコストレビュー時、予算管理時、利用状況の分析時、チームへの利用レポート作成時に利用される。特に月次や週次でのコスト確認、プロジェクト単位での使用量分析、使用モデルの選定判断時に有用である。

**主要な出力内容**：
1. オーバービュー（セッション数、メッセージ数、日数）
2. コストとトークン統計（総コスト、日次平均コスト、セッション平均トークン、入出力トークン詳細）
3. モデル別使用統計（オプション：メッセージ数、トークン数、コスト）
4. ツール使用状況（使用回数、割合、視覚的バーチャート）

**帳票の出力タイミング**：CLIから `opencode stats` コマンドを実行した時に出力される。オプションで期間、プロジェクト、表示項目を指定可能。

**帳票の利用者**：開発者、チームリーダー、プロジェクトマネージャー、コスト管理担当者

## 帳票種別

統計レポート / 集計表

## 利用画面

| 画面No | 画面名 | URL/ルーティング | 出力操作 |
|--------|--------|-----------------|---------|
| - | CLI | `opencode stats` | コマンド実行 |

## 出力形式

### 基本仕様

| 項目 | 内容 |
|-----|------|
| ファイル形式 | テキスト（ターミナル出力） |
| 用紙サイズ | 該当なし |
| 向き | 該当なし |
| ファイル名 | 該当なし（標準出力） |
| 出力方法 | console.log（標準出力） |
| 文字コード | UTF-8 |

### コマンドオプション

| オプション | 説明 | デフォルト |
|-----------|------|-----------|
| --days | 直近N日間の統計を表示 | 全期間 |
| --tools | 表示するツール数 | 全件 |
| --models | モデル統計を表示（数値指定でトップN） | 非表示 |
| --project | プロジェクトIDでフィルタ（空文字=現在のプロジェクト） | 全プロジェクト |

## 帳票レイアウト

### レイアウト概要

ターミナル上にASCIIボーダーで囲まれたセクションを表示する。

```
┌────────────────────────────────────────────────────────┐
│                       OVERVIEW                         │
├────────────────────────────────────────────────────────┤
│Sessions                                           xxx │
│Messages                                           xxx │
│Days                                               xxx │
└────────────────────────────────────────────────────────┘

┌────────────────────────────────────────────────────────┐
│                    COST & TOKENS                       │
├────────────────────────────────────────────────────────┤
│Total Cost                                        $x.xx │
│Avg Cost/Day                                      $x.xx │
│...                                                     │
└────────────────────────────────────────────────────────┘

┌────────────────────────────────────────────────────────┐
│                      MODEL USAGE                       │
├────────────────────────────────────────────────────────┤
│ provider/model                                         │
│  Messages                                          xxx │
│  ...                                                   │
└────────────────────────────────────────────────────────┘

┌────────────────────────────────────────────────────────┐
│                      TOOL USAGE                        │
├────────────────────────────────────────────────────────┤
│ tool_name        ████████████████████  xxx (xx.x%)     │
│ ...                                                    │
└────────────────────────────────────────────────────────┘
```

### OVERVIEWセクション

| No | 項目名 | 説明 | データ取得元 | 表示形式 |
|----|-------|------|-------------|---------|
| 1 | Sessions | 総セッション数 | stats.totalSessions | カンマ区切り数値 |
| 2 | Messages | 総メッセージ数 | stats.totalMessages | カンマ区切り数値 |
| 3 | Days | 集計日数 | stats.days | 数値 |

### COST & TOKENSセクション

| No | 項目名 | 説明 | データ取得元 | 表示形式 |
|----|-------|------|-------------|---------|
| 1 | Total Cost | 総コスト | stats.totalCost | $x.xx |
| 2 | Avg Cost/Day | 日次平均コスト | stats.costPerDay | $x.xx |
| 3 | Avg Tokens/Session | セッション平均トークン | stats.tokensPerSession | K/M単位 |
| 4 | Median Tokens/Session | セッション中央値トークン | stats.medianTokensPerSession | K/M単位 |
| 5 | Input | 入力トークン | stats.totalTokens.input | K/M単位 |
| 6 | Output | 出力トークン | stats.totalTokens.output | K/M単位 |
| 7 | Cache Read | キャッシュ読み取りトークン | stats.totalTokens.cache.read | K/M単位 |
| 8 | Cache Write | キャッシュ書き込みトークン | stats.totalTokens.cache.write | K/M単位 |

### MODEL USAGEセクション（オプション）

| No | 項目名 | 説明 | データ取得元 | 表示形式 |
|----|-------|------|-------------|---------|
| 1 | Model Name | プロバイダー/モデルID | modelUsage key | 文字列 |
| 2 | Messages | メッセージ数 | usage.messages | カンマ区切り |
| 3 | Input Tokens | 入力トークン | usage.tokens.input | K/M単位 |
| 4 | Output Tokens | 出力トークン | usage.tokens.output | K/M単位 |
| 5 | Cache Read | キャッシュ読み取り | usage.tokens.cache.read | K/M単位 |
| 6 | Cache Write | キャッシュ書き込み | usage.tokens.cache.write | K/M単位 |
| 7 | Cost | コスト | usage.cost | $x.xxxx |

### TOOL USAGEセクション

| No | 項目名 | 説明 | データ取得元 | 表示形式 |
|----|-------|------|-------------|---------|
| 1 | Tool Name | ツール名 | toolUsage key | 最大18文字（切り詰め） |
| 2 | Bar | 使用割合の視覚表現 | count / maxCount | ブロック文字（最大20文字） |
| 3 | Count | 使用回数 | toolUsage value | 数値 |
| 4 | Percentage | 使用割合 | count / total * 100 | xx.x% |

## 出力条件

### 抽出条件

| 条件名 | 説明 | 必須 |
|-------|------|-----|
| days | 直近N日間（0=今日のみ） | No |
| project | プロジェクトIDフィルタ | No |

### ソート順

| セクション | 優先度 | 項目 | 昇順/降順 |
|-----------|-------|------|---------|
| MODEL USAGE | 1 | messages | 降順 |
| TOOL USAGE | 1 | count | 降順 |

### 改ページ条件

該当なし（ターミナル出力のため）

## データベース参照仕様

### 参照テーブル一覧

| テーブル名 | 用途 | 結合条件 |
|-----------|------|---------|
| session | セッション一覧取得 | - |
| message | メッセージ情報取得 | session_id = session.id |
| part | ツール使用情報取得 | message_id = message.id |

### テーブル別参照項目詳細

#### session

| 参照項目（カラム名） | 帳票項目との対応 | 取得条件 | 備考 |
|-------------------|----------------|---------|------|
| id | セッション識別 | 全件 | - |
| project_id | プロジェクトフィルタ | project指定時 | - |
| time_created | 日付範囲フィルタ | days指定時 | - |
| time_updated | 日付範囲フィルタ | days指定時 | - |

#### message（JSON data列内）

| 参照項目 | 帳票項目との対応 | 取得条件 | 備考 |
|--------|----------------|---------|------|
| role | アシスタントメッセージ判定 | role = "assistant" | - |
| cost | コスト集計 | - | - |
| tokens | トークン集計 | - | - |
| providerID | モデル識別 | - | - |
| modelID | モデル識別 | - | - |

#### part（JSON data列内）

| 参照項目 | 帳票項目との対応 | 取得条件 | 備考 |
|--------|----------------|---------|------|
| type | ツール判定 | type = "tool" | - |
| tool | ツール名 | - | - |

## 計算仕様

### 計算項目一覧

| 項目名 | 計算式 | 端数処理 | 備考 |
|-------|-------|---------|------|
| totalCost | SUM(message.cost) | - | 全アシスタントメッセージのコスト合計 |
| costPerDay | totalCost / days | toFixed(2) | 日次平均コスト |
| tokensPerSession | totalTokens / sessionCount | Math.round | セッション平均トークン |
| medianTokensPerSession | セッショントークンの中央値 | - | ソート後中央値 |
| totalTokens | input + output + reasoning + cache.read + cache.write | - | 全トークン合計 |
| toolPercentage | (toolCount / totalToolUsage) * 100 | toFixed(1) | ツール使用割合 |
| barLength | (count / maxCount) * 20 | Math.floor | 視覚バー長 |

### 数値フォーマット

| 値の範囲 | 表示形式 | 例 |
|---------|---------|-----|
| >= 1,000,000 | x.xM | 1.5M |
| >= 1,000 | x.xK | 15.2K |
| < 1,000 | そのまま | 999 |

## 処理フロー

### 出力フロー

```mermaid
flowchart TD
    A[stats コマンド実行] --> B[bootstrap初期化]
    B --> C[aggregateSessionStats呼び出し]
    C --> D[getAllSessions - 全セッション取得]
    D --> E{days指定あり?}
    E -->|Yes| F[日付フィルタ適用]
    E -->|No| G[全件対象]
    F --> H{project指定あり?}
    G --> H
    H -->|Yes| I[プロジェクトフィルタ適用]
    H -->|No| J[全プロジェクト対象]
    I --> K[セッションループ - バッチ処理]
    J --> K
    K --> L[Session.messages取得]
    L --> M[メッセージ集計]
    M --> N[ツール使用集計]
    N --> O[モデル別集計]
    O --> P[統計計算]
    P --> Q[displayStats呼び出し]
    Q --> R[OVERVIEWセクション出力]
    R --> S[COST & TOKENSセクション出力]
    S --> T{models指定あり?}
    T -->|Yes| U[MODEL USAGEセクション出力]
    T -->|No| V[スキップ]
    U --> W[TOOL USAGEセクション出力]
    V --> W
    W --> X[終了]
```

## エラー処理

### エラーケース一覧

| エラー種別 | 発生条件 | 表示メッセージ | 対処方法 |
|----------|---------|--------------|---------|
| 大量データ警告 | セッション数 > 1000 | `Large dataset detected (xxx sessions). This may take a while...` | 処理継続（警告のみ） |
| データなし | セッション0件 | - | 0値で統計表示 |
| NaN処理 | コストやトークンがNaN | 0に置換 | - |

## パフォーマンス要件

| 項目 | 内容 |
|-----|------|
| 想定データ件数 | 数千セッション |
| 目標出力時間 | 数秒〜数十秒（大量データ時） |
| 同時出力数上限 | 1（CLIコマンドのため） |
| バッチサイズ | 20セッション/バッチ |

## セキュリティ考慮事項

- 統計情報には金額が含まれるため、画面共有時の注意が必要
- プロジェクト単位でのフィルタリングにより、必要な情報のみに限定可能
- ローカルデータベースのみ参照（外部通信なし）

## 備考

- 出力幅は56文字固定
- モデル使用統計はデフォルト非表示（--modelsオプションで有効化）
- 中央値計算によりトークン使用の分布を把握可能
- バッチ処理（20件ずつ）による大量データ対応

---

## コードリーディングガイド

本帳票を理解するために参照すべきファイルと、推奨する読み解き順序を以下に示す。

### 推奨読解順序

#### Step 1: データ構造を理解する

まず、統計データの構造を把握する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | stats.ts | `packages/opencode/src/cli/cmd/stats.ts` | SessionStats interface（10-47行）で集計データ構造を理解 |

**読解のコツ**: SessionStats interfaceの各プロパティが最終出力のどの項目に対応するか意識する。

#### Step 2: エントリーポイントを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | stats.ts | `packages/opencode/src/cli/cmd/stats.ts` | StatsCommand定義（49-84行）、コマンドオプションの定義を確認 |

**主要処理フロー**:
1. **52-68行**: コマンドオプション定義（days, tools, models, project）
2. **70-83行**: ハンドラーでaggregateSessionStats呼び出し後、displayStats呼び出し

#### Step 3: 集計処理を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | stats.ts | `packages/opencode/src/cli/cmd/stats.ts` | aggregateSessionStats関数（95-307行）の集計ロジック |

**主要処理フロー**:
- **96-124行**: セッションフィルタリング（日付、プロジェクト）
- **126-149行**: 初期統計オブジェクト構築
- **166-279行**: バッチ処理によるメッセージ集計
- **282-305行**: 統計計算（日次コスト、中央値等）

#### Step 4: 表示処理を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | stats.ts | `packages/opencode/src/cli/cmd/stats.ts` | displayStats関数（309-401行）の表示ロジック |

**主要処理フロー**:
- **310-316行**: renderRow関数（行フォーマット）
- **319-327行**: OVERVIEWセクション出力
- **330-346行**: COST & TOKENSセクション出力
- **349-370行**: MODEL USAGEセクション出力（条件付き）
- **374-399行**: TOOL USAGEセクション出力

### プログラム呼び出し階層図

```
StatsCommand.handler (stats.ts:70)
    │
    ├─ bootstrap() - 初期化処理
    │
    ├─ aggregateSessionStats(days, project) - 統計集計
    │      │
    │      ├─ getAllSessions() - 全セッション取得
    │      │      └─ Database.use() → SessionTable SELECT
    │      │
    │      ├─ getCurrentProject() - 現在プロジェクト取得（project=""時）
    │      │
    │      └─ Session.messages({sessionID}) - メッセージ取得（バッチ処理）
    │             └─ MessageV2.stream() → MessageTable/PartTable SELECT
    │
    └─ displayStats(stats, toolLimit, modelLimit) - 表示
           │
           ├─ renderRow() - 行フォーマット
           │
           └─ formatNumber() - 数値フォーマット（K/M単位）
```

### データフロー図

```
[入力]                    [処理]                              [出力]

--days N ─────────────▶ 日付フィルタ
                              │
--project ID ─────────▶ プロジェクトフィルタ
                              │
SessionTable ─────────▶ getAllSessions()
                              │
                              ▼
                    aggregateSessionStats()
                              │
                    ┌─────────┴──────────┐
                    ▼                    ▼
            セッションループ        統計計算
                    │                    │
                    ▼                    ▼
            Message/Part集計      costPerDay
            - cost              medianTokens
            - tokens            tokensPerSession
            - toolUsage              │
            - modelUsage             │
                    │                    │
                    └─────────┬──────────┘
                              ▼
                    displayStats()
                              │
            ┌─────────┬───────┼───────┬─────────┐
            ▼         ▼       ▼       ▼         ▼
        OVERVIEW  COST&TOKENS MODEL  TOOL    stdout
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| stats.ts | `packages/opencode/src/cli/cmd/stats.ts` | ソース | 統計コマンドメイン処理 |
| index.ts | `packages/opencode/src/session/index.ts` | ソース | Session.messages、Session.fromRow |
| session.sql.ts | `packages/opencode/src/session/session.sql.ts` | ソース | SessionTable定義 |
| db.ts | `packages/opencode/src/storage/db.ts` | ソース | Database.use |
| cmd.ts | `packages/opencode/src/cli/cmd/cmd.ts` | ソース | コマンド定義ヘルパー |
| bootstrap.ts | `packages/opencode/src/cli/bootstrap.ts` | ソース | CLI初期化処理 |
