codex-usage-tracking 0.6.1__tar.gz → 0.7.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/.codex-plugin/plugin.json +1 -1
- {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/CHANGELOG.md +8 -0
- {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/PKG-INFO +3 -3
- {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/README.md +2 -2
- {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/docs/dashboard-guide.md +3 -3
- {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/docs/development.md +7 -7
- {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/docs/one-dot-oh-readiness.md +8 -8
- {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/docs/pricing-and-credits.md +5 -4
- {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/docs/privacy.md +2 -1
- {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/pyproject.toml +1 -1
- {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/skills/codex-usage-tracker/scripts/run_mcp.py +2 -2
- {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/src/codex_usage_tracker/__init__.py +1 -1
- {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/src/codex_usage_tracker/dashboard.py +6 -0
- {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/src/codex_usage_tracker/models.py +8 -0
- {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/src/codex_usage_tracker/parser.py +87 -0
- {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/src/codex_usage_tracker/plugin_data/dashboard/dashboard.css +20 -1
- {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/src/codex_usage_tracker/plugin_data/dashboard/dashboard.js +13 -6
- {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/src/codex_usage_tracker/plugin_data/dashboard/dashboard_analysis.js +5 -0
- {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/src/codex_usage_tracker/plugin_data/dashboard/dashboard_cells.js +5 -0
- {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/src/codex_usage_tracker/plugin_data/dashboard/dashboard_format.js +1 -0
- {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/src/codex_usage_tracker/plugin_data/dashboard/dashboard_i18n.js +11 -0
- {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/src/codex_usage_tracker/plugin_data/dashboard/dashboard_insights.js +1 -1
- {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/src/codex_usage_tracker/plugin_data/dashboard/dashboard_state.js +15 -3
- {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/src/codex_usage_tracker/plugin_data/dashboard/dashboard_status.js +105 -1
- {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/src/codex_usage_tracker/plugin_data/dashboard/dashboard_tables.js +5 -7
- {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/src/codex_usage_tracker/plugin_data/dashboard/dashboard_template.html +5 -5
- {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/src/codex_usage_tracker/plugin_data/dashboard/locales/ar.json +12 -0
- {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/src/codex_usage_tracker/plugin_data/dashboard/locales/de.json +12 -0
- {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/src/codex_usage_tracker/plugin_data/dashboard/locales/en.json +12 -0
- {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/src/codex_usage_tracker/plugin_data/dashboard/locales/es.json +12 -0
- {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/src/codex_usage_tracker/plugin_data/dashboard/locales/fr.json +12 -0
- {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/src/codex_usage_tracker/plugin_data/dashboard/locales/it.json +12 -0
- {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/src/codex_usage_tracker/plugin_data/dashboard/locales/ja.json +12 -0
- {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/src/codex_usage_tracker/plugin_data/dashboard/locales/ko.json +12 -0
- {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/src/codex_usage_tracker/plugin_data/dashboard/locales/pt.json +12 -0
- {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/src/codex_usage_tracker/plugin_data/dashboard/locales/ru.json +12 -0
- {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/src/codex_usage_tracker/plugin_data/dashboard/locales/vi.json +12 -0
- {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/src/codex_usage_tracker/plugin_data/dashboard/locales/zh-Hans.json +12 -0
- {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/src/codex_usage_tracker/plugin_data/docs/dashboard-guide.html +2 -2
- {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/src/codex_usage_tracker/schema.py +8 -0
- {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/src/codex_usage_tracker/server.py +6 -0
- {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/src/codex_usage_tracker/store.py +173 -0
- {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/src/codex_usage_tracker/store_schema.py +20 -1
- {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/src/codex_usage_tracking.egg-info/PKG-INFO +3 -3
- {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/tests/store_dashboard_helpers.py +30 -0
- {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/tests/test_dashboard_payload.py +50 -2
- {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/tests/test_dashboard_server.py +3 -0
- {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/tests/test_dashboard_state.py +22 -1
- {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/tests/test_i18n.py +8 -3
- {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/tests/test_parser.py +74 -0
- {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/tests/test_store_dashboard_mcp.py +117 -6
- {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/tests/test_store_migrations.py +9 -3
- {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/.mcp.json +0 -0
- {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/AGENTS.md +0 -0
- {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/CONTRIBUTING.md +0 -0
- {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/LICENSE +0 -0
- {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/MANIFEST.in +0 -0
- {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/SECURITY.md +0 -0
- {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/assets/icon.svg +0 -0
- {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/docs/architecture.md +0 -0
- {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/docs/assets/dashboard-call-investigator-evidence.png +0 -0
- {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/docs/assets/dashboard-call-investigator-preview.png +0 -0
- {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/docs/assets/dashboard-call-investigator.png +0 -0
- {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/docs/assets/dashboard-calls-preview.png +0 -0
- {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/docs/assets/dashboard-calls.png +0 -0
- {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/docs/assets/dashboard-details.png +0 -0
- {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/docs/assets/dashboard-insights.png +0 -0
- {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/docs/assets/dashboard-threads.png +0 -0
- {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/docs/assets/plugin-prompts.png +0 -0
- {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/docs/assets/plugin-thread-leaderboard.png +0 -0
- {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/docs/assets/ux/call-detail-panel.png +0 -0
- {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/docs/assets/ux/insight-overview.png +0 -0
- {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/docs/assets/ux/thread-investigation.png +0 -0
- {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/docs/call-drilldown-performance-checklist.md +0 -0
- {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/docs/cli-json-schemas.md +0 -0
- {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/docs/cli-reference.md +0 -0
- {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/docs/install.md +0 -0
- {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/docs/mcp.md +0 -0
- {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/docs/ui-ux-improvement-plan.md +0 -0
- {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/scripts/benchmark_synthetic_history.py +0 -0
- {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/scripts/check_release.py +0 -0
- {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/scripts/install_local_plugin.py +0 -0
- {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/scripts/smoke_installed_package.py +0 -0
- {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/setup.cfg +0 -0
- {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/skills/codex-usage-api/SKILL.md +0 -0
- {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/skills/codex-usage-tracker/SKILL.md +0 -0
- {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/src/codex_usage_tracker/__main__.py +0 -0
- {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/src/codex_usage_tracker/allowance.py +0 -0
- {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/src/codex_usage_tracker/api_payloads.py +0 -0
- {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/src/codex_usage_tracker/call_origin.py +0 -0
- {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/src/codex_usage_tracker/cli.py +0 -0
- {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/src/codex_usage_tracker/cli_parser.py +0 -0
- {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/src/codex_usage_tracker/context.py +0 -0
- {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/src/codex_usage_tracker/costing.py +0 -0
- {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/src/codex_usage_tracker/diagnostics.py +0 -0
- {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/src/codex_usage_tracker/formatting.py +0 -0
- {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/src/codex_usage_tracker/i18n.py +0 -0
- {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/src/codex_usage_tracker/json_contracts.py +0 -0
- {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/src/codex_usage_tracker/mcp_server.py +0 -0
- {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/src/codex_usage_tracker/paths.py +0 -0
- {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/src/codex_usage_tracker/plugin_data/__init__.py +0 -0
- {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/src/codex_usage_tracker/plugin_data/assets/icon.svg +0 -0
- {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/src/codex_usage_tracker/plugin_data/dashboard/dashboard_actions.js +0 -0
- {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/src/codex_usage_tracker/plugin_data/dashboard/dashboard_call.css +0 -0
- {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/src/codex_usage_tracker/plugin_data/dashboard/dashboard_call_diagnostics.js +0 -0
- {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/src/codex_usage_tracker/plugin_data/dashboard/dashboard_call_investigator.js +0 -0
- {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/src/codex_usage_tracker/plugin_data/dashboard/dashboard_data.js +0 -0
- {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/src/codex_usage_tracker/plugin_data/dashboard/dashboard_detail.css +0 -0
- {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/src/codex_usage_tracker/plugin_data/dashboard/dashboard_details.js +0 -0
- {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/src/codex_usage_tracker/plugin_data/dashboard/dashboard_events.js +0 -0
- {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/src/codex_usage_tracker/plugin_data/dashboard/dashboard_filters.js +0 -0
- {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/src/codex_usage_tracker/plugin_data/dashboard/dashboard_insights.css +0 -0
- {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/src/codex_usage_tracker/plugin_data/dashboard/dashboard_layout.css +0 -0
- {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/src/codex_usage_tracker/plugin_data/dashboard/dashboard_live.js +0 -0
- {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/src/codex_usage_tracker/plugin_data/dashboard/dashboard_payload_cache.js +0 -0
- {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/src/codex_usage_tracker/plugin_data/dashboard/dashboard_responsive.css +0 -0
- {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/src/codex_usage_tracker/plugin_data/dashboard/dashboard_tables.css +0 -0
- {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/src/codex_usage_tracker/plugin_data/dashboard/dashboard_tooltips.js +0 -0
- {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/src/codex_usage_tracker/plugin_data/docs/assets/dashboard-call-investigator-evidence.png +0 -0
- {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/src/codex_usage_tracker/plugin_data/docs/assets/dashboard-call-investigator-preview.png +0 -0
- {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/src/codex_usage_tracker/plugin_data/docs/assets/dashboard-call-investigator.png +0 -0
- {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/src/codex_usage_tracker/plugin_data/docs/assets/dashboard-calls-preview.png +0 -0
- {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/src/codex_usage_tracker/plugin_data/docs/assets/dashboard-calls.png +0 -0
- {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/src/codex_usage_tracker/plugin_data/docs/assets/dashboard-details.png +0 -0
- {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/src/codex_usage_tracker/plugin_data/docs/assets/dashboard-insights.png +0 -0
- {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/src/codex_usage_tracker/plugin_data/docs/assets/dashboard-threads.png +0 -0
- {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/src/codex_usage_tracker/plugin_data/docs/assets/plugin-prompts.png +0 -0
- {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/src/codex_usage_tracker/plugin_data/docs/assets/plugin-thread-leaderboard.png +0 -0
- {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/src/codex_usage_tracker/plugin_data/rate_cards/codex-credit-rates.json +0 -0
- {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/src/codex_usage_tracker/plugin_data/skills/codex-usage-api/SKILL.md +0 -0
- {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/src/codex_usage_tracker/plugin_data/skills/codex-usage-tracker/SKILL.md +0 -0
- {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/src/codex_usage_tracker/plugin_installer.py +0 -0
- {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/src/codex_usage_tracker/pricing.py +0 -0
- {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/src/codex_usage_tracker/pricing_config.py +0 -0
- {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/src/codex_usage_tracker/pricing_estimates.py +0 -0
- {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/src/codex_usage_tracker/pricing_openai.py +0 -0
- {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/src/codex_usage_tracker/projects.py +0 -0
- {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/src/codex_usage_tracker/recommendations.py +0 -0
- {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/src/codex_usage_tracker/redaction.py +0 -0
- {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/src/codex_usage_tracker/reports.py +0 -0
- {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/src/codex_usage_tracker/server_utils.py +0 -0
- {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/src/codex_usage_tracker/store_query_sql.py +0 -0
- {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/src/codex_usage_tracker/store_sources.py +0 -0
- {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/src/codex_usage_tracker/store_thread_summaries.py +0 -0
- {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/src/codex_usage_tracker/support.py +0 -0
- {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/src/codex_usage_tracker/threads.py +0 -0
- {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/src/codex_usage_tracking.egg-info/SOURCES.txt +0 -0
- {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/src/codex_usage_tracking.egg-info/dependency_links.txt +0 -0
- {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/src/codex_usage_tracking.egg-info/entry_points.txt +0 -0
- {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/src/codex_usage_tracking.egg-info/requires.txt +0 -0
- {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/src/codex_usage_tracking.egg-info/top_level.txt +0 -0
- {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/tests/test_allowance.py +0 -0
- {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/tests/test_call_origin.py +0 -0
- {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/tests/test_cli_lifecycle.py +0 -0
- {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/tests/test_cli_release.py +0 -0
- {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/tests/test_context_evidence.py +0 -0
- {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/tests/test_dashboard_data.py +0 -0
- {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/tests/test_json_contracts.py +0 -0
- {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/tests/test_mcp_integration.py +0 -0
- {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/tests/test_mcp_launcher.py +0 -0
- {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/tests/test_plugin_installer.py +0 -0
- {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/tests/test_pricing.py +0 -0
- {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/tests/test_privacy.py +0 -0
- {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/tests/test_projects.py +0 -0
- {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/tests/test_recommendations.py +0 -0
- {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/tests/test_redaction.py +0 -0
- {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/tests/test_schema.py +0 -0
- {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/tests/test_support.py +0 -0
- {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/tests/test_threads.py +0 -0
|
@@ -2,6 +2,14 @@
|
|
|
2
2
|
|
|
3
3
|
## Unreleased
|
|
4
4
|
|
|
5
|
+
## 0.7.0 - 2026-06-18
|
|
6
|
+
|
|
7
|
+
- Parse latest observed Codex usage snapshots from local rate-limit and token-count log events without persisting raw transcript text.
|
|
8
|
+
- Store observed 5h and weekly usage snapshot fields in aggregate rows and expose a latest-observed usage summary for dashboard and API consumers.
|
|
9
|
+
- Add a dashboard card for latest observed 5h and weekly usage with wording that distinguishes local observations from authoritative account limits.
|
|
10
|
+
- Default the dashboard table experience to time-sorted Calls, replace the visible Signals column with Reasoning Output, and keep the Signals field out of the table for now.
|
|
11
|
+
- Ignore known non-token parser events so refreshes stay focused on usage-bearing records.
|
|
12
|
+
|
|
5
13
|
## 0.6.1 - 2026-06-13
|
|
6
14
|
|
|
7
15
|
- Polish the README landing screenshots with matched dashboard/investigator previews and an additional lower investigator evidence view.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: codex-usage-tracking
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.7.0
|
|
4
4
|
Summary: Unofficial local Codex plugin and dashboard for investigating aggregate token usage, costs, caching, and thread patterns.
|
|
5
5
|
Author: Douglas Monsky
|
|
6
6
|
License-Expression: MIT
|
|
@@ -188,7 +188,7 @@ Optional allowance context:
|
|
|
188
188
|
codex-usage-tracker parse-allowance "5h 79% 6:50 PM Weekly 33% Jun 7"
|
|
189
189
|
```
|
|
190
190
|
|
|
191
|
-
The tracker cannot read your logged-in ChatGPT plan or live remaining usage automatically.
|
|
191
|
+
The tracker cannot read your logged-in ChatGPT plan or live remaining usage automatically. When local Codex logs include `token_count.rate_limits`, the dashboard can show the latest observed 5-hour and weekly remaining percentages from those logs. Otherwise, allowance values are only as accurate as the values you manually copy from Codex Settings, `/status`, or another trusted usage display. Details: [Pricing, Credits, And Allowance](docs/pricing-and-credits.md).
|
|
192
192
|
|
|
193
193
|
## What It Includes
|
|
194
194
|
|
|
@@ -296,7 +296,7 @@ This is optional. The normal shell install above is the fastest trusted path for
|
|
|
296
296
|
- Token counts come from Codex's logged counters; the tracker does not re-tokenize prompts.
|
|
297
297
|
- Pricing and rate-card sources can change outside this project.
|
|
298
298
|
- Pricing and Codex credit estimates depend on local rate data and confidence labels and are not guaranteed to match exact billing.
|
|
299
|
-
- Live account allowance cannot be read automatically by this local tracker; remaining 5-hour and weekly allowance is only
|
|
299
|
+
- Live account allowance cannot be read automatically by this local tracker; remaining 5-hour and weekly allowance is shown only from local Codex `token_count.rate_limits` snapshots when present, or from copied values you configure.
|
|
300
300
|
- Local Codex logs may not include usage from other ChatGPT agentic surfaces that share the same allowance.
|
|
301
301
|
- Plugin discovery limitations are separate from core Python CLI/dashboard support.
|
|
302
302
|
- Parent-child thread relationships are only as good as the metadata Codex logs; inferred auto-review attachments are labeled as inferred.
|
|
@@ -150,7 +150,7 @@ Optional allowance context:
|
|
|
150
150
|
codex-usage-tracker parse-allowance "5h 79% 6:50 PM Weekly 33% Jun 7"
|
|
151
151
|
```
|
|
152
152
|
|
|
153
|
-
The tracker cannot read your logged-in ChatGPT plan or live remaining usage automatically.
|
|
153
|
+
The tracker cannot read your logged-in ChatGPT plan or live remaining usage automatically. When local Codex logs include `token_count.rate_limits`, the dashboard can show the latest observed 5-hour and weekly remaining percentages from those logs. Otherwise, allowance values are only as accurate as the values you manually copy from Codex Settings, `/status`, or another trusted usage display. Details: [Pricing, Credits, And Allowance](docs/pricing-and-credits.md).
|
|
154
154
|
|
|
155
155
|
## What It Includes
|
|
156
156
|
|
|
@@ -258,7 +258,7 @@ This is optional. The normal shell install above is the fastest trusted path for
|
|
|
258
258
|
- Token counts come from Codex's logged counters; the tracker does not re-tokenize prompts.
|
|
259
259
|
- Pricing and rate-card sources can change outside this project.
|
|
260
260
|
- Pricing and Codex credit estimates depend on local rate data and confidence labels and are not guaranteed to match exact billing.
|
|
261
|
-
- Live account allowance cannot be read automatically by this local tracker; remaining 5-hour and weekly allowance is only
|
|
261
|
+
- Live account allowance cannot be read automatically by this local tracker; remaining 5-hour and weekly allowance is shown only from local Codex `token_count.rate_limits` snapshots when present, or from copied values you configure.
|
|
262
262
|
- Local Codex logs may not include usage from other ChatGPT agentic surfaces that share the same allowance.
|
|
263
263
|
- Plugin discovery limitations are separate from core Python CLI/dashboard support.
|
|
264
264
|
- Parent-child thread relationships are only as good as the metadata Codex logs; inferred auto-review attachments are labeled as inferred.
|
|
@@ -111,7 +111,7 @@ Useful interpretation notes:
|
|
|
111
111
|
- `Cached input` and `Uncached input` are split so cache behavior is visible without storing transcript text.
|
|
112
112
|
- A cost with `*` means the pricing row is marked as a best-guess estimate.
|
|
113
113
|
- Codex credits are estimated from aggregate input, cached-input, and output token counters. Direct model matches use the bundled OpenAI Codex rate-card snapshot; inferred labels are marked estimated, and local credit-rate overrides are marked user-provided.
|
|
114
|
-
- `Usage
|
|
114
|
+
- `Usage observed` is not a live account query. It uses the latest local Codex `token_count.rate_limits` snapshot when present; otherwise configure `~/.codex-usage-tracker/allowance.json` with values copied from Codex Settings > Usage, the Codex Usage dashboard, or `/status` when you want current remaining allowance context.
|
|
115
115
|
|
|
116
116
|
## Threads View
|
|
117
117
|
|
|
@@ -212,7 +212,7 @@ The dashboard is designed to be shareable as an aggregate report, but only after
|
|
|
212
212
|
|
|
213
213
|
It includes:
|
|
214
214
|
|
|
215
|
-
- session ids, thread names, cwd values, source file paths, timestamps, model labels, reasoning effort, token counts, cost estimates, Codex credit estimates, optional
|
|
215
|
+
- session ids, thread names, cwd values, source file paths, timestamps, model labels, reasoning effort, token counts, cost estimates, Codex credit estimates, optional observed/copied allowance windows, and derived ratios
|
|
216
216
|
|
|
217
217
|
It does not include:
|
|
218
218
|
|
|
@@ -222,7 +222,7 @@ The screenshots in this guide are produced from synthetic fixture data used by t
|
|
|
222
222
|
|
|
223
223
|
Use `--privacy-mode redacted` or `--privacy-mode strict` before sharing generated dashboards, CSV exports, query JSON, or support bundles. Redacted mode removes raw cwd/source paths and hides unnamed project names behind stable hashes. Strict mode also hides project-relative cwd, branch, and tags. Configured project aliases are treated as explicit display opt-ins in both modes.
|
|
224
224
|
|
|
225
|
-
Remaining 5-hour and weekly allowance is not
|
|
225
|
+
Remaining 5-hour and weekly allowance is not inferred from the logged-in account plan. When Codex writes local `token_count.rate_limits` snapshots, the dashboard can show the latest observed local-log percentages; otherwise add `~/.codex-usage-tracker/allowance.json` when you want copied allowance state. Local Codex logs may also omit usage from other ChatGPT agentic surfaces that share the same allowance.
|
|
226
226
|
|
|
227
227
|
Archived sessions are excluded from dashboard payloads by default. The `All history` mode is an explicit opt-in because archived logs can make refreshes slower and can make current dashboards look inflated by older work.
|
|
228
228
|
|
|
@@ -38,7 +38,7 @@ fix/<issue-number>-short-description
|
|
|
38
38
|
docs/<issue-number>-short-description
|
|
39
39
|
chore/<issue-number>-short-description
|
|
40
40
|
test/<issue-number>-short-description
|
|
41
|
-
release/0.
|
|
41
|
+
release/0.7.0
|
|
42
42
|
hotfix/0.3.3
|
|
43
43
|
```
|
|
44
44
|
|
|
@@ -91,7 +91,7 @@ blocked
|
|
|
91
91
|
Recommended milestones:
|
|
92
92
|
|
|
93
93
|
```text
|
|
94
|
-
0.
|
|
94
|
+
0.7.0
|
|
95
95
|
1.0-readiness
|
|
96
96
|
1.0.0
|
|
97
97
|
```
|
|
@@ -146,8 +146,8 @@ python scripts/smoke_installed_package.py --docker
|
|
|
146
146
|
To verify the public PyPI package instead of the local checkout:
|
|
147
147
|
|
|
148
148
|
```bash
|
|
149
|
-
python scripts/smoke_installed_package.py --from-pypi --version 0.
|
|
150
|
-
python scripts/smoke_installed_package.py --docker --from-pypi --version 0.
|
|
149
|
+
python scripts/smoke_installed_package.py --from-pypi --version 0.7.0
|
|
150
|
+
python scripts/smoke_installed_package.py --docker --from-pypi --version 0.7.0
|
|
151
151
|
```
|
|
152
152
|
|
|
153
153
|
`scripts/check_release.py` treats these public-package smoke commands as release-state claims. Keep their `--version` and `codex-usage-tracking==...` values aligned with `pyproject.toml`; the release gate fails when the docs claim a different public version. It also checks that install docs point at the real PyPI distribution, `codex-usage-tracking`, and keep the warning that `codex-usage-tracker` is a different PyPI package.
|
|
@@ -286,8 +286,8 @@ After the release branch merges, tag from updated `main`, not from an unreviewed
|
|
|
286
286
|
```bash
|
|
287
287
|
git switch main
|
|
288
288
|
git pull --ff-only
|
|
289
|
-
git tag -a v0.
|
|
290
|
-
git push origin v0.
|
|
289
|
+
git tag -a v0.7.0 -m "codex-usage-tracker 0.7.0"
|
|
290
|
+
git push origin v0.7.0
|
|
291
291
|
```
|
|
292
292
|
|
|
293
293
|
Do not create or push release tags without maintainer approval.
|
|
@@ -296,7 +296,7 @@ Do not create or push release tags without maintainer approval.
|
|
|
296
296
|
|
|
297
297
|
Publishing uses GitHub Actions Trusted Publishing through `.github/workflows/publish.yml`; do not upload from a local machine and do not add PyPI or TestPyPI API tokens.
|
|
298
298
|
|
|
299
|
-
The first public package release, `0.3.0`, was published on June 8, 2026. Patch release `0.3.1` followed the same day to ship the live-dashboard skill launch fix. Patch release `0.3.2` made dashboard launch refresh the default and added runtime enablement for context loading. Minor release `0.4.0` added Python 3.14 support, release recovery docs, stricter privacy/support-bundle regression coverage, and large-history benchmark thresholds. Patch release `0.4.1` was published by workflow dispatch from `main`; it hardened the PyPI publish workflow and checked off completed 1.0 readiness gates. Minor release `0.5.0` added dashboard localization support and initial language catalogs. Minor release `0.6.0` is the performance and call-drilldown release with SQL-backed live API slices, materialized thread summaries, faster evidence loading, and dashboard runtime module refactors. Patch release `0.6.1` aligns the final README/package screenshots and companion plugin assets.
|
|
299
|
+
The first public package release, `0.3.0`, was published on June 8, 2026. Patch release `0.3.1` followed the same day to ship the live-dashboard skill launch fix. Patch release `0.3.2` made dashboard launch refresh the default and added runtime enablement for context loading. Minor release `0.4.0` added Python 3.14 support, release recovery docs, stricter privacy/support-bundle regression coverage, and large-history benchmark thresholds. Patch release `0.4.1` was published by workflow dispatch from `main`; it hardened the PyPI publish workflow and checked off completed 1.0 readiness gates. Minor release `0.5.0` added dashboard localization support and initial language catalogs. Minor release `0.6.0` is the performance and call-drilldown release with SQL-backed live API slices, materialized thread summaries, faster evidence loading, and dashboard runtime module refactors. Patch release `0.6.1` aligns the final README/package screenshots and companion plugin assets. Minor release `0.7.0` adds observed usage snapshots and the latest-observed dashboard card while keeping raw evidence on demand only.
|
|
300
300
|
|
|
301
301
|
- GitHub Release: `https://github.com/douglasmonsky/codex-usage-tracker/releases/tag/v0.3.0`
|
|
302
302
|
- GitHub Release: `https://github.com/douglasmonsky/codex-usage-tracker/releases/tag/v0.3.1`
|
|
@@ -24,12 +24,12 @@ Not guaranteed:
|
|
|
24
24
|
|
|
25
25
|
## 1. Public Install And Package Metadata
|
|
26
26
|
|
|
27
|
-
- [x] Verify the current public PyPI version is visible as `0.
|
|
28
|
-
- [x] Verify public venv install for `0.
|
|
29
|
-
- [x] Verify public pipx install path for `0.
|
|
27
|
+
- [x] Verify the current public PyPI version is visible as `0.7.0`: `python -c "import json, urllib.request; print(json.load(urllib.request.urlopen('https://pypi.org/pypi/codex-usage-tracking/json'))['info']['version'])"`.
|
|
28
|
+
- [x] Verify public venv install for `0.7.0`: `python -m venv /tmp/codex-usage-pypi-smoke && . /tmp/codex-usage-pypi-smoke/bin/activate && python -m pip install codex-usage-tracking==0.7.0 && codex-usage-tracker --version`.
|
|
29
|
+
- [x] Verify public pipx install path for `0.7.0`: `PIPX_HOME=/tmp/codex-usage-pipx-home PIPX_BIN_DIR=/tmp/codex-usage-pipx-bin pipx install codex-usage-tracking==0.7.0 && /tmp/codex-usage-pipx-bin/codex-usage-tracker --version`.
|
|
30
30
|
- [x] Verify installed package resources from a built wheel: `python scripts/smoke_installed_package.py`.
|
|
31
31
|
- [x] Verify installed package resources in Linux Docker: `python scripts/smoke_installed_package.py --docker`.
|
|
32
|
-
- [x] Verify public PyPI package in Docker: `python scripts/smoke_installed_package.py --docker --from-pypi --version 0.
|
|
32
|
+
- [x] Verify public PyPI package in Docker: `python scripts/smoke_installed_package.py --docker --from-pypi --version 0.7.0`.
|
|
33
33
|
- [x] Verify PyPI metadata names remain unchanged: `python scripts/check_release.py`.
|
|
34
34
|
- [x] Add Python 3.14 as an official support target after CI, package classifiers, docs, and installed-package smoke coverage were added. Docker smoke coverage uses `python:3.14-slim` by default. Track this in issue #12.
|
|
35
35
|
|
|
@@ -134,14 +134,14 @@ Not guaranteed:
|
|
|
134
134
|
|
|
135
135
|
## Evidence References
|
|
136
136
|
|
|
137
|
-
These references are the concrete proof behind completed checklist items. Public package smoke commands are version-specific to `0.
|
|
137
|
+
These references are the concrete proof behind completed checklist items. Public package smoke commands are version-specific to `0.7.0`; all repo tests use synthetic or aggregate-only data.
|
|
138
138
|
|
|
139
139
|
### Public Install And Package Metadata
|
|
140
140
|
|
|
141
141
|
- Public PyPI version, public venv install, and public pipx install are proven by the exact public-install commands in section 1.
|
|
142
142
|
- Built-wheel and installed-resource coverage is proven by `scripts/smoke_installed_package.py` and `tests/test_cli_release.py::test_installed_package_smoke_checks_help_for_stable_commands`.
|
|
143
143
|
- Linux package-resource coverage is proven by `scripts/smoke_installed_package.py --docker`.
|
|
144
|
-
- Public PyPI Docker coverage is proven by `scripts/smoke_installed_package.py --docker --from-pypi --version 0.
|
|
144
|
+
- Public PyPI Docker coverage is proven by `scripts/smoke_installed_package.py --docker --from-pypi --version 0.7.0`.
|
|
145
145
|
- PyPI metadata, package/distribution names, package resources, source/wheel member names, Python 3.10-3.14 support metadata, CI workflow requirements, publish workflow safety text, and tracked secret patterns are proven by `scripts/check_release.py`, `scripts/check_release.py --dist`, and `tests/test_cli_release.py::test_release_check_script_passes`.
|
|
146
146
|
|
|
147
147
|
### Upgrade And Migration
|
|
@@ -219,8 +219,8 @@ These references are the concrete proof behind completed checklist items. Public
|
|
|
219
219
|
- Publish workflow package name, Trusted Publishing, TestPyPI/PyPI job presence, event guards, no push/PR publishing, no token/password publishing, and manual PyPI main/tag preflight are proven by `scripts/check_release.py::_check_publish_workflow`.
|
|
220
220
|
- The GitHub `pypi` environment gate is proven by `gh api repos/douglasmonsky/codex-usage-tracker/environments/pypi`, which reports a `required_reviewers` protection rule and `can_admins_bypass=false`.
|
|
221
221
|
- Dist filename and wheel/sdist member checks are proven by `python -m build`, `python -m twine check dist/*`, and `python scripts/check_release.py --dist`.
|
|
222
|
-
- TestPyPI publish process is proven by a workflow-dispatch run on `main`, followed by TestPyPI metadata and clean virtualenv install checks for `codex-usage-tracking==0.
|
|
223
|
-
- PyPI publish process is proven by a workflow-dispatch run on `main`, protected `pypi` environment approval, PyPI metadata visibility, clean virtualenv install, temporary pipx install, and Docker public-package smoke for `codex-usage-tracking==0.
|
|
222
|
+
- TestPyPI publish process is proven by a workflow-dispatch run on `main`, followed by TestPyPI metadata and clean virtualenv install checks for `codex-usage-tracking==0.7.0`.
|
|
223
|
+
- PyPI publish process is proven by a workflow-dispatch run on `main`, protected `pypi` environment approval, PyPI metadata visibility, clean virtualenv install, temporary pipx install, and Docker public-package smoke for `codex-usage-tracking==0.7.0`.
|
|
224
224
|
- Release recovery documentation is proven by `scripts/check_release.py` required-file and docs checks.
|
|
225
225
|
|
|
226
226
|
### Known Limitations
|
|
@@ -4,7 +4,7 @@ Codex Usage Tracker has three related but different concepts:
|
|
|
4
4
|
|
|
5
5
|
- `Estimated Cost`: optional USD estimates from a local pricing file.
|
|
6
6
|
- `Codex Credits`: calculated usage credits from aggregate token counters and Codex credit rates.
|
|
7
|
-
- `Usage
|
|
7
|
+
- `Usage observed`: optional latest local-log 5-hour and weekly allowance snapshots, falling back to copied allowance config when logs do not include rate-limit snapshots.
|
|
8
8
|
|
|
9
9
|
## Cost Estimates
|
|
10
10
|
|
|
@@ -58,11 +58,11 @@ codex-usage-tracker update-rate-card
|
|
|
58
58
|
|
|
59
59
|
The local snapshot is written to `~/.codex-usage-tracker/rate-card.json`. Each bundled rate and alias includes source URL, fetched date, tier, confidence, and alias rationale where applicable. Use `--source-file` only when you have a reviewed replacement JSON snapshot you want the tracker to validate and use.
|
|
60
60
|
|
|
61
|
-
## Usage
|
|
61
|
+
## Usage Observed
|
|
62
62
|
|
|
63
|
-
`Usage
|
|
63
|
+
`Usage observed` is different from `Codex Credits`. The tracker cannot currently read your logged-in ChatGPT plan, live remaining credits, reset windows, or usage from other agentic surfaces automatically.
|
|
64
64
|
|
|
65
|
-
A plan name such as Free, Plus, Pro, Business, or Enterprise can provide context, but it is not enough to know the current remaining allowance.
|
|
65
|
+
A plan name such as Free, Plus, Pro, Business, or Enterprise can provide context, but it is not enough to know the current remaining allowance. When local Codex logs include `token_count.rate_limits`, the dashboard shows the latest observed 5-hour and weekly percentages from those logs. Otherwise, the dashboard shows remaining values only when you copy them into `~/.codex-usage-tracker/allowance.json`.
|
|
66
66
|
|
|
67
67
|
Enable optional allowance context:
|
|
68
68
|
|
|
@@ -87,6 +87,7 @@ Configure the usage component:
|
|
|
87
87
|
- Pricing and rate-card sources can change outside this project. Refresh or pin local files when reports need a known source snapshot.
|
|
88
88
|
- Local Codex logs may not include usage from other ChatGPT agentic surfaces that share the same allowance.
|
|
89
89
|
- Live account allowance cannot be read automatically by this local tracker, and the dashboard does not infer live remaining allowance from the logged-in account plan.
|
|
90
|
+
- Observed local-log snapshots may be stale until Codex records another model call, and may omit other agentic surfaces that share the same allowance.
|
|
90
91
|
- Pricing can change after a report is generated. Use `pin-pricing` when you need reproducible historical cost estimates.
|
|
91
92
|
- Rows with direct model/rate-card matches are more trustworthy than inferred aliases or local overrides.
|
|
92
93
|
- Cost and credit calculations use aggregate counters; the tracker does not re-tokenize prompts or reconstruct usage from raw text.
|
|
@@ -14,6 +14,7 @@ The local SQLite database is stored at `~/.codex-usage-tracker/usage.sqlite3` by
|
|
|
14
14
|
- archived-session flag, conservative thread key, and adjacent aggregate record ids for dashboard navigation
|
|
15
15
|
- materialized thread-level aggregate summaries for active and all-history scopes
|
|
16
16
|
- source-file refresh metadata such as path, path hash, size, mtime, indexed line/byte offsets, latest aggregate record id, parser diagnostics, and last indexed time
|
|
17
|
+
- observed Codex rate-limit snapshot metadata from local token-count logs, such as plan type, limit id, 5-hour/weekly used percentages, window lengths, and reset times
|
|
17
18
|
- pricing, credit, allowance, recommendation, and project metadata derived from aggregate fields
|
|
18
19
|
|
|
19
20
|
## Not Stored
|
|
@@ -104,7 +105,7 @@ Cost estimates are calculated only from aggregate token fields and your local pr
|
|
|
104
105
|
|
|
105
106
|
Codex credit estimates are calculated only from aggregate token fields and bundled or locally configured rate-card values.
|
|
106
107
|
|
|
107
|
-
The optional allowance config is local and stores only the remaining percentages, reset times, or credit totals you manually enter.
|
|
108
|
+
The optional allowance config is local and stores only the remaining percentages, reset times, or credit totals you manually enter. Observed rate-limit snapshots, when present in Codex token-count logs, store only structured percentages, window lengths, reset times, plan type, and limit id.
|
|
108
109
|
|
|
109
110
|
## Sharing Checklist
|
|
110
111
|
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "codex-usage-tracking"
|
|
7
|
-
version = "0.
|
|
7
|
+
version = "0.7.0"
|
|
8
8
|
description = "Unofficial local Codex plugin and dashboard for investigating aggregate token usage, costs, caching, and thread patterns."
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
requires-python = ">=3.10"
|
|
@@ -15,9 +15,9 @@ from pathlib import Path
|
|
|
15
15
|
|
|
16
16
|
PACKAGE_SPEC = os.environ.get(
|
|
17
17
|
"CODEX_USAGE_TRACKER_PACKAGE_SPEC",
|
|
18
|
-
"codex-usage-tracking==0.
|
|
18
|
+
"codex-usage-tracking==0.7.0",
|
|
19
19
|
)
|
|
20
|
-
RUNTIME_VERSION = "0.
|
|
20
|
+
RUNTIME_VERSION = "0.7.0"
|
|
21
21
|
PACKAGE_SPEC_MARKER = ".codex-usage-tracker-package-spec"
|
|
22
22
|
MODULE_CHECK = (
|
|
23
23
|
"import importlib.metadata; "
|
{codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/src/codex_usage_tracker/dashboard.py
RENAMED
|
@@ -44,6 +44,7 @@ from codex_usage_tracker.store import (
|
|
|
44
44
|
query_dashboard_event_count,
|
|
45
45
|
query_dashboard_events,
|
|
46
46
|
query_dashboard_token_summary,
|
|
47
|
+
query_latest_observed_usage,
|
|
47
48
|
refresh_metadata,
|
|
48
49
|
)
|
|
49
50
|
from codex_usage_tracker.threads import annotate_thread_attachments
|
|
@@ -153,6 +154,10 @@ def dashboard_payload(
|
|
|
153
154
|
token_summary["priced_model_rows"],
|
|
154
155
|
allowance,
|
|
155
156
|
)
|
|
157
|
+
observed_usage = query_latest_observed_usage(
|
|
158
|
+
db_path=db_path,
|
|
159
|
+
include_archived=include_archived,
|
|
160
|
+
)
|
|
156
161
|
normalized_limit = _normalize_limit(limit)
|
|
157
162
|
total_available_rows = query_dashboard_event_count(
|
|
158
163
|
db_path=db_path,
|
|
@@ -187,6 +192,7 @@ def dashboard_payload(
|
|
|
187
192
|
"allowance_source": allowance_summary["source"],
|
|
188
193
|
"allowance_windows": allowance_summary["windows"],
|
|
189
194
|
"allowance_error": allowance_summary["error"],
|
|
195
|
+
"observed_usage": observed_usage,
|
|
190
196
|
"rate_card_configured": allowance_summary["rate_card_loaded"],
|
|
191
197
|
"rate_card_error": allowance_summary["rate_card_error"],
|
|
192
198
|
"loaded_row_count": len(rows),
|
|
@@ -58,6 +58,14 @@ class UsageEvent:
|
|
|
58
58
|
cumulative_output_tokens: int
|
|
59
59
|
cumulative_reasoning_output_tokens: int
|
|
60
60
|
cumulative_total_tokens: int
|
|
61
|
+
rate_limit_plan_type: str | None = None
|
|
62
|
+
rate_limit_limit_id: str | None = None
|
|
63
|
+
rate_limit_primary_used_percent: float | None = None
|
|
64
|
+
rate_limit_primary_window_minutes: int | None = None
|
|
65
|
+
rate_limit_primary_resets_at: int | None = None
|
|
66
|
+
rate_limit_secondary_used_percent: float | None = None
|
|
67
|
+
rate_limit_secondary_window_minutes: int | None = None
|
|
68
|
+
rate_limit_secondary_resets_at: int | None = None
|
|
61
69
|
|
|
62
70
|
@property
|
|
63
71
|
def uncached_input_tokens(self) -> int:
|
|
@@ -40,7 +40,19 @@ PARSER_DIAGNOSTIC_KEYS = (
|
|
|
40
40
|
)
|
|
41
41
|
|
|
42
42
|
KNOWN_NON_TOKEN_EVENT_MSG_TYPES = frozenset({
|
|
43
|
+
"agent_message",
|
|
43
44
|
"context_compacted",
|
|
45
|
+
"image_generation_end",
|
|
46
|
+
"item_completed",
|
|
47
|
+
"mcp_tool_call_end",
|
|
48
|
+
"patch_apply_end",
|
|
49
|
+
"task_complete",
|
|
50
|
+
"task_started",
|
|
51
|
+
"thread_goal_updated",
|
|
52
|
+
"thread_rolled_back",
|
|
53
|
+
"turn_aborted",
|
|
54
|
+
"user_message",
|
|
55
|
+
"web_search_end",
|
|
44
56
|
})
|
|
45
57
|
|
|
46
58
|
|
|
@@ -426,6 +438,7 @@ def _parse_codex_jsonl_v1(
|
|
|
426
438
|
),
|
|
427
439
|
last_usage=last_usage,
|
|
428
440
|
total_usage=total_usage,
|
|
441
|
+
rate_limits=payload.get("rate_limits"),
|
|
429
442
|
stats=stats,
|
|
430
443
|
)
|
|
431
444
|
except ValueError:
|
|
@@ -462,6 +475,7 @@ def _build_event(
|
|
|
462
475
|
model_context_window: int | None,
|
|
463
476
|
last_usage: dict[str, Any],
|
|
464
477
|
total_usage: dict[str, Any],
|
|
478
|
+
rate_limits: object = None,
|
|
465
479
|
stats: MutableMapping[str, int] | None = None,
|
|
466
480
|
) -> UsageEvent:
|
|
467
481
|
input_tokens = _required_usage_int(last_usage, "input_tokens", stats=stats)
|
|
@@ -477,6 +491,7 @@ def _build_event(
|
|
|
477
491
|
stats=stats,
|
|
478
492
|
missing_key="missing_cumulative_total",
|
|
479
493
|
)
|
|
494
|
+
observed_usage = _observed_usage_from_rate_limits(rate_limits, stats=stats)
|
|
480
495
|
record_id = _record_id(
|
|
481
496
|
session_id=session_id,
|
|
482
497
|
turn_id=_optional_str(current_turn.get("turn_id")),
|
|
@@ -533,9 +548,51 @@ def _build_event(
|
|
|
533
548
|
total_usage, "reasoning_output_tokens", stats=stats
|
|
534
549
|
),
|
|
535
550
|
cumulative_total_tokens=cumulative_total_tokens,
|
|
551
|
+
**observed_usage,
|
|
536
552
|
)
|
|
537
553
|
|
|
538
554
|
|
|
555
|
+
def _observed_usage_from_rate_limits(
|
|
556
|
+
value: object,
|
|
557
|
+
*,
|
|
558
|
+
stats: MutableMapping[str, int] | None = None,
|
|
559
|
+
) -> dict[str, Any]:
|
|
560
|
+
if not isinstance(value, dict):
|
|
561
|
+
return {}
|
|
562
|
+
primary = _rate_limit_window(value.get("primary"), "primary", stats=stats)
|
|
563
|
+
secondary = _rate_limit_window(value.get("secondary"), "secondary", stats=stats)
|
|
564
|
+
return {
|
|
565
|
+
"rate_limit_plan_type": _optional_str(value.get("plan_type")),
|
|
566
|
+
"rate_limit_limit_id": _optional_str(value.get("limit_id")),
|
|
567
|
+
**primary,
|
|
568
|
+
**secondary,
|
|
569
|
+
}
|
|
570
|
+
|
|
571
|
+
|
|
572
|
+
def _rate_limit_window(
|
|
573
|
+
value: object,
|
|
574
|
+
prefix: str,
|
|
575
|
+
*,
|
|
576
|
+
stats: MutableMapping[str, int] | None = None,
|
|
577
|
+
) -> dict[str, object]:
|
|
578
|
+
if not isinstance(value, dict):
|
|
579
|
+
return {}
|
|
580
|
+
return {
|
|
581
|
+
f"rate_limit_{prefix}_used_percent": _nullable_float(
|
|
582
|
+
value.get("used_percent"),
|
|
583
|
+
stats=stats,
|
|
584
|
+
),
|
|
585
|
+
f"rate_limit_{prefix}_window_minutes": _nullable_int(
|
|
586
|
+
value.get("window_minutes"),
|
|
587
|
+
stats=stats,
|
|
588
|
+
),
|
|
589
|
+
f"rate_limit_{prefix}_resets_at": _nullable_int(
|
|
590
|
+
value.get("resets_at"),
|
|
591
|
+
stats=stats,
|
|
592
|
+
),
|
|
593
|
+
}
|
|
594
|
+
|
|
595
|
+
|
|
539
596
|
def _session_metadata(
|
|
540
597
|
payload: dict[str, Any],
|
|
541
598
|
session_index: dict[str, SessionInfo],
|
|
@@ -678,6 +735,23 @@ def _nullable_int(
|
|
|
678
735
|
return None
|
|
679
736
|
|
|
680
737
|
|
|
738
|
+
def _nullable_float(
|
|
739
|
+
value: object,
|
|
740
|
+
*,
|
|
741
|
+
stats: MutableMapping[str, int] | None = None,
|
|
742
|
+
invalid_key: str = "partial_field_count",
|
|
743
|
+
) -> float | None:
|
|
744
|
+
if value is None:
|
|
745
|
+
return None
|
|
746
|
+
try:
|
|
747
|
+
return _strict_float(value)
|
|
748
|
+
except ValueError:
|
|
749
|
+
_increment_stat(stats, invalid_key)
|
|
750
|
+
if invalid_key != "partial_field_count":
|
|
751
|
+
_increment_stat(stats, "partial_field_count")
|
|
752
|
+
return None
|
|
753
|
+
|
|
754
|
+
|
|
681
755
|
def _strict_int(value: object) -> int:
|
|
682
756
|
if isinstance(value, bool):
|
|
683
757
|
raise ValueError(f"invalid integer value: {value!r}")
|
|
@@ -693,6 +767,19 @@ def _strict_int(value: object) -> int:
|
|
|
693
767
|
raise ValueError(f"invalid integer value: {value!r}")
|
|
694
768
|
|
|
695
769
|
|
|
770
|
+
def _strict_float(value: object) -> float:
|
|
771
|
+
if isinstance(value, bool):
|
|
772
|
+
raise ValueError(f"invalid float value: {value!r}")
|
|
773
|
+
if isinstance(value, (int, float)):
|
|
774
|
+
return float(value)
|
|
775
|
+
if isinstance(value, str) and value.strip():
|
|
776
|
+
try:
|
|
777
|
+
return float(value)
|
|
778
|
+
except ValueError as exc:
|
|
779
|
+
raise ValueError(f"invalid float value: {value!r}") from exc
|
|
780
|
+
raise ValueError(f"invalid float value: {value!r}")
|
|
781
|
+
|
|
782
|
+
|
|
696
783
|
def _required_usage_int(
|
|
697
784
|
values: dict[str, Any],
|
|
698
785
|
key: str,
|
|
@@ -222,6 +222,26 @@
|
|
|
222
222
|
}
|
|
223
223
|
.card span { display: block; color: var(--muted); font-size: 12px; font-weight: 680; }
|
|
224
224
|
.card strong { display: block; margin-top: 7px; font-size: 22px; }
|
|
225
|
+
.usage-card {
|
|
226
|
+
display: flex;
|
|
227
|
+
flex-direction: column;
|
|
228
|
+
align-items: flex-start;
|
|
229
|
+
}
|
|
230
|
+
.usage-reconcile {
|
|
231
|
+
display: inline-flex;
|
|
232
|
+
align-items: center;
|
|
233
|
+
width: fit-content;
|
|
234
|
+
margin-top: 10px;
|
|
235
|
+
padding: 3px 8px;
|
|
236
|
+
border-radius: 999px;
|
|
237
|
+
border: 1px solid #f2c66d;
|
|
238
|
+
background: #fff8e5;
|
|
239
|
+
color: #8a5b00;
|
|
240
|
+
font-size: 11px;
|
|
241
|
+
font-weight: 780;
|
|
242
|
+
}
|
|
243
|
+
.usage-reconcile[hidden] { display: none; }
|
|
244
|
+
#allowanceImpact { white-space: pre-line; line-height: 1.18; }
|
|
225
245
|
.row-load-progress {
|
|
226
246
|
display: grid;
|
|
227
247
|
gap: 8px;
|
|
@@ -259,4 +279,3 @@
|
|
|
259
279
|
background: linear-gradient(90deg, var(--blue), #74a3ff);
|
|
260
280
|
transition: width 160ms ease;
|
|
261
281
|
}
|
|
262
|
-
#allowanceImpact { white-space: pre-line; line-height: 1.18; }
|
|
@@ -104,6 +104,7 @@
|
|
|
104
104
|
let allowanceSource = activeInitialPayload.allowance_source || {};
|
|
105
105
|
let allowanceWindows = Array.isArray(activeInitialPayload.allowance_windows) ? activeInitialPayload.allowance_windows : [];
|
|
106
106
|
let allowanceError = activeInitialPayload.allowance_error || '';
|
|
107
|
+
let observedUsage = activeInitialPayload.observed_usage || { available: false, windows: [] };
|
|
107
108
|
let rateCardError = activeInitialPayload.rate_card_error || '';
|
|
108
109
|
let projectMetadataPrivacy = activeInitialPayload.project_metadata_privacy || { mode: activeInitialPayload.privacy_mode || 'normal' };
|
|
109
110
|
let parserDiagnostics = activeInitialPayload.parser_diagnostics || {};
|
|
@@ -181,9 +182,11 @@
|
|
|
181
182
|
custom: 'option.custom_range',
|
|
182
183
|
};
|
|
183
184
|
const allowedDatePresets = new Set(Object.keys(datePresetLabels));
|
|
184
|
-
|
|
185
|
+
const defaultDashboardView = 'calls';
|
|
186
|
+
const defaultDashboardSort = 'time';
|
|
187
|
+
let activeView = ['calls', 'threads', 'insights', 'call'].includes(initialState.view) ? initialState.view : defaultDashboardView;
|
|
185
188
|
document.body.dataset.activeView = activeView;
|
|
186
|
-
let sortKey = optionValueExists(sortEl, initialState.sort) ? initialState.sort : sortEl.value ||
|
|
189
|
+
let sortKey = optionValueExists(sortEl, initialState.sort) ? initialState.sort : sortEl.value || defaultDashboardSort;
|
|
187
190
|
let sortDirection = ['asc', 'desc'].includes(initialState.direction) ? initialState.direction : defaultSortDirection(sortKey);
|
|
188
191
|
let threadCallSortKey = 'time';
|
|
189
192
|
let threadCallSortDirection = 'desc';
|
|
@@ -388,6 +391,7 @@
|
|
|
388
391
|
cached: t('table.cached'),
|
|
389
392
|
uncached: t('table.uncached'),
|
|
390
393
|
output: t('table.output'),
|
|
394
|
+
reasoning: t('metric.reasoning_output'),
|
|
391
395
|
signals: t('table.signals'),
|
|
392
396
|
thread: t('table.thread'),
|
|
393
397
|
time: t('table.time'),
|
|
@@ -461,6 +465,7 @@
|
|
|
461
465
|
}
|
|
462
466
|
dashboardStatus = dashboardStatusFactory.create({
|
|
463
467
|
allowanceImpactElement: document.getElementById('allowanceImpact'),
|
|
468
|
+
allowanceReconcileElement: document.getElementById('allowanceReconcile'),
|
|
464
469
|
allowanceSourceElement: document.getElementById('allowanceSource'),
|
|
465
470
|
creditCoverageRatio,
|
|
466
471
|
credits,
|
|
@@ -471,6 +476,7 @@
|
|
|
471
476
|
getAllowanceSource: () => allowanceSource,
|
|
472
477
|
getAllowanceWindows: () => allowanceWindows,
|
|
473
478
|
getData: () => data,
|
|
479
|
+
getObservedUsage: () => observedUsage,
|
|
474
480
|
getParserDiagnostics: () => parserDiagnostics,
|
|
475
481
|
getPricingConfigured: () => pricingConfigured,
|
|
476
482
|
getPricingSnapshotWarning: () => pricingSnapshotWarning,
|
|
@@ -741,7 +747,7 @@
|
|
|
741
747
|
function clearPreset() {
|
|
742
748
|
activePreset = '';
|
|
743
749
|
pricingStatusEl.value = '';
|
|
744
|
-
sortKey =
|
|
750
|
+
sortKey = defaultDashboardSort;
|
|
745
751
|
sortDirection = defaultSortDirection(sortKey);
|
|
746
752
|
sortEl.value = sortKey;
|
|
747
753
|
resetVisibleRows();
|
|
@@ -780,7 +786,7 @@
|
|
|
780
786
|
effortTooltipText,
|
|
781
787
|
outputTokenCell,
|
|
782
788
|
outputTokens,
|
|
783
|
-
|
|
789
|
+
reasoningTokenCell,
|
|
784
790
|
sourceLabelText,
|
|
785
791
|
threadInitiatorSummary,
|
|
786
792
|
tokenNumberCell,
|
|
@@ -964,7 +970,7 @@
|
|
|
964
970
|
threadCallSortDirection = threadCallSortDirection === 'asc' ? 'desc' : 'asc';
|
|
965
971
|
} else {
|
|
966
972
|
threadCallSortKey = key;
|
|
967
|
-
threadCallSortDirection = key === 'time' || key === 'total' || key === 'cached' || key === 'uncached' || key === 'output' || key === '
|
|
973
|
+
threadCallSortDirection = key === 'time' || key === 'total' || key === 'cached' || key === 'uncached' || key === 'output' || key === 'reasoning' || key === 'cost' || key === 'cache' ? 'desc' : 'asc';
|
|
968
974
|
}
|
|
969
975
|
render();
|
|
970
976
|
}
|
|
@@ -1039,7 +1045,7 @@
|
|
|
1039
1045
|
number,
|
|
1040
1046
|
outputTokenCell,
|
|
1041
1047
|
pct,
|
|
1042
|
-
|
|
1048
|
+
reasoningTokenCell,
|
|
1043
1049
|
renderTimeCell,
|
|
1044
1050
|
renderWithState: () => render(),
|
|
1045
1051
|
rowInvestigatorLink,
|
|
@@ -1247,6 +1253,7 @@
|
|
|
1247
1253
|
allowanceSource = nextPayload.allowance_source || {};
|
|
1248
1254
|
allowanceWindows = Array.isArray(nextPayload.allowance_windows) ? nextPayload.allowance_windows : [];
|
|
1249
1255
|
allowanceError = nextPayload.allowance_error || '';
|
|
1256
|
+
observedUsage = nextPayload.observed_usage || { available: false, windows: [] };
|
|
1250
1257
|
rateCardError = nextPayload.rate_card_error || '';
|
|
1251
1258
|
parserDiagnostics = nextPayload.parser_diagnostics || {};
|
|
1252
1259
|
projectMetadataPrivacy = nextPayload.project_metadata_privacy || { mode: nextPayload.privacy_mode || 'normal' };
|
|
@@ -69,6 +69,7 @@
|
|
|
69
69
|
if (key === 'cached') return cachedInputTokens(row);
|
|
70
70
|
if (key === 'uncached') return uncachedInputTokens(row);
|
|
71
71
|
if (key === 'output') return outputTokens(row);
|
|
72
|
+
if (key === 'reasoning') return Number(row.reasoning_output_tokens || 0);
|
|
72
73
|
if (key === 'signals') return signalCount(row);
|
|
73
74
|
if (key === 'thread') return textValue(rowThreadLabel(row));
|
|
74
75
|
if (key === 'time') return String(row.event_timestamp || '');
|
|
@@ -93,6 +94,7 @@
|
|
|
93
94
|
if (key === 'cached') return cachedInputTokens(row);
|
|
94
95
|
if (key === 'uncached') return uncachedInputTokens(row);
|
|
95
96
|
if (key === 'output') return outputTokens(row);
|
|
97
|
+
if (key === 'reasoning') return Number(row.reasoning_output_tokens || 0);
|
|
96
98
|
if (key === 'signals') return signalCount(row);
|
|
97
99
|
if (key === 'source') return textValue(callInitiatorText(row));
|
|
98
100
|
if (key === 'time') return String(row.event_timestamp || '');
|
|
@@ -125,6 +127,7 @@
|
|
|
125
127
|
if (key === 'cached') return group.cachedTokens;
|
|
126
128
|
if (key === 'uncached') return group.uncachedTokens;
|
|
127
129
|
if (key === 'output') return group.outputTokens;
|
|
130
|
+
if (key === 'reasoning') return group.reasoningOutputTokens;
|
|
128
131
|
if (key === 'signals') return group.signalCount;
|
|
129
132
|
if (key === 'thread') return textValue(group.label);
|
|
130
133
|
if (key === 'time') return String(group.latestActivity || '');
|
|
@@ -321,6 +324,7 @@
|
|
|
321
324
|
const cachedTokens = calls.reduce((sum, row) => sum + Number(row.cached_input_tokens || 0), 0);
|
|
322
325
|
const uncachedTokens = calls.reduce((sum, row) => sum + uncachedInputTokens(row), 0);
|
|
323
326
|
const outputTokensTotal = calls.reduce((sum, row) => sum + outputTokens(row), 0);
|
|
327
|
+
const reasoningOutputTokens = calls.reduce((sum, row) => sum + Number(row.reasoning_output_tokens || 0), 0);
|
|
324
328
|
const estimatedCost = calls.reduce((sum, row) => sum + Number(row.estimated_cost_usd || 0), 0);
|
|
325
329
|
const usageCredits = sumUsageCredits(calls);
|
|
326
330
|
const signalTotal = calls.reduce((sum, row) => sum + signalCount(row), 0);
|
|
@@ -348,6 +352,7 @@
|
|
|
348
352
|
cachedTokens,
|
|
349
353
|
uncachedTokens,
|
|
350
354
|
outputTokens: outputTokensTotal,
|
|
355
|
+
reasoningOutputTokens,
|
|
351
356
|
estimatedCost,
|
|
352
357
|
usageCredits,
|
|
353
358
|
cacheRatio: inputTokens ? cachedTokens / inputTokens : 0,
|