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.
Files changed (169) hide show
  1. {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/.codex-plugin/plugin.json +1 -1
  2. {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/CHANGELOG.md +8 -0
  3. {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/PKG-INFO +3 -3
  4. {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/README.md +2 -2
  5. {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/docs/dashboard-guide.md +3 -3
  6. {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/docs/development.md +7 -7
  7. {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/docs/one-dot-oh-readiness.md +8 -8
  8. {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/docs/pricing-and-credits.md +5 -4
  9. {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/docs/privacy.md +2 -1
  10. {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/pyproject.toml +1 -1
  11. {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/skills/codex-usage-tracker/scripts/run_mcp.py +2 -2
  12. {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/src/codex_usage_tracker/__init__.py +1 -1
  13. {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/src/codex_usage_tracker/dashboard.py +6 -0
  14. {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/src/codex_usage_tracker/models.py +8 -0
  15. {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/src/codex_usage_tracker/parser.py +87 -0
  16. {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/src/codex_usage_tracker/plugin_data/dashboard/dashboard.css +20 -1
  17. {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/src/codex_usage_tracker/plugin_data/dashboard/dashboard.js +13 -6
  18. {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/src/codex_usage_tracker/plugin_data/dashboard/dashboard_analysis.js +5 -0
  19. {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/src/codex_usage_tracker/plugin_data/dashboard/dashboard_cells.js +5 -0
  20. {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/src/codex_usage_tracker/plugin_data/dashboard/dashboard_format.js +1 -0
  21. {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/src/codex_usage_tracker/plugin_data/dashboard/dashboard_i18n.js +11 -0
  22. {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/src/codex_usage_tracker/plugin_data/dashboard/dashboard_insights.js +1 -1
  23. {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/src/codex_usage_tracker/plugin_data/dashboard/dashboard_state.js +15 -3
  24. {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/src/codex_usage_tracker/plugin_data/dashboard/dashboard_status.js +105 -1
  25. {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/src/codex_usage_tracker/plugin_data/dashboard/dashboard_tables.js +5 -7
  26. {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/src/codex_usage_tracker/plugin_data/dashboard/dashboard_template.html +5 -5
  27. {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/src/codex_usage_tracker/plugin_data/dashboard/locales/ar.json +12 -0
  28. {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/src/codex_usage_tracker/plugin_data/dashboard/locales/de.json +12 -0
  29. {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/src/codex_usage_tracker/plugin_data/dashboard/locales/en.json +12 -0
  30. {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/src/codex_usage_tracker/plugin_data/dashboard/locales/es.json +12 -0
  31. {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/src/codex_usage_tracker/plugin_data/dashboard/locales/fr.json +12 -0
  32. {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/src/codex_usage_tracker/plugin_data/dashboard/locales/it.json +12 -0
  33. {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/src/codex_usage_tracker/plugin_data/dashboard/locales/ja.json +12 -0
  34. {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/src/codex_usage_tracker/plugin_data/dashboard/locales/ko.json +12 -0
  35. {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/src/codex_usage_tracker/plugin_data/dashboard/locales/pt.json +12 -0
  36. {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/src/codex_usage_tracker/plugin_data/dashboard/locales/ru.json +12 -0
  37. {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/src/codex_usage_tracker/plugin_data/dashboard/locales/vi.json +12 -0
  38. {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
  39. {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/src/codex_usage_tracker/plugin_data/docs/dashboard-guide.html +2 -2
  40. {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/src/codex_usage_tracker/schema.py +8 -0
  41. {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/src/codex_usage_tracker/server.py +6 -0
  42. {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/src/codex_usage_tracker/store.py +173 -0
  43. {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/src/codex_usage_tracker/store_schema.py +20 -1
  44. {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/src/codex_usage_tracking.egg-info/PKG-INFO +3 -3
  45. {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/tests/store_dashboard_helpers.py +30 -0
  46. {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/tests/test_dashboard_payload.py +50 -2
  47. {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/tests/test_dashboard_server.py +3 -0
  48. {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/tests/test_dashboard_state.py +22 -1
  49. {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/tests/test_i18n.py +8 -3
  50. {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/tests/test_parser.py +74 -0
  51. {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/tests/test_store_dashboard_mcp.py +117 -6
  52. {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/tests/test_store_migrations.py +9 -3
  53. {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/.mcp.json +0 -0
  54. {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/AGENTS.md +0 -0
  55. {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/CONTRIBUTING.md +0 -0
  56. {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/LICENSE +0 -0
  57. {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/MANIFEST.in +0 -0
  58. {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/SECURITY.md +0 -0
  59. {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/assets/icon.svg +0 -0
  60. {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/docs/architecture.md +0 -0
  61. {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/docs/assets/dashboard-call-investigator-evidence.png +0 -0
  62. {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/docs/assets/dashboard-call-investigator-preview.png +0 -0
  63. {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/docs/assets/dashboard-call-investigator.png +0 -0
  64. {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/docs/assets/dashboard-calls-preview.png +0 -0
  65. {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/docs/assets/dashboard-calls.png +0 -0
  66. {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/docs/assets/dashboard-details.png +0 -0
  67. {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/docs/assets/dashboard-insights.png +0 -0
  68. {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/docs/assets/dashboard-threads.png +0 -0
  69. {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/docs/assets/plugin-prompts.png +0 -0
  70. {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/docs/assets/plugin-thread-leaderboard.png +0 -0
  71. {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/docs/assets/ux/call-detail-panel.png +0 -0
  72. {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/docs/assets/ux/insight-overview.png +0 -0
  73. {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/docs/assets/ux/thread-investigation.png +0 -0
  74. {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/docs/call-drilldown-performance-checklist.md +0 -0
  75. {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/docs/cli-json-schemas.md +0 -0
  76. {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/docs/cli-reference.md +0 -0
  77. {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/docs/install.md +0 -0
  78. {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/docs/mcp.md +0 -0
  79. {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/docs/ui-ux-improvement-plan.md +0 -0
  80. {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/scripts/benchmark_synthetic_history.py +0 -0
  81. {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/scripts/check_release.py +0 -0
  82. {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/scripts/install_local_plugin.py +0 -0
  83. {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/scripts/smoke_installed_package.py +0 -0
  84. {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/setup.cfg +0 -0
  85. {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/skills/codex-usage-api/SKILL.md +0 -0
  86. {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/skills/codex-usage-tracker/SKILL.md +0 -0
  87. {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/src/codex_usage_tracker/__main__.py +0 -0
  88. {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/src/codex_usage_tracker/allowance.py +0 -0
  89. {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/src/codex_usage_tracker/api_payloads.py +0 -0
  90. {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/src/codex_usage_tracker/call_origin.py +0 -0
  91. {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/src/codex_usage_tracker/cli.py +0 -0
  92. {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/src/codex_usage_tracker/cli_parser.py +0 -0
  93. {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/src/codex_usage_tracker/context.py +0 -0
  94. {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/src/codex_usage_tracker/costing.py +0 -0
  95. {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/src/codex_usage_tracker/diagnostics.py +0 -0
  96. {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/src/codex_usage_tracker/formatting.py +0 -0
  97. {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/src/codex_usage_tracker/i18n.py +0 -0
  98. {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/src/codex_usage_tracker/json_contracts.py +0 -0
  99. {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/src/codex_usage_tracker/mcp_server.py +0 -0
  100. {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/src/codex_usage_tracker/paths.py +0 -0
  101. {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/src/codex_usage_tracker/plugin_data/__init__.py +0 -0
  102. {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/src/codex_usage_tracker/plugin_data/assets/icon.svg +0 -0
  103. {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/src/codex_usage_tracker/plugin_data/dashboard/dashboard_actions.js +0 -0
  104. {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/src/codex_usage_tracker/plugin_data/dashboard/dashboard_call.css +0 -0
  105. {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
  106. {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
  107. {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/src/codex_usage_tracker/plugin_data/dashboard/dashboard_data.js +0 -0
  108. {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/src/codex_usage_tracker/plugin_data/dashboard/dashboard_detail.css +0 -0
  109. {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/src/codex_usage_tracker/plugin_data/dashboard/dashboard_details.js +0 -0
  110. {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/src/codex_usage_tracker/plugin_data/dashboard/dashboard_events.js +0 -0
  111. {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/src/codex_usage_tracker/plugin_data/dashboard/dashboard_filters.js +0 -0
  112. {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/src/codex_usage_tracker/plugin_data/dashboard/dashboard_insights.css +0 -0
  113. {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/src/codex_usage_tracker/plugin_data/dashboard/dashboard_layout.css +0 -0
  114. {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/src/codex_usage_tracker/plugin_data/dashboard/dashboard_live.js +0 -0
  115. {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
  116. {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/src/codex_usage_tracker/plugin_data/dashboard/dashboard_responsive.css +0 -0
  117. {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/src/codex_usage_tracker/plugin_data/dashboard/dashboard_tables.css +0 -0
  118. {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/src/codex_usage_tracker/plugin_data/dashboard/dashboard_tooltips.js +0 -0
  119. {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
  120. {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
  121. {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
  122. {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
  123. {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
  124. {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
  125. {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
  126. {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
  127. {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
  128. {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
  129. {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
  130. {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
  131. {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
  132. {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/src/codex_usage_tracker/plugin_installer.py +0 -0
  133. {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/src/codex_usage_tracker/pricing.py +0 -0
  134. {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/src/codex_usage_tracker/pricing_config.py +0 -0
  135. {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/src/codex_usage_tracker/pricing_estimates.py +0 -0
  136. {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/src/codex_usage_tracker/pricing_openai.py +0 -0
  137. {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/src/codex_usage_tracker/projects.py +0 -0
  138. {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/src/codex_usage_tracker/recommendations.py +0 -0
  139. {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/src/codex_usage_tracker/redaction.py +0 -0
  140. {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/src/codex_usage_tracker/reports.py +0 -0
  141. {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/src/codex_usage_tracker/server_utils.py +0 -0
  142. {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/src/codex_usage_tracker/store_query_sql.py +0 -0
  143. {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/src/codex_usage_tracker/store_sources.py +0 -0
  144. {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/src/codex_usage_tracker/store_thread_summaries.py +0 -0
  145. {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/src/codex_usage_tracker/support.py +0 -0
  146. {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/src/codex_usage_tracker/threads.py +0 -0
  147. {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/src/codex_usage_tracking.egg-info/SOURCES.txt +0 -0
  148. {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/src/codex_usage_tracking.egg-info/dependency_links.txt +0 -0
  149. {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/src/codex_usage_tracking.egg-info/entry_points.txt +0 -0
  150. {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/src/codex_usage_tracking.egg-info/requires.txt +0 -0
  151. {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/src/codex_usage_tracking.egg-info/top_level.txt +0 -0
  152. {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/tests/test_allowance.py +0 -0
  153. {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/tests/test_call_origin.py +0 -0
  154. {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/tests/test_cli_lifecycle.py +0 -0
  155. {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/tests/test_cli_release.py +0 -0
  156. {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/tests/test_context_evidence.py +0 -0
  157. {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/tests/test_dashboard_data.py +0 -0
  158. {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/tests/test_json_contracts.py +0 -0
  159. {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/tests/test_mcp_integration.py +0 -0
  160. {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/tests/test_mcp_launcher.py +0 -0
  161. {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/tests/test_plugin_installer.py +0 -0
  162. {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/tests/test_pricing.py +0 -0
  163. {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/tests/test_privacy.py +0 -0
  164. {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/tests/test_projects.py +0 -0
  165. {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/tests/test_recommendations.py +0 -0
  166. {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/tests/test_redaction.py +0 -0
  167. {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/tests/test_schema.py +0 -0
  168. {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/tests/test_support.py +0 -0
  169. {codex_usage_tracking-0.6.1 → codex_usage_tracking-0.7.0}/tests/test_threads.py +0 -0
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "codex-usage-tracker",
3
- "version": "0.6.1",
3
+ "version": "0.7.0",
4
4
  "description": "Unofficial local tracker for aggregate Codex token usage from local session logs.",
5
5
  "author": {
6
6
  "name": "Douglas Monsky"
@@ -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.6.1
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. 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).
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 available when you configure copied values.
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. 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).
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 available when you configure copied values.
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 Remaining` is not read from the logged-in account plan. 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.
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 manually entered allowance windows, and derived ratios
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 read from Codex logs or inferred from the logged-in account plan automatically. Add `~/.codex-usage-tracker/allowance.json` only when you want the dashboard to show current copied allowance state. Local Codex logs may also omit usage from other ChatGPT agentic surfaces that share the same allowance.
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.6.1
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.6.1
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.6.1
150
- python scripts/smoke_installed_package.py --docker --from-pypi --version 0.6.1
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.6.1 -m "codex-usage-tracker 0.6.1"
290
- git push origin v0.6.1
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.6.1`: `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.6.1`: `python -m venv /tmp/codex-usage-pypi-smoke && . /tmp/codex-usage-pypi-smoke/bin/activate && python -m pip install codex-usage-tracking==0.6.1 && codex-usage-tracker --version`.
29
- - [x] Verify public pipx install path for `0.6.1`: `PIPX_HOME=/tmp/codex-usage-pipx-home PIPX_BIN_DIR=/tmp/codex-usage-pipx-bin pipx install codex-usage-tracking==0.6.1 && /tmp/codex-usage-pipx-bin/codex-usage-tracker --version`.
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.6.1`.
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.6.1`; all repo tests use synthetic or aggregate-only data.
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.6.1`.
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.6.1`.
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.6.1`.
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 Remaining`: optional user-provided 5-hour and weekly allowance snapshots.
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 Remaining
61
+ ## Usage Observed
62
62
 
63
- `Usage Remaining` 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.
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. The dashboard shows remaining values only when you copy them into `~/.codex-usage-tracker/allowance.json`.
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.6.1"
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.6.1",
18
+ "codex-usage-tracking==0.7.0",
19
19
  )
20
- RUNTIME_VERSION = "0.6.1"
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; "
@@ -2,6 +2,6 @@
2
2
 
3
3
  from codex_usage_tracker.models import UsageEvent
4
4
 
5
- __version__ = "0.6.1"
5
+ __version__ = "0.7.0"
6
6
 
7
7
  __all__ = ["UsageEvent", "__version__"]
@@ -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
- let activeView = ['calls', 'threads', 'insights', 'call'].includes(initialState.view) ? initialState.view : 'insights';
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 || 'attention';
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 = 'attention';
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
- renderSignalPucks,
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 === 'cost' || key === 'cache' || key === 'signals' ? 'desc' : 'asc';
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
- renderSignalPucks,
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,