from __future__ import annotations import argparse import os from pathlib import Path from zoneinfo import ZoneInfo, ZoneInfoNotFoundError from .core import build_report from .render import write_reports def main(argv: list[str] | None = None) -> int: parser = _build_parser() args = parser.parse_args(argv) try: ZoneInfo(args.tz) except ZoneInfoNotFoundError: parser.error(f"unknown timezone: {args.tz}") report = build_report( state_path=Path(args.state).expanduser(), sessions_dir=Path(args.sessions_dir).expanduser(), tz_name=args.tz, days=args.days, top=args.top, ) written = write_reports(report, Path(args.out).expanduser(), args.format) for path in written: print(f"Wrote {path}") print(f"Sessions: {len(report.sessions):,}") print(f"Total tokens: {report.total_tokens:,}") if report.warnings: print(f"Warnings: {len(report.warnings):,}") return 0 def _build_parser() -> argparse.ArgumentParser: parser = argparse.ArgumentParser( prog="codex-usage-profiler", description="Summarize local Codex usage from state_5.sqlite and rollout JSONL files.", ) parser.add_argument( "--state", default="~/.codex/state_5.sqlite", help="Path to Codex state_5.sqlite. Default: %(default)s", ) parser.add_argument( "--sessions-dir", default="~/.codex/sessions", help="Root directory containing rollout JSONL files. Default: %(default)s", ) parser.add_argument( "--out", default="reports", help="Output directory. Default: %(default)s", ) parser.add_argument( "--format", choices=["md", "html", "both"], default="both", help="Report format to write. Default: %(default)s", ) parser.add_argument( "--tz", default=os.environ.get("TZ", "Europe/Berlin"), help="Timezone for day/week grouping. Default: %(default)s", ) parser.add_argument( "--days", type=int, default=None, help="Include the last N local calendar days including today.", ) parser.add_argument( "--top", type=int, default=20, help="Number of top sessions to include. Default: %(default)s", ) return parser