codex-usage-tracking 0.4.1__tar.gz → 0.5.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 (124) hide show
  1. {codex_usage_tracking-0.4.1 → codex_usage_tracking-0.5.0}/.codex-plugin/plugin.json +1 -1
  2. {codex_usage_tracking-0.4.1 → codex_usage_tracking-0.5.0}/CHANGELOG.md +9 -0
  3. {codex_usage_tracking-0.4.1 → codex_usage_tracking-0.5.0}/PKG-INFO +29 -1
  4. {codex_usage_tracking-0.4.1 → codex_usage_tracking-0.5.0}/README.md +28 -0
  5. {codex_usage_tracking-0.4.1 → codex_usage_tracking-0.5.0}/docs/cli-reference.md +2 -0
  6. {codex_usage_tracking-0.4.1 → codex_usage_tracking-0.5.0}/docs/dashboard-guide.md +9 -0
  7. {codex_usage_tracking-0.4.1 → codex_usage_tracking-0.5.0}/docs/development.md +10 -9
  8. {codex_usage_tracking-0.4.1 → codex_usage_tracking-0.5.0}/docs/one-dot-oh-readiness.md +11 -9
  9. {codex_usage_tracking-0.4.1 → codex_usage_tracking-0.5.0}/pyproject.toml +2 -1
  10. {codex_usage_tracking-0.4.1 → codex_usage_tracking-0.5.0}/scripts/check_release.py +101 -17
  11. {codex_usage_tracking-0.4.1 → codex_usage_tracking-0.5.0}/scripts/smoke_installed_package.py +12 -0
  12. {codex_usage_tracking-0.4.1 → codex_usage_tracking-0.5.0}/skills/codex-usage-tracker/scripts/run_mcp.py +2 -2
  13. {codex_usage_tracking-0.4.1 → codex_usage_tracking-0.5.0}/src/codex_usage_tracker/__init__.py +1 -1
  14. {codex_usage_tracking-0.4.1 → codex_usage_tracking-0.5.0}/src/codex_usage_tracker/cli.py +15 -0
  15. {codex_usage_tracking-0.4.1 → codex_usage_tracking-0.5.0}/src/codex_usage_tracker/costing.py +14 -0
  16. {codex_usage_tracking-0.4.1 → codex_usage_tracking-0.5.0}/src/codex_usage_tracker/dashboard.py +16 -2
  17. codex_usage_tracking-0.5.0/src/codex_usage_tracker/i18n.py +182 -0
  18. {codex_usage_tracking-0.4.1 → codex_usage_tracking-0.5.0}/src/codex_usage_tracker/plugin_data/dashboard/dashboard.css +20 -4
  19. {codex_usage_tracking-0.4.1 → codex_usage_tracking-0.5.0}/src/codex_usage_tracker/plugin_data/dashboard/dashboard.js +617 -303
  20. codex_usage_tracking-0.5.0/src/codex_usage_tracker/plugin_data/dashboard/dashboard_template.html +146 -0
  21. codex_usage_tracking-0.5.0/src/codex_usage_tracker/plugin_data/dashboard/locales/ar.json +438 -0
  22. codex_usage_tracking-0.5.0/src/codex_usage_tracker/plugin_data/dashboard/locales/de.json +438 -0
  23. codex_usage_tracking-0.5.0/src/codex_usage_tracker/plugin_data/dashboard/locales/en.json +438 -0
  24. codex_usage_tracking-0.5.0/src/codex_usage_tracker/plugin_data/dashboard/locales/es.json +438 -0
  25. codex_usage_tracking-0.5.0/src/codex_usage_tracker/plugin_data/dashboard/locales/fr.json +438 -0
  26. codex_usage_tracking-0.5.0/src/codex_usage_tracker/plugin_data/dashboard/locales/it.json +438 -0
  27. codex_usage_tracking-0.5.0/src/codex_usage_tracker/plugin_data/dashboard/locales/ja.json +438 -0
  28. codex_usage_tracking-0.5.0/src/codex_usage_tracker/plugin_data/dashboard/locales/ko.json +438 -0
  29. codex_usage_tracking-0.5.0/src/codex_usage_tracker/plugin_data/dashboard/locales/pt.json +438 -0
  30. codex_usage_tracking-0.5.0/src/codex_usage_tracker/plugin_data/dashboard/locales/ru.json +438 -0
  31. codex_usage_tracking-0.5.0/src/codex_usage_tracker/plugin_data/dashboard/locales/vi.json +438 -0
  32. codex_usage_tracking-0.5.0/src/codex_usage_tracker/plugin_data/dashboard/locales/zh-Hans.json +438 -0
  33. {codex_usage_tracking-0.4.1 → codex_usage_tracking-0.5.0}/src/codex_usage_tracker/recommendations.py +11 -1
  34. {codex_usage_tracking-0.4.1 → codex_usage_tracking-0.5.0}/src/codex_usage_tracker/server.py +9 -0
  35. {codex_usage_tracking-0.4.1 → codex_usage_tracking-0.5.0}/src/codex_usage_tracking.egg-info/PKG-INFO +29 -1
  36. {codex_usage_tracking-0.4.1 → codex_usage_tracking-0.5.0}/src/codex_usage_tracking.egg-info/SOURCES.txt +14 -0
  37. {codex_usage_tracking-0.4.1 → codex_usage_tracking-0.5.0}/tests/test_cli_release.py +79 -2
  38. codex_usage_tracking-0.5.0/tests/test_i18n.py +402 -0
  39. {codex_usage_tracking-0.4.1 → codex_usage_tracking-0.5.0}/tests/test_pricing.py +45 -0
  40. {codex_usage_tracking-0.4.1 → codex_usage_tracking-0.5.0}/tests/test_recommendations.py +9 -0
  41. {codex_usage_tracking-0.4.1 → codex_usage_tracking-0.5.0}/tests/test_store_dashboard_mcp.py +52 -25
  42. codex_usage_tracking-0.4.1/src/codex_usage_tracker/plugin_data/dashboard/dashboard_template.html +0 -141
  43. {codex_usage_tracking-0.4.1 → codex_usage_tracking-0.5.0}/.mcp.json +0 -0
  44. {codex_usage_tracking-0.4.1 → codex_usage_tracking-0.5.0}/AGENTS.md +0 -0
  45. {codex_usage_tracking-0.4.1 → codex_usage_tracking-0.5.0}/CONTRIBUTING.md +0 -0
  46. {codex_usage_tracking-0.4.1 → codex_usage_tracking-0.5.0}/LICENSE +0 -0
  47. {codex_usage_tracking-0.4.1 → codex_usage_tracking-0.5.0}/MANIFEST.in +0 -0
  48. {codex_usage_tracking-0.4.1 → codex_usage_tracking-0.5.0}/SECURITY.md +0 -0
  49. {codex_usage_tracking-0.4.1 → codex_usage_tracking-0.5.0}/assets/icon.svg +0 -0
  50. {codex_usage_tracking-0.4.1 → codex_usage_tracking-0.5.0}/docs/architecture.md +0 -0
  51. {codex_usage_tracking-0.4.1 → codex_usage_tracking-0.5.0}/docs/assets/dashboard-calls-preview.png +0 -0
  52. {codex_usage_tracking-0.4.1 → codex_usage_tracking-0.5.0}/docs/assets/dashboard-calls.png +0 -0
  53. {codex_usage_tracking-0.4.1 → codex_usage_tracking-0.5.0}/docs/assets/dashboard-details.png +0 -0
  54. {codex_usage_tracking-0.4.1 → codex_usage_tracking-0.5.0}/docs/assets/dashboard-insights.png +0 -0
  55. {codex_usage_tracking-0.4.1 → codex_usage_tracking-0.5.0}/docs/assets/dashboard-threads.png +0 -0
  56. {codex_usage_tracking-0.4.1 → codex_usage_tracking-0.5.0}/docs/assets/plugin-prompts.png +0 -0
  57. {codex_usage_tracking-0.4.1 → codex_usage_tracking-0.5.0}/docs/assets/plugin-thread-leaderboard.png +0 -0
  58. {codex_usage_tracking-0.4.1 → codex_usage_tracking-0.5.0}/docs/assets/ux/call-detail-panel.png +0 -0
  59. {codex_usage_tracking-0.4.1 → codex_usage_tracking-0.5.0}/docs/assets/ux/insight-overview.png +0 -0
  60. {codex_usage_tracking-0.4.1 → codex_usage_tracking-0.5.0}/docs/assets/ux/thread-investigation.png +0 -0
  61. {codex_usage_tracking-0.4.1 → codex_usage_tracking-0.5.0}/docs/cli-json-schemas.md +0 -0
  62. {codex_usage_tracking-0.4.1 → codex_usage_tracking-0.5.0}/docs/install.md +0 -0
  63. {codex_usage_tracking-0.4.1 → codex_usage_tracking-0.5.0}/docs/mcp.md +0 -0
  64. {codex_usage_tracking-0.4.1 → codex_usage_tracking-0.5.0}/docs/pricing-and-credits.md +0 -0
  65. {codex_usage_tracking-0.4.1 → codex_usage_tracking-0.5.0}/docs/privacy.md +0 -0
  66. {codex_usage_tracking-0.4.1 → codex_usage_tracking-0.5.0}/docs/ui-ux-improvement-plan.md +0 -0
  67. {codex_usage_tracking-0.4.1 → codex_usage_tracking-0.5.0}/scripts/benchmark_synthetic_history.py +0 -0
  68. {codex_usage_tracking-0.4.1 → codex_usage_tracking-0.5.0}/scripts/install_local_plugin.py +0 -0
  69. {codex_usage_tracking-0.4.1 → codex_usage_tracking-0.5.0}/setup.cfg +0 -0
  70. {codex_usage_tracking-0.4.1 → codex_usage_tracking-0.5.0}/skills/codex-usage-api/SKILL.md +0 -0
  71. {codex_usage_tracking-0.4.1 → codex_usage_tracking-0.5.0}/skills/codex-usage-tracker/SKILL.md +0 -0
  72. {codex_usage_tracking-0.4.1 → codex_usage_tracking-0.5.0}/src/codex_usage_tracker/__main__.py +0 -0
  73. {codex_usage_tracking-0.4.1 → codex_usage_tracking-0.5.0}/src/codex_usage_tracker/allowance.py +0 -0
  74. {codex_usage_tracking-0.4.1 → codex_usage_tracking-0.5.0}/src/codex_usage_tracker/api_payloads.py +0 -0
  75. {codex_usage_tracking-0.4.1 → codex_usage_tracking-0.5.0}/src/codex_usage_tracker/context.py +0 -0
  76. {codex_usage_tracking-0.4.1 → codex_usage_tracking-0.5.0}/src/codex_usage_tracker/diagnostics.py +0 -0
  77. {codex_usage_tracking-0.4.1 → codex_usage_tracking-0.5.0}/src/codex_usage_tracker/formatting.py +0 -0
  78. {codex_usage_tracking-0.4.1 → codex_usage_tracking-0.5.0}/src/codex_usage_tracker/json_contracts.py +0 -0
  79. {codex_usage_tracking-0.4.1 → codex_usage_tracking-0.5.0}/src/codex_usage_tracker/mcp_server.py +0 -0
  80. {codex_usage_tracking-0.4.1 → codex_usage_tracking-0.5.0}/src/codex_usage_tracker/models.py +0 -0
  81. {codex_usage_tracking-0.4.1 → codex_usage_tracking-0.5.0}/src/codex_usage_tracker/parser.py +0 -0
  82. {codex_usage_tracking-0.4.1 → codex_usage_tracking-0.5.0}/src/codex_usage_tracker/paths.py +0 -0
  83. {codex_usage_tracking-0.4.1 → codex_usage_tracking-0.5.0}/src/codex_usage_tracker/plugin_data/__init__.py +0 -0
  84. {codex_usage_tracking-0.4.1 → codex_usage_tracking-0.5.0}/src/codex_usage_tracker/plugin_data/assets/icon.svg +0 -0
  85. {codex_usage_tracking-0.4.1 → codex_usage_tracking-0.5.0}/src/codex_usage_tracker/plugin_data/dashboard/dashboard_data.js +0 -0
  86. {codex_usage_tracking-0.4.1 → codex_usage_tracking-0.5.0}/src/codex_usage_tracker/plugin_data/dashboard/dashboard_format.js +0 -0
  87. {codex_usage_tracking-0.4.1 → codex_usage_tracking-0.5.0}/src/codex_usage_tracker/plugin_data/dashboard/dashboard_state.js +0 -0
  88. {codex_usage_tracking-0.4.1 → codex_usage_tracking-0.5.0}/src/codex_usage_tracker/plugin_data/docs/assets/dashboard-calls.png +0 -0
  89. {codex_usage_tracking-0.4.1 → codex_usage_tracking-0.5.0}/src/codex_usage_tracker/plugin_data/docs/assets/dashboard-details.png +0 -0
  90. {codex_usage_tracking-0.4.1 → codex_usage_tracking-0.5.0}/src/codex_usage_tracker/plugin_data/docs/assets/dashboard-insights.png +0 -0
  91. {codex_usage_tracking-0.4.1 → codex_usage_tracking-0.5.0}/src/codex_usage_tracker/plugin_data/docs/assets/dashboard-threads.png +0 -0
  92. {codex_usage_tracking-0.4.1 → codex_usage_tracking-0.5.0}/src/codex_usage_tracker/plugin_data/docs/dashboard-guide.html +0 -0
  93. {codex_usage_tracking-0.4.1 → codex_usage_tracking-0.5.0}/src/codex_usage_tracker/plugin_data/rate_cards/codex-credit-rates.json +0 -0
  94. {codex_usage_tracking-0.4.1 → codex_usage_tracking-0.5.0}/src/codex_usage_tracker/plugin_data/skills/codex-usage-api/SKILL.md +0 -0
  95. {codex_usage_tracking-0.4.1 → codex_usage_tracking-0.5.0}/src/codex_usage_tracker/plugin_data/skills/codex-usage-tracker/SKILL.md +0 -0
  96. {codex_usage_tracking-0.4.1 → codex_usage_tracking-0.5.0}/src/codex_usage_tracker/plugin_installer.py +0 -0
  97. {codex_usage_tracking-0.4.1 → codex_usage_tracking-0.5.0}/src/codex_usage_tracker/pricing.py +0 -0
  98. {codex_usage_tracking-0.4.1 → codex_usage_tracking-0.5.0}/src/codex_usage_tracker/pricing_config.py +0 -0
  99. {codex_usage_tracking-0.4.1 → codex_usage_tracking-0.5.0}/src/codex_usage_tracker/pricing_estimates.py +0 -0
  100. {codex_usage_tracking-0.4.1 → codex_usage_tracking-0.5.0}/src/codex_usage_tracker/pricing_openai.py +0 -0
  101. {codex_usage_tracking-0.4.1 → codex_usage_tracking-0.5.0}/src/codex_usage_tracker/projects.py +0 -0
  102. {codex_usage_tracking-0.4.1 → codex_usage_tracking-0.5.0}/src/codex_usage_tracker/redaction.py +0 -0
  103. {codex_usage_tracking-0.4.1 → codex_usage_tracking-0.5.0}/src/codex_usage_tracker/reports.py +0 -0
  104. {codex_usage_tracking-0.4.1 → codex_usage_tracking-0.5.0}/src/codex_usage_tracker/schema.py +0 -0
  105. {codex_usage_tracking-0.4.1 → codex_usage_tracking-0.5.0}/src/codex_usage_tracker/store.py +0 -0
  106. {codex_usage_tracking-0.4.1 → codex_usage_tracking-0.5.0}/src/codex_usage_tracker/support.py +0 -0
  107. {codex_usage_tracking-0.4.1 → codex_usage_tracking-0.5.0}/src/codex_usage_tracker/threads.py +0 -0
  108. {codex_usage_tracking-0.4.1 → codex_usage_tracking-0.5.0}/src/codex_usage_tracking.egg-info/dependency_links.txt +0 -0
  109. {codex_usage_tracking-0.4.1 → codex_usage_tracking-0.5.0}/src/codex_usage_tracking.egg-info/entry_points.txt +0 -0
  110. {codex_usage_tracking-0.4.1 → codex_usage_tracking-0.5.0}/src/codex_usage_tracking.egg-info/requires.txt +0 -0
  111. {codex_usage_tracking-0.4.1 → codex_usage_tracking-0.5.0}/src/codex_usage_tracking.egg-info/top_level.txt +0 -0
  112. {codex_usage_tracking-0.4.1 → codex_usage_tracking-0.5.0}/tests/test_allowance.py +0 -0
  113. {codex_usage_tracking-0.4.1 → codex_usage_tracking-0.5.0}/tests/test_cli_lifecycle.py +0 -0
  114. {codex_usage_tracking-0.4.1 → codex_usage_tracking-0.5.0}/tests/test_dashboard_state.py +0 -0
  115. {codex_usage_tracking-0.4.1 → codex_usage_tracking-0.5.0}/tests/test_json_contracts.py +0 -0
  116. {codex_usage_tracking-0.4.1 → codex_usage_tracking-0.5.0}/tests/test_mcp_launcher.py +0 -0
  117. {codex_usage_tracking-0.4.1 → codex_usage_tracking-0.5.0}/tests/test_parser.py +0 -0
  118. {codex_usage_tracking-0.4.1 → codex_usage_tracking-0.5.0}/tests/test_plugin_installer.py +0 -0
  119. {codex_usage_tracking-0.4.1 → codex_usage_tracking-0.5.0}/tests/test_privacy.py +0 -0
  120. {codex_usage_tracking-0.4.1 → codex_usage_tracking-0.5.0}/tests/test_projects.py +0 -0
  121. {codex_usage_tracking-0.4.1 → codex_usage_tracking-0.5.0}/tests/test_schema.py +0 -0
  122. {codex_usage_tracking-0.4.1 → codex_usage_tracking-0.5.0}/tests/test_store_migrations.py +0 -0
  123. {codex_usage_tracking-0.4.1 → codex_usage_tracking-0.5.0}/tests/test_support.py +0 -0
  124. {codex_usage_tracking-0.4.1 → codex_usage_tracking-0.5.0}/tests/test_threads.py +0 -0
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "codex-usage-tracker",
3
- "version": "0.4.1",
3
+ "version": "0.5.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,9 +2,18 @@
2
2
 
3
3
  ## Unreleased
4
4
 
5
+ ## 0.5.0 - 2026-06-10
6
+
7
+ - Add the dashboard localization foundation, including starter locale catalogs, language metadata, local browser language selection, `--lang`, and `CODEX_USAGE_TRACKER_LANG`.
8
+ - Add Vietnamese dashboard localization and focused validation coverage for translated dashboard labels.
9
+ - Keep the README landing page focused on dashboard screenshots and companion usage workflows before detailed localization guidance.
10
+ - Stabilize the CI synthetic benchmark smoke so coverage instrumentation does not create false release failures.
11
+ - Pin the marketplace MCP runtime launcher to the exact `codex-usage-tracking==0.5.0` package.
12
+
5
13
  ## 0.4.1 - 2026-06-09
6
14
 
7
15
  - Harden the production PyPI workflow so manual publishing must run from `main` or a tag ref before artifacts are downloaded and uploaded.
16
+ - Skip TestPyPI/PyPI uploads when the exact distribution version already exists on the target index, allowing a GitHub Release to be reconciled after a workflow-dispatch publish.
8
17
  - Strengthen `scripts/check_release.py` so it validates the publish-ref preflight inside both the TestPyPI and PyPI jobs.
9
18
  - Check off completed 1.0 readiness items with evidence for migration coverage, localhost dashboard smoke testing, and the protected GitHub `pypi` environment.
10
19
  - Pin the marketplace MCP runtime launcher to the exact `codex-usage-tracking==0.4.1` package.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: codex-usage-tracking
3
- Version: 0.4.1
3
+ Version: 0.5.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
@@ -190,6 +190,34 @@ The tracker cannot read your logged-in ChatGPT plan or live remaining usage auto
190
190
  - Companion Codex skills for operational setup and conversational usage analysis.
191
191
  - Optional local pricing, Codex credit, allowance, threshold, project alias, and privacy-mode configuration.
192
192
 
193
+ ## Dashboard Language
194
+
195
+ The dashboard supports localized UI text. English is the canonical catalog, and the project includes starter locale catalogs for common dashboard languages.
196
+
197
+ Set the initial dashboard language with `--lang`:
198
+
199
+ ```bash
200
+ codex-usage-tracker --lang vi serve-dashboard --open
201
+ ```
202
+
203
+ Or set a default with:
204
+
205
+ ```bash
206
+ CODEX_USAGE_TRACKER_LANG=vi codex-usage-tracker serve-dashboard --open
207
+ ```
208
+
209
+ The dashboard also includes a language selector. Browser selections are stored locally and can override the generated default for that browser.
210
+
211
+ Supported starter locales include English, Vietnamese, Spanish, French, German, Portuguese, Japanese, Simplified Chinese, Korean, Russian, Italian, and Arabic. This localizes dashboard UI text, not the full CLI output or data exports.
212
+
213
+ ### Adding A Dashboard Language
214
+
215
+ 1. Add a locale JSON file named by language code under `src/codex_usage_tracker/plugin_data/dashboard/locales/`.
216
+ 2. Include every key from the English catalog.
217
+ 3. Preserve every placeholder from the English string.
218
+ 4. Add the language code, native name, English name, and text direction to the supported language metadata.
219
+ 5. Run the i18n validation tests.
220
+
193
221
  ## Common Commands
194
222
 
195
223
  ```bash
@@ -153,6 +153,34 @@ The tracker cannot read your logged-in ChatGPT plan or live remaining usage auto
153
153
  - Companion Codex skills for operational setup and conversational usage analysis.
154
154
  - Optional local pricing, Codex credit, allowance, threshold, project alias, and privacy-mode configuration.
155
155
 
156
+ ## Dashboard Language
157
+
158
+ The dashboard supports localized UI text. English is the canonical catalog, and the project includes starter locale catalogs for common dashboard languages.
159
+
160
+ Set the initial dashboard language with `--lang`:
161
+
162
+ ```bash
163
+ codex-usage-tracker --lang vi serve-dashboard --open
164
+ ```
165
+
166
+ Or set a default with:
167
+
168
+ ```bash
169
+ CODEX_USAGE_TRACKER_LANG=vi codex-usage-tracker serve-dashboard --open
170
+ ```
171
+
172
+ The dashboard also includes a language selector. Browser selections are stored locally and can override the generated default for that browser.
173
+
174
+ Supported starter locales include English, Vietnamese, Spanish, French, German, Portuguese, Japanese, Simplified Chinese, Korean, Russian, Italian, and Arabic. This localizes dashboard UI text, not the full CLI output or data exports.
175
+
176
+ ### Adding A Dashboard Language
177
+
178
+ 1. Add a locale JSON file named by language code under `src/codex_usage_tracker/plugin_data/dashboard/locales/`.
179
+ 2. Include every key from the English catalog.
180
+ 3. Preserve every placeholder from the English string.
181
+ 4. Add the language code, native name, English name, and text direction to the supported language metadata.
182
+ 5. Run the i18n validation tests.
183
+
156
184
  ## Common Commands
157
185
 
158
186
  ```bash
@@ -83,6 +83,8 @@ codex-usage-tracker serve-dashboard --no-context-api --open
83
83
 
84
84
  Dashboards default to active sessions only. Use `--include-archived` for an all-history static/opened dashboard, or switch the served dashboard's `History` control from `Active sessions only` to `All history` when you intentionally want archived logs scanned and included.
85
85
 
86
+ Use global `--lang <code>` before the dashboard command, or set `CODEX_USAGE_TRACKER_LANG`, to choose the dashboard's initial UI language. The dashboard language selector can then override that default in the browser. Localization applies to dashboard UI text, not JSON fields, CSV columns, model names, thread names, paths, or full CLI output.
87
+
86
88
  The localhost `/api/usage` endpoint accepts `limit` and `offset` query parameters, so automation can page aggregate rows without asking the server to load an entire large history at once.
87
89
 
88
90
  ## Summaries
@@ -37,6 +37,15 @@ Redacted mode hides raw cwd/source paths, hides Git remote labels, and hashes un
37
37
 
38
38
  `serve-dashboard` refreshes active-session logs before opening by default. Use `--no-refresh` only when you intentionally want a cached view of the existing local index.
39
39
 
40
+ Set the initial dashboard language with the global `--lang` option before the command, or use `CODEX_USAGE_TRACKER_LANG`:
41
+
42
+ ```bash
43
+ codex-usage-tracker --lang vi serve-dashboard --open
44
+ CODEX_USAGE_TRACKER_LANG=vi codex-usage-tracker serve-dashboard --open
45
+ ```
46
+
47
+ The dashboard language selector stores your browser preference locally. It localizes dashboard UI labels, captions, badges, empty states, detail-panel labels, context controls, and recommendation text; it does not translate raw data values, JSON fields, CSV columns, model names, thread names, project names, paths, or full CLI output.
48
+
40
49
  The server keeps the HTML aggregate-only and enables two live features:
41
50
 
42
51
  - `Refresh` rescans local Codex logs and updates the dashboard rows.
@@ -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.4.1
41
+ release/0.5.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.4.1
94
+ 0.5.0
95
95
  1.0-readiness
96
96
  1.0.0
97
97
  ```
@@ -147,10 +147,12 @@ python scripts/smoke_installed_package.py --docker
147
147
  To verify the public PyPI package instead of the local checkout:
148
148
 
149
149
  ```bash
150
- python scripts/smoke_installed_package.py --from-pypi --version 0.4.1
151
- python scripts/smoke_installed_package.py --docker --from-pypi --version 0.4.1
150
+ python scripts/smoke_installed_package.py --from-pypi --version 0.5.0
151
+ python scripts/smoke_installed_package.py --docker --from-pypi --version 0.5.0
152
152
  ```
153
153
 
154
+ `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.
155
+
154
156
  Docker avoids local toolchain side effects during install testing. Keep one local `pipx` smoke for platform-specific PATH and plugin-discovery behavior, but use Docker for repeatable Linux package verification.
155
157
 
156
158
  For documentation-only branches, at minimum run:
@@ -222,7 +224,7 @@ Tracked timings:
222
224
  | `pricing_coverage_seconds` | Pricing coverage report |
223
225
  | `project_summary_seconds` | Project summary report |
224
226
 
225
- The normal CI smoke uses a tiny synthetic history with `--enforce-thresholds` so regressions in the benchmark contract are visible on pull requests. The 10k/100k runs are a practical local gate for performance-sensitive changes; the 500k run is the release-sized gate and can take about a minute on a modern laptop because recommendations and project summary intentionally scan all aggregate rows.
227
+ The normal CI smoke uses a tiny synthetic history with `--enforce-thresholds` and a small `--threshold-scale` allowance so coverage instrumentation and shared runner noise do not create false failures. The 10k/100k runs are a practical local gate for performance-sensitive changes; the 500k run is the release-sized gate and can take about a minute on a modern laptop because recommendations and project summary intentionally scan all aggregate rows.
226
228
 
227
229
  ## Release Checklist
228
230
 
@@ -264,8 +266,8 @@ After the release branch merges, tag from updated `main`, not from an unreviewed
264
266
  ```bash
265
267
  git switch main
266
268
  git pull --ff-only
267
- git tag -a v0.4.1 -m "codex-usage-tracker 0.4.1"
268
- git push origin v0.4.1
269
+ git tag -a v0.5.0 -m "codex-usage-tracker 0.5.0"
270
+ git push origin v0.5.0
269
271
  ```
270
272
 
271
273
  Do not create or push release tags without maintainer approval.
@@ -274,13 +276,12 @@ Do not create or push release tags without maintainer approval.
274
276
 
275
277
  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.
276
278
 
277
- 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` hardened the PyPI publish workflow and checked off completed 1.0 readiness gates:
279
+ 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 starter language catalogs.
278
280
 
279
281
  - GitHub Release: `https://github.com/douglasmonsky/codex-usage-tracker/releases/tag/v0.3.0`
280
282
  - GitHub Release: `https://github.com/douglasmonsky/codex-usage-tracker/releases/tag/v0.3.1`
281
283
  - GitHub Release: `https://github.com/douglasmonsky/codex-usage-tracker/releases/tag/v0.3.2`
282
284
  - GitHub Release: `https://github.com/douglasmonsky/codex-usage-tracker/releases/tag/v0.4.0`
283
- - GitHub Release: `https://github.com/douglasmonsky/codex-usage-tracker/releases/tag/v0.4.1`
284
285
  - PyPI: `https://pypi.org/project/codex-usage-tracking/`
285
286
  - TestPyPI: `https://test.pypi.org/project/codex-usage-tracking/`
286
287
 
@@ -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.4.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.4.1`: `python -m venv /tmp/codex-usage-pypi-smoke && . /tmp/codex-usage-pypi-smoke/bin/activate && python -m pip install codex-usage-tracking==0.4.1 && codex-usage-tracker --version`.
29
- - [x] Verify public pipx install path for `0.4.1`: `PIPX_HOME=/tmp/codex-usage-pipx-home PIPX_BIN_DIR=/tmp/codex-usage-pipx-bin pipx install codex-usage-tracking==0.4.1 && /tmp/codex-usage-pipx-bin/codex-usage-tracker --version`.
27
+ - [x] Verify the current public PyPI version is visible as `0.5.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.5.0`: `python -m venv /tmp/codex-usage-pypi-smoke && . /tmp/codex-usage-pypi-smoke/bin/activate && python -m pip install codex-usage-tracking==0.5.0 && codex-usage-tracker --version`.
29
+ - [x] Verify public pipx install path for `0.5.0`: `PIPX_HOME=/tmp/codex-usage-pipx-home PIPX_BIN_DIR=/tmp/codex-usage-pipx-bin pipx install codex-usage-tracking==0.5.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.4.1`.
32
+ - [x] Verify public PyPI package in Docker: `python scripts/smoke_installed_package.py --docker --from-pypi --version 0.5.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
 
@@ -120,8 +120,8 @@ Not guaranteed:
120
120
  - [x] Verify manual PyPI workflow dispatch is restricted to `main` or tag refs: `python scripts/check_release.py`.
121
121
  - [x] Verify PyPI job is gated by environment `pypi`: `gh api repos/douglasmonsky/codex-usage-tracker/environments/pypi`.
122
122
  - [x] Verify dist filenames match `codex_usage_tracking`: `python -m build && python scripts/check_release.py --dist`.
123
- - [ ] Verify TestPyPI process: run `Publish Python package` with `target=testpypi` only when intentionally testing release publication.
124
- - [ ] Verify PyPI process: publish a GitHub Release or run workflow dispatch with `target=pypi` only when intentionally publishing a reviewed release.
123
+ - [x] Verify TestPyPI process: run `Publish Python package` with `target=testpypi` only when intentionally testing release publication.
124
+ - [x] Verify PyPI process: publish a GitHub Release or run workflow dispatch with `target=pypi` only when intentionally publishing a reviewed release.
125
125
  - [x] Document release recovery by cutting a new patch version when an uploaded artifact is wrong: see `docs/development.md`.
126
126
 
127
127
  ## 13. Known Limitations
@@ -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.4.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.5.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.4.1`.
144
+ - Public PyPI Docker coverage is proven by `scripts/smoke_installed_package.py --docker --from-pypi --version 0.5.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
@@ -211,7 +211,7 @@ These references are the concrete proof behind completed checklist items. Public
211
211
 
212
212
  - Benchmark command behavior and threshold contract are smoke-tested by `tests/test_cli_release.py::test_synthetic_history_benchmark_script_smoke`.
213
213
  - Release-size 10k, 100k, and 500k benchmark claims are proven by running `python scripts/benchmark_synthetic_history.py --rows 10000 100000 500000 --json --enforce-thresholds` before release work when practical.
214
- - CI-safe benchmark coverage is proven by the CI `Release readiness` job through `tests/test_cli_release.py::test_synthetic_history_benchmark_script_smoke`.
214
+ - CI-safe benchmark coverage is proven by the CI `Release readiness` job through `tests/test_cli_release.py::test_synthetic_history_benchmark_script_smoke`, using a small `--threshold-scale` allowance for coverage instrumentation and shared runner noise.
215
215
 
216
216
  ### Release Process
217
217
 
@@ -219,6 +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.5.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.5.0`.
222
224
  - Release recovery documentation is proven by `scripts/check_release.py` required-file and docs checks.
223
225
 
224
226
  ### Known Limitations
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "codex-usage-tracking"
7
- version = "0.4.1"
7
+ version = "0.5.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"
@@ -62,6 +62,7 @@ where = ["src"]
62
62
  "codex_usage_tracker.plugin_data" = [
63
63
  "assets/*",
64
64
  "dashboard/*",
65
+ "dashboard/locales/*",
65
66
  "docs/*",
66
67
  "docs/assets/*",
67
68
  "rate_cards/*",
@@ -23,6 +23,43 @@ DIST_FILE_STEM = "codex_usage_tracking"
23
23
  IMPORT_PACKAGE = "codex_usage_tracker"
24
24
  CONSOLE_SCRIPT = "codex-usage-tracker"
25
25
  SUPPORTED_PYTHON_VERSIONS = ["3.10", "3.11", "3.12", "3.13", "3.14"]
26
+ OLD_PYPI_DISTRIBUTION_NAME = "codex-usage-tracker"
27
+ DASHBOARD_LOCALE_CODES = [
28
+ "en",
29
+ "vi",
30
+ "es",
31
+ "fr",
32
+ "de",
33
+ "pt",
34
+ "ja",
35
+ "zh-Hans",
36
+ "ko",
37
+ "ru",
38
+ "it",
39
+ "ar",
40
+ ]
41
+ DASHBOARD_LOCALE_SOURCE_FILES = [
42
+ f"src/codex_usage_tracker/plugin_data/dashboard/locales/{code}.json"
43
+ for code in DASHBOARD_LOCALE_CODES
44
+ ]
45
+ DASHBOARD_LOCALE_WHEEL_MEMBERS = {
46
+ f"codex_usage_tracker/plugin_data/dashboard/locales/{code}.json"
47
+ for code in DASHBOARD_LOCALE_CODES
48
+ }
49
+ PUBLIC_RELEASE_DOCS = [
50
+ "docs/one-dot-oh-readiness.md",
51
+ "docs/development.md",
52
+ ]
53
+ PACKAGE_NAMING_DOCS = [
54
+ "README.md",
55
+ "docs/install.md",
56
+ "docs/development.md",
57
+ ]
58
+ PUBLIC_VERSION_PATTERNS = [
59
+ re.compile(r"codex-usage-tracking==([0-9]+(?:\.[0-9]+){2})"),
60
+ re.compile(r"--from-pypi --version ([0-9]+(?:\.[0-9]+){2})"),
61
+ re.compile(r"visible as `([0-9]+(?:\.[0-9]+){2})`"),
62
+ ]
26
63
  SECRET_PATTERNS = {
27
64
  "OpenAI API key": re.compile(r"\bsk-(?:proj-)?[A-Za-z0-9_-]{20,}"),
28
65
  "GitHub token": re.compile(r"\b(?:ghp|github_pat)_[A-Za-z0-9_]{20,}"),
@@ -62,6 +99,7 @@ REQUIRED_FILES = [
62
99
  "src/codex_usage_tracker/plugin_data/dashboard/dashboard.js",
63
100
  "src/codex_usage_tracker/plugin_data/dashboard/dashboard_state.js",
64
101
  "src/codex_usage_tracker/plugin_data/dashboard/dashboard_template.html",
102
+ *DASHBOARD_LOCALE_SOURCE_FILES,
65
103
  "src/codex_usage_tracker/plugin_data/docs/dashboard-guide.html",
66
104
  "src/codex_usage_tracker/plugin_data/rate_cards/codex-credit-rates.json",
67
105
  "src/codex_usage_tracker/plugin_data/docs/assets/dashboard-insights.png",
@@ -79,6 +117,7 @@ WHEEL_REQUIRED_MEMBERS = {
79
117
  "codex_usage_tracker/plugin_data/dashboard/dashboard.js",
80
118
  "codex_usage_tracker/plugin_data/dashboard/dashboard_state.js",
81
119
  "codex_usage_tracker/plugin_data/dashboard/dashboard_template.html",
120
+ *DASHBOARD_LOCALE_WHEEL_MEMBERS,
82
121
  "codex_usage_tracker/plugin_data/docs/dashboard-guide.html",
83
122
  "codex_usage_tracker/plugin_data/rate_cards/codex-credit-rates.json",
84
123
  "codex_usage_tracker/plugin_data/docs/assets/dashboard-insights.png",
@@ -156,6 +195,7 @@ def _check_versions() -> list[str]:
156
195
  failures.append(".codex-plugin/plugin.json version does not match pyproject.toml")
157
196
  if f"## {package_version}" not in changelog:
158
197
  failures.append("CHANGELOG.md does not contain an entry for the package version")
198
+ failures.extend(_check_public_release_doc_versions(package_version))
159
199
  return failures
160
200
 
161
201
 
@@ -164,6 +204,7 @@ def _check_docs() -> list[str]:
164
204
  failures: list[str] = []
165
205
  for required in [
166
206
  "pipx install",
207
+ "codex-usage-tracking",
167
208
  "codex-usage-tracker install-plugin",
168
209
  "codex-usage-tracker doctor",
169
210
  "Data Privacy",
@@ -171,6 +212,57 @@ def _check_docs() -> list[str]:
171
212
  ]:
172
213
  if required not in readme:
173
214
  failures.append(f"README.md is missing required install/privacy text: {required}")
215
+ failures.extend(_check_package_naming_docs())
216
+ return failures
217
+
218
+
219
+ def _check_public_release_doc_versions(package_version: str) -> list[str]:
220
+ failures: list[str] = []
221
+ for relative_path in PUBLIC_RELEASE_DOCS:
222
+ path = REPO_ROOT / relative_path
223
+ text = path.read_text(encoding="utf-8")
224
+ for pattern in PUBLIC_VERSION_PATTERNS:
225
+ for match in pattern.finditer(text):
226
+ if match.group(1) != package_version:
227
+ failures.append(
228
+ f"{relative_path} public release version {match.group(1)} "
229
+ f"does not match pyproject.toml {package_version}"
230
+ )
231
+ return failures
232
+
233
+
234
+ def _check_package_naming_docs() -> list[str]:
235
+ failures: list[str] = []
236
+ old_name_warning = f"The `{OLD_PYPI_DISTRIBUTION_NAME}` PyPI name is not this project"
237
+ for relative_path in PACKAGE_NAMING_DOCS:
238
+ text = (REPO_ROOT / relative_path).read_text(encoding="utf-8")
239
+ if DISTRIBUTION_NAME not in text:
240
+ failures.append(f"{relative_path} must name the public PyPI package {DISTRIBUTION_NAME}")
241
+ if relative_path in {"README.md", "docs/install.md"} and old_name_warning not in text:
242
+ failures.append(
243
+ f"{relative_path} must warn that {OLD_PYPI_DISTRIBUTION_NAME} "
244
+ "is a different PyPI package"
245
+ )
246
+ failures.extend(_check_doc_install_lines(relative_path, text))
247
+ return failures
248
+
249
+
250
+ def _check_doc_install_lines(relative_path: str, text: str) -> list[str]:
251
+ failures: list[str] = []
252
+ for line_number, line in enumerate(text.splitlines(), start=1):
253
+ normalized = line.strip().strip("`")
254
+ if not normalized:
255
+ continue
256
+ if not re.search(r"\b(?:pipx|pip|python(?:3)? -m pip)\s+install\b", normalized):
257
+ continue
258
+ if OLD_PYPI_DISTRIBUTION_NAME not in normalized:
259
+ continue
260
+ if DISTRIBUTION_NAME in normalized or "git+" in normalized or "github.com" in normalized:
261
+ continue
262
+ failures.append(
263
+ f"{relative_path}:{line_number} installs {OLD_PYPI_DISTRIBUTION_NAME}; "
264
+ f"use {DISTRIBUTION_NAME}"
265
+ )
174
266
  return failures
175
267
 
176
268
 
@@ -322,6 +414,8 @@ def _check_publish_workflow() -> list[str]:
322
414
  "name: pypi",
323
415
  "https://test.pypi.org/project/codex-usage-tracking/",
324
416
  "https://pypi.org/project/codex-usage-tracking/",
417
+ "steps.package-version.outputs.exists != 'true'",
418
+ "codex-usage-tracking {version} already exists on {index_name}; skipping upload.",
325
419
  ]:
326
420
  if required not in workflow:
327
421
  failures.append(f"publish workflow is missing required Trusted Publishing text: {required}")
@@ -343,6 +437,11 @@ def _check_publish_workflow() -> list[str]:
343
437
  "echo \"sha=$GITHUB_SHA\"",
344
438
  "refs/heads/main|refs/tags/*",
345
439
  "Manual PyPI publishing must run from main or a tag ref.",
440
+ "Check target package version",
441
+ "id: package-version",
442
+ "PACKAGE_INDEX_JSON_URL",
443
+ "PACKAGE_INDEX_NAME",
444
+ "steps.package-version.outputs.exists != 'true'",
346
445
  ]:
347
446
  if required not in job_block:
348
447
  failures.append(f"publish workflow {job_name} job is missing preflight: {required}")
@@ -376,27 +475,12 @@ def _check_ci_workflow() -> list[str]:
376
475
  return failures
377
476
 
378
477
 
379
- def _check_ci_workflow() -> list[str]:
380
- workflow_path = REPO_ROOT / ".github" / "workflows" / "ci.yml"
381
- if not workflow_path.exists():
382
- return ["missing CI workflow: .github/workflows/ci.yml"]
383
- workflow = workflow_path.read_text(encoding="utf-8")
384
- failures: list[str] = []
385
- for required in [
386
- "name: Build package",
387
- "python -m build",
388
- "python -m twine check dist/*",
389
- "python scripts/check_release.py --dist",
390
- ]:
391
- if required not in workflow:
392
- failures.append(f"CI package job is missing required build check: {required}")
393
- return failures
394
-
395
-
396
478
  def _check_skill_packaging() -> list[str]:
397
479
  failures: list[str] = []
398
480
  pyproject = tomllib.loads((REPO_ROOT / "pyproject.toml").read_text(encoding="utf-8"))
399
481
  package_data = set(pyproject["tool"]["setuptools"]["package-data"]["codex_usage_tracker.plugin_data"])
482
+ if "dashboard/locales/*" not in package_data:
483
+ failures.append("pyproject.toml package data is missing dashboard locale catalogs")
400
484
  for source_skill in sorted((REPO_ROOT / "skills").glob("*/SKILL.md")):
401
485
  skill_name = source_skill.parent.name
402
486
  package_skill = (
@@ -73,6 +73,18 @@ RESOURCE_PATHS = [
73
73
  "dashboard/dashboard.js",
74
74
  "dashboard/dashboard_state.js",
75
75
  "dashboard/dashboard_template.html",
76
+ "dashboard/locales/en.json",
77
+ "dashboard/locales/vi.json",
78
+ "dashboard/locales/es.json",
79
+ "dashboard/locales/fr.json",
80
+ "dashboard/locales/de.json",
81
+ "dashboard/locales/pt.json",
82
+ "dashboard/locales/ja.json",
83
+ "dashboard/locales/zh-Hans.json",
84
+ "dashboard/locales/ko.json",
85
+ "dashboard/locales/ru.json",
86
+ "dashboard/locales/it.json",
87
+ "dashboard/locales/ar.json",
76
88
  "docs/dashboard-guide.html",
77
89
  "docs/assets/dashboard-insights.png",
78
90
  "docs/assets/dashboard-calls.png",
@@ -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.4.1",
18
+ "codex-usage-tracking==0.5.0",
19
19
  )
20
- RUNTIME_VERSION = "0.4.1"
20
+ RUNTIME_VERSION = "0.5.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.4.1"
5
+ __version__ = "0.5.0"
6
6
 
7
7
  __all__ = ["UsageEvent", "__version__"]
@@ -30,6 +30,7 @@ from codex_usage_tracker.formatting import (
30
30
  format_doctor,
31
31
  format_session,
32
32
  )
33
+ from codex_usage_tracker.i18n import normalize_language
33
34
  from codex_usage_tracker.parser import inspect_log, load_session_index
34
35
  from codex_usage_tracker.paths import (
35
36
  DEFAULT_ALLOWANCE_PATH,
@@ -110,6 +111,14 @@ def _build_parser() -> argparse.ArgumentParser:
110
111
  parser.add_argument("--rate-card", type=Path, default=DEFAULT_RATE_CARD_PATH)
111
112
  parser.add_argument("--thresholds", type=Path, default=DEFAULT_THRESHOLDS_PATH)
112
113
  parser.add_argument("--projects", type=Path, default=DEFAULT_PROJECTS_PATH)
114
+ parser.add_argument(
115
+ "--lang",
116
+ default=None,
117
+ help=(
118
+ "Initial dashboard language. Accepts supported language codes and common aliases; "
119
+ "defaults to CODEX_USAGE_TRACKER_LANG or en."
120
+ ),
121
+ )
113
122
  parser.add_argument(
114
123
  "--privacy-mode",
115
124
  choices=PRIVACY_MODE_CHOICES,
@@ -942,6 +951,7 @@ def _run_dashboard(args: argparse.Namespace) -> int:
942
951
  projects_path=args.projects,
943
952
  privacy_mode=args.privacy_mode,
944
953
  include_archived=args.include_archived,
954
+ language=normalize_language(args.lang),
945
955
  )
946
956
  if args.as_json:
947
957
  _print_json(
@@ -954,6 +964,7 @@ def _run_dashboard(args: argparse.Namespace) -> int:
954
964
  "since": args.since,
955
965
  "privacy_mode": args.privacy_mode,
956
966
  "include_archived": args.include_archived,
967
+ "language": normalize_language(args.lang),
957
968
  }
958
969
  )
959
970
  else:
@@ -986,6 +997,7 @@ def _run_open_dashboard(args: argparse.Namespace) -> int:
986
997
  projects_path=args.projects,
987
998
  privacy_mode=args.privacy_mode,
988
999
  include_archived=args.include_archived,
1000
+ language=normalize_language(args.lang),
989
1001
  )
990
1002
  if args.as_json:
991
1003
  _print_json(
@@ -999,6 +1011,7 @@ def _run_open_dashboard(args: argparse.Namespace) -> int:
999
1011
  "refresh": refresh_payload,
1000
1012
  "privacy_mode": args.privacy_mode,
1001
1013
  "include_archived": args.include_archived,
1014
+ "language": normalize_language(args.lang),
1002
1015
  }
1003
1016
  )
1004
1017
  else:
@@ -1021,6 +1034,7 @@ def _run_serve_dashboard(args: argparse.Namespace) -> int:
1021
1034
  "refresh_before_start": args.refresh,
1022
1035
  "privacy_mode": args.privacy_mode,
1023
1036
  "include_archived": args.include_archived,
1037
+ "language": normalize_language(args.lang),
1024
1038
  }
1025
1039
  )
1026
1040
  if args.refresh:
@@ -1047,6 +1061,7 @@ def _run_serve_dashboard(args: argparse.Namespace) -> int:
1047
1061
  thresholds_path=args.thresholds,
1048
1062
  projects_path=args.projects,
1049
1063
  privacy_mode=args.privacy_mode,
1064
+ language=normalize_language(args.lang),
1050
1065
  )
1051
1066
  return 0
1052
1067
 
@@ -8,6 +8,15 @@ from typing import Any
8
8
  from codex_usage_tracker.paths import DEFAULT_PRICING_PATH
9
9
  from codex_usage_tracker.pricing_config import PricingConfig, load_pricing_config
10
10
 
11
+ EFFICIENCY_FLAG_KEYS = {
12
+ "high context use": "flag.high_context_use",
13
+ "elevated context use": "flag.elevated_context_use",
14
+ "high reasoning share": "flag.high_reasoning_share",
15
+ "low cache reuse": "flag.low_cache_reuse",
16
+ "expensive low-output call": "flag.expensive_low_output_call",
17
+ "high estimated cost": "flag.high_estimated_cost",
18
+ }
19
+
11
20
 
12
21
  def summarize_pricing_coverage(
13
22
  rows: list[dict[str, Any]],
@@ -92,6 +101,11 @@ def annotate_rows_with_efficiency(
92
101
  copy["pricing_model"] = config.priced_as(model)
93
102
  copy["pricing_estimated"] = config.is_estimated_model(model)
94
103
  copy["efficiency_flags"] = efficiency_flags(copy)
104
+ copy["efficiency_flag_keys"] = [
105
+ EFFICIENCY_FLAG_KEYS[flag]
106
+ for flag in copy["efficiency_flags"]
107
+ if flag in EFFICIENCY_FLAG_KEYS
108
+ ]
95
109
  annotated.append(copy)
96
110
  return annotated
97
111