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.
- {kimi_code_usage-0.1.6 → kimi_code_usage-0.2.0}/.gitignore +9 -0
- kimi_code_usage-0.2.0/CHANGELOG.md +40 -0
- {kimi_code_usage-0.1.6 → kimi_code_usage-0.2.0}/PKG-INFO +10 -4
- {kimi_code_usage-0.1.6 → kimi_code_usage-0.2.0}/README.md +5 -0
- {kimi_code_usage-0.1.6 → kimi_code_usage-0.2.0}/README.zh.md +5 -0
- {kimi_code_usage-0.1.6 → kimi_code_usage-0.2.0}/pyproject.toml +16 -3
- kimi_code_usage-0.2.0/src/kimi_code_usage/__main__.py +3 -0
- {kimi_code_usage-0.1.6 → kimi_code_usage-0.2.0}/src/kimi_code_usage/config.py +42 -12
- {kimi_code_usage-0.1.6 → kimi_code_usage-0.2.0}/src/kimi_code_usage/main.py +359 -105
- {kimi_code_usage-0.1.6 → kimi_code_usage-0.2.0}/src/kimi_code_usage/providers/__init__.py +4 -0
- kimi_code_usage-0.2.0/src/kimi_code_usage/providers/claude.py +308 -0
- kimi_code_usage-0.2.0/src/kimi_code_usage/providers/codex.py +481 -0
- {kimi_code_usage-0.1.6 → kimi_code_usage-0.2.0}/src/kimi_code_usage/providers/kimi.py +201 -3
- kimi_code_usage-0.2.0/src/kimi_code_usage/providers/kimi_membership.py +269 -0
- {kimi_code_usage-0.1.6 → kimi_code_usage-0.2.0}/src/kimi_code_usage/providers/openrouter.py +8 -8
- kimi_code_usage-0.2.0/src/kimi_code_usage/providers/webbridge.py +115 -0
- {kimi_code_usage-0.1.6 → kimi_code_usage-0.2.0}/src/kimi_code_usage/server.py +1 -1
- kimi_code_usage-0.2.0/tests/conftest.py +15 -0
- {kimi_code_usage-0.1.6 → kimi_code_usage-0.2.0}/tests/test_config.py +76 -45
- {kimi_code_usage-0.1.6 → kimi_code_usage-0.2.0}/tests/test_main.py +864 -131
- kimi_code_usage-0.2.0/tests/test_mcp_smoke.py +48 -0
- kimi_code_usage-0.2.0/tests/test_provider_claude.py +467 -0
- kimi_code_usage-0.2.0/tests/test_provider_codex.py +656 -0
- kimi_code_usage-0.2.0/tests/test_provider_kimi.py +732 -0
- kimi_code_usage-0.2.0/tests/test_provider_kimi_membership.py +389 -0
- {kimi_code_usage-0.1.6 → kimi_code_usage-0.2.0}/tests/test_provider_openrouter.py +28 -0
- kimi_code_usage-0.2.0/tests/test_provider_webbridge.py +133 -0
- kimi_code_usage-0.2.0/tests/test_server.py +370 -0
- {kimi_code_usage-0.1.6 → kimi_code_usage-0.2.0}/uv.lock +1268 -665
- kimi_code_usage-0.2.0/vscode-extension/package-lock.json +4874 -0
- kimi_code_usage-0.1.6/.github/workflows/ci.yml +0 -42
- kimi_code_usage-0.1.6/docs/kimi-code-usage.md +0 -54
- kimi_code_usage-0.1.6/docs/superpowers/plans/2026-05-09-pace-indicator.md +0 -220
- kimi_code_usage-0.1.6/docs/superpowers/plans/2026-05-14-pace-theme-thresholds.md +0 -501
- kimi_code_usage-0.1.6/docs/superpowers/plans/2026-06-10-multi-llm-quota.md +0 -108
- kimi_code_usage-0.1.6/docs/superpowers/plans/2026-06-10-vscode-extension-ts-strictness.md +0 -679
- kimi_code_usage-0.1.6/docs/superpowers/specs/2026-05-09-pace-indicator-design.md +0 -189
- kimi_code_usage-0.1.6/docs/superpowers/specs/2026-05-14-pace-theme-thresholds-design.md +0 -106
- kimi_code_usage-0.1.6/docs/superpowers/specs/2026-06-10-multi-llm-quota-design.md +0 -307
- kimi_code_usage-0.1.6/docs/superpowers/specs/2026-06-10-vscode-extension-multi-provider-design.md +0 -394
- kimi_code_usage-0.1.6/docs/superpowers/specs/2026-06-10-vscode-extension-ts-refactor-design.md +0 -115
- kimi_code_usage-0.1.6/tests/conftest.py +0 -4
- kimi_code_usage-0.1.6/tests/test_provider_kimi.py +0 -289
- kimi_code_usage-0.1.6/vscode-extension/.claude/settings.local.json +0 -8
- kimi_code_usage-0.1.6/vscode-extension/.github/workflows/ci.yml +0 -34
- kimi_code_usage-0.1.6/vscode-extension/.prettierignore +0 -10
- kimi_code_usage-0.1.6/vscode-extension/.prettierrc.json +0 -9
- kimi_code_usage-0.1.6/vscode-extension/.vscodeignore +0 -19
- kimi_code_usage-0.1.6/vscode-extension/LICENSE +0 -21
- kimi_code_usage-0.1.6/vscode-extension/README.md +0 -236
- kimi_code_usage-0.1.6/vscode-extension/assets/icon.png +0 -0
- kimi_code_usage-0.1.6/vscode-extension/assets/moon.svg +0 -3
- kimi_code_usage-0.1.6/vscode-extension/eslint.config.mjs +0 -48
- kimi_code_usage-0.1.6/vscode-extension/l10n/bundle.l10n.de.json +0 -151
- kimi_code_usage-0.1.6/vscode-extension/l10n/bundle.l10n.en.json +0 -151
- kimi_code_usage-0.1.6/vscode-extension/l10n/bundle.l10n.es.json +0 -151
- kimi_code_usage-0.1.6/vscode-extension/l10n/bundle.l10n.fr.json +0 -151
- kimi_code_usage-0.1.6/vscode-extension/l10n/bundle.l10n.it.json +0 -151
- kimi_code_usage-0.1.6/vscode-extension/l10n/bundle.l10n.ja.json +0 -151
- kimi_code_usage-0.1.6/vscode-extension/l10n/bundle.l10n.ko.json +0 -151
- kimi_code_usage-0.1.6/vscode-extension/l10n/bundle.l10n.pt.json +0 -151
- kimi_code_usage-0.1.6/vscode-extension/l10n/bundle.l10n.ru.json +0 -151
- kimi_code_usage-0.1.6/vscode-extension/l10n/bundle.l10n.zh-cn.json +0 -151
- kimi_code_usage-0.1.6/vscode-extension/package.json +0 -277
- kimi_code_usage-0.1.6/vscode-extension/scripts/copy-assets.ts +0 -24
- kimi_code_usage-0.1.6/vscode-extension/src/__mocks__/vscode.ts +0 -125
- kimi_code_usage-0.1.6/vscode-extension/src/api.test.ts +0 -641
- kimi_code_usage-0.1.6/vscode-extension/src/api.ts +0 -339
- kimi_code_usage-0.1.6/vscode-extension/src/apiCache.test.ts +0 -123
- kimi_code_usage-0.1.6/vscode-extension/src/apiCache.ts +0 -62
- kimi_code_usage-0.1.6/vscode-extension/src/config.test.ts +0 -298
- kimi_code_usage-0.1.6/vscode-extension/src/config.ts +0 -113
- kimi_code_usage-0.1.6/vscode-extension/src/extension.test.ts +0 -581
- kimi_code_usage-0.1.6/vscode-extension/src/extension.ts +0 -147
- kimi_code_usage-0.1.6/vscode-extension/src/historyPanel.test.ts +0 -359
- kimi_code_usage-0.1.6/vscode-extension/src/historyPanel.ts +0 -641
- kimi_code_usage-0.1.6/vscode-extension/src/i18n.test.ts +0 -247
- kimi_code_usage-0.1.6/vscode-extension/src/i18n.ts +0 -124
- kimi_code_usage-0.1.6/vscode-extension/src/notifier.test.ts +0 -213
- kimi_code_usage-0.1.6/vscode-extension/src/notifier.ts +0 -101
- kimi_code_usage-0.1.6/vscode-extension/src/pace.test.ts +0 -246
- kimi_code_usage-0.1.6/vscode-extension/src/pace.ts +0 -141
- kimi_code_usage-0.1.6/vscode-extension/src/predict.test.ts +0 -578
- kimi_code_usage-0.1.6/vscode-extension/src/predict.ts +0 -180
- kimi_code_usage-0.1.6/vscode-extension/src/statusBar.test.ts +0 -947
- kimi_code_usage-0.1.6/vscode-extension/src/statusBar.ts +0 -423
- kimi_code_usage-0.1.6/vscode-extension/src/storage-unlink.test.ts +0 -36
- kimi_code_usage-0.1.6/vscode-extension/src/storage.test.ts +0 -233
- kimi_code_usage-0.1.6/vscode-extension/src/storage.ts +0 -137
- kimi_code_usage-0.1.6/vscode-extension/src/types.ts +0 -102
- kimi_code_usage-0.1.6/vscode-extension/src/vscode-mock.test.ts +0 -106
- kimi_code_usage-0.1.6/vscode-extension/tsconfig.eslint.json +0 -10
- kimi_code_usage-0.1.6/vscode-extension/tsconfig.json +0 -20
- kimi_code_usage-0.1.6/vscode-extension/vitest.config.ts +0 -16
- {kimi_code_usage-0.1.6 → kimi_code_usage-0.2.0}/.claude/settings.local.json +0 -0
- {kimi_code_usage-0.1.6 → kimi_code_usage-0.2.0}/.env.example +0 -0
- {kimi_code_usage-0.1.6 → kimi_code_usage-0.2.0}/AGENTS.md +0 -0
- {kimi_code_usage-0.1.6 → kimi_code_usage-0.2.0}/kimi_usage.code-workspace +0 -0
- {kimi_code_usage-0.1.6 → kimi_code_usage-0.2.0}/requirements.txt +0 -0
- {kimi_code_usage-0.1.6 → kimi_code_usage-0.2.0}/src/kimi_code_usage/__init__.py +0 -0
- {kimi_code_usage-0.1.6 → kimi_code_usage-0.2.0}/src/kimi_code_usage/mcp.py +0 -0
- {kimi_code_usage-0.1.6 → kimi_code_usage-0.2.0}/src/kimi_code_usage/providers/anthropic.py +0 -0
- {kimi_code_usage-0.1.6 → kimi_code_usage-0.2.0}/src/kimi_code_usage/providers/openai.py +0 -0
- {kimi_code_usage-0.1.6 → kimi_code_usage-0.2.0}/tests/__init__.py +0 -0
- {kimi_code_usage-0.1.6 → kimi_code_usage-0.2.0}/tests/test_mcp.py +0 -0
- {kimi_code_usage-0.1.6 → kimi_code_usage-0.2.0}/tests/test_provider_anthropic.py +0 -0
- {kimi_code_usage-0.1.6 → kimi_code_usage-0.2.0}/tests/test_provider_openai.py +0 -0
- {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.
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
2
|
Name: kimi-code-usage
|
|
3
|
-
Version: 0.
|
|
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.
|
|
13
|
-
Requires-Dist:
|
|
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.
|
|
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.
|
|
13
|
+
"aiohttp>=3.14.3",
|
|
14
14
|
"rich>=12.0.0",
|
|
15
15
|
"python-dotenv>=1.0.0",
|
|
16
|
-
"fastmcp>=
|
|
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
|
+
]
|
|
@@ -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
|
|
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
|
-
#
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
enabled = env_enabled
|
|
137
|
-
|
|
138
|
-
|
|
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
|
-
|
|
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:
|