@foxden-app/foxclaw 0.5.61 → 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/CHANGELOG.md +12 -0
- package/dist/controller/controller.d.ts +1 -0
- package/dist/controller/controller.js +76 -4
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,18 @@
|
|
|
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
|
+
|
|
5
17
|
## 0.5.61 - 2026-06-21
|
|
6
18
|
|
|
7
19
|
### 中文
|
|
@@ -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;
|
|
@@ -8175,11 +8177,23 @@ export class BridgeSessionCore {
|
|
|
8175
8177
|
messageId = await this.sendMessage(active.scopeId, content.text);
|
|
8176
8178
|
}
|
|
8177
8179
|
if (messageId !== null) {
|
|
8178
|
-
|
|
8180
|
+
this.recordArchivedMessageId(active, messageId);
|
|
8179
8181
|
}
|
|
8180
8182
|
}
|
|
8181
8183
|
catch (error) {
|
|
8182
|
-
|
|
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
|
+
}
|
|
8183
8197
|
this.scheduleRenderRetry(active);
|
|
8184
8198
|
return false;
|
|
8185
8199
|
}
|
|
@@ -8192,7 +8206,7 @@ export class BridgeSessionCore {
|
|
|
8192
8206
|
else {
|
|
8193
8207
|
await this.editMessage(active.scopeId, active.previewMessageId, content.text, []);
|
|
8194
8208
|
}
|
|
8195
|
-
|
|
8209
|
+
this.recordArchivedMessageId(active, active.previewMessageId);
|
|
8196
8210
|
}
|
|
8197
8211
|
catch (error) {
|
|
8198
8212
|
if (isTelegramMessageGone(error)) {
|
|
@@ -8202,6 +8216,37 @@ export class BridgeSessionCore {
|
|
|
8202
8216
|
this.store.removeActiveTurnPreview(active.turnId);
|
|
8203
8217
|
return this.archiveStatusMessage(active, content);
|
|
8204
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
|
+
}
|
|
8205
8250
|
this.logger.warn('telegram.preview_archive_failed', {
|
|
8206
8251
|
error: String(error),
|
|
8207
8252
|
turnId: active.turnId,
|
|
@@ -8216,6 +8261,21 @@ export class BridgeSessionCore {
|
|
|
8216
8261
|
this.store.removeActiveTurnPreview(active.turnId);
|
|
8217
8262
|
return true;
|
|
8218
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
|
+
}
|
|
8219
8279
|
noteToolCommandStart(active, event) {
|
|
8220
8280
|
if (!active.toolBatch) {
|
|
8221
8281
|
active.toolBatch = createToolBatchState();
|
|
@@ -8652,9 +8712,12 @@ function renderArchivedToolBatchStatus(locale, counts, actionLines) {
|
|
|
8652
8712
|
return { text, html: null };
|
|
8653
8713
|
}
|
|
8654
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));
|
|
8655
8718
|
const html = [
|
|
8656
8719
|
telegramBold(heading),
|
|
8657
|
-
telegramExpandableBlockquote(
|
|
8720
|
+
telegramExpandableBlockquote(detailLines.join('\n')),
|
|
8658
8721
|
].join('\n');
|
|
8659
8722
|
return { text, html };
|
|
8660
8723
|
}
|
|
@@ -8803,6 +8866,9 @@ function truncateInline(value, limit) {
|
|
|
8803
8866
|
}
|
|
8804
8867
|
return `${value.slice(0, Math.max(0, limit - 1))}…`;
|
|
8805
8868
|
}
|
|
8869
|
+
function firstLine(value) {
|
|
8870
|
+
return value.split(/\r?\n/, 1)[0]?.trim() || value.trim();
|
|
8871
|
+
}
|
|
8806
8872
|
function parseReviewTarget(args) {
|
|
8807
8873
|
if (args.length === 0) {
|
|
8808
8874
|
return { type: 'uncommittedChanges' };
|
|
@@ -11406,6 +11472,12 @@ function isTelegramMessageGone(error) {
|
|
|
11406
11472
|
|| message.includes('message to edit not found')
|
|
11407
11473
|
|| message.includes('message not found');
|
|
11408
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
|
+
}
|
|
11409
11481
|
function isFileMissingError(error) {
|
|
11410
11482
|
return error instanceof Error && /enoent|no such file or directory/i.test(error.message);
|
|
11411
11483
|
}
|