mcpField
T
time-lens

time-lens

github.com/vladmdgolam生产力946 次安装2 周前更新
代码仓库

关于 time-lens

time-lens 是面向开发者的项目工时追踪技能,可汇总多个代码库和编码工具的活动以估算工时。它整合 Git、WakaTime、Claude Code、Codex CLI 和 Cursor 数据,并指导生成 HTML 与 Markdown 报告。

主要功能

  1. 01收集 Git 会话数据
  2. 02获取 WakaTime 项目活动
  3. 03读取 Claude Code、Codex CLI 和 Cursor 活动
  4. 04整合数据并估算工时
  5. 05区分监督与无人值守时间
  6. 06生成 HTML 和 Markdown 报告

适用场景

  1. 01估算多代码库项目的工时
  2. 02对照编码 Agent 活动、提交记录和 IDE 使用
  3. 03查看每日会话与监督时长

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/vladmdgolam/agent-skills --skill time-lens

安装后在 Claude Code 中输入/time-lens确认已加载。

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

references/
data-sources.md
folder-move-detection.md
reconciliation.md
scripts/
claude_messages.py
codex_messages.py
cursor_messages.py
git_sessions.py
reconcile.py
wakatime_fetch.py

详细介绍

项目时间跟踪器

整合五种数据源 → 对账 → 生成 HTML 仪表板和 Markdown 报告。

脚本

所有脚本都位于与此 SKILL.md 同级的 scripts/ 目录中。使用 python3 运行:

脚本用途主要参数
git_sessions.py解析 Git 历史记录 → 会话 → 小时数<repo> --since YYYY-MM-DD --until YYYY-MM-DD [--raw]
wakatime_fetch.pyWakaTime 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 各自输出两个时间戳数组:timestamps(仅包含用户提示词,用于提示词计数指标)和 activity_timestamps(包含每个带时间戳的事件,包括工具调用/工具结果循环和助手回复;对账时请使用此数组)。有关这一区别为何重要,请参阅 references/reconciliation.md 中的“使用 activity_timestamps,而非 timestamps”:使用仅包含提示词的时间戳对账工时时,会悄无声息地漏掉实际工作时间。

请使用 reconcile.py,不要在 Python 中手动编写合并逻辑。 它是对下方算法的确定性实现——请在其他脚本已生成的 JSON 文件上运行它,而不是每次都重新推导合并/会话化/求交逻辑。临时手动编写这段逻辑,正是之前出现过一次真实错误的原因:将两次使用不同间隔阈值(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. 提取数据

对每个发现的仓库运行全部五个脚本。对于 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/ 的 monorepo 可能包含名为 my-project、frontend、backend 和 shared 的 WakaTime 项目)。单次 --project 查询会遗漏其他项目。

  1. 首先运行 wakatime_fetch.py,不带 --project,获取该日期范围的完整项目列表:

    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}, ...] }
    
  2. 筛选返回的 projects 列表,保留名称符合以下任一条件的项目:

    • 根项目目录的基名(例如 my-project)
    • 任一子仓库目录的基名(例如 frontend、backend)
    • 包含子仓库的任一中间目录的基名(例如 libs)
  3. 获取每个匹配项目的时间段:

    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
    
  4. 将所有匹配的 WakaTime 项目的时间段合并到一个列表中,以供对账。

这样做很重要: 在一个包含 4 个子仓库的项目中,单次 --project 查询只获取了实际 26.5 小时 WakaTime 数据中的 9 小时。其余 17.5 小时记录在子目录项目名称下。

文件夹移动检测: 如果 claude_messages.py、codex_messages.py 或 cursor_messages.py 返回 0 条结果,请检查输出中是否有 alternate_paths。如果有,请询问用户:

“在 /current/path 未找到 Claude/Codex 历史记录,但发现 project-name 在 /old/path 有会话记录。这个项目是否已移动?是否应该一并纳入这些历史记录?”

如果用户确认,请使用 --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 都可以重复传入——对于多仓库项目,每个子仓库传入一个;reconcile.py 会将它们合并。)

该脚本会确定性地执行以下操作:

  1. 将 git 的原始提交 timestamps,以及 Claude/Codex/Cursor 的 activity_timestamps(不是 timestamps——见下文)作为时间点事件。
  2. 根据间隔阈值分别对每个来源进行会话划分(--gap-hours,默认 0.5h;如需更严格、偏保守的估算,可使用 0.25)。
  3. 将 WakaTime 已生成的 [start, end] 区间与划分好的时间点来源合并。
  4. 将所有重叠或间隔不超过阈值的内容合并为最终会话。
  5. 累加原始时长——不加 +0.5h 缓冲,也不设 0.5h 下限(这是旧版行为;如需使用,例如针对没有活动级粒度、仅有 timestamps 的来源,请参阅 reconciliation.md)。
  6. 如果 --presence-window-min > 0(默认 10),还会计算有人监督与无人值守时长的拆分——合并后的引擎运行时长中,有多少落在实际用户提示词或 git 提交时间前后的这个时间窗口内,又有多少是 Agent 在附近没有人工确认的情况下运行。请参阅下文“有人监督与无人值守时长”。
  7. 如果指定 --daily,则使用当地时间 08:00 作为界限(--day-boundary-hour,默认 8)按天归类,避免跨夜会话在表格中被拆分到两天。

核算引擎运行时长时,务必使用 activity_timestamps,而非 timestamps(reconcile.py 会自动执行此操作)。timestamps 仅记录提示词;如果 Agent 在最后一条已记录提示词之后仍持续运行,就会让仍在活跃工作的会话看起来像一个时长为 0 的单点事件。activity_timestamps 包含工具调用/工具结果周期和助手回复,因此能反映 Agent 实际仍在工作的时间。具体示例(一个看似“时长为 0”的会话,实际连续工作了约 50 分钟)以及间隔阈值为何从旧默认值 1.5h 降至 0.5h,请参阅 references/reconciliation.md。

不要把不同 --gap-hours 运行结果中的 engine_hours 当作同一种度量进行比较——阈值为 15 分钟的总时长与阈值为 30 分钟的总时长是两种不同的量。如需同时获得两者,请运行两次 reconcile.py,并在每个结果中标明所用阈值。

有监督与无人值守时间

engine_hours 衡量的是 Agent 处于活动状态的时间,不一定代表有人类在旁监督。如果任务自主运行了 20 分钟以上,期间没有收到新提示词,这段时间仍会计入引擎时间,但未必能反映实际的亲自操作时间。reconcile.py 的有监督时间拆分功能会处理这个问题:它会围绕每条真实的用户提示词或 git 提交,构建一个前后各为 --presence-window-min 分钟的“在线窗口”,并报告 engine_hours 中有多少时间在窗口内、多少在窗口外。

窗口大小是一个会影响结果的参数,并非已确定的固定值:在一个实际项目中,±5 分钟时有监督时间占 72%,±30 分钟时占 99%。推荐的默认值是 ±10 分钟:时间足够长,可以涵盖正常的“阅读输出、思考、回复”间隔;也足够短,能让真正离开键盘的时段显示为无人值守。请始终在报告数字的同时注明所用的窗口大小。

为何合并很重要:AI Agent 提示词(Claude/Codex/Cursor)常会在同一工作时段的 git 提交前后几分钟出现。WakaTime 捕获的 IDE 击键可能发生在两次提交之间。用户可能先用 Claude 调研,再使用 Cursor 的 AI,然后编写代码(WakaTime),最后提交(git)——这些都属于同一时段。合并所有五种来源,可以捕获真实的时段边界,同时避免重复计数。

  • 合并后的总时长取代“仅 git”总时长,作为主要估算值
  • 显示 WakaTime 小时数供参考(仅统计活动击键,始终更低)

完整的底层算法说明(由 reconcile.py 实现)、按天分桶的依据,以及旧版缓冲区/下限公式,请参阅 references/reconciliation.md。

4. 生成 HTML 仪表板

生成单文件 HTML,内嵌 Chart.js(CDN)。使用深色主题(背景为 #0a0a0a,卡片为 #1a1a1a)。

必需部分:

  1. 统计卡片 — 合并总时长(git∪claude∪codex∪cursor∪waka)、Git 估算值、WakaTime、时段数、提交数、Claude 提示词数、Codex 提示词数、Cursor 提示词数
  2. 每日活动图表 — 重叠柱形图(git + WakaTime + 合并时长)+ 次坐标轴上的 AI 提示词折线
  3. 甘特时间线 — UTC 水平条形图;git、Claude、Codex 和 Cursor 分别使用不同颜色的数据集,显示在同一图表上(同一天内有重叠时,使用不同的泳道行)
  4. 数据表 — 时段 | 时间(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;所有图表均已渲染;JS 控制台中没有错误。
  • 总时长一致 — HTML 中的“合并总时长”统计卡片与 total_hours.md 中的“预计总工作时长”一致(允许因四舍五入产生 ±0.01h 的误差)。
  • 日期范围与输入一致 — 数据表和时间线部分中的首尾日期与请求的 --since/--until 值一致。
  • 会话数不为零 — 至少有一个来源提供了会话数据。如果所有来源都返回 0,则说明有问题(路径错误、项目名称错误,或日期范围不在项目历史记录内)。

示例

示例 1:单个代码仓库,标准报告

触发语句:“我这个月在 api-server 项目上花了多少小时?生成完整报告。”

操作:

  1. 确定范围:项目位于 /Users/alice/code/api-server,日期范围推断为 2026-02-01 → 2026-02-23(本月至今)。

  2. 提取数据:

    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
    
  3. 对账:git_sessions.py 返回 14 个会话(22.5h),WakaTime 返回 11.2h,Claude 返回 9 天内的 47 条提示词,Codex 返回 0 条,Cursor 返回 3 天内的 12 条提示词。合并并去重、合并间隔后,总时长为:27.1h。

  4. 在 /Users/alice/code/api-server/ 中生成 work-hours-analysis.html 和 total_hours.md。

结果:“你在 2026 年 2 月于 api-server 项目上花费了约 27.1 小时(14 个 git 会话、47 条 Claude 提示词、12 条 Cursor 提示词;WakaTime 参考值:11.2h 的活跃打字时间)。报告已保存至 /Users/alice/code/api-server/work-hours-analysis.html。”


示例 2:包含文件夹迁移的多代码仓库项目

触发语句:“计算 marketplace 项目的开发总时长——它有一个前端代码仓库和一个后端代码仓库。另外我记得我曾经重命名过文件夹。”

操作:

  1. 确定范围:两个代码仓库分别位于 /Users/bob/marketplace-backend 和 /Users/bob/marketplace-frontend,用户指定日期范围为 2025-11-01 → 2026-01-31。

  2. 提取数据:

    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
    
  3. claude_messages.py 返回 0 条结果,并附带 alternate_paths: ["/Users/bob/old-market/backend"]。

  4. 询问用户:“在 /Users/bob/marketplace-backend 中没有找到 Claude 历史记录,但在 /Users/bob/old-market/backend 中找到了 backend 的会话。这是之前的位置吗?要包含那里的历史记录吗?”

  5. 用户确认。重新运行:python3 claude_messages.py --project-path /Users/bob/old-market/backend。合并两次运行的时间戳。

  6. 合并两个代码仓库(后端 + 前端)的 git 提交时间戳与 Claude 的 activity_timestamps,排序后,在 0.5h 间隔阈值内重新合并。与所有来源的数据进行对账。

结果:“预计总时长:84.7h,跨越 3 个月(后端 + 前端合计,包括旧路径 /Users/bob/old-market/backend 中的 Claude 历史记录)。”


故障排除

WakaTime API 密钥缺失或无效

症状:wakatime_fetch.py 因身份验证错误、HTTP 401 或 KeyError: 'api_key' 而退出。

解决方法:

  1. 检查配置文件是否存在:cat ~/.wakatime.cfg
  2. 如果不存在,请创建:
    [settings]
    api_key = waka_xxxx...
    
  3. 从 wakatime.com/settings/api-key 获取密钥。
  4. 如果密钥存在但返回 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

找到了 alternate_paths,但用户表示路径不正确

**症状:**脚本报告了备用路径,但用户表示其中没有一个是旧项目位置。

**解决方法:**改用 --filter <project-name>,它会匹配目录名称中的子字符串,而不是精确匹配路径。请注意,这可能会找到名称相似但无关的项目——合并前与用户一起检查会话列表。

python3 claude_messages.py --filter marketplace

HTML 图表显示空白或 NaN

**症状:**HTML 文件可以打开,但图表为空或显示“NaN”值。

可能原因:

  • 对账产生了 null 或 None 值,这些值被序列化到 JS 数据数组中。
  • 写入 HTML 前未将时间戳转换为 UTC(本地 epoch 与 UTC epoch 不匹配)。
  • Chart.js CDN 加载失败(离线环境)。

解决方法:

  1. 打开浏览器 DevTools 控制台——具体的 JS 错误会指出问题所在。
  2. 确认所有 epoch 时间戳都是 UTC 浮点数,而不是字符串。
  3. 对于离线环境,下载 Chart.js 并将其内嵌:<script>/* chart.js source */</script>。

HTML 与 Markdown 中的总时长不一致

**症状:**HTML 统计卡片显示的合并总时长与 total_hours.md 不同。

**原因:**分别独立运行了两次对账,结果略有不同(例如,由于浮点数舍入,或其中一个文件使用了过期数据)。

**解决方法:**只运行一次对账,将结果存储在变量中,并将相同的计算值写入两个输出文件。不要为每个输出文件分别重新计算。


备注

**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,而不是假定它固定不变)、用于表示实际提示词的 event_msg 条目(payload.type == "user_message"),以及许多其他带时间戳的 response_item/event_msg 条目(工具调用、补丁、推理),用于标记 Agent 在提示词之间的执行活动。输出包括 timestamps(仅提示词)、activity_timestamps(每个带时间戳的事件——用于对账)和用于检测文件夹移动的 alternate_paths。有关完整的文件结构,请参阅 references/data-sources.md。 Claude Code 数据源: claude_messages.py 使用两个数据源:~/.claude/history.jsonl(主要数据源;project 字段 = 绝对路径,timestamp 以毫秒为单位,仅包含提示词)和 ~/.claude/projects/<encoded>/*.jsonl(会话文件;包含 cwd 字段、type=="user" 和 type=="assistant" 条目,以及 ISO 时间戳)。编码后的目录名格式:/Users/foo/bar → -Users-foo-bar。始终优先使用 --project-path,而非 --filter。输出包含 timestamps(仅真实用户提示词)和 activity_timestamps(用户提示词 + tool_result 条目 + assistant 条目——使用此字段进行对账)。完整字段参考请见 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 表包含 composerData:{sessionId} 条目(带有用于项目匹配的 workspaceUri)和 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 的 activity_timestamps(而非 timestamps),以及 git 的原始提交 timestamps。所有数据源都会转换为 UTC epoch 浮点时间间隔。若间隔 ≤ 阈值,则合并时间间隔。每个时间间隔的估算值为原始时长(end - start),不加缓冲,也不设下限。旧的 1.5h 阈值 + max(duration + 0.5h, 0.5h) 公式已弃用——它用于补偿基于仅包含提示词的时间戳进行对账所造成的低估;只要 Agent 在最后一条记录的提示词之后仍继续执行,就会低估实际工作量(已在真实项目中证实:一个看似孤立的提示词在接下来 50 分钟内触发了 1,343 个 Agent 执行事件,仅凭 timestamps 无法看到这些事件)。对于缺少活动级粒度的数据源,该功能仍可通过 git_sessions.py 的默认(非 --raw)模式使用。reconcile.py 默认还会计算受监督与无人值守的时间划分(--presence-window-min,默认值为 10)——请参见上方工作流部分中的“受监督与无人值守时间”。完整底层伪代码、会话检测辅助函数,以及用于每日明细的按日边界分组辅助函数,请见 references/reconciliation.md。

文件夹移动检测: 当提供的路径下未找到结果时,claude_messages.py、codex_messages.py 和 cursor_messages.py 都会扫描已知历史记录,查找名称匹配的项目。返回 alternate_paths 列表。如果列表非空,请询问用户确认,然后使用旧路径重新运行并合并时间戳。检测逻辑和边缘情况请见 references/folder-move-detection.md。

多仓库项目: 默认情况下,扫描 .git 子目录以自动发现所有子仓库。在每个子仓库和根目录上运行 git_sessions.py、claude_messages.py、codex_messages.py 和 cursor_messages.py。使用 WakaTime 多项目发现功能查找所有匹配的 WakaTime 项目名称。合并所有会话数组,按日期重新排序,并重新计算每日总计和总计数。

评论

支持 Markdown