cc-claw 0.29.1 → 0.29.2
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 +52 -13
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -33,7 +33,7 @@ var VERSION;
|
|
|
33
33
|
var init_version = __esm({
|
|
34
34
|
"src/version.ts"() {
|
|
35
35
|
"use strict";
|
|
36
|
-
VERSION = true ? "0.29.
|
|
36
|
+
VERSION = true ? "0.29.2" : (() => {
|
|
37
37
|
try {
|
|
38
38
|
return JSON.parse(readFileSync(join(process.cwd(), "package.json"), "utf-8")).version ?? "unknown";
|
|
39
39
|
} catch {
|
|
@@ -7593,7 +7593,7 @@ var init_telegram_throttle = __esm({
|
|
|
7593
7593
|
RETRY_DELAY_MS = 1e3;
|
|
7594
7594
|
MAX_QUEUE_SIZE = 60;
|
|
7595
7595
|
EDIT_PRESSURE_THRESHOLD = MAX_QUEUE_SIZE / 2;
|
|
7596
|
-
MAX_PER_CHAT_QUEUE =
|
|
7596
|
+
MAX_PER_CHAT_QUEUE = 30;
|
|
7597
7597
|
MAX_TOTAL_PAUSE_MS = 5 * 60 * 1e3;
|
|
7598
7598
|
CIRCUIT_TRIP_THRESHOLD = 3;
|
|
7599
7599
|
CIRCUIT_TRIP_WINDOW_MS = 5 * 60 * 1e3;
|
|
@@ -14088,18 +14088,24 @@ function spawnQuery(adapter, config2, model2, cancelState, thinkingLevel, timeou
|
|
|
14088
14088
|
let contentSilenceTimer;
|
|
14089
14089
|
const silenceTimeoutMs = CONTENT_SILENCE_TIMEOUT_MS;
|
|
14090
14090
|
let silenceResetCount = 0;
|
|
14091
|
-
const MAX_SILENCE_RESETS =
|
|
14091
|
+
const MAX_SILENCE_RESETS = 3;
|
|
14092
14092
|
function resetContentSilenceTimer() {
|
|
14093
14093
|
if (silenceTimeoutMs <= 0) return;
|
|
14094
14094
|
if (contentSilenceTimer) clearTimeout(contentSilenceTimer);
|
|
14095
14095
|
contentSilenceTimer = setTimeout(() => {
|
|
14096
14096
|
if (cancelState.cancelled || timedOut) return;
|
|
14097
14097
|
if (pendingTools.size > 0 && silenceResetCount < MAX_SILENCE_RESETS) {
|
|
14098
|
-
|
|
14099
|
-
const
|
|
14100
|
-
|
|
14101
|
-
|
|
14102
|
-
|
|
14098
|
+
const now = Date.now();
|
|
14099
|
+
const hungTool = Array.from(pendingTools.values()).find((t) => now - t.startedAt > silenceTimeoutMs);
|
|
14100
|
+
if (hungTool) {
|
|
14101
|
+
warn(`[agent] Tool "${hungTool.name}" has been running for ${Math.round((now - hungTool.startedAt) / 1e3)}s \u2014 treating as hung, killing`);
|
|
14102
|
+
} else {
|
|
14103
|
+
silenceResetCount++;
|
|
14104
|
+
const tools2 = Array.from(pendingTools.values()).map((t) => `${t.name} (${Math.round((now - t.startedAt) / 1e3)}s)`).join(", ");
|
|
14105
|
+
log(`[agent] Content silence timer fired but ${pendingTools.size} tool(s) still running (${tools2}) \u2014 resetting (${silenceResetCount}/${MAX_SILENCE_RESETS})`);
|
|
14106
|
+
resetContentSilenceTimer();
|
|
14107
|
+
return;
|
|
14108
|
+
}
|
|
14103
14109
|
}
|
|
14104
14110
|
warn(`[agent] Content silence timeout after ${silenceTimeoutMs / 1e3}s for ${adapter.id} \u2014 no content events, killing`);
|
|
14105
14111
|
timedOut = true;
|
|
@@ -14178,7 +14184,7 @@ function spawnQuery(adapter, config2, model2, cancelState, thinkingLevel, timeou
|
|
|
14178
14184
|
sawToolEvents = true;
|
|
14179
14185
|
if (opts?.onToolAction && ev.toolName) {
|
|
14180
14186
|
const toolInput = ev.toolInput ?? {};
|
|
14181
|
-
if (ev.toolId) pendingTools.set(ev.toolId, { name: ev.toolName, input: toolInput });
|
|
14187
|
+
if (ev.toolId) pendingTools.set(ev.toolId, { name: ev.toolName, input: toolInput, startedAt: Date.now() });
|
|
14182
14188
|
opts.onToolAction(ev.toolName, toolInput, void 0, ev.toolId).catch((err) => {
|
|
14183
14189
|
error("[agent] tool action error:", err);
|
|
14184
14190
|
});
|
|
@@ -24547,7 +24553,7 @@ function getEditCoordinator() {
|
|
|
24547
24553
|
function resetEditCoordinator() {
|
|
24548
24554
|
EditCoordinator.resetInstance();
|
|
24549
24555
|
}
|
|
24550
|
-
var TICK_INTERVAL_MS, MAX_EDITS_PER_WINDOW, EDIT_WINDOW_MS, EditCoordinator;
|
|
24556
|
+
var TICK_INTERVAL_MS, MAX_EDITS_PER_WINDOW, EDIT_WINDOW_MS, MIN_FLUSH_GAP_DM_MS, MIN_FLUSH_GAP_GROUP_MS, EditCoordinator;
|
|
24551
24557
|
var init_edit_coordinator = __esm({
|
|
24552
24558
|
"src/channels/edit-coordinator.ts"() {
|
|
24553
24559
|
"use strict";
|
|
@@ -24555,10 +24561,14 @@ var init_edit_coordinator = __esm({
|
|
|
24555
24561
|
TICK_INTERVAL_MS = 1e3;
|
|
24556
24562
|
MAX_EDITS_PER_WINDOW = 4;
|
|
24557
24563
|
EDIT_WINDOW_MS = 6e4;
|
|
24564
|
+
MIN_FLUSH_GAP_DM_MS = 2e3;
|
|
24565
|
+
MIN_FLUSH_GAP_GROUP_MS = 4e3;
|
|
24558
24566
|
EditCoordinator = class _EditCoordinator {
|
|
24559
24567
|
static instance = null;
|
|
24560
24568
|
/** Active streams indexed by messageId. */
|
|
24561
24569
|
activeStreams = /* @__PURE__ */ new Map();
|
|
24570
|
+
/** Last flush timestamp per stream — prevents flushing faster than the throttle can drain. */
|
|
24571
|
+
lastFlushAt = /* @__PURE__ */ new Map();
|
|
24562
24572
|
/** Per-message edit tracking for the sliding window cap. */
|
|
24563
24573
|
perMessageEditCount = /* @__PURE__ */ new Map();
|
|
24564
24574
|
/** Single flush timer shared across all streams. */
|
|
@@ -24599,6 +24609,7 @@ var init_edit_coordinator = __esm({
|
|
|
24599
24609
|
unregister(messageId) {
|
|
24600
24610
|
this.activeStreams.delete(messageId);
|
|
24601
24611
|
this.perMessageEditCount.delete(messageId);
|
|
24612
|
+
this.lastFlushAt.delete(messageId);
|
|
24602
24613
|
this.rebuildKeys();
|
|
24603
24614
|
log(`[edit-coordinator] unregistered stream ${messageId} (${this.activeStreams.size} remaining)`);
|
|
24604
24615
|
if (this.activeStreams.size === 0 && this.flushTimer) {
|
|
@@ -24616,6 +24627,7 @@ var init_edit_coordinator = __esm({
|
|
|
24616
24627
|
}
|
|
24617
24628
|
this.activeStreams.clear();
|
|
24618
24629
|
this.perMessageEditCount.clear();
|
|
24630
|
+
this.lastFlushAt.clear();
|
|
24619
24631
|
this.streamKeys = [];
|
|
24620
24632
|
this.roundRobinIndex = 0;
|
|
24621
24633
|
}
|
|
@@ -24644,6 +24656,17 @@ var init_edit_coordinator = __esm({
|
|
|
24644
24656
|
}
|
|
24645
24657
|
}
|
|
24646
24658
|
// ── Internal ──────────────────────────────────────────────────────────
|
|
24659
|
+
/** Check whether enough time has passed since the last flush for this stream.
|
|
24660
|
+
* Group chats need longer gaps (4s) to match the throttle's group pacing (3.5s).
|
|
24661
|
+
* Without this, the coordinator pushes edits faster than the throttle drains them,
|
|
24662
|
+
* causing per-chat queue buildup. */
|
|
24663
|
+
canFlushStream(messageId, stream) {
|
|
24664
|
+
const last = this.lastFlushAt.get(messageId);
|
|
24665
|
+
if (last === void 0) return true;
|
|
24666
|
+
const chatId = stream.getChatId();
|
|
24667
|
+
const minGap = parseInt(chatId) < 0 ? MIN_FLUSH_GAP_GROUP_MS : MIN_FLUSH_GAP_DM_MS;
|
|
24668
|
+
return Date.now() - last >= minGap;
|
|
24669
|
+
}
|
|
24647
24670
|
/** Rebuild the ordered keys array after registration changes. */
|
|
24648
24671
|
rebuildKeys() {
|
|
24649
24672
|
this.streamKeys = Array.from(this.activeStreams.keys());
|
|
@@ -24663,11 +24686,12 @@ var init_edit_coordinator = __esm({
|
|
|
24663
24686
|
const idx = (startIdx + tried) % this.streamKeys.length;
|
|
24664
24687
|
const messageId = this.streamKeys[idx];
|
|
24665
24688
|
const stream = this.activeStreams.get(messageId);
|
|
24666
|
-
if (stream && this.canEditMessage(messageId)) {
|
|
24689
|
+
if (stream && this.canEditMessage(messageId) && this.canFlushStream(messageId, stream)) {
|
|
24667
24690
|
this.roundRobinIndex = (idx + 1) % this.streamKeys.length;
|
|
24668
24691
|
try {
|
|
24669
24692
|
await stream.flush();
|
|
24670
24693
|
this.recordEdit(messageId);
|
|
24694
|
+
this.lastFlushAt.set(messageId, Date.now());
|
|
24671
24695
|
} catch {
|
|
24672
24696
|
}
|
|
24673
24697
|
return;
|
|
@@ -25360,10 +25384,12 @@ function getTypingManager() {
|
|
|
25360
25384
|
function resetTypingManager() {
|
|
25361
25385
|
TypingManager.resetInstance();
|
|
25362
25386
|
}
|
|
25363
|
-
var TypingManager;
|
|
25387
|
+
var MAX_TYPING_DURATION_MS, TypingManager;
|
|
25364
25388
|
var init_typing_manager = __esm({
|
|
25365
25389
|
"src/channels/typing-manager.ts"() {
|
|
25366
25390
|
"use strict";
|
|
25391
|
+
init_log();
|
|
25392
|
+
MAX_TYPING_DURATION_MS = 15 * 60 * 1e3;
|
|
25367
25393
|
TypingManager = class _TypingManager {
|
|
25368
25394
|
static instance = null;
|
|
25369
25395
|
activeChats = /* @__PURE__ */ new Map();
|
|
@@ -25385,11 +25411,17 @@ var init_typing_manager = __esm({
|
|
|
25385
25411
|
}
|
|
25386
25412
|
channel.sendTyping?.(chatId).catch(() => {
|
|
25387
25413
|
});
|
|
25414
|
+
const acquiredAt = Date.now();
|
|
25388
25415
|
const timer = setInterval(() => {
|
|
25416
|
+
if (Date.now() - acquiredAt > MAX_TYPING_DURATION_MS) {
|
|
25417
|
+
warn(`[typing-manager] Auto-releasing chat ${chatId} after ${MAX_TYPING_DURATION_MS / 6e4}min (likely leak)`);
|
|
25418
|
+
this.forceRelease(chatId);
|
|
25419
|
+
return;
|
|
25420
|
+
}
|
|
25389
25421
|
channel.sendTyping?.(chatId).catch(() => {
|
|
25390
25422
|
});
|
|
25391
25423
|
}, 4e3);
|
|
25392
|
-
this.activeChats.set(chatId, { refCount: 1, timer });
|
|
25424
|
+
this.activeChats.set(chatId, { refCount: 1, timer, acquiredAt });
|
|
25393
25425
|
}
|
|
25394
25426
|
/**
|
|
25395
25427
|
* Stop showing typing for this agent's perspective.
|
|
@@ -25404,6 +25436,13 @@ var init_typing_manager = __esm({
|
|
|
25404
25436
|
this.activeChats.delete(chatId);
|
|
25405
25437
|
}
|
|
25406
25438
|
}
|
|
25439
|
+
/** Force-release a chat regardless of refCount (for leak recovery). */
|
|
25440
|
+
forceRelease(chatId) {
|
|
25441
|
+
const entry = this.activeChats.get(chatId);
|
|
25442
|
+
if (!entry) return;
|
|
25443
|
+
clearInterval(entry.timer);
|
|
25444
|
+
this.activeChats.delete(chatId);
|
|
25445
|
+
}
|
|
25407
25446
|
/** Clean shutdown — clear all timers. */
|
|
25408
25447
|
shutdown() {
|
|
25409
25448
|
for (const [, entry] of this.activeChats) {
|
package/package.json
CHANGED