codex-usage-tracking 0.8.1__tar.gz → 0.9.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.8.1 → codex_usage_tracking-0.9.0}/.codex-plugin/plugin.json +1 -1
- {codex_usage_tracking-0.8.1 → codex_usage_tracking-0.9.0}/CHANGELOG.md +10 -0
- {codex_usage_tracking-0.8.1 → codex_usage_tracking-0.9.0}/PKG-INFO +1 -1
- {codex_usage_tracking-0.8.1 → codex_usage_tracking-0.9.0}/docs/architecture.md +4 -2
- {codex_usage_tracking-0.8.1 → codex_usage_tracking-0.9.0}/docs/cli-json-schemas.md +259 -0
- {codex_usage_tracking-0.8.1 → codex_usage_tracking-0.9.0}/docs/cli-reference.md +11 -1
- {codex_usage_tracking-0.8.1 → codex_usage_tracking-0.9.0}/docs/dashboard-guide.md +6 -0
- {codex_usage_tracking-0.8.1 → codex_usage_tracking-0.9.0}/docs/development.md +14 -7
- {codex_usage_tracking-0.8.1 → codex_usage_tracking-0.9.0}/docs/one-dot-oh-readiness.md +8 -8
- {codex_usage_tracking-0.8.1 → codex_usage_tracking-0.9.0}/docs/privacy.md +4 -0
- {codex_usage_tracking-0.8.1 → codex_usage_tracking-0.9.0}/pyproject.toml +1 -1
- {codex_usage_tracking-0.8.1 → codex_usage_tracking-0.9.0}/skills/codex-usage-tracker/scripts/run_mcp.py +2 -2
- {codex_usage_tracking-0.8.1 → codex_usage_tracking-0.9.0}/src/codex_usage_tracker/__init__.py +1 -1
- {codex_usage_tracking-0.8.1 → codex_usage_tracking-0.9.0}/src/codex_usage_tracker/cli.py +45 -0
- {codex_usage_tracking-0.8.1 → codex_usage_tracking-0.9.0}/src/codex_usage_tracker/cli_parser.py +72 -0
- {codex_usage_tracking-0.8.1 → codex_usage_tracking-0.9.0}/src/codex_usage_tracker/dashboard.py +14 -0
- codex_usage_tracking-0.9.0/src/codex_usage_tracker/diagnostic_snapshot_analysis.py +446 -0
- codex_usage_tracking-0.9.0/src/codex_usage_tracker/diagnostic_snapshot_concentration.py +338 -0
- codex_usage_tracking-0.9.0/src/codex_usage_tracker/diagnostic_snapshot_constants.py +21 -0
- codex_usage_tracking-0.9.0/src/codex_usage_tracker/diagnostic_snapshot_events.py +399 -0
- codex_usage_tracking-0.9.0/src/codex_usage_tracker/diagnostic_snapshot_report.py +140 -0
- codex_usage_tracking-0.9.0/src/codex_usage_tracker/diagnostic_snapshot_rows.py +182 -0
- codex_usage_tracking-0.9.0/src/codex_usage_tracker/diagnostic_snapshots.py +635 -0
- {codex_usage_tracking-0.8.1 → codex_usage_tracking-0.9.0}/src/codex_usage_tracker/json_contracts.py +81 -0
- codex_usage_tracking-0.9.0/src/codex_usage_tracker/plugin_data/dashboard/dashboard_diagnostics.js +522 -0
- codex_usage_tracking-0.9.0/src/codex_usage_tracker/plugin_data/dashboard/dashboard_diagnostics_facts.js +283 -0
- codex_usage_tracking-0.9.0/src/codex_usage_tracker/plugin_data/dashboard/dashboard_diagnostics_snapshots.js +343 -0
- {codex_usage_tracking-0.8.1 → codex_usage_tracking-0.9.0}/src/codex_usage_tracker/plugin_data/dashboard/dashboard_live.js +15 -10
- {codex_usage_tracking-0.8.1 → codex_usage_tracking-0.9.0}/src/codex_usage_tracker/plugin_data/dashboard/dashboard_responsive.css +3 -0
- {codex_usage_tracking-0.8.1 → codex_usage_tracking-0.9.0}/src/codex_usage_tracker/plugin_data/dashboard/dashboard_tables.css +121 -0
- {codex_usage_tracking-0.8.1 → codex_usage_tracking-0.9.0}/src/codex_usage_tracker/plugin_data/dashboard/dashboard_template.html +2 -0
- {codex_usage_tracking-0.8.1 → codex_usage_tracking-0.9.0}/src/codex_usage_tracker/server.py +218 -0
- {codex_usage_tracking-0.8.1 → codex_usage_tracking-0.9.0}/src/codex_usage_tracker/store.py +91 -0
- {codex_usage_tracking-0.8.1 → codex_usage_tracking-0.9.0}/src/codex_usage_tracker/store_schema.py +28 -1
- {codex_usage_tracking-0.8.1 → codex_usage_tracking-0.9.0}/src/codex_usage_tracking.egg-info/PKG-INFO +1 -1
- {codex_usage_tracking-0.8.1 → codex_usage_tracking-0.9.0}/src/codex_usage_tracking.egg-info/SOURCES.txt +11 -0
- {codex_usage_tracking-0.8.1 → codex_usage_tracking-0.9.0}/tests/store_dashboard_helpers.py +14 -4
- {codex_usage_tracking-0.8.1 → codex_usage_tracking-0.9.0}/tests/test_cli_lifecycle.py +142 -3
- codex_usage_tracking-0.9.0/tests/test_dashboard_diagnostics_snapshots.py +164 -0
- {codex_usage_tracking-0.8.1 → codex_usage_tracking-0.9.0}/tests/test_dashboard_live.py +89 -0
- {codex_usage_tracking-0.8.1 → codex_usage_tracking-0.9.0}/tests/test_dashboard_payload.py +50 -11
- {codex_usage_tracking-0.8.1 → codex_usage_tracking-0.9.0}/tests/test_dashboard_server.py +114 -0
- codex_usage_tracking-0.9.0/tests/test_diagnostic_snapshots.py +515 -0
- {codex_usage_tracking-0.8.1 → codex_usage_tracking-0.9.0}/tests/test_store_dashboard_mcp.py +6 -6
- {codex_usage_tracking-0.8.1 → codex_usage_tracking-0.9.0}/tests/test_store_migrations.py +6 -3
- codex_usage_tracking-0.8.1/src/codex_usage_tracker/plugin_data/dashboard/dashboard_diagnostics.js +0 -672
- {codex_usage_tracking-0.8.1 → codex_usage_tracking-0.9.0}/.mcp.json +0 -0
- {codex_usage_tracking-0.8.1 → codex_usage_tracking-0.9.0}/AGENTS.md +0 -0
- {codex_usage_tracking-0.8.1 → codex_usage_tracking-0.9.0}/CONTRIBUTING.md +0 -0
- {codex_usage_tracking-0.8.1 → codex_usage_tracking-0.9.0}/LICENSE +0 -0
- {codex_usage_tracking-0.8.1 → codex_usage_tracking-0.9.0}/MANIFEST.in +0 -0
- {codex_usage_tracking-0.8.1 → codex_usage_tracking-0.9.0}/README.md +0 -0
- {codex_usage_tracking-0.8.1 → codex_usage_tracking-0.9.0}/SECURITY.md +0 -0
- {codex_usage_tracking-0.8.1 → codex_usage_tracking-0.9.0}/assets/icon.svg +0 -0
- {codex_usage_tracking-0.8.1 → codex_usage_tracking-0.9.0}/docs/assets/dashboard-call-investigator-evidence.png +0 -0
- {codex_usage_tracking-0.8.1 → codex_usage_tracking-0.9.0}/docs/assets/dashboard-call-investigator-preview.png +0 -0
- {codex_usage_tracking-0.8.1 → codex_usage_tracking-0.9.0}/docs/assets/dashboard-call-investigator.png +0 -0
- {codex_usage_tracking-0.8.1 → codex_usage_tracking-0.9.0}/docs/assets/dashboard-calls-preview.png +0 -0
- {codex_usage_tracking-0.8.1 → codex_usage_tracking-0.9.0}/docs/assets/dashboard-calls.png +0 -0
- {codex_usage_tracking-0.8.1 → codex_usage_tracking-0.9.0}/docs/assets/dashboard-details.png +0 -0
- {codex_usage_tracking-0.8.1 → codex_usage_tracking-0.9.0}/docs/assets/dashboard-insights.png +0 -0
- {codex_usage_tracking-0.8.1 → codex_usage_tracking-0.9.0}/docs/assets/dashboard-threads.png +0 -0
- {codex_usage_tracking-0.8.1 → codex_usage_tracking-0.9.0}/docs/assets/plugin-prompts.png +0 -0
- {codex_usage_tracking-0.8.1 → codex_usage_tracking-0.9.0}/docs/assets/plugin-thread-leaderboard.png +0 -0
- {codex_usage_tracking-0.8.1 → codex_usage_tracking-0.9.0}/docs/assets/ux/call-detail-panel.png +0 -0
- {codex_usage_tracking-0.8.1 → codex_usage_tracking-0.9.0}/docs/assets/ux/insight-overview.png +0 -0
- {codex_usage_tracking-0.8.1 → codex_usage_tracking-0.9.0}/docs/assets/ux/thread-investigation.png +0 -0
- {codex_usage_tracking-0.8.1 → codex_usage_tracking-0.9.0}/docs/call-drilldown-performance-checklist.md +0 -0
- {codex_usage_tracking-0.8.1 → codex_usage_tracking-0.9.0}/docs/install.md +0 -0
- {codex_usage_tracking-0.8.1 → codex_usage_tracking-0.9.0}/docs/mcp.md +0 -0
- {codex_usage_tracking-0.8.1 → codex_usage_tracking-0.9.0}/docs/pricing-and-credits.md +0 -0
- {codex_usage_tracking-0.8.1 → codex_usage_tracking-0.9.0}/docs/ui-ux-improvement-plan.md +0 -0
- {codex_usage_tracking-0.8.1 → codex_usage_tracking-0.9.0}/scripts/benchmark_synthetic_history.py +0 -0
- {codex_usage_tracking-0.8.1 → codex_usage_tracking-0.9.0}/scripts/check_release.py +0 -0
- {codex_usage_tracking-0.8.1 → codex_usage_tracking-0.9.0}/scripts/install_local_plugin.py +0 -0
- {codex_usage_tracking-0.8.1 → codex_usage_tracking-0.9.0}/scripts/smoke_installed_package.py +0 -0
- {codex_usage_tracking-0.8.1 → codex_usage_tracking-0.9.0}/setup.cfg +0 -0
- {codex_usage_tracking-0.8.1 → codex_usage_tracking-0.9.0}/skills/codex-usage-api/SKILL.md +0 -0
- {codex_usage_tracking-0.8.1 → codex_usage_tracking-0.9.0}/skills/codex-usage-tracker/SKILL.md +0 -0
- {codex_usage_tracking-0.8.1 → codex_usage_tracking-0.9.0}/src/codex_usage_tracker/__main__.py +0 -0
- {codex_usage_tracking-0.8.1 → codex_usage_tracking-0.9.0}/src/codex_usage_tracker/allowance.py +0 -0
- {codex_usage_tracking-0.8.1 → codex_usage_tracking-0.9.0}/src/codex_usage_tracker/api_payloads.py +0 -0
- {codex_usage_tracking-0.8.1 → codex_usage_tracking-0.9.0}/src/codex_usage_tracker/call_origin.py +0 -0
- {codex_usage_tracking-0.8.1 → codex_usage_tracking-0.9.0}/src/codex_usage_tracker/context.py +0 -0
- {codex_usage_tracking-0.8.1 → codex_usage_tracking-0.9.0}/src/codex_usage_tracker/costing.py +0 -0
- {codex_usage_tracking-0.8.1 → codex_usage_tracking-0.9.0}/src/codex_usage_tracker/diagnostic_facts.py +0 -0
- {codex_usage_tracking-0.8.1 → codex_usage_tracking-0.9.0}/src/codex_usage_tracker/diagnostic_reports.py +0 -0
- {codex_usage_tracking-0.8.1 → codex_usage_tracking-0.9.0}/src/codex_usage_tracker/diagnostics.py +0 -0
- {codex_usage_tracking-0.8.1 → codex_usage_tracking-0.9.0}/src/codex_usage_tracker/formatting.py +0 -0
- {codex_usage_tracking-0.8.1 → codex_usage_tracking-0.9.0}/src/codex_usage_tracker/i18n.py +0 -0
- {codex_usage_tracking-0.8.1 → codex_usage_tracking-0.9.0}/src/codex_usage_tracker/mcp_server.py +0 -0
- {codex_usage_tracking-0.8.1 → codex_usage_tracking-0.9.0}/src/codex_usage_tracker/models.py +0 -0
- {codex_usage_tracking-0.8.1 → codex_usage_tracking-0.9.0}/src/codex_usage_tracker/parser.py +0 -0
- {codex_usage_tracking-0.8.1 → codex_usage_tracking-0.9.0}/src/codex_usage_tracker/paths.py +0 -0
- {codex_usage_tracking-0.8.1 → codex_usage_tracking-0.9.0}/src/codex_usage_tracker/plugin_data/__init__.py +0 -0
- {codex_usage_tracking-0.8.1 → codex_usage_tracking-0.9.0}/src/codex_usage_tracker/plugin_data/assets/icon.svg +0 -0
- {codex_usage_tracking-0.8.1 → codex_usage_tracking-0.9.0}/src/codex_usage_tracker/plugin_data/dashboard/dashboard.css +0 -0
- {codex_usage_tracking-0.8.1 → codex_usage_tracking-0.9.0}/src/codex_usage_tracker/plugin_data/dashboard/dashboard.js +0 -0
- {codex_usage_tracking-0.8.1 → codex_usage_tracking-0.9.0}/src/codex_usage_tracker/plugin_data/dashboard/dashboard_actions.js +0 -0
- {codex_usage_tracking-0.8.1 → codex_usage_tracking-0.9.0}/src/codex_usage_tracker/plugin_data/dashboard/dashboard_analysis.js +0 -0
- {codex_usage_tracking-0.8.1 → codex_usage_tracking-0.9.0}/src/codex_usage_tracker/plugin_data/dashboard/dashboard_call.css +0 -0
- {codex_usage_tracking-0.8.1 → codex_usage_tracking-0.9.0}/src/codex_usage_tracker/plugin_data/dashboard/dashboard_call_diagnostics.js +0 -0
- {codex_usage_tracking-0.8.1 → codex_usage_tracking-0.9.0}/src/codex_usage_tracker/plugin_data/dashboard/dashboard_call_investigator.js +0 -0
- {codex_usage_tracking-0.8.1 → codex_usage_tracking-0.9.0}/src/codex_usage_tracker/plugin_data/dashboard/dashboard_cells.js +0 -0
- {codex_usage_tracking-0.8.1 → codex_usage_tracking-0.9.0}/src/codex_usage_tracker/plugin_data/dashboard/dashboard_data.js +0 -0
- {codex_usage_tracking-0.8.1 → codex_usage_tracking-0.9.0}/src/codex_usage_tracker/plugin_data/dashboard/dashboard_detail.css +0 -0
- {codex_usage_tracking-0.8.1 → codex_usage_tracking-0.9.0}/src/codex_usage_tracker/plugin_data/dashboard/dashboard_details.js +0 -0
- {codex_usage_tracking-0.8.1 → codex_usage_tracking-0.9.0}/src/codex_usage_tracker/plugin_data/dashboard/dashboard_events.js +0 -0
- {codex_usage_tracking-0.8.1 → codex_usage_tracking-0.9.0}/src/codex_usage_tracker/plugin_data/dashboard/dashboard_filters.js +0 -0
- {codex_usage_tracking-0.8.1 → codex_usage_tracking-0.9.0}/src/codex_usage_tracker/plugin_data/dashboard/dashboard_format.js +0 -0
- {codex_usage_tracking-0.8.1 → codex_usage_tracking-0.9.0}/src/codex_usage_tracker/plugin_data/dashboard/dashboard_i18n.js +0 -0
- {codex_usage_tracking-0.8.1 → codex_usage_tracking-0.9.0}/src/codex_usage_tracker/plugin_data/dashboard/dashboard_insights.css +0 -0
- {codex_usage_tracking-0.8.1 → codex_usage_tracking-0.9.0}/src/codex_usage_tracker/plugin_data/dashboard/dashboard_insights.js +0 -0
- {codex_usage_tracking-0.8.1 → codex_usage_tracking-0.9.0}/src/codex_usage_tracker/plugin_data/dashboard/dashboard_layout.css +0 -0
- {codex_usage_tracking-0.8.1 → codex_usage_tracking-0.9.0}/src/codex_usage_tracker/plugin_data/dashboard/dashboard_payload_cache.js +0 -0
- {codex_usage_tracking-0.8.1 → codex_usage_tracking-0.9.0}/src/codex_usage_tracker/plugin_data/dashboard/dashboard_state.js +0 -0
- {codex_usage_tracking-0.8.1 → codex_usage_tracking-0.9.0}/src/codex_usage_tracker/plugin_data/dashboard/dashboard_status.js +0 -0
- {codex_usage_tracking-0.8.1 → codex_usage_tracking-0.9.0}/src/codex_usage_tracker/plugin_data/dashboard/dashboard_tables.js +0 -0
- {codex_usage_tracking-0.8.1 → codex_usage_tracking-0.9.0}/src/codex_usage_tracker/plugin_data/dashboard/dashboard_tooltips.js +0 -0
- {codex_usage_tracking-0.8.1 → codex_usage_tracking-0.9.0}/src/codex_usage_tracker/plugin_data/dashboard/locales/ar.json +0 -0
- {codex_usage_tracking-0.8.1 → codex_usage_tracking-0.9.0}/src/codex_usage_tracker/plugin_data/dashboard/locales/de.json +0 -0
- {codex_usage_tracking-0.8.1 → codex_usage_tracking-0.9.0}/src/codex_usage_tracker/plugin_data/dashboard/locales/en.json +0 -0
- {codex_usage_tracking-0.8.1 → codex_usage_tracking-0.9.0}/src/codex_usage_tracker/plugin_data/dashboard/locales/es.json +0 -0
- {codex_usage_tracking-0.8.1 → codex_usage_tracking-0.9.0}/src/codex_usage_tracker/plugin_data/dashboard/locales/fr.json +0 -0
- {codex_usage_tracking-0.8.1 → codex_usage_tracking-0.9.0}/src/codex_usage_tracker/plugin_data/dashboard/locales/it.json +0 -0
- {codex_usage_tracking-0.8.1 → codex_usage_tracking-0.9.0}/src/codex_usage_tracker/plugin_data/dashboard/locales/ja.json +0 -0
- {codex_usage_tracking-0.8.1 → codex_usage_tracking-0.9.0}/src/codex_usage_tracker/plugin_data/dashboard/locales/ko.json +0 -0
- {codex_usage_tracking-0.8.1 → codex_usage_tracking-0.9.0}/src/codex_usage_tracker/plugin_data/dashboard/locales/pt.json +0 -0
- {codex_usage_tracking-0.8.1 → codex_usage_tracking-0.9.0}/src/codex_usage_tracker/plugin_data/dashboard/locales/ru.json +0 -0
- {codex_usage_tracking-0.8.1 → codex_usage_tracking-0.9.0}/src/codex_usage_tracker/plugin_data/dashboard/locales/vi.json +0 -0
- {codex_usage_tracking-0.8.1 → codex_usage_tracking-0.9.0}/src/codex_usage_tracker/plugin_data/dashboard/locales/zh-Hans.json +0 -0
- {codex_usage_tracking-0.8.1 → codex_usage_tracking-0.9.0}/src/codex_usage_tracker/plugin_data/docs/assets/dashboard-call-investigator-evidence.png +0 -0
- {codex_usage_tracking-0.8.1 → codex_usage_tracking-0.9.0}/src/codex_usage_tracker/plugin_data/docs/assets/dashboard-call-investigator-preview.png +0 -0
- {codex_usage_tracking-0.8.1 → codex_usage_tracking-0.9.0}/src/codex_usage_tracker/plugin_data/docs/assets/dashboard-call-investigator.png +0 -0
- {codex_usage_tracking-0.8.1 → codex_usage_tracking-0.9.0}/src/codex_usage_tracker/plugin_data/docs/assets/dashboard-calls-preview.png +0 -0
- {codex_usage_tracking-0.8.1 → codex_usage_tracking-0.9.0}/src/codex_usage_tracker/plugin_data/docs/assets/dashboard-calls.png +0 -0
- {codex_usage_tracking-0.8.1 → codex_usage_tracking-0.9.0}/src/codex_usage_tracker/plugin_data/docs/assets/dashboard-details.png +0 -0
- {codex_usage_tracking-0.8.1 → codex_usage_tracking-0.9.0}/src/codex_usage_tracker/plugin_data/docs/assets/dashboard-insights.png +0 -0
- {codex_usage_tracking-0.8.1 → codex_usage_tracking-0.9.0}/src/codex_usage_tracker/plugin_data/docs/assets/dashboard-threads.png +0 -0
- {codex_usage_tracking-0.8.1 → codex_usage_tracking-0.9.0}/src/codex_usage_tracker/plugin_data/docs/assets/plugin-prompts.png +0 -0
- {codex_usage_tracking-0.8.1 → codex_usage_tracking-0.9.0}/src/codex_usage_tracker/plugin_data/docs/assets/plugin-thread-leaderboard.png +0 -0
- {codex_usage_tracking-0.8.1 → codex_usage_tracking-0.9.0}/src/codex_usage_tracker/plugin_data/docs/dashboard-guide.html +0 -0
- {codex_usage_tracking-0.8.1 → codex_usage_tracking-0.9.0}/src/codex_usage_tracker/plugin_data/rate_cards/codex-credit-rates.json +0 -0
- {codex_usage_tracking-0.8.1 → codex_usage_tracking-0.9.0}/src/codex_usage_tracker/plugin_data/skills/codex-usage-api/SKILL.md +0 -0
- {codex_usage_tracking-0.8.1 → codex_usage_tracking-0.9.0}/src/codex_usage_tracker/plugin_data/skills/codex-usage-tracker/SKILL.md +0 -0
- {codex_usage_tracking-0.8.1 → codex_usage_tracking-0.9.0}/src/codex_usage_tracker/plugin_installer.py +0 -0
- {codex_usage_tracking-0.8.1 → codex_usage_tracking-0.9.0}/src/codex_usage_tracker/pricing.py +0 -0
- {codex_usage_tracking-0.8.1 → codex_usage_tracking-0.9.0}/src/codex_usage_tracker/pricing_config.py +0 -0
- {codex_usage_tracking-0.8.1 → codex_usage_tracking-0.9.0}/src/codex_usage_tracker/pricing_estimates.py +0 -0
- {codex_usage_tracking-0.8.1 → codex_usage_tracking-0.9.0}/src/codex_usage_tracker/pricing_openai.py +0 -0
- {codex_usage_tracking-0.8.1 → codex_usage_tracking-0.9.0}/src/codex_usage_tracker/projects.py +0 -0
- {codex_usage_tracking-0.8.1 → codex_usage_tracking-0.9.0}/src/codex_usage_tracker/recommendations.py +0 -0
- {codex_usage_tracking-0.8.1 → codex_usage_tracking-0.9.0}/src/codex_usage_tracker/redaction.py +0 -0
- {codex_usage_tracking-0.8.1 → codex_usage_tracking-0.9.0}/src/codex_usage_tracker/reports.py +0 -0
- {codex_usage_tracking-0.8.1 → codex_usage_tracking-0.9.0}/src/codex_usage_tracker/schema.py +0 -0
- {codex_usage_tracking-0.8.1 → codex_usage_tracking-0.9.0}/src/codex_usage_tracker/server_utils.py +0 -0
- {codex_usage_tracking-0.8.1 → codex_usage_tracking-0.9.0}/src/codex_usage_tracker/store_query_sql.py +0 -0
- {codex_usage_tracking-0.8.1 → codex_usage_tracking-0.9.0}/src/codex_usage_tracker/store_sources.py +0 -0
- {codex_usage_tracking-0.8.1 → codex_usage_tracking-0.9.0}/src/codex_usage_tracker/store_thread_summaries.py +0 -0
- {codex_usage_tracking-0.8.1 → codex_usage_tracking-0.9.0}/src/codex_usage_tracker/support.py +0 -0
- {codex_usage_tracking-0.8.1 → codex_usage_tracking-0.9.0}/src/codex_usage_tracker/threads.py +0 -0
- {codex_usage_tracking-0.8.1 → codex_usage_tracking-0.9.0}/src/codex_usage_tracking.egg-info/dependency_links.txt +0 -0
- {codex_usage_tracking-0.8.1 → codex_usage_tracking-0.9.0}/src/codex_usage_tracking.egg-info/entry_points.txt +0 -0
- {codex_usage_tracking-0.8.1 → codex_usage_tracking-0.9.0}/src/codex_usage_tracking.egg-info/requires.txt +0 -0
- {codex_usage_tracking-0.8.1 → codex_usage_tracking-0.9.0}/src/codex_usage_tracking.egg-info/top_level.txt +0 -0
- {codex_usage_tracking-0.8.1 → codex_usage_tracking-0.9.0}/tests/test_allowance.py +0 -0
- {codex_usage_tracking-0.8.1 → codex_usage_tracking-0.9.0}/tests/test_call_origin.py +0 -0
- {codex_usage_tracking-0.8.1 → codex_usage_tracking-0.9.0}/tests/test_cli_release.py +0 -0
- {codex_usage_tracking-0.8.1 → codex_usage_tracking-0.9.0}/tests/test_context_evidence.py +0 -0
- {codex_usage_tracking-0.8.1 → codex_usage_tracking-0.9.0}/tests/test_dashboard_data.py +0 -0
- {codex_usage_tracking-0.8.1 → codex_usage_tracking-0.9.0}/tests/test_dashboard_state.py +0 -0
- {codex_usage_tracking-0.8.1 → codex_usage_tracking-0.9.0}/tests/test_i18n.py +0 -0
- {codex_usage_tracking-0.8.1 → codex_usage_tracking-0.9.0}/tests/test_json_contracts.py +0 -0
- {codex_usage_tracking-0.8.1 → codex_usage_tracking-0.9.0}/tests/test_mcp_integration.py +0 -0
- {codex_usage_tracking-0.8.1 → codex_usage_tracking-0.9.0}/tests/test_mcp_launcher.py +0 -0
- {codex_usage_tracking-0.8.1 → codex_usage_tracking-0.9.0}/tests/test_parser.py +0 -0
- {codex_usage_tracking-0.8.1 → codex_usage_tracking-0.9.0}/tests/test_plugin_installer.py +0 -0
- {codex_usage_tracking-0.8.1 → codex_usage_tracking-0.9.0}/tests/test_pricing.py +0 -0
- {codex_usage_tracking-0.8.1 → codex_usage_tracking-0.9.0}/tests/test_privacy.py +0 -0
- {codex_usage_tracking-0.8.1 → codex_usage_tracking-0.9.0}/tests/test_projects.py +0 -0
- {codex_usage_tracking-0.8.1 → codex_usage_tracking-0.9.0}/tests/test_recommendations.py +0 -0
- {codex_usage_tracking-0.8.1 → codex_usage_tracking-0.9.0}/tests/test_redaction.py +0 -0
- {codex_usage_tracking-0.8.1 → codex_usage_tracking-0.9.0}/tests/test_schema.py +0 -0
- {codex_usage_tracking-0.8.1 → codex_usage_tracking-0.9.0}/tests/test_support.py +0 -0
- {codex_usage_tracking-0.8.1 → codex_usage_tracking-0.9.0}/tests/test_threads.py +0 -0
|
@@ -2,6 +2,16 @@
|
|
|
2
2
|
|
|
3
3
|
## Unreleased
|
|
4
4
|
|
|
5
|
+
## 0.9.0 - 2026-06-21
|
|
6
|
+
|
|
7
|
+
- Add persisted aggregate diagnostic snapshots with explicit on-demand refresh metadata and schema-versioned CLI/API contracts.
|
|
8
|
+
- Add dashboard Diagnostics panels for overview, tool output, commands, file reads, read productivity, and concentration.
|
|
9
|
+
- Add tool-output and command reports with terminal token-count buckets, missing-count coverage, command roots, and expandable command children.
|
|
10
|
+
- Add file-read and read-productivity reports with token allocation, largest read commands, read-to-modify correlation, and privacy-safe path labels.
|
|
11
|
+
- Add concentration reports for top source/session, project/cwd, and day shares without leaking raw source-log paths.
|
|
12
|
+
- Keep Diagnostics refresh isolated from normal live dashboard refresh so regular usage updates do not recompute or blink diagnostic panels.
|
|
13
|
+
- Add Playwright diagnostics smoke coverage and release documentation for the snapshot pipeline, privacy boundary, and on-demand refresh behavior.
|
|
14
|
+
|
|
5
15
|
## 0.8.1 - 2026-06-20
|
|
6
16
|
|
|
7
17
|
- Make Diagnostics fact tables easier to scan by widening and pinning the Fact column while horizontally scrolling.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: codex-usage-tracking
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.9.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
|
|
@@ -13,7 +13,8 @@ Codex Usage Tracker is a local sidecar app. It reads aggregate token counters fr
|
|
|
13
13
|
- `costing.py`, `pricing_config.py`, `pricing_openai.py`, `pricing_estimates.py`, and `allowance.py` own cost, credit, rate-card, and allowance annotation. Keep estimate confidence and source metadata attached to rows.
|
|
14
14
|
- `projects.py`, `threads.py`, and `recommendations.py` annotate aggregate rows with project identity, thread relationships, and actionable signals. Project privacy redaction also belongs in `projects.py` so CLI, MCP, dashboard, CSV, and support-bundle surfaces share the same behavior.
|
|
15
15
|
- `dashboard.py` builds aggregate-only static dashboard payloads and writes HTML/assets. `server.py` adds localhost refresh, the compatibility `/api/usage` endpoint, SQL-backed live API slices, and explicit lazy context loading.
|
|
16
|
-
- `
|
|
16
|
+
- `diagnostic_snapshots.py` owns persisted diagnostic snapshot refresh/load orchestration. `diagnostic_snapshot_analysis.py`, `diagnostic_snapshot_events.py`, `diagnostic_snapshot_rows.py`, and `diagnostic_snapshot_concentration.py` own source-log aggregation, safe event parsing, row shaping, and concentration math. `diagnostic_snapshot_report.py` owns CLI rendering. Keep these modules synthetic-testable and aggregate-only.
|
|
17
|
+
- `plugin_data/dashboard/dashboard_format.js` owns dashboard formatting primitives. `dashboard_data.js` owns row payload and thread relationship helpers. `dashboard_analysis.js` owns scoring, sorting, recommendation, and thread grouping logic. `dashboard_cells.js` owns reusable table/cell HTML helpers. `dashboard_details.js` owns sidebar detail and thread narrative rendering. `dashboard_insights.js` owns insight cards and investigation preset UI. `dashboard_tables.js` owns Calls, Threads, and expanded thread-call table rendering. `dashboard_diagnostics.js` coordinates the Diagnostics tab data flow and events, `dashboard_diagnostics_snapshots.js` renders on-demand snapshot panels, and `dashboard_diagnostics_facts.js` renders the fact tables and drilldowns. `dashboard_filters.js` owns date range parsing and row date matching. `dashboard_state.js` owns URL, CSV, and download state utilities. `dashboard_i18n.js`, `dashboard_payload_cache.js`, and `dashboard_tooltips.js` own localization, session aggregate cache, and fast tooltip helpers. `dashboard_call_investigator.js` owns the dedicated call drilldown surface. `dashboard.js` owns top-level DOM rendering, event handling, and API refresh orchestration.
|
|
17
18
|
- `context.py` is the only normal path that reads raw log context, and it does so only for one selected record on demand with redaction and size limits. Its default quick mode omits tool output and serialized groups; full serialized JSONL group analysis is explicit.
|
|
18
19
|
- `plugin_installer.py`, `.mcp.json`, `skills/`, and `scripts/check_release.py` own install and packaging behavior.
|
|
19
20
|
- `scripts/benchmark_synthetic_history.py` owns generated large-history query timing and threshold enforcement for 10k, 100k, and 500k aggregate-row fixtures. Its optional `--with-source-logs` mode writes synthetic JSONL source logs to time explicit context loading and to guard normal dashboard payload assembly against source-log reads. It must stay synthetic-only and must not read real Codex logs.
|
|
@@ -26,10 +27,11 @@ Codex Usage Tracker is a local sidecar app. It reads aggregate token counters fr
|
|
|
26
27
|
1. Add new persisted usage-event metrics through `UsageEvent`, `schema.py`, migrations, store queries, dashboard payload tests, and CSV/export checks. Add auxiliary aggregate tables such as `thread_summaries` or `source_files` through `store.py` migrations plus focused migration/privacy tests.
|
|
27
28
|
2. Add new report views through `reports.py` first, then wire CLI and MCP wrappers to that shared service.
|
|
28
29
|
3. Add new machine-readable outputs through `api_payloads.py` or report payload methods with a `schema` value, a `json_contracts.py` entry, and focused tests.
|
|
29
|
-
4. Add dashboard-only interactions in
|
|
30
|
+
4. Add dashboard-only interactions in the narrowest dashboard module and keep URL state in `dashboard_state.js`. Diagnostics snapshot panels should stay in `dashboard_diagnostics_snapshots.js`; fact tables should stay in `dashboard_diagnostics_facts.js`.
|
|
30
31
|
5. Keep all examples, screenshots, mocks, and tests synthetic. Never derive fixtures from real logs.
|
|
31
32
|
6. When editing skill instructions, update both the source `skills/...` file and the bundled `src/codex_usage_tracker/plugin_data/skills/...` copy. `scripts/check_release.py` verifies that installable plugin assets stay complete and synced.
|
|
32
33
|
7. When adding fields derived from `cwd`, Git metadata, source paths, or log-event metadata, decide how they behave in `normal`, `redacted`, and `strict` privacy modes before exposing them in dashboard, JSON, CSV, MCP, or support-bundle output.
|
|
34
|
+
8. Diagnostic snapshot refresh must remain explicit and on demand. Normal usage refresh paths may load stored snapshots, but they must not rescan source logs for diagnostic sections unless the user calls a diagnostics `--refresh` command or a `/api/diagnostics/<section>/refresh` endpoint.
|
|
33
35
|
|
|
34
36
|
## Validation
|
|
35
37
|
|
|
@@ -47,6 +47,12 @@ Tracked schema ids:
|
|
|
47
47
|
| `codex-usage-tracker-query-v1` | CLI `query`, MCP `usage_query(...)` |
|
|
48
48
|
| `codex-usage-tracker-recommendations-v1` | CLI `recommendations --json`, MCP `usage_recommendations(response_format="json")` |
|
|
49
49
|
| `codex-usage-tracker-diagnostics-v1` | CLI `diagnostics ... --json`, dashboard server `/api/diagnostics/*` |
|
|
50
|
+
| `codex-usage-tracker-diagnostic-overview-v1` | CLI `diagnostics overview --json`, dashboard server `/api/diagnostics/overview` |
|
|
51
|
+
| `codex-usage-tracker-diagnostic-tool-output-v1` | CLI `diagnostics tool-output --json`, dashboard server `/api/diagnostics/tool-output` |
|
|
52
|
+
| `codex-usage-tracker-diagnostic-commands-v1` | CLI `diagnostics commands --json`, dashboard server `/api/diagnostics/commands` |
|
|
53
|
+
| `codex-usage-tracker-diagnostic-file-reads-v1` | CLI `diagnostics file-reads --json`, dashboard server `/api/diagnostics/file-reads` |
|
|
54
|
+
| `codex-usage-tracker-diagnostic-read-productivity-v1` | CLI `diagnostics read-productivity --json`, dashboard server `/api/diagnostics/read-productivity` |
|
|
55
|
+
| `codex-usage-tracker-diagnostic-concentration-v1` | CLI `diagnostics concentration --json`, dashboard server `/api/diagnostics/concentration` |
|
|
50
56
|
| `codex-usage-tracker-session-v1` | CLI `session --json`, MCP `session_usage(response_format="json")` |
|
|
51
57
|
| `codex-usage-tracker-context-v1` | CLI `context`, MCP `usage_call_context` when raw context is explicitly enabled |
|
|
52
58
|
| `codex-usage-tracker-context-disabled-v1` | MCP `usage_call_context` when raw context is disabled |
|
|
@@ -281,6 +287,259 @@ Schema: `codex-usage-tracker-diagnostics-v1`
|
|
|
281
287
|
|
|
282
288
|
Diagnostics payloads report aggregate structured facts such as compaction, tool/function/MCP activity, command families, structured skill labels, search/read loops, and outcome events. They do not include prompts, assistant messages, tool arguments, tool output, patch text, raw commands, command arguments, file contents, or JSONL fragments. Token totals are associated with facts observed before a token-count row; they are not causal allocations.
|
|
283
289
|
|
|
290
|
+
Diagnostic snapshots use separate section endpoints instead of one large read payload. `GET` returns the latest stored section snapshot or `status: "missing"`; `POST /api/diagnostics/<section>/refresh` recomputes and replaces only that section. The dashboard button calls `POST /api/diagnostics/refresh`, which returns a small wrapper with `sections` and recomputes source-log-derived sections with one shared analyzer pass. This keeps ordinary dashboard refresh fast and prevents source-log rescans unless a diagnostics refresh is explicit.
|
|
291
|
+
|
|
292
|
+
## Diagnostic Overview Snapshot
|
|
293
|
+
|
|
294
|
+
Commands:
|
|
295
|
+
|
|
296
|
+
```bash
|
|
297
|
+
codex-usage-tracker diagnostics overview --json
|
|
298
|
+
codex-usage-tracker diagnostics overview --refresh --json
|
|
299
|
+
```
|
|
300
|
+
|
|
301
|
+
Dashboard server API:
|
|
302
|
+
|
|
303
|
+
- `GET /api/diagnostics/overview`
|
|
304
|
+
- `POST /api/diagnostics/overview/refresh`
|
|
305
|
+
|
|
306
|
+
Schema: `codex-usage-tracker-diagnostic-overview-v1`
|
|
307
|
+
|
|
308
|
+
```json
|
|
309
|
+
{
|
|
310
|
+
"schema": "codex-usage-tracker-diagnostic-overview-v1",
|
|
311
|
+
"section": "overview",
|
|
312
|
+
"status": "ready",
|
|
313
|
+
"refreshed": false,
|
|
314
|
+
"raw_context_included": false,
|
|
315
|
+
"snapshot": {
|
|
316
|
+
"computed_at": "2026-06-20T18:00:00+00:00",
|
|
317
|
+
"history_scope": "active",
|
|
318
|
+
"source_logs_scanned": 3,
|
|
319
|
+
"usage_rows_scanned": 10,
|
|
320
|
+
"raw_content_included": false
|
|
321
|
+
},
|
|
322
|
+
"overview": {
|
|
323
|
+
"usage_rows": 10,
|
|
324
|
+
"total_tokens": 12345,
|
|
325
|
+
"cached_input_tokens": 9000,
|
|
326
|
+
"uncached_input_tokens": 2000,
|
|
327
|
+
"cache_ratio": 0.75
|
|
328
|
+
},
|
|
329
|
+
"notes": []
|
|
330
|
+
}
|
|
331
|
+
```
|
|
332
|
+
|
|
333
|
+
The overview snapshot is recomputed only when explicitly refreshed. Ordinary dashboard usage refreshes do not update diagnostic snapshots.
|
|
334
|
+
|
|
335
|
+
## Diagnostic Tool Output Snapshot
|
|
336
|
+
|
|
337
|
+
Commands:
|
|
338
|
+
|
|
339
|
+
```bash
|
|
340
|
+
codex-usage-tracker diagnostics tool-output --json
|
|
341
|
+
codex-usage-tracker diagnostics tool-output --refresh --json
|
|
342
|
+
```
|
|
343
|
+
|
|
344
|
+
Dashboard server API:
|
|
345
|
+
|
|
346
|
+
- `GET /api/diagnostics/tool-output`
|
|
347
|
+
- `POST /api/diagnostics/tool-output/refresh`
|
|
348
|
+
|
|
349
|
+
Schema: `codex-usage-tracker-diagnostic-tool-output-v1`
|
|
350
|
+
|
|
351
|
+
```json
|
|
352
|
+
{
|
|
353
|
+
"schema": "codex-usage-tracker-diagnostic-tool-output-v1",
|
|
354
|
+
"section": "tool-output",
|
|
355
|
+
"status": "ready",
|
|
356
|
+
"refreshed": false,
|
|
357
|
+
"raw_context_included": false,
|
|
358
|
+
"snapshot": {},
|
|
359
|
+
"summary": {
|
|
360
|
+
"function_calls": 1,
|
|
361
|
+
"function_outputs": 1,
|
|
362
|
+
"outputs_with_original_token_count": 1,
|
|
363
|
+
"outputs_missing_original_token_count": 0,
|
|
364
|
+
"original_token_sum": 42
|
|
365
|
+
},
|
|
366
|
+
"functions": [],
|
|
367
|
+
"command_roots": [],
|
|
368
|
+
"missing_reasons": [],
|
|
369
|
+
"notes": []
|
|
370
|
+
}
|
|
371
|
+
```
|
|
372
|
+
|
|
373
|
+
The tool-output snapshot stores function names, conservative command roots, numeric counts, and terminal `Original token count` totals. It does not store raw tool output or command text.
|
|
374
|
+
|
|
375
|
+
## Diagnostic Commands Snapshot
|
|
376
|
+
|
|
377
|
+
Commands:
|
|
378
|
+
|
|
379
|
+
```bash
|
|
380
|
+
codex-usage-tracker diagnostics commands --json
|
|
381
|
+
codex-usage-tracker diagnostics commands --refresh --json
|
|
382
|
+
```
|
|
383
|
+
|
|
384
|
+
Dashboard server API:
|
|
385
|
+
|
|
386
|
+
- `GET /api/diagnostics/commands`
|
|
387
|
+
- `POST /api/diagnostics/commands/refresh`
|
|
388
|
+
|
|
389
|
+
Schema: `codex-usage-tracker-diagnostic-commands-v1`
|
|
390
|
+
|
|
391
|
+
```json
|
|
392
|
+
{
|
|
393
|
+
"schema": "codex-usage-tracker-diagnostic-commands-v1",
|
|
394
|
+
"section": "commands",
|
|
395
|
+
"status": "ready",
|
|
396
|
+
"refreshed": false,
|
|
397
|
+
"raw_context_included": false,
|
|
398
|
+
"snapshot": {},
|
|
399
|
+
"summary": {
|
|
400
|
+
"shell_function_calls": 1,
|
|
401
|
+
"command_root_count": 1,
|
|
402
|
+
"missing_command": 0
|
|
403
|
+
},
|
|
404
|
+
"commands": [
|
|
405
|
+
{
|
|
406
|
+
"root": "git",
|
|
407
|
+
"total": 1,
|
|
408
|
+
"children": [{"child": "status", "count": 1}]
|
|
409
|
+
}
|
|
410
|
+
],
|
|
411
|
+
"notes": []
|
|
412
|
+
}
|
|
413
|
+
```
|
|
414
|
+
|
|
415
|
+
The commands snapshot keeps only command roots and a bounded list of safe one-level child labels such as `status`, `diff`, or `-m:pytest`.
|
|
416
|
+
|
|
417
|
+
## Diagnostic File Reads Snapshot
|
|
418
|
+
|
|
419
|
+
Commands:
|
|
420
|
+
|
|
421
|
+
```bash
|
|
422
|
+
codex-usage-tracker diagnostics file-reads --json
|
|
423
|
+
codex-usage-tracker diagnostics file-reads --refresh --json
|
|
424
|
+
```
|
|
425
|
+
|
|
426
|
+
Dashboard server API:
|
|
427
|
+
|
|
428
|
+
- `GET /api/diagnostics/file-reads`
|
|
429
|
+
- `POST /api/diagnostics/file-reads/refresh`
|
|
430
|
+
|
|
431
|
+
Schema: `codex-usage-tracker-diagnostic-file-reads-v1`
|
|
432
|
+
|
|
433
|
+
```json
|
|
434
|
+
{
|
|
435
|
+
"schema": "codex-usage-tracker-diagnostic-file-reads-v1",
|
|
436
|
+
"section": "file-reads",
|
|
437
|
+
"status": "ready",
|
|
438
|
+
"refreshed": false,
|
|
439
|
+
"raw_context_included": false,
|
|
440
|
+
"snapshot": {},
|
|
441
|
+
"summary": {
|
|
442
|
+
"read_commands": 1,
|
|
443
|
+
"read_events": 1,
|
|
444
|
+
"unique_paths_read": 1,
|
|
445
|
+
"read_events_with_output_count": 1,
|
|
446
|
+
"read_events_missing_output_count": 0,
|
|
447
|
+
"allocated_output_token_sum": 42
|
|
448
|
+
},
|
|
449
|
+
"by_reader": [],
|
|
450
|
+
"top_paths": [],
|
|
451
|
+
"largest_read_commands": [],
|
|
452
|
+
"path_privacy": {},
|
|
453
|
+
"notes": []
|
|
454
|
+
}
|
|
455
|
+
```
|
|
456
|
+
|
|
457
|
+
The file-reads snapshot classifies common shell readers such as `cat`, `sed`, `nl`, `rg`, and `find`. Path labels are basename-only with a short irreversible hash; raw commands, command arguments, absolute paths, file contents, and tool output are not stored.
|
|
458
|
+
|
|
459
|
+
## Diagnostic Read Productivity Snapshot
|
|
460
|
+
|
|
461
|
+
Commands:
|
|
462
|
+
|
|
463
|
+
```bash
|
|
464
|
+
codex-usage-tracker diagnostics read-productivity --json
|
|
465
|
+
codex-usage-tracker diagnostics read-productivity --refresh --json
|
|
466
|
+
```
|
|
467
|
+
|
|
468
|
+
Dashboard server API:
|
|
469
|
+
|
|
470
|
+
- `GET /api/diagnostics/read-productivity`
|
|
471
|
+
- `POST /api/diagnostics/read-productivity/refresh`
|
|
472
|
+
|
|
473
|
+
Schema: `codex-usage-tracker-diagnostic-read-productivity-v1`
|
|
474
|
+
|
|
475
|
+
```json
|
|
476
|
+
{
|
|
477
|
+
"schema": "codex-usage-tracker-diagnostic-read-productivity-v1",
|
|
478
|
+
"section": "read-productivity",
|
|
479
|
+
"status": "ready",
|
|
480
|
+
"refreshed": false,
|
|
481
|
+
"raw_context_included": false,
|
|
482
|
+
"snapshot": {},
|
|
483
|
+
"summary": {
|
|
484
|
+
"read_events": 1,
|
|
485
|
+
"read_events_modified_later": 1,
|
|
486
|
+
"read_events_modified_later_pct": 1.0,
|
|
487
|
+
"unique_paths_read": 1,
|
|
488
|
+
"unique_paths_modified_later": 1,
|
|
489
|
+
"unique_path_modified_later_pct": 1.0,
|
|
490
|
+
"correlation_note": "Read-to-modify counts are temporal correlations."
|
|
491
|
+
},
|
|
492
|
+
"by_reader": [],
|
|
493
|
+
"top_modified_paths": [],
|
|
494
|
+
"path_privacy": {},
|
|
495
|
+
"notes": []
|
|
496
|
+
}
|
|
497
|
+
```
|
|
498
|
+
|
|
499
|
+
Read productivity is a temporal correlation, not causation. A read is counted as modified later only when the same privacy-preserving path key appears in a later structured patch event in the same source log.
|
|
500
|
+
|
|
501
|
+
## Diagnostic Concentration Snapshot
|
|
502
|
+
|
|
503
|
+
Commands:
|
|
504
|
+
|
|
505
|
+
```bash
|
|
506
|
+
codex-usage-tracker diagnostics concentration --json
|
|
507
|
+
codex-usage-tracker diagnostics concentration --refresh --json
|
|
508
|
+
```
|
|
509
|
+
|
|
510
|
+
Dashboard server API:
|
|
511
|
+
|
|
512
|
+
- `GET /api/diagnostics/concentration`
|
|
513
|
+
- `POST /api/diagnostics/concentration/refresh`
|
|
514
|
+
|
|
515
|
+
Schema: `codex-usage-tracker-diagnostic-concentration-v1`
|
|
516
|
+
|
|
517
|
+
```json
|
|
518
|
+
{
|
|
519
|
+
"schema": "codex-usage-tracker-diagnostic-concentration-v1",
|
|
520
|
+
"section": "concentration",
|
|
521
|
+
"status": "ready",
|
|
522
|
+
"refreshed": false,
|
|
523
|
+
"raw_context_included": false,
|
|
524
|
+
"snapshot": {},
|
|
525
|
+
"summary": {
|
|
526
|
+
"usage_rows": 4,
|
|
527
|
+
"total_tokens": 100,
|
|
528
|
+
"dimension_count": 3,
|
|
529
|
+
"history_scope": "active"
|
|
530
|
+
},
|
|
531
|
+
"metrics": [
|
|
532
|
+
{"metric": "top_1_source_log_share", "dimension": "source_log", "top_n": 1, "share": 0.5}
|
|
533
|
+
],
|
|
534
|
+
"dimensions": [],
|
|
535
|
+
"largest_impact_rows": [],
|
|
536
|
+
"privacy": {},
|
|
537
|
+
"notes": []
|
|
538
|
+
}
|
|
539
|
+
```
|
|
540
|
+
|
|
541
|
+
The concentration snapshot computes top-1/top-3/top-5 share and effective group count by source log/session, cwd/project label, and day. Metric ids such as `top_1_source_log_share` are stable JSON contract fields; dashboard views should render them as reader-facing labels. Source log labels use session-id prefixes or source hashes, cwd labels use basename-only labels, and raw source paths/cwd paths are not included.
|
|
542
|
+
|
|
284
543
|
## Pricing Coverage
|
|
285
544
|
|
|
286
545
|
Command:
|
|
@@ -120,12 +120,22 @@ codex-usage-tracker diagnostics summary
|
|
|
120
120
|
codex-usage-tracker diagnostics facts --sort uncached
|
|
121
121
|
codex-usage-tracker diagnostics compactions
|
|
122
122
|
codex-usage-tracker diagnostics tools
|
|
123
|
+
codex-usage-tracker diagnostics overview --refresh
|
|
124
|
+
codex-usage-tracker diagnostics tool-output --refresh
|
|
125
|
+
codex-usage-tracker diagnostics commands --refresh
|
|
126
|
+
codex-usage-tracker diagnostics file-reads --refresh
|
|
127
|
+
codex-usage-tracker diagnostics read-productivity --refresh
|
|
128
|
+
codex-usage-tracker diagnostics concentration --refresh
|
|
123
129
|
codex-usage-tracker diagnostics fact-calls --fact-type compaction --fact-name post_compaction
|
|
124
130
|
```
|
|
125
131
|
|
|
126
132
|
Diagnostics expose structured event patterns and their associated token totals. They can show compactions, tool/function/MCP activity, safe command families, structured skill labels, patch outcomes, task completion, search/read loops, and aborted or rolled-back turns. Associated totals are not causal allocations and are not additive when one model call has multiple diagnostic facts.
|
|
127
133
|
|
|
128
|
-
|
|
134
|
+
Snapshot diagnostics are persisted aggregate reports. Without `--refresh`, snapshot commands return the latest stored payload or a `missing` status. With `--refresh`, they recompute from indexed source logs and replace the stored section snapshot. Ordinary `refresh`, `open-dashboard`, and dashboard `Refresh` update usage rows only; they do not recompute diagnostic snapshots.
|
|
135
|
+
|
|
136
|
+
The snapshot sections answer different questions: `overview` summarizes usage rows and aggregate token totals, `tool-output` counts functions and terminal `Original token count` coverage, `commands` keeps command roots plus bounded safe child labels, `file-reads` counts reader/path activity and allocated read-output tokens, `read-productivity` reports later-edit correlations for matching path keys, and `concentration` shows top-N token share by source/session, cwd/project, and day.
|
|
137
|
+
|
|
138
|
+
Diagnostic payloads are aggregate-only. They do not include prompts, assistant text, tool arguments, tool output, patch text, raw commands, command arguments, file contents, raw absolute paths, or JSONL fragments. File-read diagnostics use basename-only path labels plus short irreversible hashes, read-productivity percentages are temporal correlations rather than proof that a read caused a later edit, and concentration reports use safe source/session, cwd, and day labels only.
|
|
129
139
|
|
|
130
140
|
## JSON Queries
|
|
131
141
|
|
|
@@ -133,6 +133,12 @@ Use `Diagnostics` view when you want to see what structured event patterns are h
|
|
|
133
133
|
- The tab consumes the localhost `/api/diagnostics/*` endpoints; static file dashboards show a live-API unavailable state.
|
|
134
134
|
- The first table shows top diagnostic facts by associated uncached input tokens. Tool/function/MCP/command-family and compaction sections expose narrower slices of the same fact data.
|
|
135
135
|
- Command diagnostics store only a command family such as `pytest`, `git`, or `unknown_command`. Skill and MCP labels are detected only when they are present as structured event metadata.
|
|
136
|
+
- Newer on-demand diagnostic snapshot endpoints are section-specific (`overview`, `tool-output`, `commands`, `file-reads`, `read-productivity`, and `concentration`). Heavy recomputation happens only through explicit diagnostic refresh endpoints. The dashboard's `Refresh diagnostics` button uses one batched refresh so source-log sections share one scan.
|
|
137
|
+
- Click `Refresh diagnostics` when you want to recompute stored diagnostic snapshots. The normal dashboard `Refresh` action updates usage rows only.
|
|
138
|
+
- Snapshot panels show their stored status, last computed time, history scope, and logs scanned count. Missing or stale panels still render without forcing a source-log scan.
|
|
139
|
+
- `Tool Output` totals come from terminal wrapper metadata such as `Original token count`; missing-count rows show coverage gaps where that header was absent.
|
|
140
|
+
- File-read snapshots use basename-only path labels and short hashes. Read-productivity rates are temporal correlations between earlier reads and later structured patch events, not causation.
|
|
141
|
+
- Concentration snapshots show top-N share and effective group count by source log/session, cwd/project label, and day without exposing raw source-log or cwd paths.
|
|
136
142
|
- Click `Calls` on a fact row to load associated model calls. Call links and largest-call links open the Call Investigator, where raw context remains explicit and on demand.
|
|
137
143
|
- Associated token totals are not causal allocations and are not additive when one call has multiple diagnostic facts.
|
|
138
144
|
|
|
@@ -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.9.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.9.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.9.0
|
|
150
|
+
python scripts/smoke_installed_package.py --docker --from-pypi --version 0.9.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.
|
|
@@ -182,6 +182,13 @@ codex-usage-tracker summary --preset by-subagent-role
|
|
|
182
182
|
codex-usage-tracker expensive --limit 5
|
|
183
183
|
```
|
|
184
184
|
|
|
185
|
+
For browser-level dashboard smoke after starting a live dashboard server:
|
|
186
|
+
|
|
187
|
+
```bash
|
|
188
|
+
npm install
|
|
189
|
+
DASHBOARD_BASE_URL=http://127.0.0.1:8898 npm run smoke:dashboard:diagnostics
|
|
190
|
+
```
|
|
191
|
+
|
|
185
192
|
## Dashboard Screenshots
|
|
186
193
|
|
|
187
194
|
Dashboard screenshots in `docs/assets/` and `src/codex_usage_tracker/plugin_data/docs/assets/` must be generated from synthetic aggregate fixture data only.
|
|
@@ -286,8 +293,8 @@ After the release branch merges, tag from updated `main`, not from an unreviewed
|
|
|
286
293
|
```bash
|
|
287
294
|
git switch main
|
|
288
295
|
git pull --ff-only
|
|
289
|
-
git tag -a v0.
|
|
290
|
-
git push origin v0.
|
|
296
|
+
git tag -a v0.9.0 -m "codex-usage-tracker 0.9.0"
|
|
297
|
+
git push origin v0.9.0
|
|
291
298
|
```
|
|
292
299
|
|
|
293
300
|
Do not create or push release tags without maintainer approval.
|
|
@@ -296,7 +303,7 @@ Do not create or push release tags without maintainer approval.
|
|
|
296
303
|
|
|
297
304
|
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
305
|
|
|
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. Minor release `0.8.0` adds aggregate diagnostics, source-offset context seeking, and live dashboard loading hardening. Patch release `0.8.1` improves Diagnostics fact table readability with pinned fact names and sortable fact columns.
|
|
306
|
+
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. Minor release `0.8.0` adds aggregate diagnostics, source-offset context seeking, and live dashboard loading hardening. Patch release `0.8.1` improves Diagnostics fact table readability with pinned fact names and sortable fact columns. Minor release `0.9.0` adds persisted diagnostic snapshots, on-demand diagnostic refresh, tool/command/file-read/concentration reports, and Diagnostics dashboard panels.
|
|
300
307
|
|
|
301
308
|
- GitHub Release: `https://github.com/douglasmonsky/codex-usage-tracker/releases/tag/v0.3.0`
|
|
302
309
|
- 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.9.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.9.0`: `python -m venv /tmp/codex-usage-pypi-smoke && . /tmp/codex-usage-pypi-smoke/bin/activate && python -m pip install codex-usage-tracking==0.9.0 && codex-usage-tracker --version`.
|
|
29
|
+
- [x] Verify public pipx install path for `0.9.0`: `PIPX_HOME=/tmp/codex-usage-pipx-home PIPX_BIN_DIR=/tmp/codex-usage-pipx-bin pipx install codex-usage-tracking==0.9.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.9.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.9.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.9.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.9.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.9.0`.
|
|
224
224
|
- Release recovery documentation is proven by `scripts/check_release.py` required-file and docs checks.
|
|
225
225
|
|
|
226
226
|
### Known Limitations
|
|
@@ -35,6 +35,10 @@ Call-origin metadata is heuristic and confidence-labeled. It stores categories s
|
|
|
35
35
|
|
|
36
36
|
Diagnostic facts follow the same aggregate-only rule. They can store safe structured labels such as `patch_applied`, `function_call_output`, `post_compaction`, MCP tool/server labels, structured skill labels, and command families such as `pytest`, `git`, or `unknown_command`, along with event counts and source line ranges. Command text may be classified in memory during parsing, but it is not persisted. Diagnostic facts do not store tool arguments, command text, command output, patch text, prompt or assistant text, file contents, raw JSONL fragments, or raw context evidence.
|
|
37
37
|
|
|
38
|
+
On-demand diagnostic snapshots follow the same boundary. Tool-output snapshots use terminal wrapper metadata such as `Original token count` when present and persist only counts, coverage gaps, and safe function/command labels. Command snapshots keep command roots plus a bounded list of conservative one-level child labels. File-read snapshots classify common read commands and path scans, but persist only counters, reader families, basename-only path labels, and short irreversible path hashes. They do not persist raw absolute paths, raw command strings, command arguments, file contents, tool output, or patch text. Read-productivity snapshots report only temporal read-to-modify correlations for matching path keys in the same source log; they do not claim causation. Concentration snapshots group by safe source/session, cwd, and day labels and do not expose raw source-log or cwd paths.
|
|
39
|
+
|
|
40
|
+
Diagnostic snapshots are not live recomputed during ordinary dashboard or usage refresh. Stored snapshots can be displayed without rescanning source logs, and recomputation requires an explicit diagnostics `--refresh` command, the batched localhost `/api/diagnostics/refresh` request, or a targeted `/api/diagnostics/<section>/refresh` request.
|
|
41
|
+
|
|
38
42
|
## On-Demand Context
|
|
39
43
|
|
|
40
44
|
`usage_call_context`, `codex-usage-tracker context`, and the `serve-dashboard` context endpoint read a single source JSONL file only when explicitly requested. Returned context is redacted for common secret patterns and capped in size by default for CLI/MCP requests. The call investigator uses the same endpoint at runtime and requests quick redacted evidence for the selected call when the local context API is enabled; that still does not persist raw context into SQLite, CSV, support bundles, or generated dashboard HTML.
|
|
@@ -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.9.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.9.0",
|
|
19
19
|
)
|
|
20
|
-
RUNTIME_VERSION = "0.
|
|
20
|
+
RUNTIME_VERSION = "0.9.0"
|
|
21
21
|
PACKAGE_SPEC_MARKER = ".codex-usage-tracker-package-spec"
|
|
22
22
|
MODULE_CHECK = (
|
|
23
23
|
"import importlib.metadata; "
|
|
@@ -29,6 +29,14 @@ from codex_usage_tracker.diagnostic_reports import (
|
|
|
29
29
|
build_diagnostics_facts_report,
|
|
30
30
|
build_diagnostics_summary_report,
|
|
31
31
|
)
|
|
32
|
+
from codex_usage_tracker.diagnostic_snapshots import (
|
|
33
|
+
build_diagnostic_commands_report,
|
|
34
|
+
build_diagnostic_concentration_report,
|
|
35
|
+
build_diagnostic_file_reads_report,
|
|
36
|
+
build_diagnostic_overview_report,
|
|
37
|
+
build_diagnostic_read_productivity_report,
|
|
38
|
+
build_diagnostic_tool_output_report,
|
|
39
|
+
)
|
|
32
40
|
from codex_usage_tracker.diagnostics import run_doctor
|
|
33
41
|
from codex_usage_tracker.formatting import (
|
|
34
42
|
format_doctor,
|
|
@@ -394,6 +402,7 @@ def _run_recommendations(args: argparse.Namespace) -> int:
|
|
|
394
402
|
|
|
395
403
|
def _run_diagnostics(args: argparse.Namespace) -> int:
|
|
396
404
|
command = args.diagnostics_command
|
|
405
|
+
report: Any
|
|
397
406
|
if command == "summary":
|
|
398
407
|
report = build_diagnostics_summary_report(
|
|
399
408
|
db_path=args.db,
|
|
@@ -448,6 +457,42 @@ def _run_diagnostics(args: argparse.Namespace) -> int:
|
|
|
448
457
|
direction=args.direction,
|
|
449
458
|
privacy_mode=args.privacy_mode,
|
|
450
459
|
)
|
|
460
|
+
elif command == "overview":
|
|
461
|
+
report = build_diagnostic_overview_report(
|
|
462
|
+
db_path=args.db,
|
|
463
|
+
include_archived=args.include_archived,
|
|
464
|
+
refresh=args.refresh,
|
|
465
|
+
)
|
|
466
|
+
elif command == "tool-output":
|
|
467
|
+
report = build_diagnostic_tool_output_report(
|
|
468
|
+
db_path=args.db,
|
|
469
|
+
include_archived=args.include_archived,
|
|
470
|
+
refresh=args.refresh,
|
|
471
|
+
)
|
|
472
|
+
elif command == "commands":
|
|
473
|
+
report = build_diagnostic_commands_report(
|
|
474
|
+
db_path=args.db,
|
|
475
|
+
include_archived=args.include_archived,
|
|
476
|
+
refresh=args.refresh,
|
|
477
|
+
)
|
|
478
|
+
elif command == "file-reads":
|
|
479
|
+
report = build_diagnostic_file_reads_report(
|
|
480
|
+
db_path=args.db,
|
|
481
|
+
include_archived=args.include_archived,
|
|
482
|
+
refresh=args.refresh,
|
|
483
|
+
)
|
|
484
|
+
elif command == "read-productivity":
|
|
485
|
+
report = build_diagnostic_read_productivity_report(
|
|
486
|
+
db_path=args.db,
|
|
487
|
+
include_archived=args.include_archived,
|
|
488
|
+
refresh=args.refresh,
|
|
489
|
+
)
|
|
490
|
+
elif command == "concentration":
|
|
491
|
+
report = build_diagnostic_concentration_report(
|
|
492
|
+
db_path=args.db,
|
|
493
|
+
include_archived=args.include_archived,
|
|
494
|
+
refresh=args.refresh,
|
|
495
|
+
)
|
|
451
496
|
else:
|
|
452
497
|
raise ValueError(f"unknown diagnostics command: {command}")
|
|
453
498
|
|