@foxden-app/foxclaw 0.4.12 → 0.4.13
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/CHANGELOG.md +10 -0
- package/README.md +2 -2
- package/README_EN.md +2 -2
- package/dist/controller/controller.d.ts +1 -0
- package/dist/controller/controller.js +27 -5
- package/dist/i18n.d.ts +2 -0
- package/dist/i18n.js +2 -0
- package/dist/types.d.ts +2 -0
- package/dist/update.d.ts +2 -0
- package/dist/update.js +44 -6
- package/docs/user-manual.md +4 -4
- package/docs/zh/user-manual.md +4 -4
- package/package.json +1 -1
- package/skills/foxclaw/SKILL.md +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,16 @@
|
|
|
2
2
|
|
|
3
3
|
All notable FoxClaw changes are listed here. Each release note is bilingual so GitHub Releases and the npm package are useful to both Chinese and English readers.
|
|
4
4
|
|
|
5
|
+
## 0.4.13 - 2026-06-03
|
|
6
|
+
|
|
7
|
+
### 中文
|
|
8
|
+
- `/update` 完成回报新增 Codex CLI 版本变化,和 FoxClaw 版本变化并排行展示。
|
|
9
|
+
- `/auth` 文本列表继续保留额度窗口详情,候选按钮改为只显示两个剩余百分比数字,未知值用 `—`,减少窄屏按钮截断。
|
|
10
|
+
|
|
11
|
+
### English
|
|
12
|
+
- Added Codex CLI from/to version reporting to completed `/update` messages alongside the FoxClaw version change.
|
|
13
|
+
- Kept quota-window detail in `/auth` text rows, while compacting candidate buttons to two remaining-percent numbers with `—` for unknown values.
|
|
14
|
+
|
|
5
15
|
## 0.4.12 - 2026-06-02
|
|
6
16
|
|
|
7
17
|
### 中文
|
package/README.md
CHANGED
|
@@ -85,7 +85,7 @@ DEFAULT_SANDBOX_MODE=workspace-write
|
|
|
85
85
|
|
|
86
86
|
配置文件默认在 `~/.foxclaw/.env`。想放别处的话设 `FOXCLAW_ENV=/path/to/.env`。
|
|
87
87
|
|
|
88
|
-
`foxclaw start` 会自动检查环境并安装/重启后台服务。后续升级直接运行 `foxclaw update`,它会沿用当前的 npm/pnpm 全局安装方式,尝试同步升级 npm/pnpm 安装的 Codex CLI
|
|
88
|
+
`foxclaw start` 会自动检查环境并安装/重启后台服务。后续升级直接运行 `foxclaw update`,它会沿用当前的 npm/pnpm 全局安装方式,尝试同步升级 npm/pnpm 安装的 Codex CLI,再完成安装、自检和服务重启,并在聊天回报 FoxClaw 与 Codex CLI 的版本变化。
|
|
89
89
|
|
|
90
90
|
FoxClaw 只响应 `TG_ALLOWED_USER_ID` 的消息——把机器人拉进群不代表群里所有人都能用。
|
|
91
91
|
|
|
@@ -128,7 +128,7 @@ FoxClaw 的一大特色是自动多账号切换。当一个账号触发用量限
|
|
|
128
128
|
3. 用 `/auth` 查看所有候选账号状态。
|
|
129
129
|
4. 用 `/auth enable <n>` / `/auth disable <n>` 控制哪些账号参与自动轮换。
|
|
130
130
|
|
|
131
|
-
候选较多时,`/auth` 每页显示 8 个账号,并提供翻页、`全部 / 已启用 / 需关注` 筛选。也可以用 `/auth list <关键词>` 搜索文件名,或用 `/auth page <页码>`
|
|
131
|
+
候选较多时,`/auth` 每页显示 8 个账号,并提供翻页、`全部 / 已启用 / 需关注` 筛选。也可以用 `/auth list <关键词>` 搜索文件名,或用 `/auth page <页码>` 直接跳页。文本列表的额度窗口按 Codex 实际返回值展示,例如 `5h:20|7d:25` 或单月窗口 `30d:97`;按钮只显示紧凑的两个剩余数字,例如 `20|25`,未知值显示为 `—`。面板会省略候选名中重复的 `auth.json_` 前缀,磁盘文件名保持不变。
|
|
132
132
|
|
|
133
133
|
当 Codex 报告用量限制错误时,FoxClaw 会自动:
|
|
134
134
|
- 切换到下一个未失败的候选账号
|
package/README_EN.md
CHANGED
|
@@ -85,7 +85,7 @@ DEFAULT_SANDBOX_MODE=workspace-write
|
|
|
85
85
|
|
|
86
86
|
The default config file is `~/.foxclaw/.env`. Set `FOXCLAW_ENV=/path/to/.env` if you want to keep it somewhere else.
|
|
87
87
|
|
|
88
|
-
`foxclaw start` runs checks and installs or restarts the background service. For later upgrades, run `foxclaw update`; it preserves the current npm/pnpm global-install method, attempts to update an npm/pnpm-managed Codex CLI, runs checks,
|
|
88
|
+
`foxclaw start` runs checks and installs or restarts the background service. For later upgrades, run `foxclaw update`; it preserves the current npm/pnpm global-install method, attempts to update an npm/pnpm-managed Codex CLI, runs checks, restarts the service, and reports both FoxClaw and Codex CLI version changes in chat.
|
|
89
89
|
|
|
90
90
|
FoxClaw accepts messages only from `TG_ALLOWED_USER_ID`. Putting the bot in a group does not make it available to every group member.
|
|
91
91
|
|
|
@@ -128,7 +128,7 @@ Setup:
|
|
|
128
128
|
3. Use `/auth` to view all candidate account statuses.
|
|
129
129
|
4. Use `/auth enable <n>` / `/auth disable <n>` to control which accounts participate in auto-rotation.
|
|
130
130
|
|
|
131
|
-
For larger inventories, `/auth` shows 8 candidates per page with paging and `All / Enabled / Attention` filters. Use `/auth list <keyword>` to search filenames or `/auth page <n>` to jump directly.
|
|
131
|
+
For larger inventories, `/auth` shows 8 candidates per page with paging and `All / Enabled / Attention` filters. Use `/auth list <keyword>` to search filenames or `/auth page <n>` to jump directly. Candidate rows use the quota windows reported by Codex, for example `5h:20|7d:25` or a single monthly window such as `30d:97`; buttons use compact remaining numbers such as `20|25`, with `—` for unknown values. The panel omits the repeated `auth.json_` prefix from candidate labels without renaming files on disk.
|
|
132
132
|
|
|
133
133
|
When Codex reports a usage-limit error, FoxClaw automatically:
|
|
134
134
|
- Switches to the next non-failed candidate account
|
|
@@ -238,6 +238,7 @@ export declare class BridgeSessionCore {
|
|
|
238
238
|
private clearSelfUpdateStatusPoll;
|
|
239
239
|
private pollSelfUpdateStatus;
|
|
240
240
|
private formatSelfUpdateResult;
|
|
241
|
+
private formatCodexUpdateResult;
|
|
241
242
|
private handleAuthCommand;
|
|
242
243
|
private handleAuthRefreshAllCommand;
|
|
243
244
|
private handleAuthUseCommand;
|
|
@@ -433,8 +433,9 @@ export class BridgeSessionCore {
|
|
|
433
433
|
to: serviceStatus.lastUpdate.toVersion ?? t(locale, 'unknown'),
|
|
434
434
|
time: serviceStatus.lastUpdate.updatedAt,
|
|
435
435
|
}));
|
|
436
|
-
|
|
437
|
-
|
|
436
|
+
const codexUpdateLine = this.formatCodexUpdateResult(serviceStatus.lastUpdate);
|
|
437
|
+
if (codexUpdateLine) {
|
|
438
|
+
lines.push(t(locale, 'status_last_codex_update', { value: codexUpdateLine }));
|
|
438
439
|
}
|
|
439
440
|
}
|
|
440
441
|
else {
|
|
@@ -3871,15 +3872,25 @@ export class BridgeSessionCore {
|
|
|
3871
3872
|
await this.selfUpdater?.clearStatus();
|
|
3872
3873
|
}
|
|
3873
3874
|
formatSelfUpdateResult(status) {
|
|
3875
|
+
const codexUpdateLine = this.formatCodexUpdateResult(status);
|
|
3874
3876
|
if (status.state === 'succeeded') {
|
|
3875
3877
|
const result = t(status.locale, 'update_succeeded', {
|
|
3876
3878
|
from: status.fromVersion,
|
|
3877
3879
|
to: status.toVersion ?? t(status.locale, 'unknown'),
|
|
3878
3880
|
});
|
|
3879
|
-
return
|
|
3881
|
+
return codexUpdateLine ? `${result}\n${codexUpdateLine}` : result;
|
|
3880
3882
|
}
|
|
3881
3883
|
const result = t(status.locale, 'update_failed', { error: status.error ?? t(status.locale, 'unknown') });
|
|
3882
|
-
return
|
|
3884
|
+
return codexUpdateLine ? `${result}\n${codexUpdateLine}` : result;
|
|
3885
|
+
}
|
|
3886
|
+
formatCodexUpdateResult(status) {
|
|
3887
|
+
if (status.codexFromVersion || status.codexToVersion) {
|
|
3888
|
+
return t(status.locale, 'update_codex_result', {
|
|
3889
|
+
from: status.codexFromVersion ?? t(status.locale, 'unknown'),
|
|
3890
|
+
to: status.codexToVersion ?? t(status.locale, 'unknown'),
|
|
3891
|
+
});
|
|
3892
|
+
}
|
|
3893
|
+
return status.codexUpdate ?? null;
|
|
3883
3894
|
}
|
|
3884
3895
|
async handleAuthCommand(scopeId, locale, args) {
|
|
3885
3896
|
const action = args[0]?.toLowerCase() ?? 'list';
|
|
@@ -7834,7 +7845,7 @@ function authChoiceKeyboard(locale, record) {
|
|
|
7834
7845
|
const page = codexAuthListPage(record.candidates, record);
|
|
7835
7846
|
const rows = page.visible.map(({ candidate, index }) => [
|
|
7836
7847
|
{
|
|
7837
|
-
text: clipButtonText(`${candidate.isCurrent ? '✅ ' : '🔐 '}${
|
|
7848
|
+
text: clipButtonText(`${candidate.isCurrent ? '✅ ' : '🔐 '}${formatAuthQuotaButtonPrefix(candidate.quota)}|${formatCodexAuthCandidateDisplayName(candidate.name)}${candidate.disabled ? ' · off' : ''}`),
|
|
7838
7849
|
callback_data: `auth:${record.localId}:${index}`,
|
|
7839
7850
|
},
|
|
7840
7851
|
{
|
|
@@ -8576,6 +8587,17 @@ function formatAuthQuotaPrefix(locale, snapshot) {
|
|
|
8576
8587
|
.map(([duration, remaining, fallback]) => (`${formatCompactRateLimitWindowLabel(locale, duration, fallback)}:${remaining === null ? '--' : formatUsagePercent(remaining)}`));
|
|
8577
8588
|
return values.length > 0 ? values.join('|') : '--';
|
|
8578
8589
|
}
|
|
8590
|
+
function formatAuthQuotaButtonPrefix(snapshot) {
|
|
8591
|
+
return [
|
|
8592
|
+
snapshot?.primaryRemainingPercent ?? null,
|
|
8593
|
+
snapshot?.secondaryRemainingPercent ?? null,
|
|
8594
|
+
].map(formatAuthQuotaButtonValue).join('|');
|
|
8595
|
+
}
|
|
8596
|
+
function formatAuthQuotaButtonValue(value) {
|
|
8597
|
+
return typeof value === 'number' && Number.isFinite(value)
|
|
8598
|
+
? formatUsagePercent(value)
|
|
8599
|
+
: '—';
|
|
8600
|
+
}
|
|
8579
8601
|
function isCodexAuthQuotaSnapshot(value) {
|
|
8580
8602
|
if (!value || typeof value !== 'object') {
|
|
8581
8603
|
return false;
|
package/dist/i18n.d.ts
CHANGED
|
@@ -130,6 +130,7 @@ declare const MESSAGES: {
|
|
|
130
130
|
readonly status_last_codex_update: "Last Codex update: {value}";
|
|
131
131
|
readonly update_started: "FoxClaw update started. I will report here after installation, checks, and service restart complete.";
|
|
132
132
|
readonly update_succeeded: "FoxClaw updated and restarted: {from} -> {to}.";
|
|
133
|
+
readonly update_codex_result: "Codex CLI: {from} -> {to}.";
|
|
133
134
|
readonly update_failed: "FoxClaw update failed: {error}\nRun foxclaw update in a terminal for details.";
|
|
134
135
|
readonly update_unavailable: "Self-update is unavailable in this runtime. Run foxclaw update in a terminal.";
|
|
135
136
|
readonly update_already_running: "A FoxClaw update is already running. I will report here when it finishes.";
|
|
@@ -735,6 +736,7 @@ declare const MESSAGES: {
|
|
|
735
736
|
readonly status_last_codex_update: "最近 Codex 升级:{value}";
|
|
736
737
|
readonly update_started: "已开始升级 FoxClaw。安装、自检和服务重启完成后,我会在这里回报结果。";
|
|
737
738
|
readonly update_succeeded: "FoxClaw 已升级并重启:{from} -> {to}。";
|
|
739
|
+
readonly update_codex_result: "Codex CLI:{from} -> {to}。";
|
|
738
740
|
readonly update_failed: "FoxClaw 升级失败:{error}\n请在终端运行 foxclaw update 查看详情。";
|
|
739
741
|
readonly update_unavailable: "当前运行方式不支持自升级,请在终端运行 foxclaw update。";
|
|
740
742
|
readonly update_already_running: "FoxClaw 升级已经在进行中,结束后我会在这里回报结果。";
|
package/dist/i18n.js
CHANGED
|
@@ -128,6 +128,7 @@ const MESSAGES = {
|
|
|
128
128
|
status_last_codex_update: 'Last Codex update: {value}',
|
|
129
129
|
update_started: 'FoxClaw update started. I will report here after installation, checks, and service restart complete.',
|
|
130
130
|
update_succeeded: 'FoxClaw updated and restarted: {from} -> {to}.',
|
|
131
|
+
update_codex_result: 'Codex CLI: {from} -> {to}.',
|
|
131
132
|
update_failed: 'FoxClaw update failed: {error}\nRun foxclaw update in a terminal for details.',
|
|
132
133
|
update_unavailable: 'Self-update is unavailable in this runtime. Run foxclaw update in a terminal.',
|
|
133
134
|
update_already_running: 'A FoxClaw update is already running. I will report here when it finishes.',
|
|
@@ -733,6 +734,7 @@ const MESSAGES = {
|
|
|
733
734
|
status_last_codex_update: '最近 Codex 升级:{value}',
|
|
734
735
|
update_started: '已开始升级 FoxClaw。安装、自检和服务重启完成后,我会在这里回报结果。',
|
|
735
736
|
update_succeeded: 'FoxClaw 已升级并重启:{from} -> {to}。',
|
|
737
|
+
update_codex_result: 'Codex CLI:{from} -> {to}。',
|
|
736
738
|
update_failed: 'FoxClaw 升级失败:{error}\n请在终端运行 foxclaw update 查看详情。',
|
|
737
739
|
update_unavailable: '当前运行方式不支持自升级,请在终端运行 foxclaw update。',
|
|
738
740
|
update_already_running: 'FoxClaw 升级已经在进行中,结束后我会在这里回报结果。',
|
package/dist/types.d.ts
CHANGED
package/dist/update.d.ts
CHANGED
package/dist/update.js
CHANGED
|
@@ -132,6 +132,8 @@ export function readSelfUpdateStatus(statusFile) {
|
|
|
132
132
|
fromVersion: parsed.fromVersion,
|
|
133
133
|
toVersion: typeof parsed.toVersion === 'string' ? parsed.toVersion : null,
|
|
134
134
|
...(typeof parsed.codexUpdate === 'string' ? { codexUpdate: parsed.codexUpdate } : {}),
|
|
135
|
+
...(typeof parsed.codexFromVersion === 'string' ? { codexFromVersion: parsed.codexFromVersion } : {}),
|
|
136
|
+
...(typeof parsed.codexToVersion === 'string' ? { codexToVersion: parsed.codexToVersion } : {}),
|
|
135
137
|
error: typeof parsed.error === 'string' ? parsed.error : null,
|
|
136
138
|
updatedAt: parsed.updatedAt,
|
|
137
139
|
};
|
|
@@ -161,6 +163,8 @@ export function createSelfUpdateRuntime(options) {
|
|
|
161
163
|
fromVersion: options.version,
|
|
162
164
|
toVersion: null,
|
|
163
165
|
codexUpdate: null,
|
|
166
|
+
codexFromVersion: null,
|
|
167
|
+
codexToVersion: null,
|
|
164
168
|
error: null,
|
|
165
169
|
updatedAt: new Date().toISOString(),
|
|
166
170
|
});
|
|
@@ -182,6 +186,8 @@ export function createSelfUpdateRuntime(options) {
|
|
|
182
186
|
fromVersion: options.version,
|
|
183
187
|
toVersion: null,
|
|
184
188
|
codexUpdate: null,
|
|
189
|
+
codexFromVersion: null,
|
|
190
|
+
codexToVersion: null,
|
|
185
191
|
error: formatError(error),
|
|
186
192
|
updatedAt: new Date().toISOString(),
|
|
187
193
|
});
|
|
@@ -205,7 +211,7 @@ export function performSelfUpdate(options) {
|
|
|
205
211
|
let codexUpdate = null;
|
|
206
212
|
try {
|
|
207
213
|
codexUpdate = updateManagedCodexCli(options.codexCliBin ?? env.CODEX_CLI_BIN ?? '', options.nodePath, env);
|
|
208
|
-
console.log(`[UPDATE] ${codexUpdate}`);
|
|
214
|
+
console.log(`[UPDATE] ${codexUpdate.message}`);
|
|
209
215
|
const installer = resolveSelfUpdateInstaller(options.entryPoint, options.nodePath, fs.existsSync, env);
|
|
210
216
|
const installerEnv = buildInstallerEnv(options.entryPoint, installer, env);
|
|
211
217
|
console.log(`[UPDATE] Installing ${PACKAGE_SPEC} with ${installer.manager}...`);
|
|
@@ -236,22 +242,52 @@ export function performSelfUpdate(options) {
|
|
|
236
242
|
}
|
|
237
243
|
}
|
|
238
244
|
function updateManagedCodexCli(codexCliBin, nodePath, env) {
|
|
245
|
+
const fromVersion = readCodexCliVersion(codexCliBin, env);
|
|
239
246
|
if (!codexCliBin) {
|
|
240
|
-
return
|
|
247
|
+
return {
|
|
248
|
+
message: 'Codex CLI update skipped: CODEX_CLI_BIN is not configured.',
|
|
249
|
+
fromVersion,
|
|
250
|
+
toVersion: fromVersion,
|
|
251
|
+
};
|
|
241
252
|
}
|
|
242
253
|
const installer = resolveCodexUpdateInstaller(codexCliBin, nodePath, fs.existsSync, env);
|
|
243
254
|
if (!installer) {
|
|
244
|
-
return
|
|
255
|
+
return {
|
|
256
|
+
message: 'Codex CLI update skipped: configured installation is not a recognized global npm/pnpm package.',
|
|
257
|
+
fromVersion,
|
|
258
|
+
toVersion: fromVersion,
|
|
259
|
+
};
|
|
245
260
|
}
|
|
246
261
|
try {
|
|
247
262
|
const installerEnv = buildInstallerEnv(fs.realpathSync(codexCliBin), installer, env);
|
|
248
263
|
runInherited(installer.command, installer.installArgs, installerEnv);
|
|
249
|
-
return
|
|
264
|
+
return {
|
|
265
|
+
message: `Codex CLI updated with ${installer.manager}.`,
|
|
266
|
+
fromVersion,
|
|
267
|
+
toVersion: readCodexCliVersion(codexCliBin, installerEnv) ?? fromVersion,
|
|
268
|
+
};
|
|
250
269
|
}
|
|
251
270
|
catch (error) {
|
|
252
|
-
return
|
|
271
|
+
return {
|
|
272
|
+
message: `Codex CLI update failed without blocking FoxClaw update: ${formatError(error)}`,
|
|
273
|
+
fromVersion,
|
|
274
|
+
toVersion: readCodexCliVersion(codexCliBin, env) ?? fromVersion,
|
|
275
|
+
};
|
|
253
276
|
}
|
|
254
277
|
}
|
|
278
|
+
function readCodexCliVersion(codexCliBin, env) {
|
|
279
|
+
if (!codexCliBin) {
|
|
280
|
+
return null;
|
|
281
|
+
}
|
|
282
|
+
const result = spawnSync(codexCliBin, ['--version'], { encoding: 'utf8', env });
|
|
283
|
+
if (result.error || result.status !== 0) {
|
|
284
|
+
return null;
|
|
285
|
+
}
|
|
286
|
+
return parseCodexCliVersion(`${result.stdout}\n${result.stderr}`);
|
|
287
|
+
}
|
|
288
|
+
function parseCodexCliVersion(output) {
|
|
289
|
+
return output.match(/\b\d+\.\d+\.\d+(?:[-+][0-9A-Za-z.-]+)?\b/)?.[0] ?? null;
|
|
290
|
+
}
|
|
255
291
|
function executableCandidates(commandName, nodePath, env, preferred = []) {
|
|
256
292
|
return [
|
|
257
293
|
...preferred,
|
|
@@ -329,7 +365,9 @@ function completeNotification(notificationFile, state, toVersion, codexUpdate, e
|
|
|
329
365
|
...pending,
|
|
330
366
|
state,
|
|
331
367
|
toVersion,
|
|
332
|
-
codexUpdate,
|
|
368
|
+
codexUpdate: codexUpdate?.message ?? null,
|
|
369
|
+
codexFromVersion: codexUpdate?.fromVersion ?? null,
|
|
370
|
+
codexToVersion: codexUpdate?.toVersion ?? null,
|
|
333
371
|
error,
|
|
334
372
|
updatedAt: new Date().toISOString(),
|
|
335
373
|
});
|
package/docs/user-manual.md
CHANGED
|
@@ -233,7 +233,7 @@ Later commands are sorted by recent usage. Plain text, photos, and files continu
|
|
|
233
233
|
- `/status`: FoxClaw, app-server, current thread binding, model, access, and Codex usage summary. In multi-bot mode it also lists every bot's connection, current auth, active turns, and the most recent auth mirror and service/Codex update outcomes. Local session, token, and visible-reply-throughput metrics use a background-generated historical snapshot instead of scanning large logs during the request; throughput is computed end-to-end for completed turns, excluding reasoning tokens while including waiting and tool execution time.
|
|
234
234
|
- `/account`: current Codex account.
|
|
235
235
|
- `/quota`: Codex usage and quota window.
|
|
236
|
-
- `/update`: upgrade FoxClaw, attempt to update an npm/pnpm-managed Codex CLI, run checks, and restart the service; it refuses while any Telegram bot runtime, an enabled Weixin default runtime, or an auth mirror write is busy, then reports
|
|
236
|
+
- `/update`: upgrade FoxClaw, attempt to update an npm/pnpm-managed Codex CLI, run checks, and restart the service; it refuses while any Telegram bot runtime, an enabled Weixin default runtime, or an auth mirror write is busy, then reports both FoxClaw and Codex CLI version changes through the initiating bot after restart.
|
|
237
237
|
|
|
238
238
|
### 3.3 `/config`, `/requirements`, `/provider`
|
|
239
239
|
|
|
@@ -391,7 +391,7 @@ If the login is cancelled or fails, FoxClaw tries to restore the previous auth t
|
|
|
391
391
|
|
|
392
392
|
`/auth` lists candidate accounts, the current account, and the auth directory. It also provides buttons for switching, disabling, login, and reload. In multi-bot mode the panel names the `@botname` runtime being managed, because private chats, groups, and topics on one bot share that bot's current auth. The panel shows 8 candidates per page and supports paging, `All / Enabled / Attention` filters, and `/auth list <keyword>` filename search for large local inventories. Panel text and buttons omit the repeated `auth.json_` prefix from standard candidate filenames, so `auth.json_personal` on disk renders as `personal`; files are not renamed, and search and commands still operate on the original candidates. `/auth use <n>` always uses the full-list candidate number, independent of panel paging.
|
|
393
393
|
|
|
394
|
-
|
|
394
|
+
Candidate rows are prefixed with observed `window:remaining-percent` values. For example, a Plus account may show `5h:20|7d:25`, while an account with one monthly window may show `30d:97`. Buttons use a compact two-number `primary|secondary` form such as `20|25`; unknown values render as `—`. The current auth quota is refreshed when the panel opens; other candidates are not switched merely to query quota. When multiple bot runtimes have recently used the same ChatGPT account, FoxClaw combines their cached quota snapshots by verified account ID, so one bot's `/auth` panel can show quota information learned by another bot without mixing different accounts.
|
|
395
395
|
|
|
396
396
|
Approximation:
|
|
397
397
|
|
|
@@ -404,8 +404,8 @@ Quota remaining: window:percent|auth
|
|
|
404
404
|
1. 5h:20|7d:25|personal * [Plus · ready · refreshed 2h ago]
|
|
405
405
|
2. --|team [quota unknown]
|
|
406
406
|
|
|
407
|
-
[✅
|
|
408
|
-
[🔐
|
|
407
|
+
[✅ 20|25|personal] [✅]
|
|
408
|
+
[🔐 —|—|team] [✅]
|
|
409
409
|
[☑️ All] [Enabled] [Attention]
|
|
410
410
|
[🛡️ Access] [🔑 Login]
|
|
411
411
|
[🔄 Reload auth]
|
package/docs/zh/user-manual.md
CHANGED
|
@@ -233,7 +233,7 @@ TG_ALLOWED_TOPIC_ID=42
|
|
|
233
233
|
- `/status`:查看 FoxClaw、app-server、当前绑定线程、模型、权限和 Codex 用量摘要。多 bot 模式还会列出所有 bot 的连接、当前 auth、活动 turn,以及最近一次 auth 镜像和服务/Codex 升级结果。本地 session/Token/可见答复吞吐使用后台生成的历史快照,避免状态查询现场扫描大量日志;答复吞吐按完成轮次端到端耗时计算,排除推理 token,但包含等待与工具执行时间。
|
|
234
234
|
- `/account`:查看当前 Codex 登录账号。
|
|
235
235
|
- `/quota`:查看 Codex 用量和额度窗口。
|
|
236
|
-
- `/update`:升级 FoxClaw,并尝试升级 npm/pnpm 安装的 Codex CLI,然后自检和重启服务;任意 Telegram bot、启用的微信默认 runtime 或 auth 镜像写入不空闲时都会拒绝执行,重启后通过发起命令的 bot
|
|
236
|
+
- `/update`:升级 FoxClaw,并尝试升级 npm/pnpm 安装的 Codex CLI,然后自检和重启服务;任意 Telegram bot、启用的微信默认 runtime 或 auth 镜像写入不空闲时都会拒绝执行,重启后通过发起命令的 bot 回报 FoxClaw 与 Codex CLI 的版本变化。
|
|
237
237
|
|
|
238
238
|
### 3.3 `/config`、`/requirements`、`/provider`
|
|
239
239
|
|
|
@@ -391,7 +391,7 @@ cp -L ~/.codex/auth.json ~/.codex/auth.json_personal
|
|
|
391
391
|
|
|
392
392
|
`/auth` 会列出候选账号、当前账号和 auth 目录,并提供按钮切换、禁用、登录和重载。多 bot 模式中,面板顶部还会显示当前正在管理的 `@botname`,因为该 bot 内的私聊、群聊和话题共享同一个当前 auth。面板每页显示 8 个候选,支持翻页、`全部 / 已启用 / 需关注` 筛选和 `/auth list <关键词>` 文件名搜索,适合管理较大的本地候选清单。面板文本和按钮会省略标准候选文件名中重复的 `auth.json_` 前缀,例如磁盘上的 `auth.json_personal` 显示为 `personal`;文件本身不会重命名,搜索和命令仍按原候选工作。命令 `/auth use <n>` 的编号始终对应完整候选列表,不会因为分页变化。
|
|
393
393
|
|
|
394
|
-
|
|
394
|
+
文本列表中每个候选名前的 `窗口:剩余百分比` 来自最近一次观察到的真实额度窗口,例如 Plus 账号可能显示 `5h:20|7d:25`,只有一个月度窗口的账号可能显示 `30d:97`。按钮为了适配窄屏,只显示两个剩余百分比数字,例如 `20|25`;未知值显示为 `—`。当前 auth 会在打开面板时刷新额度;其他候选不会为了查询额度被自动切换。如果多个 bot runtime 最近使用过同一个 ChatGPT 账号,FoxClaw 会按已验证的账号 ID 合并它们缓存到的额度快照,因此一个 bot 的 `/auth` 面板可以显示另一个 bot 掌握到的额度信息,同时不会把不同账号混在一起。
|
|
395
395
|
|
|
396
396
|
示意:
|
|
397
397
|
|
|
@@ -404,8 +404,8 @@ Candidates: 2
|
|
|
404
404
|
1. 5h:20|7d:25|personal * [Plus · 正常 · 刷新于 2小时前]
|
|
405
405
|
2. --|team [额度未知]
|
|
406
406
|
|
|
407
|
-
[✅
|
|
408
|
-
[🔐
|
|
407
|
+
[✅ 20|25|personal] [✅]
|
|
408
|
+
[🔐 —|—|team] [✅]
|
|
409
409
|
[☑️ 全部] [已启用] [需关注]
|
|
410
410
|
[🛡️ Access] [🔑 设备登录]
|
|
411
411
|
[🔄 Reload auth]
|
package/package.json
CHANGED
package/skills/foxclaw/SKILL.md
CHANGED
|
@@ -67,7 +67,7 @@ Telegram behavior:
|
|
|
67
67
|
- when `TG_BOT_TOKENS` contains multiple bots, one FoxClaw service starts independent Codex app-servers and auth selections per bot
|
|
68
68
|
- isolated Telegram runtimes use independent `CODEX_HOME` directories and file-backed credentials; they do not share Codex sessions
|
|
69
69
|
- refreshed ChatGPT candidates are mirrored only after online usage-endpoint validation; before auth switch or reload, a runtime restores any newer same-account credential found in another Codex home
|
|
70
|
-
- `/auth` paginates large candidate inventories at 8 rows per page, supports all/enabled/attention filters and filename search, renders
|
|
70
|
+
- `/auth` paginates large candidate inventories at 8 rows per page, supports all/enabled/attention filters and filename search, renders actual observed quota windows in text rows, uses compact two-number remaining quota labels on buttons, and omits the repeated `auth.json_` prefix from panel labels without renaming files
|
|
71
71
|
- treat the `/auth` `not recently refreshed` state as a maintenance hint only: OpenAI does not publish a fixed ChatGPT refresh-token lifetime or replay grace period, and FoxClaw must not add routine bulk keepalive refreshes
|
|
72
72
|
- `/auth refresh all` remains a command-only maintenance action, not a panel button; it requires explicit token-rotation risk confirmation, then force-refreshes every ChatGPT candidate through Codex `account/read refreshToken=true`, validates usage, mirrors successful candidates, and restores the original current auth while every runtime is globally idle
|
|
73
73
|
- if `TG_BOT_TOKEN` is also set to one exact token from `TG_BOT_TOKENS`, that bot uses the default/shared-terminal runtime instead of an isolated Telegram home
|
|
@@ -205,7 +205,7 @@ When the user says development is complete, asks to "收尾", or asks to push/pu
|
|
|
205
205
|
- For macOS launchd, use the launchd install/start path from this skill and verify with `node dist/main.js status`.
|
|
206
206
|
- Verify the running service reports the expected FoxClaw version in `status`.
|
|
207
207
|
- If `doctor` fails only because `DEFAULT_CWD` is missing, report that separately; do not treat it as evidence that the service update failed.
|
|
208
|
-
- `/update` now attempts to update globally npm/pnpm-managed Codex CLI installations and refuses to restart while any configured Telegram runtime, enabled Weixin default runtime, or auth mirror write is busy.
|
|
208
|
+
- `/update` now attempts to update globally npm/pnpm-managed Codex CLI installations, reports FoxClaw and Codex CLI version changes, and refuses to restart while any configured Telegram runtime, enabled Weixin default runtime, or auth mirror write is busy.
|
|
209
209
|
7. Publish to npm when requested:
|
|
210
210
|
- Prefer GitHub Actions trusted publishing via `.github/workflows/publish.yml`: bump and commit the package version, push `main`, then push a matching `v<version>` tag. The tag version must match `package.json`.
|
|
211
211
|
- Ensure the matching changelog section exists before pushing the version tag; the publish workflow uses it to create or update the GitHub Release.
|