@foxden-app/foxclaw 0.5.60 → 0.5.62
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/.env.example +2 -2
- package/CHANGELOG.md +24 -0
- package/dist/config.js +1 -1
- package/dist/controller/controller.d.ts +2 -1
- package/dist/controller/controller.js +166 -30
- package/dist/i18n.d.ts +12 -0
- package/dist/i18n.js +12 -0
- package/package.json +1 -1
package/.env.example
CHANGED
|
@@ -38,9 +38,9 @@ TELEGRAM_PREVIEW_THROTTLE_MS=800
|
|
|
38
38
|
# Set to false if you prefer to keep "read files / edited files / ran command"
|
|
39
39
|
# detail cards in the chat history.
|
|
40
40
|
# TELEGRAM_DELETE_TOOL_DETAILS_AFTER_FINAL=true
|
|
41
|
-
# Delete time-sensitive interactive panels such as /auth and /threads after
|
|
41
|
+
# Delete time-sensitive interactive panels such as /auth, /setup, and /threads after 5 minutes.
|
|
42
42
|
# The timer restarts whenever the panel is refreshed. Set to 0 to disable.
|
|
43
|
-
# TELEGRAM_PANEL_TTL_MS=
|
|
43
|
+
# TELEGRAM_PANEL_TTL_MS=300000
|
|
44
44
|
THREAD_LIST_LIMIT=10
|
|
45
45
|
CODEX_CLI_BIN=/absolute/path/to/codex
|
|
46
46
|
|
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,30 @@
|
|
|
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.5.62 - 2026-06-22
|
|
6
|
+
|
|
7
|
+
### 中文
|
|
8
|
+
- 修复超长工具操作明细无法折叠或最终删除的问题:当 Telegram 拒绝编辑超长归档消息时,FoxClaw 会降级为短摘要,并仍登记原消息用于最终回复后的清理。
|
|
9
|
+
- 工具归档 details 现在会截短单条命令行,避免长 shell 命令触发 `MESSAGE_TOO_LONG` 后反复重试。
|
|
10
|
+
- 归档操作明细的 message id 会在登记时同步持久化,降低网络切换或重启窗口中丢失最终清理目标的概率。
|
|
11
|
+
|
|
12
|
+
### English
|
|
13
|
+
- Fixed oversized tool activity details failing to collapse or delete after the final reply. If Telegram rejects an oversized archive edit, FoxClaw now falls back to a short summary while still tracking the message for final cleanup.
|
|
14
|
+
- Tool archive details now truncate individual command lines to avoid repeated `MESSAGE_TOO_LONG` retries for long shell commands.
|
|
15
|
+
- Archived tool-detail message ids are persisted as soon as they are registered, reducing cleanup loss during network changes or restarts.
|
|
16
|
+
|
|
17
|
+
## 0.5.61 - 2026-06-21
|
|
18
|
+
|
|
19
|
+
### 中文
|
|
20
|
+
- 将 `/auth`、`/setup`、`/threads` 等交互面板的默认自动清理时间从 30 分钟改为 5 分钟,并把 `/where`、旧 model/access 设置面板和 `/config` 面板纳入同一类时效清理。
|
|
21
|
+
- `/config` 现在明确定位为 FoxClaw 自身设置面板,新增“最终回复后删除操作明细”开关;可通过按钮或 `/config delete_tool_details <on|off>` 修改,并写回 `TELEGRAM_DELETE_TOOL_DETAILS_AFTER_FINAL`。
|
|
22
|
+
- `/config` 展示当前 `TELEGRAM_DELETE_TOOL_DETAILS_AFTER_FINAL` 和 `TELEGRAM_PANEL_TTL_MS`,方便确认聊天清理策略是否生效。
|
|
23
|
+
|
|
24
|
+
### English
|
|
25
|
+
- Changed the default cleanup timeout for interactive panels such as `/auth`, `/setup`, and `/threads` from 30 minutes to 5 minutes, and applied the same stale-panel cleanup to `/where`, legacy model/access settings panels, and `/config`.
|
|
26
|
+
- `/config` is now the FoxClaw runtime settings panel and includes a "delete operation details after final reply" toggle. It can be changed via the button or `/config delete_tool_details <on|off>`, writing `TELEGRAM_DELETE_TOOL_DETAILS_AFTER_FINAL`.
|
|
27
|
+
- `/config` shows the current `TELEGRAM_DELETE_TOOL_DETAILS_AFTER_FINAL` and `TELEGRAM_PANEL_TTL_MS` values so cleanup behavior is visible.
|
|
28
|
+
|
|
5
29
|
## 0.5.60 - 2026-06-21
|
|
6
30
|
|
|
7
31
|
### 中文
|
package/dist/config.js
CHANGED
|
@@ -78,7 +78,7 @@ export function loadConfig() {
|
|
|
78
78
|
telegramPollIntervalMs: intEnv('TELEGRAM_POLL_INTERVAL_MS', 1200),
|
|
79
79
|
telegramPreviewThrottleMs: intEnv('TELEGRAM_PREVIEW_THROTTLE_MS', 800),
|
|
80
80
|
telegramDeleteToolDetailsAfterFinal: boolEnv('TELEGRAM_DELETE_TOOL_DETAILS_AFTER_FINAL', true),
|
|
81
|
-
telegramPanelTtlMs: intEnv('TELEGRAM_PANEL_TTL_MS',
|
|
81
|
+
telegramPanelTtlMs: intEnv('TELEGRAM_PANEL_TTL_MS', 5 * 60_000),
|
|
82
82
|
threadListLimit: intEnv('THREAD_LIST_LIMIT', 10),
|
|
83
83
|
statusPath: DEFAULT_STATUS_PATH,
|
|
84
84
|
logPath: DEFAULT_LOG_PATH,
|
|
@@ -352,7 +352,7 @@ export declare class BridgeSessionCore {
|
|
|
352
352
|
private handleFeaturesCommand;
|
|
353
353
|
private handleConfigCommand;
|
|
354
354
|
private handleConfigToggleCallback;
|
|
355
|
-
private
|
|
355
|
+
private setFoxClawBooleanConfig;
|
|
356
356
|
private formatConfigToggleUpdate;
|
|
357
357
|
private handleRequirementsCommand;
|
|
358
358
|
private handleProviderCommand;
|
|
@@ -464,6 +464,7 @@ export declare class BridgeSessionCore {
|
|
|
464
464
|
private ensureStatusMessage;
|
|
465
465
|
private rebaseStatusMessage;
|
|
466
466
|
private archiveStatusMessage;
|
|
467
|
+
private recordArchivedMessageId;
|
|
467
468
|
private noteToolCommandStart;
|
|
468
469
|
private noteToolCommandEnd;
|
|
469
470
|
private scheduleToolBatchArchive;
|
|
@@ -28,6 +28,8 @@ import { renderActiveTurnStatus } from './status.js';
|
|
|
28
28
|
import { writeRuntimeStatus } from '../runtime.js';
|
|
29
29
|
const AUTH_DELETE_REASON_NEEDS_REPAIR = 'needs_repair';
|
|
30
30
|
const RESTART_PREVIEW_RECOVERY_RETRY_DELAYS_MS = [3000, 7000, 15_000, 30_000, 45_000, 60_000, 60_000, 60_000];
|
|
31
|
+
const TOOL_ARCHIVE_MAX_LINES = 12;
|
|
32
|
+
const TOOL_ARCHIVE_LINE_LIMIT = 240;
|
|
31
33
|
class UserFacingError extends Error {
|
|
32
34
|
}
|
|
33
35
|
const OBSERVED_THREAD_POLL_MS = 1500;
|
|
@@ -1088,9 +1090,9 @@ export class BridgeSessionCore {
|
|
|
1088
1090
|
await this.handleSetupCallback(event, setupMatch[1], setupMatch[2], locale);
|
|
1089
1091
|
return;
|
|
1090
1092
|
}
|
|
1091
|
-
const configMatch = /^config:auth_auto_delete:(on|off)$/.exec(event.data);
|
|
1093
|
+
const configMatch = /^config:(auth_auto_delete|delete_tool_details):(on|off)$/.exec(event.data);
|
|
1092
1094
|
if (configMatch) {
|
|
1093
|
-
await this.handleConfigToggleCallback(event, configMatch[1] === 'on', locale);
|
|
1095
|
+
await this.handleConfigToggleCallback(event, configMatch[1], configMatch[2] === 'on', locale);
|
|
1094
1096
|
return;
|
|
1095
1097
|
}
|
|
1096
1098
|
const voiceMatch = /^voice:([a-f0-9]+)$/.exec(event.data);
|
|
@@ -5583,46 +5585,73 @@ export class BridgeSessionCore {
|
|
|
5583
5585
|
await this.sendMessage(scopeId, t(locale, 'config_auth_auto_delete_usage'));
|
|
5584
5586
|
return;
|
|
5585
5587
|
}
|
|
5586
|
-
const update = await this.
|
|
5588
|
+
const update = await this.setFoxClawBooleanConfig('auth_auto_delete', enabled);
|
|
5587
5589
|
const binding = this.store.getBinding(scopeId);
|
|
5588
5590
|
const result = await this.app.readConfig(binding?.cwd ?? this.config.defaultCwd, true);
|
|
5589
|
-
await this.sendMessage(scopeId, `${this.formatConfigToggleUpdate(locale, update)}\n\n${formatConfigMessage(locale, result, this.config, this.store.getCodexAuthPoolStats())}`, configKeyboard(locale, this.config));
|
|
5591
|
+
const sentMessageId = await this.sendMessage(scopeId, `${this.formatConfigToggleUpdate(locale, update)}\n\n${formatConfigMessage(locale, result, this.config, this.store.getCodexAuthPoolStats())}`, configKeyboard(locale, this.config));
|
|
5592
|
+
this.scheduleStalePanelDeletion(scopeId, sentMessageId);
|
|
5593
|
+
return;
|
|
5594
|
+
}
|
|
5595
|
+
if (['delete_tool_details', 'delete-tool-details', 'tool_details', 'tool-details'].includes(action)) {
|
|
5596
|
+
const enabled = parseConfigBooleanArg(args[1]);
|
|
5597
|
+
if (enabled === null) {
|
|
5598
|
+
await this.sendMessage(scopeId, t(locale, 'config_delete_tool_details_usage'));
|
|
5599
|
+
return;
|
|
5600
|
+
}
|
|
5601
|
+
const update = await this.setFoxClawBooleanConfig('delete_tool_details', enabled);
|
|
5602
|
+
const binding = this.store.getBinding(scopeId);
|
|
5603
|
+
const result = await this.app.readConfig(binding?.cwd ?? this.config.defaultCwd, true);
|
|
5604
|
+
const sentMessageId = await this.sendMessage(scopeId, `${this.formatConfigToggleUpdate(locale, update)}\n\n${formatConfigMessage(locale, result, this.config, this.store.getCodexAuthPoolStats())}`, configKeyboard(locale, this.config));
|
|
5605
|
+
this.scheduleStalePanelDeletion(scopeId, sentMessageId);
|
|
5590
5606
|
return;
|
|
5591
5607
|
}
|
|
5592
5608
|
const binding = this.store.getBinding(scopeId);
|
|
5593
5609
|
const result = await this.app.readConfig(binding?.cwd ?? this.config.defaultCwd, true);
|
|
5594
|
-
await this.sendMessage(scopeId, formatConfigMessage(locale, result, this.config, this.store.getCodexAuthPoolStats()), configKeyboard(locale, this.config));
|
|
5610
|
+
const sentMessageId = await this.sendMessage(scopeId, formatConfigMessage(locale, result, this.config, this.store.getCodexAuthPoolStats()), configKeyboard(locale, this.config));
|
|
5611
|
+
this.scheduleStalePanelDeletion(scopeId, sentMessageId);
|
|
5595
5612
|
}
|
|
5596
|
-
async handleConfigToggleCallback(event, enabled, locale) {
|
|
5597
|
-
const update = await this.
|
|
5613
|
+
async handleConfigToggleCallback(event, key, enabled, locale) {
|
|
5614
|
+
const update = await this.setFoxClawBooleanConfig(key, enabled);
|
|
5598
5615
|
await this.messaging.answerCallback(event.callbackQueryId, t(locale, 'decision_recorded'));
|
|
5599
5616
|
const binding = this.store.getBinding(event.scopeId);
|
|
5600
5617
|
const result = await this.app.readConfig(binding?.cwd ?? this.config.defaultCwd, true);
|
|
5601
5618
|
const message = `${this.formatConfigToggleUpdate(locale, update)}\n\n${formatConfigMessage(locale, result, this.config, this.store.getCodexAuthPoolStats())}`;
|
|
5602
5619
|
if (event.messageId !== null) {
|
|
5603
5620
|
await this.editMessage(event.scopeId, event.messageId, message, configKeyboard(locale, this.config));
|
|
5621
|
+
this.scheduleStalePanelDeletion(event.scopeId, event.messageId);
|
|
5604
5622
|
}
|
|
5605
5623
|
else {
|
|
5606
|
-
await this.sendMessage(event.scopeId, message, configKeyboard(locale, this.config));
|
|
5624
|
+
const sentMessageId = await this.sendMessage(event.scopeId, message, configKeyboard(locale, this.config));
|
|
5625
|
+
this.scheduleStalePanelDeletion(event.scopeId, sentMessageId);
|
|
5607
5626
|
}
|
|
5608
5627
|
}
|
|
5609
|
-
async
|
|
5610
|
-
|
|
5628
|
+
async setFoxClawBooleanConfig(key, enabled) {
|
|
5629
|
+
const envKey = key === 'auth_auto_delete'
|
|
5630
|
+
? 'AUTH_AUTO_DELETE_NEEDS_REPAIR'
|
|
5631
|
+
: 'TELEGRAM_DELETE_TOOL_DETAILS_AFTER_FINAL';
|
|
5632
|
+
if (key === 'auth_auto_delete') {
|
|
5633
|
+
this.config.authAutoDeleteNeedsRepair = enabled;
|
|
5634
|
+
}
|
|
5635
|
+
else {
|
|
5636
|
+
this.config.telegramDeleteToolDetailsAfterFinal = enabled;
|
|
5637
|
+
}
|
|
5611
5638
|
const envPath = this.config.envPath;
|
|
5612
5639
|
if (!envPath) {
|
|
5613
|
-
return { enabled, envPath: null, envUpdated: false, envError: null };
|
|
5640
|
+
return { key, enabled, envKey, envPath: null, envUpdated: false, envError: null };
|
|
5614
5641
|
}
|
|
5615
5642
|
try {
|
|
5616
|
-
await writeEnvBoolean(envPath,
|
|
5617
|
-
return { enabled, envPath, envUpdated: true, envError: null };
|
|
5643
|
+
await writeEnvBoolean(envPath, envKey, enabled);
|
|
5644
|
+
return { key, enabled, envKey, envPath, envUpdated: true, envError: null };
|
|
5618
5645
|
}
|
|
5619
5646
|
catch (error) {
|
|
5620
|
-
this.logger.warn('config.env_update_failed', { key:
|
|
5621
|
-
return { enabled, envPath, envUpdated: false, envError: formatUserError(error) };
|
|
5647
|
+
this.logger.warn('config.env_update_failed', { key: envKey, envPath, error: toErrorMeta(error) });
|
|
5648
|
+
return { key, enabled, envKey, envPath, envUpdated: false, envError: formatUserError(error) };
|
|
5622
5649
|
}
|
|
5623
5650
|
}
|
|
5624
5651
|
formatConfigToggleUpdate(locale, update) {
|
|
5625
|
-
const lines = [t(locale, '
|
|
5652
|
+
const lines = [t(locale, update.key === 'auth_auto_delete' ? 'config_auth_auto_delete_updated' : 'config_delete_tool_details_updated', {
|
|
5653
|
+
value: t(locale, update.enabled ? 'yes' : 'no'),
|
|
5654
|
+
})];
|
|
5626
5655
|
if (update.envError) {
|
|
5627
5656
|
lines.push(t(locale, 'config_env_update_failed', { value: update.envPath ?? t(locale, 'unknown'), error: update.envError }));
|
|
5628
5657
|
}
|
|
@@ -7207,9 +7236,11 @@ export class BridgeSessionCore {
|
|
|
7207
7236
|
}
|
|
7208
7237
|
if (messageId !== undefined) {
|
|
7209
7238
|
await this.editMessage(scopeId, messageId, text, whereKeyboard(locale, false));
|
|
7239
|
+
this.scheduleStalePanelDeletion(scopeId, messageId);
|
|
7210
7240
|
return;
|
|
7211
7241
|
}
|
|
7212
|
-
await this.sendMessage(scopeId, text, whereKeyboard(locale, false));
|
|
7242
|
+
const sentMessageId = await this.sendMessage(scopeId, text, whereKeyboard(locale, false));
|
|
7243
|
+
this.scheduleStalePanelDeletion(scopeId, sentMessageId);
|
|
7213
7244
|
return;
|
|
7214
7245
|
}
|
|
7215
7246
|
const readyBinding = await this.ensureThreadReady(scopeId, binding);
|
|
@@ -7221,9 +7252,11 @@ export class BridgeSessionCore {
|
|
|
7221
7252
|
}
|
|
7222
7253
|
if (messageId !== undefined) {
|
|
7223
7254
|
await this.editMessage(scopeId, messageId, text, whereKeyboard(locale, false));
|
|
7255
|
+
this.scheduleStalePanelDeletion(scopeId, messageId);
|
|
7224
7256
|
return;
|
|
7225
7257
|
}
|
|
7226
|
-
await this.sendMessage(scopeId, text, whereKeyboard(locale, false));
|
|
7258
|
+
const sentMessageId = await this.sendMessage(scopeId, text, whereKeyboard(locale, false));
|
|
7259
|
+
this.scheduleStalePanelDeletion(scopeId, sentMessageId);
|
|
7227
7260
|
return;
|
|
7228
7261
|
}
|
|
7229
7262
|
let text = formatWhereMessage(locale, thread, settings, this.config.defaultCwd, access, fastStatus);
|
|
@@ -7232,9 +7265,11 @@ export class BridgeSessionCore {
|
|
|
7232
7265
|
}
|
|
7233
7266
|
if (messageId !== undefined) {
|
|
7234
7267
|
await this.editMessage(scopeId, messageId, text, whereKeyboard(locale, true));
|
|
7268
|
+
this.scheduleStalePanelDeletion(scopeId, messageId);
|
|
7235
7269
|
return;
|
|
7236
7270
|
}
|
|
7237
|
-
await this.sendMessage(scopeId, text, whereKeyboard(locale, true));
|
|
7271
|
+
const sentMessageId = await this.sendMessage(scopeId, text, whereKeyboard(locale, true));
|
|
7272
|
+
this.scheduleStalePanelDeletion(scopeId, sentMessageId);
|
|
7238
7273
|
}
|
|
7239
7274
|
async handleThreadListNavigationCallback(event, action, locale) {
|
|
7240
7275
|
const state = this.threadListPresentationState.get(event.scopeId) ?? {
|
|
@@ -7342,9 +7377,11 @@ export class BridgeSessionCore {
|
|
|
7342
7377
|
const keyboard = buildModelSettingsKeyboard(locale, models, settings);
|
|
7343
7378
|
if (messageId !== undefined) {
|
|
7344
7379
|
await this.editHtmlMessage(scopeId, messageId, text, keyboard);
|
|
7380
|
+
this.scheduleStalePanelDeletion(scopeId, messageId);
|
|
7345
7381
|
return;
|
|
7346
7382
|
}
|
|
7347
|
-
await this.sendHtmlMessage(scopeId, text, keyboard);
|
|
7383
|
+
const sentMessageId = await this.sendHtmlMessage(scopeId, text, keyboard);
|
|
7384
|
+
this.scheduleStalePanelDeletion(scopeId, sentMessageId);
|
|
7348
7385
|
}
|
|
7349
7386
|
async showSetupPanel(scopeId, focus, messageId, locale = this.localeForChat(scopeId)) {
|
|
7350
7387
|
const models = await this.app.listModels();
|
|
@@ -7375,9 +7412,11 @@ export class BridgeSessionCore {
|
|
|
7375
7412
|
const keyboard = buildAccessSettingsKeyboard(locale, access);
|
|
7376
7413
|
if (messageId !== undefined) {
|
|
7377
7414
|
await this.editHtmlMessage(scopeId, messageId, text, keyboard);
|
|
7415
|
+
this.scheduleStalePanelDeletion(scopeId, messageId);
|
|
7378
7416
|
return;
|
|
7379
7417
|
}
|
|
7380
|
-
await this.sendHtmlMessage(scopeId, text, keyboard);
|
|
7418
|
+
const sentMessageId = await this.sendHtmlMessage(scopeId, text, keyboard);
|
|
7419
|
+
this.scheduleStalePanelDeletion(scopeId, sentMessageId);
|
|
7381
7420
|
}
|
|
7382
7421
|
async handleSettingsCallback(event, kind, rawValue, locale) {
|
|
7383
7422
|
await this.handleSetupCallback(event, kind, rawValue, locale);
|
|
@@ -8138,11 +8177,23 @@ export class BridgeSessionCore {
|
|
|
8138
8177
|
messageId = await this.sendMessage(active.scopeId, content.text);
|
|
8139
8178
|
}
|
|
8140
8179
|
if (messageId !== null) {
|
|
8141
|
-
|
|
8180
|
+
this.recordArchivedMessageId(active, messageId);
|
|
8142
8181
|
}
|
|
8143
8182
|
}
|
|
8144
8183
|
catch (error) {
|
|
8145
|
-
|
|
8184
|
+
if (isTelegramMessageTooLong(error)) {
|
|
8185
|
+
try {
|
|
8186
|
+
const messageId = await this.sendMessage(active.scopeId, firstLine(content.text));
|
|
8187
|
+
this.recordArchivedMessageId(active, messageId);
|
|
8188
|
+
return true;
|
|
8189
|
+
}
|
|
8190
|
+
catch (fallbackError) {
|
|
8191
|
+
this.logger.warn('telegram.preview_archive_fallback_send_failed', { error: String(fallbackError), turnId: active.turnId });
|
|
8192
|
+
}
|
|
8193
|
+
}
|
|
8194
|
+
else {
|
|
8195
|
+
this.logger.warn('telegram.preview_archive_send_failed', { error: String(error), turnId: active.turnId });
|
|
8196
|
+
}
|
|
8146
8197
|
this.scheduleRenderRetry(active);
|
|
8147
8198
|
return false;
|
|
8148
8199
|
}
|
|
@@ -8155,7 +8206,7 @@ export class BridgeSessionCore {
|
|
|
8155
8206
|
else {
|
|
8156
8207
|
await this.editMessage(active.scopeId, active.previewMessageId, content.text, []);
|
|
8157
8208
|
}
|
|
8158
|
-
|
|
8209
|
+
this.recordArchivedMessageId(active, active.previewMessageId);
|
|
8159
8210
|
}
|
|
8160
8211
|
catch (error) {
|
|
8161
8212
|
if (isTelegramMessageGone(error)) {
|
|
@@ -8165,6 +8216,37 @@ export class BridgeSessionCore {
|
|
|
8165
8216
|
this.store.removeActiveTurnPreview(active.turnId);
|
|
8166
8217
|
return this.archiveStatusMessage(active, content);
|
|
8167
8218
|
}
|
|
8219
|
+
if (isTelegramMessageTooLong(error)) {
|
|
8220
|
+
try {
|
|
8221
|
+
await this.editMessage(active.scopeId, active.previewMessageId, firstLine(content.text), []);
|
|
8222
|
+
this.recordArchivedMessageId(active, active.previewMessageId);
|
|
8223
|
+
active.previewActive = false;
|
|
8224
|
+
active.statusMessageText = null;
|
|
8225
|
+
active.statusNeedsRebase = false;
|
|
8226
|
+
this.store.removeActiveTurnPreview(active.turnId);
|
|
8227
|
+
return true;
|
|
8228
|
+
}
|
|
8229
|
+
catch (fallbackError) {
|
|
8230
|
+
if (isTelegramMessageGone(fallbackError)) {
|
|
8231
|
+
active.previewActive = false;
|
|
8232
|
+
active.statusMessageText = null;
|
|
8233
|
+
active.statusNeedsRebase = false;
|
|
8234
|
+
this.store.removeActiveTurnPreview(active.turnId);
|
|
8235
|
+
return this.archiveStatusMessage(active, { text: firstLine(content.text), html: null });
|
|
8236
|
+
}
|
|
8237
|
+
this.logger.warn('telegram.preview_archive_fallback_failed', {
|
|
8238
|
+
error: String(fallbackError),
|
|
8239
|
+
turnId: active.turnId,
|
|
8240
|
+
messageId: active.previewMessageId,
|
|
8241
|
+
});
|
|
8242
|
+
this.recordArchivedMessageId(active, active.previewMessageId);
|
|
8243
|
+
active.previewActive = false;
|
|
8244
|
+
active.statusMessageText = null;
|
|
8245
|
+
active.statusNeedsRebase = false;
|
|
8246
|
+
this.store.removeActiveTurnPreview(active.turnId);
|
|
8247
|
+
return true;
|
|
8248
|
+
}
|
|
8249
|
+
}
|
|
8168
8250
|
this.logger.warn('telegram.preview_archive_failed', {
|
|
8169
8251
|
error: String(error),
|
|
8170
8252
|
turnId: active.turnId,
|
|
@@ -8179,6 +8261,21 @@ export class BridgeSessionCore {
|
|
|
8179
8261
|
this.store.removeActiveTurnPreview(active.turnId);
|
|
8180
8262
|
return true;
|
|
8181
8263
|
}
|
|
8264
|
+
recordArchivedMessageId(active, messageId) {
|
|
8265
|
+
if (!active.archivedMessageIds.includes(messageId)) {
|
|
8266
|
+
active.archivedMessageIds.push(messageId);
|
|
8267
|
+
}
|
|
8268
|
+
if (active.previewActive && active.previewMessageId > 0) {
|
|
8269
|
+
this.store.saveActiveTurnPreview({
|
|
8270
|
+
turnId: active.turnId,
|
|
8271
|
+
scopeId: active.scopeId,
|
|
8272
|
+
threadId: active.threadId,
|
|
8273
|
+
messageId: active.previewMessageId,
|
|
8274
|
+
isObserved: active.isObserved,
|
|
8275
|
+
archivedMessageIds: active.archivedMessageIds,
|
|
8276
|
+
});
|
|
8277
|
+
}
|
|
8278
|
+
}
|
|
8182
8279
|
noteToolCommandStart(active, event) {
|
|
8183
8280
|
if (!active.toolBatch) {
|
|
8184
8281
|
active.toolBatch = createToolBatchState();
|
|
@@ -8615,9 +8712,12 @@ function renderArchivedToolBatchStatus(locale, counts, actionLines) {
|
|
|
8615
8712
|
return { text, html: null };
|
|
8616
8713
|
}
|
|
8617
8714
|
const heading = formatToolBatchHeading(locale, counts, false);
|
|
8715
|
+
const detailLines = actionLines
|
|
8716
|
+
.slice(0, TOOL_ARCHIVE_MAX_LINES)
|
|
8717
|
+
.map(line => truncateInline(line, TOOL_ARCHIVE_LINE_LIMIT));
|
|
8618
8718
|
const html = [
|
|
8619
8719
|
telegramBold(heading),
|
|
8620
|
-
telegramExpandableBlockquote(
|
|
8720
|
+
telegramExpandableBlockquote(detailLines.join('\n')),
|
|
8621
8721
|
].join('\n');
|
|
8622
8722
|
return { text, html };
|
|
8623
8723
|
}
|
|
@@ -8766,6 +8866,9 @@ function truncateInline(value, limit) {
|
|
|
8766
8866
|
}
|
|
8767
8867
|
return `${value.slice(0, Math.max(0, limit - 1))}…`;
|
|
8768
8868
|
}
|
|
8869
|
+
function firstLine(value) {
|
|
8870
|
+
return value.split(/\r?\n/, 1)[0]?.trim() || value.trim();
|
|
8871
|
+
}
|
|
8769
8872
|
function parseReviewTarget(args) {
|
|
8770
8873
|
if (args.length === 0) {
|
|
8771
8874
|
return { type: 'uncommittedChanges' };
|
|
@@ -9359,6 +9462,12 @@ function formatConfigMessage(locale, result, appConfig, authPoolStats) {
|
|
|
9359
9462
|
value: t(locale, appConfig.authAutoDeleteNeedsRepair ? 'yes' : 'no'),
|
|
9360
9463
|
}));
|
|
9361
9464
|
lines.push(`AUTH_AUTO_DELETE_NEEDS_REPAIR=${appConfig.authAutoDeleteNeedsRepair ? 'true' : 'false'}`);
|
|
9465
|
+
lines.push(t(locale, 'config_delete_tool_details_after_final', {
|
|
9466
|
+
value: t(locale, appConfig.telegramDeleteToolDetailsAfterFinal ? 'yes' : 'no'),
|
|
9467
|
+
}));
|
|
9468
|
+
lines.push(`TELEGRAM_DELETE_TOOL_DETAILS_AFTER_FINAL=${appConfig.telegramDeleteToolDetailsAfterFinal ? 'true' : 'false'}`);
|
|
9469
|
+
lines.push(t(locale, 'config_panel_ttl', { value: formatDurationMs(locale, appConfig.telegramPanelTtlMs) }));
|
|
9470
|
+
lines.push(`TELEGRAM_PANEL_TTL_MS=${appConfig.telegramPanelTtlMs}`);
|
|
9362
9471
|
lines.push(formatCodexAuthPoolSummary(locale, authPoolStats));
|
|
9363
9472
|
return lines.join('\n');
|
|
9364
9473
|
}
|
|
@@ -9373,11 +9482,32 @@ function isInvalidCodexAuthDeleteReason(reason) {
|
|
|
9373
9482
|
return reason === AUTH_DELETE_REASON_NEEDS_REPAIR;
|
|
9374
9483
|
}
|
|
9375
9484
|
function configKeyboard(locale, appConfig) {
|
|
9376
|
-
const
|
|
9377
|
-
|
|
9378
|
-
|
|
9379
|
-
|
|
9380
|
-
|
|
9485
|
+
const authAutoDeleteEnabled = appConfig.authAutoDeleteNeedsRepair;
|
|
9486
|
+
const deleteToolDetailsEnabled = appConfig.telegramDeleteToolDetailsAfterFinal;
|
|
9487
|
+
return [
|
|
9488
|
+
[{
|
|
9489
|
+
text: t(locale, authAutoDeleteEnabled ? 'button_config_auth_auto_delete_off' : 'button_config_auth_auto_delete_on'),
|
|
9490
|
+
callback_data: `config:auth_auto_delete:${authAutoDeleteEnabled ? 'off' : 'on'}`,
|
|
9491
|
+
}],
|
|
9492
|
+
[{
|
|
9493
|
+
text: t(locale, deleteToolDetailsEnabled ? 'button_config_delete_tool_details_off' : 'button_config_delete_tool_details_on'),
|
|
9494
|
+
callback_data: `config:delete_tool_details:${deleteToolDetailsEnabled ? 'off' : 'on'}`,
|
|
9495
|
+
}],
|
|
9496
|
+
];
|
|
9497
|
+
}
|
|
9498
|
+
function formatDurationMs(locale, value) {
|
|
9499
|
+
if (value <= 0) {
|
|
9500
|
+
return locale === 'zh' ? '关闭' : 'disabled';
|
|
9501
|
+
}
|
|
9502
|
+
if (value % 60_000 === 0) {
|
|
9503
|
+
const minutes = value / 60_000;
|
|
9504
|
+
return locale === 'zh' ? `${minutes} 分钟` : `${minutes} min`;
|
|
9505
|
+
}
|
|
9506
|
+
if (value % 1000 === 0) {
|
|
9507
|
+
const seconds = value / 1000;
|
|
9508
|
+
return locale === 'zh' ? `${seconds} 秒` : `${seconds} sec`;
|
|
9509
|
+
}
|
|
9510
|
+
return `${value}ms`;
|
|
9381
9511
|
}
|
|
9382
9512
|
function parseConfigBooleanArg(value) {
|
|
9383
9513
|
const normalized = value?.trim().toLowerCase();
|
|
@@ -11342,6 +11472,12 @@ function isTelegramMessageGone(error) {
|
|
|
11342
11472
|
|| message.includes('message to edit not found')
|
|
11343
11473
|
|| message.includes('message not found');
|
|
11344
11474
|
}
|
|
11475
|
+
function isTelegramMessageTooLong(error) {
|
|
11476
|
+
const message = formatUserError(error).toLowerCase();
|
|
11477
|
+
return message.includes('message_too_long')
|
|
11478
|
+
|| message.includes('message is too long')
|
|
11479
|
+
|| message.includes('message too long');
|
|
11480
|
+
}
|
|
11345
11481
|
function isFileMissingError(error) {
|
|
11346
11482
|
return error instanceof Error && /enoent|no such file or directory/i.test(error.message);
|
|
11347
11483
|
}
|
package/dist/i18n.d.ts
CHANGED
|
@@ -282,6 +282,8 @@ declare const MESSAGES: {
|
|
|
282
282
|
readonly button_auth_filter_attention: "Attention";
|
|
283
283
|
readonly button_config_auth_auto_delete_on: "Auto-delete on";
|
|
284
284
|
readonly button_config_auth_auto_delete_off: "Auto-delete off";
|
|
285
|
+
readonly button_config_delete_tool_details_on: "Delete tool details";
|
|
286
|
+
readonly button_config_delete_tool_details_off: "Keep tool details";
|
|
285
287
|
readonly another_turn_running: "Another turn is already running. Use /interrupt, /takeover, /queue, or wait.";
|
|
286
288
|
readonly working: "Working...";
|
|
287
289
|
readonly usage_open: "Usage: /open <n>";
|
|
@@ -617,6 +619,10 @@ declare const MESSAGES: {
|
|
|
617
619
|
readonly config_auth_auto_delete_needs_repair: "Auto-delete unrecoverable auth candidates: {value}";
|
|
618
620
|
readonly config_auth_auto_delete_updated: "Auto-delete unrecoverable auth candidates set to: {value}";
|
|
619
621
|
readonly config_auth_auto_delete_usage: "Usage: /config auth_auto_delete <on|off>";
|
|
622
|
+
readonly config_delete_tool_details_after_final: "Delete operation details after final reply: {value}";
|
|
623
|
+
readonly config_delete_tool_details_updated: "Delete operation details after final reply set to: {value}";
|
|
624
|
+
readonly config_delete_tool_details_usage: "Usage: /config delete_tool_details <on|off>";
|
|
625
|
+
readonly config_panel_ttl: "Interactive panel cleanup: {value}";
|
|
620
626
|
readonly config_env_update_failed: "Runtime setting changed, but updating {value} failed: {error}";
|
|
621
627
|
readonly requirements_title: "Config requirements";
|
|
622
628
|
readonly requirements_empty: "No config requirements are configured.";
|
|
@@ -982,6 +988,8 @@ declare const MESSAGES: {
|
|
|
982
988
|
readonly button_auth_filter_attention: "需关注";
|
|
983
989
|
readonly button_config_auth_auto_delete_on: "开启自动剔除";
|
|
984
990
|
readonly button_config_auth_auto_delete_off: "关闭自动剔除";
|
|
991
|
+
readonly button_config_delete_tool_details_on: "删除操作明细";
|
|
992
|
+
readonly button_config_delete_tool_details_off: "保留操作明细";
|
|
985
993
|
readonly another_turn_running: "已经有一个回复在进行中。请先等待,或使用 /interrupt、/takeover、/queue。";
|
|
986
994
|
readonly working: "处理中...";
|
|
987
995
|
readonly usage_open: "用法:/open <编号>";
|
|
@@ -1317,6 +1325,10 @@ declare const MESSAGES: {
|
|
|
1317
1325
|
readonly config_auth_auto_delete_needs_repair: "自动剔除无法恢复的 auth 候选:{value}";
|
|
1318
1326
|
readonly config_auth_auto_delete_updated: "自动剔除无法恢复的 auth 候选已设置为:{value}";
|
|
1319
1327
|
readonly config_auth_auto_delete_usage: "用法:/config auth_auto_delete <on|off>";
|
|
1328
|
+
readonly config_delete_tool_details_after_final: "最终回复后删除操作明细:{value}";
|
|
1329
|
+
readonly config_delete_tool_details_updated: "最终回复后删除操作明细已设置为:{value}";
|
|
1330
|
+
readonly config_delete_tool_details_usage: "用法:/config delete_tool_details <on|off>";
|
|
1331
|
+
readonly config_panel_ttl: "交互面板自动清理:{value}";
|
|
1320
1332
|
readonly config_env_update_failed: "运行时设置已改变,但更新 {value} 失败:{error}";
|
|
1321
1333
|
readonly requirements_title: "配置要求";
|
|
1322
1334
|
readonly requirements_empty: "当前没有配置要求。";
|
package/dist/i18n.js
CHANGED
|
@@ -280,6 +280,8 @@ const MESSAGES = {
|
|
|
280
280
|
button_auth_filter_attention: 'Attention',
|
|
281
281
|
button_config_auth_auto_delete_on: 'Auto-delete on',
|
|
282
282
|
button_config_auth_auto_delete_off: 'Auto-delete off',
|
|
283
|
+
button_config_delete_tool_details_on: 'Delete tool details',
|
|
284
|
+
button_config_delete_tool_details_off: 'Keep tool details',
|
|
283
285
|
another_turn_running: 'Another turn is already running. Use /interrupt, /takeover, /queue, or wait.',
|
|
284
286
|
working: 'Working...',
|
|
285
287
|
usage_open: 'Usage: /open <n>',
|
|
@@ -615,6 +617,10 @@ const MESSAGES = {
|
|
|
615
617
|
config_auth_auto_delete_needs_repair: 'Auto-delete unrecoverable auth candidates: {value}',
|
|
616
618
|
config_auth_auto_delete_updated: 'Auto-delete unrecoverable auth candidates set to: {value}',
|
|
617
619
|
config_auth_auto_delete_usage: 'Usage: /config auth_auto_delete <on|off>',
|
|
620
|
+
config_delete_tool_details_after_final: 'Delete operation details after final reply: {value}',
|
|
621
|
+
config_delete_tool_details_updated: 'Delete operation details after final reply set to: {value}',
|
|
622
|
+
config_delete_tool_details_usage: 'Usage: /config delete_tool_details <on|off>',
|
|
623
|
+
config_panel_ttl: 'Interactive panel cleanup: {value}',
|
|
618
624
|
config_env_update_failed: 'Runtime setting changed, but updating {value} failed: {error}',
|
|
619
625
|
requirements_title: 'Config requirements',
|
|
620
626
|
requirements_empty: 'No config requirements are configured.',
|
|
@@ -980,6 +986,8 @@ const MESSAGES = {
|
|
|
980
986
|
button_auth_filter_attention: '需关注',
|
|
981
987
|
button_config_auth_auto_delete_on: '开启自动剔除',
|
|
982
988
|
button_config_auth_auto_delete_off: '关闭自动剔除',
|
|
989
|
+
button_config_delete_tool_details_on: '删除操作明细',
|
|
990
|
+
button_config_delete_tool_details_off: '保留操作明细',
|
|
983
991
|
another_turn_running: '已经有一个回复在进行中。请先等待,或使用 /interrupt、/takeover、/queue。',
|
|
984
992
|
working: '处理中...',
|
|
985
993
|
usage_open: '用法:/open <编号>',
|
|
@@ -1315,6 +1323,10 @@ const MESSAGES = {
|
|
|
1315
1323
|
config_auth_auto_delete_needs_repair: '自动剔除无法恢复的 auth 候选:{value}',
|
|
1316
1324
|
config_auth_auto_delete_updated: '自动剔除无法恢复的 auth 候选已设置为:{value}',
|
|
1317
1325
|
config_auth_auto_delete_usage: '用法:/config auth_auto_delete <on|off>',
|
|
1326
|
+
config_delete_tool_details_after_final: '最终回复后删除操作明细:{value}',
|
|
1327
|
+
config_delete_tool_details_updated: '最终回复后删除操作明细已设置为:{value}',
|
|
1328
|
+
config_delete_tool_details_usage: '用法:/config delete_tool_details <on|off>',
|
|
1329
|
+
config_panel_ttl: '交互面板自动清理:{value}',
|
|
1318
1330
|
config_env_update_failed: '运行时设置已改变,但更新 {value} 失败:{error}',
|
|
1319
1331
|
requirements_title: '配置要求',
|
|
1320
1332
|
requirements_empty: '当前没有配置要求。',
|