ccus-cli 0.1.23 → 0.1.25
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.
- package/dist/cli.js +14 -3
- package/dist/lib/api-mode.js +43 -2
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -982,7 +982,7 @@ async function handleApiConfig(options) {
|
|
|
982
982
|
` provider: ${next.provider}`,
|
|
983
983
|
` token 环境变量: ${next.tokenEnv}`,
|
|
984
984
|
` token 兜底: ${maskSecret(next.token)}`,
|
|
985
|
-
` 当前生效 token: ${maskSecret((0, api_mode_1.
|
|
985
|
+
` 当前生效 token: ${maskSecret((0, api_mode_1.resolveApiTokenWithSettings)(next))}`,
|
|
986
986
|
` 缓存 TTL: ${formatDurationMs(next.cacheTtlMs)}`,
|
|
987
987
|
` 请求超时: ${formatDurationMs(next.timeoutMs)}`,
|
|
988
988
|
` User-Agent: ${next.userAgent}`,
|
|
@@ -1011,8 +1011,19 @@ async function handleApiTest(options) {
|
|
|
1011
1011
|
return;
|
|
1012
1012
|
}
|
|
1013
1013
|
process.stdout.write(`正在用 provider=${config.provider} 拉取额度(超时 ${formatDurationMs(config.timeoutMs)})...\n`);
|
|
1014
|
+
// 环境变量和 config.token 都拿不到 token 时,回退到 ~/.claude/settings.json 的 env 字段。
|
|
1015
|
+
// 手动跑 api test 时不在 Claude Code 进程树下,环境变量里通常没有 ANTHROPIC_AUTH_TOKEN,
|
|
1016
|
+
// 而 settings.json 的 env 是 Claude Code 持久化这些变量的地方,正好作为来源。
|
|
1017
|
+
let env = process.env;
|
|
1018
|
+
if (!(0, api_mode_1.resolveApiToken)(config, env)) {
|
|
1019
|
+
const settingsToken = (0, api_mode_1.readClaudeSettingsEnvTokenSync)(config.tokenEnv);
|
|
1020
|
+
if (settingsToken) {
|
|
1021
|
+
env = { ...process.env, [config.tokenEnv]: settingsToken };
|
|
1022
|
+
(0, debug_1.debugLog)("api-mode", `token from settings.json env.${config.tokenEnv}`);
|
|
1023
|
+
}
|
|
1024
|
+
}
|
|
1014
1025
|
try {
|
|
1015
|
-
const quota = await (0, api_mode_1.fetchQuota)(config,
|
|
1026
|
+
const quota = await (0, api_mode_1.fetchQuota)(config, env);
|
|
1016
1027
|
const fiveHour = quota.fiveHour !== null ? `${quota.fiveHour.toFixed(1)}%` : "--";
|
|
1017
1028
|
const sevenDay = quota.sevenDay !== null ? `${quota.sevenDay.toFixed(1)}%` : "--";
|
|
1018
1029
|
process.stdout.write(`✅ 5h ${fiveHour} | 7d ${sevenDay}${quota.level ? ` | level ${quota.level}` : ""}\n`);
|
|
@@ -1042,7 +1053,7 @@ async function handleApiStatus(options) {
|
|
|
1042
1053
|
const lines = [
|
|
1043
1054
|
` 启用: ${config.enabled ? "是" : "否"}`,
|
|
1044
1055
|
` provider: ${config.provider}`,
|
|
1045
|
-
` 当前生效 token: ${maskSecret((0, api_mode_1.
|
|
1056
|
+
` 当前生效 token: ${maskSecret((0, api_mode_1.resolveApiTokenWithSettings)(config))}`,
|
|
1046
1057
|
` 缓存 TTL: ${formatDurationMs(config.cacheTtlMs)}`,
|
|
1047
1058
|
` 缓存状态: ${ageLabel}`,
|
|
1048
1059
|
];
|
package/dist/lib/api-mode.js
CHANGED
|
@@ -8,6 +8,8 @@ exports.defaultApiConfig = defaultApiConfig;
|
|
|
8
8
|
exports.readApiConfig = readApiConfig;
|
|
9
9
|
exports.writeApiConfig = writeApiConfig;
|
|
10
10
|
exports.resolveApiToken = resolveApiToken;
|
|
11
|
+
exports.readClaudeSettingsEnvTokenSync = readClaudeSettingsEnvTokenSync;
|
|
12
|
+
exports.resolveApiTokenWithSettings = resolveApiTokenWithSettings;
|
|
11
13
|
exports.extractCustomQuota = extractCustomQuota;
|
|
12
14
|
exports.runExtractor = runExtractor;
|
|
13
15
|
exports.normalizeExtractorResult = normalizeExtractorResult;
|
|
@@ -117,6 +119,41 @@ function resolveApiToken(config, env = process.env) {
|
|
|
117
119
|
}
|
|
118
120
|
return typeof config.token === "string" && config.token.trim() !== "" ? config.token : null;
|
|
119
121
|
}
|
|
122
|
+
/**
|
|
123
|
+
* 从 ~/.claude/settings.json 的 env 字段读 tokenEnv 指定的那个键。
|
|
124
|
+
*
|
|
125
|
+
* Claude Code 启动子进程时会把 settings.json 的 env 注入环境变量,但用户在终端手动跑
|
|
126
|
+
* `ccus api test` 时不在 Claude Code 进程树下,环境变量里通常没有 ANTHROPIC_AUTH_TOKEN ——
|
|
127
|
+
* 这时回退到 settings.json(env 是 Claude Code 持久化这些变量的地方)读取。
|
|
128
|
+
* 只读 env 字段(apiKeyHelper 需要 spawn 子进程、有副作用,不在此支持)。任何缺失/异常返回 null。
|
|
129
|
+
*/
|
|
130
|
+
function readClaudeSettingsEnvTokenSync(tokenEnv, settingsPath = (0, paths_1.getClaudeSettingsPath)()) {
|
|
131
|
+
try {
|
|
132
|
+
const raw = node_fs_1.default.readFileSync(settingsPath, "utf8");
|
|
133
|
+
const parsed = JSON.parse(raw);
|
|
134
|
+
if (!isRecord(parsed)) {
|
|
135
|
+
return null;
|
|
136
|
+
}
|
|
137
|
+
const envField = parsed.env;
|
|
138
|
+
if (!isRecord(envField)) {
|
|
139
|
+
return null;
|
|
140
|
+
}
|
|
141
|
+
const value = envField[tokenEnv];
|
|
142
|
+
return typeof value === "string" && value.trim() !== "" ? value : null;
|
|
143
|
+
}
|
|
144
|
+
catch {
|
|
145
|
+
return null;
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
/**
|
|
149
|
+
* 三层回退解析 token:环境变量 → config.token → ~/.claude/settings.json 的 env 字段。
|
|
150
|
+
*
|
|
151
|
+
* 仅供 `api test` / `api status` / `api config` 这类手动命令显示与判断用;statusline 高频路径
|
|
152
|
+
* 仍走纯 `resolveApiToken`(不读文件),行为不变。
|
|
153
|
+
*/
|
|
154
|
+
function resolveApiTokenWithSettings(config, env = process.env) {
|
|
155
|
+
return resolveApiToken(config, env) ?? readClaudeSettingsEnvTokenSync(config.tokenEnv);
|
|
156
|
+
}
|
|
120
157
|
/** 把 header 值里的 {{token}} / {{apikey}} 占位符替换成实际 token;token 为空则替换为空串。 */
|
|
121
158
|
function renderHeader(value, token) {
|
|
122
159
|
return value.replaceAll(/{{\s*(token|apikey)\s*}}/gi, token ?? "");
|
|
@@ -124,7 +161,9 @@ function renderHeader(value, token) {
|
|
|
124
161
|
/**
|
|
125
162
|
* 智谱 GLM Coding Plan 的内置 extractor 脚本(zhipu provider 的预设)。
|
|
126
163
|
*
|
|
127
|
-
* data.limits 里筛 type==="TOKENS_LIMIT",按 nextResetTime 升序,第 1 条 = 5h、第 2 条 =
|
|
164
|
+
* data.limits 里筛 type==="TOKENS_LIMIT",按 nextResetTime 升序,第 1 条 = 5h、第 2 条 = 每周。
|
|
165
|
+
* 智谱在 5h 桶利用率=0% 时会省略该条的 nextResetTime,缺字段兜底 -Infinity 排最前(归 5h 桶),
|
|
166
|
+
* 否则会被当 weekly、和 weekly 槽位互换(对照 cc-switch v3.16.0 的同类修复)。
|
|
128
167
|
* success !== true / code !== 200 / 缺 data.limits 时返回会让归一化判 null 的值。
|
|
129
168
|
* zhipu 不再单独维护提取函数,与 custom 走同一条 `runExtractor` 路径,只是 extractor 用这组内置脚本。
|
|
130
169
|
*/
|
|
@@ -139,7 +178,9 @@ exports.ZHIPU_EXTRACTOR = `function(response) {
|
|
|
139
178
|
const tokenLimits = limits
|
|
140
179
|
.filter((l) => l && l.type === "TOKENS_LIMIT")
|
|
141
180
|
.map((l) => ({ p: l.percentage, r: l.nextResetTime }))
|
|
142
|
-
|
|
181
|
+
// 缺 nextResetTime 的那条兜底 -Infinity 排最前(= 5h 桶):智谱在 5h=0% 时会省略该字段,
|
|
182
|
+
// 若兜底 Infinity 排最后会被当成 weekly,造成 5h/7d 槽位互换(见上方 JSDoc)。
|
|
183
|
+
.sort((a, b) => (typeof a.r === "number" ? a.r : -Infinity) - (typeof b.r === "number" ? b.r : -Infinity));
|
|
143
184
|
return {
|
|
144
185
|
fiveHour: tokenLimits[0] ? tokenLimits[0].p : null,
|
|
145
186
|
sevenDay: tokenLimits[1] ? tokenLimits[1].p : null,
|