kimi-code-usage 0.1.6__tar.gz → 0.2.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 (108) hide show
  1. {kimi_code_usage-0.1.6 → kimi_code_usage-0.2.0}/.gitignore +9 -0
  2. kimi_code_usage-0.2.0/CHANGELOG.md +40 -0
  3. {kimi_code_usage-0.1.6 → kimi_code_usage-0.2.0}/PKG-INFO +10 -4
  4. {kimi_code_usage-0.1.6 → kimi_code_usage-0.2.0}/README.md +5 -0
  5. {kimi_code_usage-0.1.6 → kimi_code_usage-0.2.0}/README.zh.md +5 -0
  6. {kimi_code_usage-0.1.6 → kimi_code_usage-0.2.0}/pyproject.toml +16 -3
  7. kimi_code_usage-0.2.0/src/kimi_code_usage/__main__.py +3 -0
  8. {kimi_code_usage-0.1.6 → kimi_code_usage-0.2.0}/src/kimi_code_usage/config.py +42 -12
  9. {kimi_code_usage-0.1.6 → kimi_code_usage-0.2.0}/src/kimi_code_usage/main.py +359 -105
  10. {kimi_code_usage-0.1.6 → kimi_code_usage-0.2.0}/src/kimi_code_usage/providers/__init__.py +4 -0
  11. kimi_code_usage-0.2.0/src/kimi_code_usage/providers/claude.py +308 -0
  12. kimi_code_usage-0.2.0/src/kimi_code_usage/providers/codex.py +481 -0
  13. {kimi_code_usage-0.1.6 → kimi_code_usage-0.2.0}/src/kimi_code_usage/providers/kimi.py +201 -3
  14. kimi_code_usage-0.2.0/src/kimi_code_usage/providers/kimi_membership.py +269 -0
  15. {kimi_code_usage-0.1.6 → kimi_code_usage-0.2.0}/src/kimi_code_usage/providers/openrouter.py +8 -8
  16. kimi_code_usage-0.2.0/src/kimi_code_usage/providers/webbridge.py +115 -0
  17. {kimi_code_usage-0.1.6 → kimi_code_usage-0.2.0}/src/kimi_code_usage/server.py +1 -1
  18. kimi_code_usage-0.2.0/tests/conftest.py +15 -0
  19. {kimi_code_usage-0.1.6 → kimi_code_usage-0.2.0}/tests/test_config.py +76 -45
  20. {kimi_code_usage-0.1.6 → kimi_code_usage-0.2.0}/tests/test_main.py +864 -131
  21. kimi_code_usage-0.2.0/tests/test_mcp_smoke.py +48 -0
  22. kimi_code_usage-0.2.0/tests/test_provider_claude.py +467 -0
  23. kimi_code_usage-0.2.0/tests/test_provider_codex.py +656 -0
  24. kimi_code_usage-0.2.0/tests/test_provider_kimi.py +732 -0
  25. kimi_code_usage-0.2.0/tests/test_provider_kimi_membership.py +389 -0
  26. {kimi_code_usage-0.1.6 → kimi_code_usage-0.2.0}/tests/test_provider_openrouter.py +28 -0
  27. kimi_code_usage-0.2.0/tests/test_provider_webbridge.py +133 -0
  28. kimi_code_usage-0.2.0/tests/test_server.py +370 -0
  29. {kimi_code_usage-0.1.6 → kimi_code_usage-0.2.0}/uv.lock +1268 -665
  30. kimi_code_usage-0.2.0/vscode-extension/package-lock.json +4874 -0
  31. kimi_code_usage-0.1.6/.github/workflows/ci.yml +0 -42
  32. kimi_code_usage-0.1.6/docs/kimi-code-usage.md +0 -54
  33. kimi_code_usage-0.1.6/docs/superpowers/plans/2026-05-09-pace-indicator.md +0 -220
  34. kimi_code_usage-0.1.6/docs/superpowers/plans/2026-05-14-pace-theme-thresholds.md +0 -501
  35. kimi_code_usage-0.1.6/docs/superpowers/plans/2026-06-10-multi-llm-quota.md +0 -108
  36. kimi_code_usage-0.1.6/docs/superpowers/plans/2026-06-10-vscode-extension-ts-strictness.md +0 -679
  37. kimi_code_usage-0.1.6/docs/superpowers/specs/2026-05-09-pace-indicator-design.md +0 -189
  38. kimi_code_usage-0.1.6/docs/superpowers/specs/2026-05-14-pace-theme-thresholds-design.md +0 -106
  39. kimi_code_usage-0.1.6/docs/superpowers/specs/2026-06-10-multi-llm-quota-design.md +0 -307
  40. kimi_code_usage-0.1.6/docs/superpowers/specs/2026-06-10-vscode-extension-multi-provider-design.md +0 -394
  41. kimi_code_usage-0.1.6/docs/superpowers/specs/2026-06-10-vscode-extension-ts-refactor-design.md +0 -115
  42. kimi_code_usage-0.1.6/tests/conftest.py +0 -4
  43. kimi_code_usage-0.1.6/tests/test_provider_kimi.py +0 -289
  44. kimi_code_usage-0.1.6/vscode-extension/.claude/settings.local.json +0 -8
  45. kimi_code_usage-0.1.6/vscode-extension/.github/workflows/ci.yml +0 -34
  46. kimi_code_usage-0.1.6/vscode-extension/.prettierignore +0 -10
  47. kimi_code_usage-0.1.6/vscode-extension/.prettierrc.json +0 -9
  48. kimi_code_usage-0.1.6/vscode-extension/.vscodeignore +0 -19
  49. kimi_code_usage-0.1.6/vscode-extension/LICENSE +0 -21
  50. kimi_code_usage-0.1.6/vscode-extension/README.md +0 -236
  51. kimi_code_usage-0.1.6/vscode-extension/assets/icon.png +0 -0
  52. kimi_code_usage-0.1.6/vscode-extension/assets/moon.svg +0 -3
  53. kimi_code_usage-0.1.6/vscode-extension/eslint.config.mjs +0 -48
  54. kimi_code_usage-0.1.6/vscode-extension/l10n/bundle.l10n.de.json +0 -151
  55. kimi_code_usage-0.1.6/vscode-extension/l10n/bundle.l10n.en.json +0 -151
  56. kimi_code_usage-0.1.6/vscode-extension/l10n/bundle.l10n.es.json +0 -151
  57. kimi_code_usage-0.1.6/vscode-extension/l10n/bundle.l10n.fr.json +0 -151
  58. kimi_code_usage-0.1.6/vscode-extension/l10n/bundle.l10n.it.json +0 -151
  59. kimi_code_usage-0.1.6/vscode-extension/l10n/bundle.l10n.ja.json +0 -151
  60. kimi_code_usage-0.1.6/vscode-extension/l10n/bundle.l10n.ko.json +0 -151
  61. kimi_code_usage-0.1.6/vscode-extension/l10n/bundle.l10n.pt.json +0 -151
  62. kimi_code_usage-0.1.6/vscode-extension/l10n/bundle.l10n.ru.json +0 -151
  63. kimi_code_usage-0.1.6/vscode-extension/l10n/bundle.l10n.zh-cn.json +0 -151
  64. kimi_code_usage-0.1.6/vscode-extension/package.json +0 -277
  65. kimi_code_usage-0.1.6/vscode-extension/scripts/copy-assets.ts +0 -24
  66. kimi_code_usage-0.1.6/vscode-extension/src/__mocks__/vscode.ts +0 -125
  67. kimi_code_usage-0.1.6/vscode-extension/src/api.test.ts +0 -641
  68. kimi_code_usage-0.1.6/vscode-extension/src/api.ts +0 -339
  69. kimi_code_usage-0.1.6/vscode-extension/src/apiCache.test.ts +0 -123
  70. kimi_code_usage-0.1.6/vscode-extension/src/apiCache.ts +0 -62
  71. kimi_code_usage-0.1.6/vscode-extension/src/config.test.ts +0 -298
  72. kimi_code_usage-0.1.6/vscode-extension/src/config.ts +0 -113
  73. kimi_code_usage-0.1.6/vscode-extension/src/extension.test.ts +0 -581
  74. kimi_code_usage-0.1.6/vscode-extension/src/extension.ts +0 -147
  75. kimi_code_usage-0.1.6/vscode-extension/src/historyPanel.test.ts +0 -359
  76. kimi_code_usage-0.1.6/vscode-extension/src/historyPanel.ts +0 -641
  77. kimi_code_usage-0.1.6/vscode-extension/src/i18n.test.ts +0 -247
  78. kimi_code_usage-0.1.6/vscode-extension/src/i18n.ts +0 -124
  79. kimi_code_usage-0.1.6/vscode-extension/src/notifier.test.ts +0 -213
  80. kimi_code_usage-0.1.6/vscode-extension/src/notifier.ts +0 -101
  81. kimi_code_usage-0.1.6/vscode-extension/src/pace.test.ts +0 -246
  82. kimi_code_usage-0.1.6/vscode-extension/src/pace.ts +0 -141
  83. kimi_code_usage-0.1.6/vscode-extension/src/predict.test.ts +0 -578
  84. kimi_code_usage-0.1.6/vscode-extension/src/predict.ts +0 -180
  85. kimi_code_usage-0.1.6/vscode-extension/src/statusBar.test.ts +0 -947
  86. kimi_code_usage-0.1.6/vscode-extension/src/statusBar.ts +0 -423
  87. kimi_code_usage-0.1.6/vscode-extension/src/storage-unlink.test.ts +0 -36
  88. kimi_code_usage-0.1.6/vscode-extension/src/storage.test.ts +0 -233
  89. kimi_code_usage-0.1.6/vscode-extension/src/storage.ts +0 -137
  90. kimi_code_usage-0.1.6/vscode-extension/src/types.ts +0 -102
  91. kimi_code_usage-0.1.6/vscode-extension/src/vscode-mock.test.ts +0 -106
  92. kimi_code_usage-0.1.6/vscode-extension/tsconfig.eslint.json +0 -10
  93. kimi_code_usage-0.1.6/vscode-extension/tsconfig.json +0 -20
  94. kimi_code_usage-0.1.6/vscode-extension/vitest.config.ts +0 -16
  95. {kimi_code_usage-0.1.6 → kimi_code_usage-0.2.0}/.claude/settings.local.json +0 -0
  96. {kimi_code_usage-0.1.6 → kimi_code_usage-0.2.0}/.env.example +0 -0
  97. {kimi_code_usage-0.1.6 → kimi_code_usage-0.2.0}/AGENTS.md +0 -0
  98. {kimi_code_usage-0.1.6 → kimi_code_usage-0.2.0}/kimi_usage.code-workspace +0 -0
  99. {kimi_code_usage-0.1.6 → kimi_code_usage-0.2.0}/requirements.txt +0 -0
  100. {kimi_code_usage-0.1.6 → kimi_code_usage-0.2.0}/src/kimi_code_usage/__init__.py +0 -0
  101. {kimi_code_usage-0.1.6 → kimi_code_usage-0.2.0}/src/kimi_code_usage/mcp.py +0 -0
  102. {kimi_code_usage-0.1.6 → kimi_code_usage-0.2.0}/src/kimi_code_usage/providers/anthropic.py +0 -0
  103. {kimi_code_usage-0.1.6 → kimi_code_usage-0.2.0}/src/kimi_code_usage/providers/openai.py +0 -0
  104. {kimi_code_usage-0.1.6 → kimi_code_usage-0.2.0}/tests/__init__.py +0 -0
  105. {kimi_code_usage-0.1.6 → kimi_code_usage-0.2.0}/tests/test_mcp.py +0 -0
  106. {kimi_code_usage-0.1.6 → kimi_code_usage-0.2.0}/tests/test_provider_anthropic.py +0 -0
  107. {kimi_code_usage-0.1.6 → kimi_code_usage-0.2.0}/tests/test_provider_openai.py +0 -0
  108. {kimi_code_usage-0.1.6 → kimi_code_usage-0.2.0}/tests/test_providers_init.py +0 -0
@@ -14,6 +14,9 @@ build/
14
14
  node_modules/
15
15
  package-lock.json
16
16
 
17
+ # The VS Code extension's lock file is tracked so CI can install reproducibly.
18
+ !vscode-extension/package-lock.json
19
+
17
20
  # VSCode Extension artifacts
18
21
  *.vsix
19
22
  vscode-extension/out/
@@ -51,3 +54,9 @@ tokscale-export-*.json
51
54
 
52
55
  # Coverage
53
56
  htmlcov/
57
+
58
+ # Isolated development worktrees
59
+ .worktrees/
60
+
61
+ # Oh My OpenAgent local session artifacts
62
+ .omo/
@@ -0,0 +1,40 @@
1
+ # Changelog
2
+
3
+ Notable changes to the Python package (`kimi-code-usage` on PyPI). The VS Code
4
+ extension has its own changelog: [`vscode-extension/CHANGELOG.md`](vscode-extension/CHANGELOG.md).
5
+
6
+ This file starts at 0.2.0; earlier releases are recorded by the `v0.1.0`–`v0.1.6`
7
+ git tags.
8
+
9
+ ## [0.2.0] — 2026-10-20
10
+
11
+ ### Added
12
+
13
+ - **Extra Usage row.** Kimi's booster wallet is now reported as its own row
14
+ (`Extra Usage`, `加油包` in Chinese) instead of being invisible. A wallet that
15
+ reports no usable amount produces no row rather than a made-up `¥0.00`.
16
+ - **Monthly quota over the CLI OAuth token.** Monthly credits are read through
17
+ the Kimi Code CLI token, preferring that path and falling back to the
18
+ WebBridge browser snapshot when one is available.
19
+ - Parsing of the live `/usages` payload shape, including its `booster_wallet`
20
+ field.
21
+
22
+ ### Changed
23
+
24
+ - **`fastmcp` floor raised from 0.1.0 to 4.1.1** (`mcp` 2). The MCP surface used
25
+ here — `FastMCP(...)`, `@mcp.tool()`, `mcp.run()` — is unchanged, and the
26
+ upgrade is covered by a real stdio smoke test (`initialize` → `tools/list` →
27
+ `call_tool`). Projects that pin `mcp<2` in their own environment will need to
28
+ relax that pin.
29
+
30
+ ### Fixed
31
+
32
+ - Kimi: read the live `/usages` shape and count only emitted windows.
33
+ - Kimi: report OAuth monthly probe failures instead of dropping them silently.
34
+ - Kimi: only treat a wallet as live on an explicit signal, and stay silent when
35
+ it is live but reports no amount.
36
+ - Codex: label each rate-limit window from its own `limit_window_seconds`.
37
+ - Claude: read the Claude Code OAuth token and utilization correctly.
38
+ - OpenRouter: handle `BaseException` from `asyncio.gather` and fix typing.
39
+ - Dependencies: upgraded the vulnerable locked packages; `aiohttp >= 3.14.3` is
40
+ required for the patched parser.
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.4
1
+ Metadata-Version: 2.5
2
2
  Name: kimi-code-usage
3
- Version: 0.1.6
3
+ Version: 0.2.0
4
4
  Summary: A curated Kimi Coding Plan usage monitor with aesthetic CLI and MCP server.
5
5
  Project-URL: Homepage, https://github.com/Golden0Voyager/kimi-code-usage
6
6
  Project-URL: Repository, https://github.com/Golden0Voyager/kimi-code-usage
@@ -9,8 +9,9 @@ Author-email: Haining Yu <hainingyu@gmail.com>
9
9
  License: MIT
10
10
  Keywords: curated,kimi,mcp,monitor,moonshot,usage
11
11
  Requires-Python: >=3.10
12
- Requires-Dist: aiohttp>=3.8.0
13
- Requires-Dist: fastmcp>=0.1.0
12
+ Requires-Dist: aiohttp>=3.14.3
13
+ Requires-Dist: cloudscraper>=1.2.0
14
+ Requires-Dist: fastmcp>=4.1.1
14
15
  Requires-Dist: httpx[socks]>=0.20.0
15
16
  Requires-Dist: python-dotenv>=1.0.0
16
17
  Requires-Dist: rich>=12.0.0
@@ -50,6 +51,10 @@ In the era of "Vibecoding," transparency of resources is a prerequisite for flow
50
51
 
51
52
  **Prerequisite:** A [Kimi Coding Plan](https://api.kimi.com/coding/v1) API Key (`sk-kimi-xxx`), set as `KIMI_API_KEY` in your environment or `.env` file.
52
53
 
54
+ > Monthly membership usage is optional. In interactive mode, if an installed Kimi WebBridge daemon is stopped, `kimi-usage` asks on every launch whether to start it. Declining affects only monthly credits. The browser extension must still be connected and Kimi must be logged in; weekly and 5-hour Kimi usage continue working when monthly usage is unavailable.
55
+
56
+ > ChatGPT Plus usage reads the local Codex authentication file. After a 401 response, it refreshes the access token and retries once. If authentication still fails, run `codex login`.
57
+
53
58
  ---
54
59
 
55
60
  ### ⚡ CLI Reporter
@@ -60,6 +65,7 @@ In the era of "Vibecoding," transparency of resources is a prerequisite for flow
60
65
  ```bash
61
66
  pip install kimi-code-usage
62
67
  kimi-usage # Aesthetic Rich panel
68
+ kimi-usage -i # Interactive panel with optional WebBridge startup prompt
63
69
  kimi-usage --json # Machine-readable JSON
64
70
  kimi-usage --plain # Plain text output
65
71
  ```
@@ -32,6 +32,10 @@ In the era of "Vibecoding," transparency of resources is a prerequisite for flow
32
32
 
33
33
  **Prerequisite:** A [Kimi Coding Plan](https://api.kimi.com/coding/v1) API Key (`sk-kimi-xxx`), set as `KIMI_API_KEY` in your environment or `.env` file.
34
34
 
35
+ > Monthly membership usage is optional. In interactive mode, if an installed Kimi WebBridge daemon is stopped, `kimi-usage` asks on every launch whether to start it. Declining affects only monthly credits. The browser extension must still be connected and Kimi must be logged in; weekly and 5-hour Kimi usage continue working when monthly usage is unavailable.
36
+
37
+ > ChatGPT Plus usage reads the local Codex authentication file. After a 401 response, it refreshes the access token and retries once. If authentication still fails, run `codex login`.
38
+
35
39
  ---
36
40
 
37
41
  ### ⚡ CLI Reporter
@@ -42,6 +46,7 @@ In the era of "Vibecoding," transparency of resources is a prerequisite for flow
42
46
  ```bash
43
47
  pip install kimi-code-usage
44
48
  kimi-usage # Aesthetic Rich panel
49
+ kimi-usage -i # Interactive panel with optional WebBridge startup prompt
45
50
  kimi-usage --json # Machine-readable JSON
46
51
  kimi-usage --plain # Plain text output
47
52
  ```
@@ -32,6 +32,10 @@
32
32
 
33
33
  **统一前提:** 在环境变量或 `.env` 文件中设置 `KIMI_API_KEY`([Kimi Coding Plan](https://api.kimi.com/coding/v1) API Key,格式 `sk-kimi-xxx`)。
34
34
 
35
+ > 月度会员额度为可选增强功能。在交互模式中,如果已安装的 Kimi WebBridge daemon 尚未运行,`kimi-usage` 每次启动都会询问是否启动它;拒绝只影响月度额度。浏览器扩展仍须保持连接且 Kimi 必须已登录;月度额度不可用时,周用量和 5 小时用量仍会正常显示。
36
+
37
+ > ChatGPT Plus 用量读取本机 Codex 认证文件。接口返回 401 后会自动刷新 access token 并重试一次;认证仍失败时请运行 `codex login`。
38
+
35
39
  ---
36
40
 
37
41
  ### ⚡ CLI 终端报告器
@@ -42,6 +46,7 @@
42
46
  ```bash
43
47
  pip install kimi-code-usage
44
48
  kimi-usage # 美观的 Rich 面板
49
+ kimi-usage -i # 带可选 WebBridge 启动询问的交互面板
45
50
  kimi-usage --json # 机器可读的 JSON
46
51
  kimi-usage --plain # 纯文本输出
47
52
  ```
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "kimi-code-usage"
3
- version = "0.1.6"
3
+ version = "0.2.0"
4
4
  description = "A curated Kimi Coding Plan usage monitor with aesthetic CLI and MCP server."
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.10"
@@ -10,11 +10,12 @@ authors = [
10
10
  license = { text = "MIT" }
11
11
  keywords = ["kimi", "moonshot", "mcp", "usage", "monitor", "curated"]
12
12
  dependencies = [
13
- "aiohttp>=3.8.0",
13
+ "aiohttp>=3.14.3",
14
14
  "rich>=12.0.0",
15
15
  "python-dotenv>=1.0.0",
16
- "fastmcp>=0.1.0",
16
+ "fastmcp>=4.1.1",
17
17
  "httpx[socks]>=0.20.0",
18
+ "cloudscraper>=1.2.0",
18
19
  ]
19
20
 
20
21
  [project.urls]
@@ -70,3 +71,15 @@ show_missing = true
70
71
 
71
72
  [tool.bandit]
72
73
  skips = ["B101", "B311", "B404", "B603"]
74
+
75
+ [tool.hatch.build.targets.sdist]
76
+ # Explicit, because the default "whatever VCS says" rule breaks inside a git
77
+ # worktree: `.git` is a file there, detection fails, and hatchling falls back to
78
+ # shipping everything untracked — including vscode-extension/node_modules, which
79
+ # turned the sdist from 0.4 MB into 50 MB.
80
+ exclude = [
81
+ "/vscode-extension",
82
+ "/docs",
83
+ "/.github",
84
+ "/.scratch",
85
+ ]
@@ -0,0 +1,3 @@
1
+ from .main import run_cli
2
+
3
+ run_cli()
@@ -5,6 +5,7 @@ from pathlib import Path
5
5
 
6
6
  DEFAULT_CONFIG_PATH = Path.home() / ".kimi-usage" / "config.json"
7
7
 
8
+
8
9
  @dataclass
9
10
  class ProviderConfig:
10
11
  api_key: str | None = None
@@ -12,6 +13,7 @@ class ProviderConfig:
12
13
  enabled: bool = True
13
14
  management_key: str | None = None
14
15
 
16
+
15
17
  @dataclass
16
18
  class AppConfig:
17
19
  providers: dict[str, ProviderConfig] = field(default_factory=dict)
@@ -28,6 +30,7 @@ class AppConfig:
28
30
  def enabled_providers(self) -> list[str]:
29
31
  return [name for name, p_conf in self.providers.items() if p_conf.api_key and p_conf.enabled]
30
32
 
33
+
31
34
  class ConfigResolver:
32
35
  def __init__(self, config_path: str | None = None):
33
36
  self.config_path = Path(config_path) if config_path else DEFAULT_CONFIG_PATH
@@ -56,9 +59,10 @@ class ConfigResolver:
56
59
  theme = os.getenv("KIMI_USAGE_THEME", "blue-dark")
57
60
  self.config.theme = theme
58
61
 
59
- # Get language and visible providers from JSON
62
+ # Get language, visible providers, and provider order from JSON
60
63
  self.config.language = general_data.get("language")
61
64
  self.config.visible_providers = general_data.get("visibleProviders")
65
+ saved_provider_order = general_data.get("providerOrder")
62
66
 
63
67
  # Get OpenRouter metric preference, default requests
64
68
  or_metric = general_data.get("orMetric", "requests")
@@ -77,7 +81,7 @@ class ConfigResolver:
77
81
  self.config.days_window = days_window
78
82
 
79
83
  # 2. Setup providers
80
- all_providers = ["kimi", "openai", "anthropic", "openrouter"]
84
+ all_providers = ["kimi", "openai", "anthropic", "openrouter", "codex", "claude"]
81
85
 
82
86
  # Envs map
83
87
  env_keys = {
@@ -85,6 +89,8 @@ class ConfigResolver:
85
89
  "openai": ("OPENAI_API_KEY",),
86
90
  "anthropic": ("ANTHROPIC_API_KEY",),
87
91
  "openrouter": ("OPENROUTER_API_KEY", "OPENROUTER_ADMIN_KEY"),
92
+ "codex": ("CODEX_API_KEY",),
93
+ "claude": ("CLAUDE_API_KEY",),
88
94
  }
89
95
 
90
96
  env_urls = {
@@ -92,6 +98,8 @@ class ConfigResolver:
92
98
  "openai": "OPENAI_BASE_URL",
93
99
  "anthropic": "ANTHROPIC_BASE_URL",
94
100
  "openrouter": "OPENROUTER_BASE_URL",
101
+ "codex": "CODEX_BASE_URL",
102
+ "claude": "CLAUDE_BASE_URL",
95
103
  }
96
104
 
97
105
  default_urls = {
@@ -99,6 +107,8 @@ class ConfigResolver:
99
107
  "openai": "https://api.openai.com",
100
108
  "anthropic": "https://api.anthropic.com",
101
109
  "openrouter": "https://openrouter.ai/api",
110
+ "codex": "https://chatgpt.com/backend-api",
111
+ "claude": "https://api.anthropic.com",
102
112
  }
103
113
 
104
114
  for p in all_providers:
@@ -128,14 +138,23 @@ class ConfigResolver:
128
138
  or os.getenv("OPENROUTER_ADMIN_KEY")
129
139
  )
130
140
 
131
- # Get Enabled status from JSON, else ENV, default True
132
- enabled = p_data.get("enabled")
133
- if enabled is None:
134
- env_enabled = os.getenv(f"{p.upper()}_ENABLED")
135
- if env_enabled is not None:
136
- enabled = env_enabled.lower() not in ("false", "0", "no")
137
- else:
138
- enabled = True
141
+ # Codex & Claude: default-off, read local auth files directly
142
+ if p in ("codex", "claude"):
143
+ enabled = p_data.get("enabled")
144
+ if enabled is None:
145
+ env_enabled: str | None = os.getenv(f"{p.upper()}_ENABLED", "").lower()
146
+ enabled = env_enabled in ("true", "1", "yes")
147
+ if enabled:
148
+ api_key = "enabled" # Sentinel: passes enabled_providers check
149
+ else:
150
+ # Get Enabled status from JSON, else ENV, default True
151
+ enabled = p_data.get("enabled")
152
+ if enabled is None:
153
+ env_enabled = os.getenv(f"{p.upper()}_ENABLED")
154
+ if env_enabled is not None:
155
+ enabled = env_enabled.lower() not in ("false", "0", "no")
156
+ else:
157
+ enabled = True
139
158
 
140
159
  self.config.providers[p] = ProviderConfig(
141
160
  api_key=api_key if api_key else None,
@@ -145,7 +164,7 @@ class ConfigResolver:
145
164
  )
146
165
 
147
166
  # 3. Determine provider ordering
148
- default_order = ["anthropic", "openai", "openrouter", "kimi"]
167
+ default_order = ["anthropic", "openai", "openrouter", "kimi", "codex", "claude"]
149
168
  json_providers = list(providers_data.keys())
150
169
 
151
170
  final_order = []
@@ -156,6 +175,14 @@ class ConfigResolver:
156
175
  if p not in final_order:
157
176
  final_order.append(p)
158
177
 
178
+ # Persisted order from settings view takes precedence over derived order
179
+ if saved_provider_order:
180
+ saved_order = [p for p in saved_provider_order if p in all_providers]
181
+ for p in default_order:
182
+ if p not in saved_order:
183
+ saved_order.append(p)
184
+ final_order = saved_order
185
+
159
186
  self.config.provider_order = final_order
160
187
 
161
188
  return self.config
@@ -167,7 +194,8 @@ def save_theme(
167
194
  visible_providers: list[str] | None = None,
168
195
  or_metric: str | None = None,
169
196
  days_window: int | None = None,
170
- config_path: Path | None = None
197
+ provider_order: list[str] | None = None,
198
+ config_path: Path | None = None,
171
199
  ) -> None:
172
200
  """Persist settings into ``general`` in the JSON config file.
173
201
 
@@ -195,6 +223,8 @@ def save_theme(
195
223
  general["orMetric"] = or_metric
196
224
  if days_window is not None:
197
225
  general["daysWindow"] = days_window
226
+ if provider_order is not None:
227
+ general["providerOrder"] = provider_order
198
228
  data["general"] = general
199
229
 
200
230
  with open(path, "w", encoding="utf-8") as fh: