time-lens について
time-lensは、複数のリポジトリやコーディングツールを横断して作業時間を推定する開発者向けスキルです。Git、WakaTime、Claude Code、Codex CLI、Cursorの活動を統合し、HTMLとMarkdownのレポート作成を案内します。
主な機能
- 01Gitのセッションデータ収集
- 02WakaTimeのプロジェクト活動取得
- 03Claude Code、Codex CLI、Cursorの活動読み取り
- 04データ統合による時間推定
- 05監督下と無人稼働時間の分割
- 06HTMLとMarkdownレポートの生成
活用シーン
- 01複数リポジトリの作業時間推定
- 02コーディングエージェントの活動とコミット・IDE利用の比較
- 03日ごとのセッションと監督下時間の確認
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ vladmdgolam/ agent-skills --skill time-lensインストール後、Claude Code で/time-lensを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
references/data-sources.mdfolder-move-detection.mdreconciliation.mdscripts/claude_messages.pycodex_messages.pycursor_messages.pygit_sessions.pyreconcile.pywakatime_fetch.py詳細
プロジェクトの時間追跡
5つのデータソースを統合 → 照合 → HTML ダッシュボードと Markdown レポートを作成します。
スクリプト
すべてのスクリプトは、この SKILL.md と同じ階層にある scripts/ にあります。python3 で実行します。
| スクリプト | 目的 | 主なフラグ |
|---|---|---|
git_sessions.py | git の履歴を解析 → セッション化 → 時間を算出 | <repo> --since YYYY-MM-DD --until YYYY-MM-DD [--raw] |
wakatime_fetch.py | WakaTime API → プロジェクトで絞り込んだ日ごとの時間 | --start YYYY-MM-DD --end YYYY-MM-DD --project name |
claude_messages.py | 日ごとの Claude Code ユーザープロンプトとアクティビティのタイムスタンプ | --project-path /abs/path または --filter name |
codex_messages.py | 日ごとの Codex CLI ユーザープロンプトとアクティビティのタイムスタンプ | --project-path /abs/path または --filter name |
cursor_messages.py | 日ごとの Cursor IDE ユーザープロンプトとアクティビティのタイムスタンプ | --project-path /abs/path または --filter name |
reconcile.py | 上記のスクリプトが出力した JSON を統合して時間を推定し、任意で監視下と無人の作業時間を分割 | --git f.json --claude f.json --codex f.json --since Y-M-D --until Y-M-D [--gap-hours 0.5] [--presence-window-min 10] [--tz Area/City] [--daily] |
claude_messages.py、codex_messages.py、cursor_messages.py はそれぞれ、2つのタイムスタンプ配列を出力します。timestamps(ユーザープロンプトのみ。プロンプト数の指標用)と、activity_timestamps(ツール呼び出し/ツール結果のサイクルやアシスタントの返信を含む、タイムスタンプ付きイベントすべて。照合にはこちらを使用)です。この違いが重要な理由については、references/reconciliation.md の「timestamps ではなく activity_timestamps を使用する」を参照してください。時間の照合にプロンプトのみのタイムスタンプを使うと、実際の作業時間が気付かないうちに除外されます。
Python でマージ処理を独自に実装するのではなく、reconcile.py を使用してください。 これは以下のアルゴリズムを決定論的に実装したものです。毎回マージ、セッション化、共通部分の抽出ロジックを再実装するのではなく、他のスクリプトがすでに生成した JSON ファイルに対して実行してください。実行中に独自実装するのは、実際にバグを招いたことがあります。ギャップしきい値が異なる2つの実行(「エンジン時間」の15分と30分)を、同じ基準であるかのように比較し、意味のない数値を生み出しました。reconcile.py ではギャップしきい値と存在確認ウィンドウを明示的なフラグにするため、各実行を再現でき、比較可能です。
ワークフロー
1. 対象範囲を決める
次の項目を確認するか、推定してください。
- プロジェクトのディレクトリ(複数可。git リポジトリ)
- 日付範囲(最初のコミットから最後のコミットまで、またはユーザー指定)
- HTML ファイルと Markdown ファイルの出力先
サブリポジトリを自動検出します: デフォルトでは、プロジェクトディレクトリ内のサブディレクトリにある .git フォルダーをスキャンします(ルートのみではありません)。.git ディレクトリの親ディレクトリをそれぞれ分析対象のサブリポジトリとします。
# Find all git repos under the project directory
find /path/to/project -name ".git" -type d 2>/dev/null | sort
次のようなリストが生成されます。
/path/to/project/frontend/.git
/path/to/project/backend/.git
/path/to/project/libs/shared/.git
これらのパス(末尾の /.git を除く)それぞれに対して、git_sessions.py、claude_messages.py、codex_messages.py を実行します。また、ルートのプロジェクトディレクトリ自体に対してもこれらのスクリプトを実行してください(モノレポ形式のワークフローでは、ルートから Claude/Codex のメッセージを送信することが多いためです)。
2. データを抽出する
見つかったすべてのリポジトリで、5つのスクリプトをすべて実行します。git、Claude、Codex、Cursorについては、サブリポジトリごとに実行します。WakaTimeについては、以下で説明する複数プロジェクトの検出方法を使用します。
# Git sessions — run per sub-repo
python3 git_sessions.py /path/to/project/frontend --since 2026-01-15 --until 2026-02-02
python3 git_sessions.py /path/to/project/backend --since 2026-01-15 --until 2026-02-02
# Claude Code — run per sub-repo AND the root directory
python3 claude_messages.py --project-path /path/to/project
python3 claude_messages.py --project-path /path/to/project/frontend
python3 claude_messages.py --project-path /path/to/project/backend
# Codex CLI — same as Claude
python3 codex_messages.py --project-path /path/to/project
python3 codex_messages.py --project-path /path/to/project/frontend
python3 codex_messages.py --project-path /path/to/project/backend
# Cursor IDE — same as Claude/Codex
python3 cursor_messages.py --project-path /path/to/project
python3 cursor_messages.py --project-path /path/to/project/frontend
python3 cursor_messages.py --project-path /path/to/project/backend
WakaTimeの複数プロジェクトの検出: WakaTimeでは、サブディレクトリが別々のプロジェクトとして記録されることがよくあります(例:my-project/にあるモノレポでは、WakaTimeのプロジェクト名がmy-project、frontend、backend、sharedとなる場合があります)。--projectを指定したクエリを1回実行するだけでは、ほかのプロジェクトが取得されません。
-
まず、日付範囲内のプロジェクト一覧をすべて取得するため、
--projectを指定せずにwakatime_fetch.pyを実行します。python3 wakatime_fetch.py --start 2026-01-15 --end 2026-02-02 # Returns: { "projects": [{"project": "my-project", "hours": 9.2}, {"project": "frontend", "hours": 5.1}, ...] } -
返された
projectsリストから、次のいずれかに一致する名前を絞り込みます。- ルートプロジェクトディレクトリのベース名(例:
my-project) - サブリポジトリのディレクトリのベース名(例:
frontend、backend) - サブリポジトリを含む中間ディレクトリのベース名(例:
libs)
- ルートプロジェクトディレクトリのベース名(例:
-
一致した各プロジェクトのインターバルを取得します。
python3 wakatime_fetch.py --start 2026-01-15 --end 2026-02-02 --project my-project python3 wakatime_fetch.py --start 2026-01-15 --end 2026-02-02 --project frontend python3 wakatime_fetch.py --start 2026-01-15 --end 2026-02-02 --project backend -
一致したすべてのWakaTimeプロジェクトのインターバルを1つのリストにまとめ、照合に使用します。
これが重要な理由: サブリポジトリが4つあるプロジェクトで、--projectを指定したクエリを1回実行しただけでは、実際のWakaTimeデータ26.5時間のうち9時間しか取得できませんでした。残りの17.5時間は、サブディレクトリのプロジェクト名で記録されていました。
フォルダー移動の検出: claude_messages.py、codex_messages.py、またはcursor_messages.pyの結果が0件の場合は、出力にalternate_pathsがあるか確認します。存在する場合は、ユーザーに次のように尋ねます。
「
/current/pathにClaude/Codexの履歴は見つかりませんでしたが、/old/pathにあるproject-nameのセッションが見つかりました。このプロジェクトは移動されましたか?その履歴も含めますか?」
確認できた場合は、--project-path /old/pathを指定して再実行し、両方のパスのタイムスタンプを統合します。
検出ロジックと例外ケースの詳細は、references/folder-move-detection.mdを参照してください。
3. 時間を照合する
統合合計 = 最良の推定値(git ∪ Claude ∪ Codex ∪ Cursor ∪ WakaTime の各区間を統合し、二重計上はしません)。手作業で統合するのではなく、手順 2 の JSON ファイルに対して reconcile.py を実行します。
python3 reconcile.py \
--git git_backend.json --git git_frontend.json \
--claude claude_backend.json --claude claude_frontend.json \
--codex codex_backend.json --codex codex_frontend.json \
--cursor cursor_backend.json \
--waka waka.json \
--since 2026-06-29 --until 2026-08-19 \
--tz Europe/Berlin --daily
(--git/--claude/--codex/--cursor/--waka はすべて複数回指定できます。複数リポジトリのプロジェクトでは、サブリポジトリごとに 1 つずつ指定してください。reconcile.py がまとめて統合します。)
この処理は、次の手順を決定論的に実行します。
- git の生のコミット
timestampsと、Claude/Codex/Cursor のactivity_timestamps(timestampsではありません。詳しくは以下を参照)を、点イベントとして扱います。 - 各ソースを個別に、ギャップのしきい値を使ってセッション化します(
--gap-hoursのデフォルトは 0.5h。より厳格で保守的な推定には 0.25 を使用してください)。 - WakaTime の既成の
[start, end]区間を、セッション化した点イベントのソースに加えて統合します。 - 重複する区間、またはしきい値以内にある区間をすべて統合し、最終的なセッションを作成します。
- 生の時間を合計します。
+0.5hのバッファも、0.5hの下限もありません(旧来の動作については reconciliation.md を参照してください。たとえば、アクティビティレベルの粒度がなく、timestampsのみのソースを使う場合など)。 --presence-window-min > 0の場合(デフォルトは 10)、監視ありと無人の時間の内訳も計算します。統合されたエンジン稼働時間のうち、実際のユーザープロンプトまたは git コミットの前後の指定時間内に該当する時間と、近くで人間による確認がないままエージェントが動作している時間を示します。詳しくは以下の「監視あり時間と無人時間」を参照してください。--dailyを指定すると、08:00 のローカル時刻境界(--day-boundary-hourのデフォルトは 8)を使って日ごとに集計します。これにより、夜間のセッションが表内で 2 日に分割されるのを防ぎます。
エンジン稼働時間の照合には、必ず timestamps ではなく activity_timestamps を使用してください(reconcile.py は自動的にこれを使用します)。timestamps はプロンプトのみを記録するため、最後に記録されたプロンプトの後もエージェントが動作し続けた場合、実際には作業中だったセッションが、継続時間 0 の単一時点のように見えてしまいます。activity_timestamps にはツール呼び出し/ツール結果のサイクルやアシスタントの返信が含まれるため、エージェントが実際に作業していた時間を反映します。継続時間 0 に見えたセッションが実際には約 50 分間の連続作業だった具体例と、ギャップのしきい値のデフォルトが以前の 1.5h から 0.5h に変更された理由については、references/reconciliation.md を参照してください。
異なる --gap-hours の実行結果である engine_hours を、同じ測定値であるかのように比較しないでください。しきい値 15 分での合計と、しきい値 30 分での合計は、異なる量です。両方が必要な場合は、reconcile.py を 2 回実行し、それぞれの結果にしきい値を明記してください。
監視ありの時間と無人実行の時間
engine_hours は、エージェントがアクティブだった時間を計測します。人間がその間ずっと見ていたとは限りません。新しいプロンプトがないままタスクが20分以上自律的に実行された場合、その時間もエンジン時間には含まれますが、キーボードを使って実際に作業した時間を反映していない可能性があります。reconcile.py の監視あり・なしの分割は、この問題に対応します。実際のユーザープロンプトまたは git コミットごとに、その前後 ± --presence-window-min 分の「在席ウィンドウ」を作成し、engine_hours のうちウィンドウ内とウィンドウ外にそれぞれどれだけの時間が含まれるかを報告します。
ウィンドウサイズは実際に結果を左右する調整可能な値であり、まだ確定したパラメーターではありません。ある実プロジェクトでは、±5分で監視ありが72%、±30分で99%になりました。推奨されるデフォルトは±10分です。通常の「出力を読む、考える、返信する」という間をカバーできる長さでありながら、実際にキーボードから離れていた時間は無人実行として表れる程度に短く設定されています。数値と併せて、使用したウィンドウも必ず報告してください。
統合が重要な理由:AI エージェントのプロンプト(Claude/Codex/Cursor)は、同じ作業セッション内の git コミットの数分前後に現れることがよくあります。WakaTime は、コミットの間に発生する可能性がある IDE のキーストロークを記録します。ユーザーが Claude で調査し、Cursor の AI を使い、コードを書き(WakaTime)、その後コミットする(git)場合、すべてが1つのセッションです。5つすべてのソースを統合することで、二重計上せずに実際のセッション境界を捉えられます。
- 統合した合計を、主要な推定値として「git のみ」の値に置き換えます
- WakaTime の時間は参考値として表示します(アクティブなキーストロークのみのため、常に少なくなります)
reconcile.py が実装するアルゴリズムの詳細、日付境界での振り分けの根拠、従来のバッファー/下限値の計算式については、references/reconciliation.md を参照してください。
4. HTML ダッシュボードを生成する
Chart.js を CDN から読み込む、インラインの単一ファイル HTML を作成します。ダークテーマ(背景色 #0a0a0a、カード色 #1a1a1a)を使用します。
必須セクション:
- 統計カード — 統合合計(git∪claude∪codex∪cursor∪waka)、Git の推定値、WakaTime、セッション数、コミット数、Claude のプロンプト数、Codex のプロンプト数、Cursor のプロンプト数
- 日次アクティビティチャート — 重ね合わせた棒グラフ(git + WakaTime + 統合値)と、第2軸に表示する AI プロンプト数の折れ線グラフ
- ガントタイムライン — UTC の横棒。git、Claude、Codex、Cursor を同じチャート上で異なる色のデータセットとして表示します(同じ日に重なる場合は、別々のスイムレーン行にします)
- データテーブル — セッション | 時刻(UTC) | アクティブ | 推定 | WakaTime | Claude | Codex | Cursor | コミット数
Chart.js の基本項目:
Chart.defaults.color = '#888';
Chart.defaults.borderColor = '#2a2a2a';
// Overlapping bars: same barPercentage/categoryPercentage on both datasets, different opacity
// Mixed chart: type:'bar' on container, each dataset has its own type + yAxisID
// Gantt floating bars: data: [[startH, endH]], indexAxis: 'y'
// Claude as line on secondary axis:
{
type: 'line',
yAxisID: 'yClaude',
// right-side axis, max ~100, different color
}
// All charts: responsive: true, maintainAspectRatio: false
<project-dir>/work-hours-analysis.html として保存します。
5. Markdown レポートを生成する
# [Project] - Work Hours Analysis
## Summary
**Estimated Total Working Hours: Xh** (based on commit timing analysis)
**Supervised: Xh (Y%) · Unattended: Xh** (±10min presence window — see Methodology)
| Date | Sessions | Time Range | Git Est. | WakaTime | Commits | Project |
...
## Timeline
- Start: [date], End: [date], Duration: N days
## Per-Project Breakdown
[sub-project sections with commit/session counts]
## Charts
### Daily Activity (ASCII)
Jan 15 ██░░░░░░░░░░░░░░░░░░ 0.5h
...
### Project Distribution
project-a ████████████████████ 45% (~18h)
...
## Methodology
- Session Detection: events within 0.5h gap = same session (git commits + Claude/Codex/Cursor activity_timestamps, not just prompts)
- Hour Estimate: Σ(session_duration), no buffer, no floor — activity_timestamps already captures real start/end
- Supervised vs. Unattended: hours within ±10min of a real user prompt/commit count as supervised; the rest is the agent running with no recent human check-in
- Why Git > WakaTime: WakaTime only tracks active IDE typing; git includes thinking/research/AI prompting
ASCII バー:blocks = round(hours / max_hours * 20)、塗りつぶしに █、空白に ░ を使用し、幅は20列です。
<project-dir>/total_hours.md として保存します。
検証チェックリスト
実行前
- WakaTime API キー —
~/.wakatime.cfgが存在し、[settings]の下にapi_key = waka_...が含まれていること。確認するにはcat ~/.wakatime.cfgを実行します。キーがない場合、WakaTime スクリプトはエラーを表示せずに失敗するか、認証エラーが発生します。 - Git リポジトリにアクセスできること — プロジェクトディレクトリがコミットを含む git リポジトリであること(
git log --oneline -5 /path/to/repoを実行すると結果が返ります)。そうでない場合、git_sessions.pyはセッション数として0を返します。 - Claude の履歴が存在すること —
~/.claude/history.jsonlが存在し、空ではないこと。または~/.claude/projects/にプロジェクトのセッションファイルが含まれていること。両方とも存在しない場合、Claude の時間は0になります。 - Cursor のデータにアクセスできること — Cursor の状態データベースがプラットフォーム固有のパスに存在すること(macOS:
~/Library/Application Support/Cursor/User/globalStorage/state.vscdb、Windows:%APPDATA%\Cursor\User\globalStorage\state.vscdb、Linux:~/.config/Cursor/User/globalStorage/state.vscdb)。存在しない場合、Cursor の時間は0になります。スクリプトはプラットフォームを自動検出し、SQLite データベースを読み取り専用モードで読み込みます。 - 日付範囲が有効であること —
--sinceが--untilより前であり、実際に作業が行われた日付が範囲に含まれていること。
生成後
- HTML がエラーなく読み込まれる — ブラウザーで
work-hours-analysis.htmlを開き、すべてのグラフが表示され、JavaScript コンソールにエラーがないことを確認します。 - 合計時間が一致する — HTML の「Merged total」統計カードの値が、
total_hours.mdの「Estimated Total Working Hours」と一致することを確認します(丸め誤差として ±0.01h まで許容)。 - 日付範囲が入力と一致する — データテーブルの最初と最後の日付、および Timeline セクションの日付が、指定された
--since/--untilの値と一致することを確認します。 - セッション数がゼロではない — 少なくとも1つのソースからセッションが取得されていることを確認します。すべてのソースで結果が0の場合は、何か問題があります(パスが間違っている、プロジェクト名が間違っている、日付範囲がプロジェクトの履歴外など)。
例
例 1:単一リポジトリ、標準レポート
トリガーフレーズ:「今月、api-server プロジェクトに何時間費やしましたか? 完全なレポートを作成してください。」
アクション:
-
対象範囲を特定します:
/Users/alice/code/api-serverのプロジェクト。日付範囲は 2026-02-01 → 2026-02-23(今月の初日から今日まで)と推定されます。 -
データを抽出します:
python3 git_sessions.py /Users/alice/code/api-server --since 2026-02-01 --until 2026-02-23 python3 wakatime_fetch.py --start 2026-02-01 --end 2026-02-23 --project api-server python3 claude_messages.py --project-path /Users/alice/code/api-server python3 codex_messages.py --project-path /Users/alice/code/api-server python3 cursor_messages.py --project-path /Users/alice/code/api-server -
照合します:
git_sessions.pyは14セッション(22.5h)を返し、WakaTime は11.2h、Claude は9日間にわたる47件のプロンプト、Codex は0件、Cursor は3日間にわたる12件のプロンプトを返します。結合後、セッションを統合した合計は 27.1h です。 -
/Users/alice/code/api-server/にwork-hours-analysis.htmlとtotal_hours.mdを生成します。
結果:「2026年2月に api-server で約 27.1時間 作業しました(git セッション14件、Claude プロンプト47件、Cursor プロンプト12件、WakaTime の参考値:アクティブなタイピング11.2時間)。レポートは /Users/alice/code/api-server/work-hours-analysis.html に保存されました。」
例 2:フォルダー移動を含む複数リポジトリのプロジェクト
トリガーフレーズ:「marketplace プロジェクトの開発時間の合計を計算してください。フロントエンドとバックエンドのリポジトリがあります。また、どこかの時点でフォルダー名を変更したと思います。」
アクション:
-
対象範囲を特定します:
/Users/bob/marketplace-backendと/Users/bob/marketplace-frontendの2つのリポジトリ。ユーザーが指定した日付範囲は 2025-11-01 → 2026-01-31 です。 -
データを抽出します:
python3 git_sessions.py /Users/bob/marketplace-backend --since 2025-11-01 --until 2026-01-31 python3 git_sessions.py /Users/bob/marketplace-frontend --since 2025-11-01 --until 2026-01-31 python3 wakatime_fetch.py --start 2025-11-01 --end 2026-01-31 --project marketplace python3 claude_messages.py --project-path /Users/bob/marketplace-backend python3 codex_messages.py --project-path /Users/bob/marketplace-backend python3 cursor_messages.py --project-path /Users/bob/marketplace-backend -
claude_messages.pyは、alternate_paths: ["/Users/bob/old-market/backend"]を伴って結果を0件返します。 -
ユーザーに尋ねます:「
/Users/bob/marketplace-backendに Claude の履歴は見つかりませんでしたが、/Users/bob/old-market/backendにbackendのセッションが見つかりました。以前の場所でしょうか? この履歴を含めますか?」 -
ユーザーの確認後、再実行します:
python3 claude_messages.py --project-path /Users/bob/old-market/backend。両方の実行結果からタイムスタンプを結合します。 -
両方のリポジトリ(バックエンド+フロントエンド)の git コミットのタイムスタンプを Claude の
activity_timestampsと統合し、並べ替えてから、0.5h のギャップしきい値以内のセッションを再統合します。すべてのソースと照合します。
結果:「3か月間の推定合計時間:84.7h(バックエンド+フロントエンドの合計。旧パス /Users/bob/old-market/backend の Claude 履歴を含む)。」
トラブルシューティング
WakaTime API キーがない、または無効
症状: wakatime_fetch.py が認証エラー、HTTP 401、または KeyError: 'api_key' で終了します。
対処方法:
- 設定ファイルがあるか確認します:
cat ~/.wakatime.cfg - ファイルがない場合は、作成します:
[settings] api_key = waka_xxxx... - キーを wakatime.com/settings/api-key から取得します。
- キーが存在するのに 401 が返される場合、有効期限が切れているか、取り消されている可能性があります。新しいキーを生成してください。
併せて確認: --project フラグの値が、WakaTime に記録されているプロジェクト名と完全に一致していることを確認します(大文字と小文字は区別されます)。WakaTime ダッシュボードの Projects でプロジェクト名を確認できます。
Git のセッション数が0件
症状: git_sessions.py が "sessions": [] または "total_hours": 0 を返します。
考えられる原因と対処方法:
| 原因 | 対処方法 |
|---|---|
| 日付範囲がプロジェクトの履歴外 | git log --oneline で実際の日付範囲を確認し、--since/--until を調整します |
| パスが git リポジトリではない | git -C /path/to/repo log --oneline -1 で確認します |
| 指定した期間に現在のユーザーによるコミットがない | 作成者で絞り込む場合は --author フラグを渡すか、フラグを外します |
| シャロークローン | git fetch --unshallow を実行して完全な履歴を復元します |
Claude、Codex、または Cursor のセッション数が 0 件になる(alternate_paths もなし)
症状: timestamps: [] と alternate_paths: [] の両方が表示されます。
考えられる原因と対処方法:
| 原因 | 対処方法 |
|---|---|
| このプロジェクトでツールを使用していない | 想定どおりです。レポートに記載してください |
--project-path が間違っている(タイプミス、シンボリックリンク、末尾のスラッシュ) | realpath /path/to/repo を使って正規の絶対パスを取得し、それを渡してください |
| 履歴ファイルが存在しない | ~/.claude/history.jsonl と ~/.claude/projects/ が存在することを確認してください。~/.codex/sessions/ が存在することも確認してください。Cursor の state.vscdb がプラットフォーム固有のパスに存在することを確認してください(Validation Checklist を参照) |
| プロジェクトパスに、解決先が異なるシンボリックリンクを使用している | 解決済みのパスを使用してください:python3 -c "import os; print(os.path.realpath('/your/path'))" |
| 実行中の Cursor インスタンスによって Cursor のデータベースがロックされている | スクリプトはデータベースを読み取り専用モードで開くため、この問題は発生しないはずですが、発生した場合は Cursor を一時的に終了してみてください |
alternate_paths は見つかるが、ユーザーがパスが間違っていると言う
症状: スクリプトは代替パスを報告しますが、ユーザーはそのどれも以前のプロジェクトの場所ではないと言います。
対処方法: --filter <project-name> に切り替えてください。これは完全一致ではなく、ディレクトリ名を部分一致で検索します。似た名前の無関係なプロジェクトが見つかる可能性があるため、マージする前にユーザーとセッションの一覧を確認してください。
python3 claude_messages.py --filter marketplace
HTML チャートが空白で表示される、または NaN が表示される
症状: HTML ファイルは開きますが、チャートが空か、「NaN」の値が表示されます。
考えられる原因:
- 照合処理によって
nullまたはNoneの値が生成され、それが JS データ配列にシリアライズされています。 - HTML に書き込む前にタイムスタンプが UTC に変換されていません(ローカルのエポックと UTC のエポックが不一致)。
- Chart.js CDN の読み込みに失敗しています(オフライン環境)。
対処方法:
- ブラウザーの DevTools コンソールを開いてください。具体的な JS エラーから問題を特定できます。
- すべてのエポックタイムスタンプが文字列ではなく、UTC の浮動小数点数であることを確認してください。
- オフライン環境では、Chart.js をダウンロードしてインラインで埋め込んでください:
<script>/* chart.js source */</script>。
HTML と Markdown で合計時間が一致しない
症状: HTML の統計カードに表示されるマージ後の合計が、total_hours.md の値と異なります。
原因: 照合処理を独立して 2 回実行したため、わずかに異なる結果が生成されています(浮動小数点の丸め誤差や、一方のファイルで古いデータが使われた場合など)。
対処方法: 照合処理を 1 回だけ実行し、結果を変数に格納して、両方の出力ファイルに同じ計算値を書き込んでください。出力ごとに個別に再計算しないでください。
注記
WakaTime の認証と設定: スクリプトは ~/.wakatime.cfg を自動的に読み込みます。プロジェクトごとのデータには、必ず --project を渡してください。WakaTime が追跡するのはアクティブなキー入力のみのため、Git の推定値より常に少なくなります。Claude Code を多用すると、WakaTime と実際の作業量に大きな差が生じます。認証の完全な設定方法、設定形式、制限事項については、references/data-sources.md を参照してください。
Codex CLI のデータソース: codex_messages.py は ~/.codex/sessions/YYYY/MM/DD/rollup-*.jsonl を読み込みます。各ファイルには session_meta(payload.cwd と payload.id を含みます。長時間継続するセッションや再開されたセッションではファイルの途中で再び現れることがあるため、cwd は固定と見なさず、継続的に追跡します)、実際のプロンプトを示す payload.type == "user_message" の event_msg エントリ、およびプロンプト間のエージェントの実行を示す、タイムスタンプ付きの多数の response_item/event_msg エントリ(ツール呼び出し、パッチ、推論)が含まれます。出力には timestamps(プロンプトのみ)、activity_timestamps(タイムスタンプ付きのすべてのイベント。照合にはこちらを使用してください)、およびフォルダーの移動を検出する alternate_paths が含まれます。ファイル構造の詳細については、references/data-sources.md を参照してください。
Claude Code のデータソース: claude_messages.py は 2 つのソースを使用します。~/.claude/history.jsonl(主要ソース。project フィールド = 絶対パス、timestamp はミリ秒、プロンプトのみ)と、~/.claude/projects/<encoded>/*.jsonl(セッションファイル。cwd フィールド、type=="user" および type=="assistant" のエントリー、ISO 形式のタイムスタンプ)です。エンコードされたディレクトリ名の形式:/Users/foo/bar → -Users-foo-bar。常に --filter より --project-path を優先してください。出力には timestamps(実際のユーザープロンプトのみ)と activity_timestamps(ユーザープロンプト + tool_result エントリー + アシスタントのエントリー。照合にはこちらを使用)が含まれます。フィールドの詳細については、references/data-sources.md を参照してください。
Cursor IDE のデータソース: cursor_messages.py は Cursor の SQLite データベース(.vscdb ファイル)を読み取ります。主要ソースはプラットフォーム固有の state.vscdb です(macOS:~/Library/Application Support/Cursor/User/globalStorage/、Windows:%APPDATA%\Cursor\User\globalStorage\、Linux:~/.config/Cursor/User/globalStorage/)。cursorDiskKV テーブルには、プロジェクトの照合に使用する workspaceUri を含む composerData:{sessionId} エントリーと、メッセージごとのタイムスタンプを含む bubbleId:{sessionId}:{messageId} エントリー(type=1 = ユーザー)が含まれています。フォールバックソースは、workspaceStorage/*/ 以下にあるワークスペースレベルの state.vscdb ファイルで、workspace.json が各ワークスペースとそのプロジェクトフォルダーを対応付けます。データベースは読み取り専用で開かれます。スクリプトはプラットフォームを自動検出します。出力形式は Claude/Codex のスクリプトと一致し、timestamps(ユーザーのバブルのみ)+ activity_timestamps(すべてのバブル/メッセージ、ロールを問わない。照合にはこちらを使用)+ フォルダー移動検出用の alternate_paths が含まれます。フィールドの詳細については、references/data-sources.md を参照してください。
照合アルゴリズム(2026-08-19 更新): 手作業で実装せず、reconcile.py を使って実行してください。ギャップのしきい値はデフォルトで 0.5h(より厳密な推定では 0.25h)で、Claude/Codex/Cursor では timestamps ではなく activity_timestamps に、Git では生のコミット timestamps に適用されます。すべてのソースは UTC のエポック秒の浮動小数点数の間隔に変換されます。ギャップがしきい値以下の場合、間隔は統合されます。間隔ごとの推定値は生の継続時間(end - start)で、バッファも下限値もありません。以前の 1.5h のしきい値 + max(duration + 0.5h, 0.5h) の式はレガシーです。これはプロンプトのみのタイムスタンプを基準に照合する際の補正用で、記録された最後のプロンプト以降もエージェントが実行を続けていた場合に、実作業を過少計上する問題への対応として使われていました(実際のプロジェクトで確認済み:単独に見えたプロンプトの後の 50 分間に、エージェント実行イベントが 1,343 件ありましたが、timestamps だけでは確認できませんでした)。アクティビティレベルの粒度がないソースでは、git_sessions.py のデフォルト(--raw なし)モードで引き続き利用できます。reconcile.py はデフォルトで、監督下と非監督下の時間の内訳(--presence-window-min、デフォルトは 10)も計算します。上記のワークフローセクションにある「監督下の時間と非監督下の時間」を参照してください。基礎となる疑似コード全体、セッション検出ヘルパー関数、日ごとの内訳用の日境界バケット分けヘルパーについては、references/reconciliation.md を参照してください。
フォルダー移動の検出: claude_messages.py、codex_messages.py、cursor_messages.py はすべて、指定されたパスで結果が 0 件の場合、既知の履歴をスキャンして一致するプロジェクト名を探します。alternate_paths リストを返します。空でない場合は、ユーザーに確認してから、古いパスを使って再実行し、タイムスタンプを統合してください。検出ロジックとエッジケースについては、references/folder-move-detection.md を参照してください。
マルチリポジトリプロジェクト: デフォルトでは、.git サブディレクトリをスキャンして、すべてのサブリポジトリを自動検出します。各サブリポジトリとルートディレクトリに対して、git_sessions.py、claude_messages.py、codex_messages.py、cursor_messages.py を実行してください。WakaTime の複数プロジェクト検出を使って、一致する WakaTime プロジェクト名をすべて見つけてください。すべてのセッション配列を統合し、日付順に再ソートして、日ごとの合計と総合計を再計算してください。