cc-claw 0.24.0 → 0.24.1

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.
Files changed (2) hide show
  1. package/dist/cli.js +61 -33
  2. 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.24.0" : (() => {
36
+ VERSION = true ? "0.24.1" : (() => {
37
37
  try {
38
38
  return JSON.parse(readFileSync(join(process.cwd(), "package.json"), "utf-8")).version ?? "unknown";
39
39
  } catch {
@@ -4370,13 +4370,45 @@ var init_env = __esm({
4370
4370
  });
4371
4371
 
4372
4372
  // src/backends/strip-thinking.ts
4373
+ function hasGeminiSystemPromptLeak(text) {
4374
+ const matches = text.match(/CRITICAL INSTRUCTION \d+:/gi);
4375
+ return !!matches && matches.length >= 2;
4376
+ }
4377
+ function isGeminiLeakFragment(text) {
4378
+ return /CRITICAL INSTRUCTION \d+:/i.test(text) || /^\s*\([a-z]\)\s+(NEVER|ALWAYS|DO NOT)\s/im.test(text);
4379
+ }
4380
+ function stripGeminiLeakedThinking(text) {
4381
+ if (!hasGeminiSystemPromptLeak(text)) return text;
4382
+ const re = /CRITICAL INSTRUCTION \d+:/gi;
4383
+ let lastMatch = null;
4384
+ let m;
4385
+ while ((m = re.exec(text)) !== null) {
4386
+ lastMatch = m;
4387
+ }
4388
+ if (!lastMatch) return text;
4389
+ const afterLast = text.slice(lastMatch.index);
4390
+ const ruleBlockEnd = afterLast.search(
4391
+ /\n(?!\s*\([a-z]\)\s)(?!CRITICAL\s)(?!\s{2,})\S/
4392
+ );
4393
+ if (ruleBlockEnd === -1) return "";
4394
+ const cleaned = afterLast.slice(ruleBlockEnd).trim();
4395
+ return cleaned.replace(GEMINI_SYSTEM_PROMPT_LEAK, "").trim();
4396
+ }
4373
4397
  function stripThinkingContent(text) {
4374
4398
  let result = text;
4375
4399
  for (const pattern of THINKING_PATTERNS) {
4376
4400
  result = result.replace(pattern, "");
4377
4401
  }
4402
+ result = stripGeminiLeakedThinking(result);
4378
4403
  return result.trim();
4379
4404
  }
4405
+ function stripThinkingTags(text) {
4406
+ let result = text;
4407
+ for (const pattern of THINKING_PATTERNS) {
4408
+ result = result.replace(pattern, "");
4409
+ }
4410
+ return result;
4411
+ }
4380
4412
  function extractThinkingEvents(text) {
4381
4413
  const thinkingEvents = [];
4382
4414
  const thinkingMatches = [...text.matchAll(/<thinking>([\s\S]*?)<\/thinking>/gi)];
@@ -4391,10 +4423,10 @@ function extractThinkingEvents(text) {
4391
4423
  for (const match of reasoningMatches) {
4392
4424
  thinkingEvents.push({ type: "thinking", text: match[1].trim() });
4393
4425
  }
4394
- const cleanText = stripThinkingContent(text);
4426
+ const cleanText = stripThinkingTags(text);
4395
4427
  return { cleanText, thinkingEvents };
4396
4428
  }
4397
- var THINKING_PATTERNS;
4429
+ var THINKING_PATTERNS, GEMINI_SYSTEM_PROMPT_LEAK;
4398
4430
  var init_strip_thinking = __esm({
4399
4431
  "src/backends/strip-thinking.ts"() {
4400
4432
  "use strict";
@@ -4410,6 +4442,7 @@ var init_strip_thinking = __esm({
4410
4442
  // so match until the next [Thought: marker or end of string.
4411
4443
  /\[Thought:\s*true\][\s\S]*?(?=\[Thought:|$)/gi
4412
4444
  ];
4445
+ GEMINI_SYSTEM_PROMPT_LEAK = /CRITICAL INSTRUCTION \d+:[\s\S]*?(?=CRITICAL INSTRUCTION \d+:|$)/gi;
4413
4446
  }
4414
4447
  });
4415
4448
 
@@ -8314,21 +8347,7 @@ var init_types2 = __esm({
8314
8347
  function appendTextChunk(accumulated, chunk) {
8315
8348
  if (!accumulated) return chunk;
8316
8349
  if (!chunk) return accumulated;
8317
- if (/\s$/.test(accumulated) || /^\s/.test(chunk)) {
8318
- return accumulated + chunk;
8319
- }
8320
- const tailChar = accumulated[accumulated.length - 1];
8321
- if ("/:@.=?&#%-_~+".includes(tailChar)) {
8322
- return accumulated + chunk;
8323
- }
8324
- const headChar = chunk[0];
8325
- if (`/:@.=?&#%-_~+,;)]}>'"`.includes(headChar)) {
8326
- return accumulated + chunk;
8327
- }
8328
- if (/\d$/.test(accumulated) && /^\d/.test(chunk)) {
8329
- return accumulated + chunk;
8330
- }
8331
- return accumulated + " " + chunk;
8350
+ return accumulated + chunk;
8332
8351
  }
8333
8352
  var init_text_utils = __esm({
8334
8353
  "src/text-utils.ts"() {
@@ -14814,6 +14833,7 @@ function spawnQuery(adapter, config2, model2, cancelState, thinkingLevel, timeou
14814
14833
  let sawResultEvent = false;
14815
14834
  let toolTurnCount = 0;
14816
14835
  let loopKillReason;
14836
+ let geminiLeakSuppressing = false;
14817
14837
  const loopDetector = new ToolLoopDetector();
14818
14838
  const t0 = Date.now();
14819
14839
  const elapsed = () => `${((Date.now() - t0) / 1e3).toFixed(1)}s`;
@@ -14894,7 +14914,16 @@ function spawnQuery(adapter, config2, model2, cancelState, thinkingLevel, timeou
14894
14914
  resetContentSilenceTimer();
14895
14915
  if (ev.text) {
14896
14916
  accumulatedText = appendTextChunk(accumulatedText, ev.text);
14897
- if (opts?.onStream) opts.onStream(ev.text);
14917
+ if (adapter.id === "gemini" && isGeminiLeakFragment(ev.text)) {
14918
+ geminiLeakSuppressing = true;
14919
+ } else if (geminiLeakSuppressing) {
14920
+ if (!isGeminiLeakFragment(ev.text)) {
14921
+ geminiLeakSuppressing = false;
14922
+ if (opts?.onStream) opts.onStream(ev.text);
14923
+ }
14924
+ } else {
14925
+ if (opts?.onStream) opts.onStream(ev.text);
14926
+ }
14898
14927
  }
14899
14928
  break;
14900
14929
  case "thinking":
@@ -14920,6 +14949,7 @@ function spawnQuery(adapter, config2, model2, cancelState, thinkingLevel, timeou
14920
14949
  }
14921
14950
  }
14922
14951
  resetContentSilenceTimer();
14952
+ geminiLeakSuppressing = false;
14923
14953
  sawToolEvents = true;
14924
14954
  if (opts?.onToolAction && ev.toolName) {
14925
14955
  const toolInput = ev.toolInput ?? {};
@@ -16111,6 +16141,9 @@ __export(telegram_throttle_exports, {
16111
16141
  getThrottleState: () => getThrottleState
16112
16142
  });
16113
16143
  import { GrammyError } from "grammy";
16144
+ function perChatInterval(chatId) {
16145
+ return parseInt(chatId) < 0 ? PER_GROUP_INTERVAL_MS : PER_DM_INTERVAL_MS;
16146
+ }
16114
16147
  function getThrottleState() {
16115
16148
  if (!_activeThrottle) return null;
16116
16149
  return _activeThrottle.getState();
@@ -16121,12 +16154,13 @@ function is429(err) {
16121
16154
  function sleep(ms) {
16122
16155
  return new Promise((r) => setTimeout(r, ms));
16123
16156
  }
16124
- var PER_CHAT_INTERVAL_MS, GLOBAL_INTERVAL_MS, MAX_RETRIES2, RETRY_DELAY_MS, MAX_QUEUE_SIZE, MAX_TOTAL_PAUSE_MS, _activeThrottle, TelegramThrottle;
16157
+ var PER_DM_INTERVAL_MS, PER_GROUP_INTERVAL_MS, GLOBAL_INTERVAL_MS, MAX_RETRIES2, RETRY_DELAY_MS, MAX_QUEUE_SIZE, MAX_TOTAL_PAUSE_MS, _activeThrottle, TelegramThrottle;
16125
16158
  var init_telegram_throttle = __esm({
16126
16159
  "src/channels/telegram-throttle.ts"() {
16127
16160
  "use strict";
16128
16161
  init_log();
16129
- PER_CHAT_INTERVAL_MS = 1e3;
16162
+ PER_DM_INTERVAL_MS = 1e3;
16163
+ PER_GROUP_INTERVAL_MS = 3500;
16130
16164
  GLOBAL_INTERVAL_MS = 100;
16131
16165
  MAX_RETRIES2 = 2;
16132
16166
  RETRY_DELAY_MS = 1e3;
@@ -16180,7 +16214,7 @@ var init_telegram_throttle = __esm({
16180
16214
  if (this.queue.length > 10) return void 0;
16181
16215
  if (!opts?.skipRecord) {
16182
16216
  const lastChat = this.lastSendPerChat.get(chatId) ?? 0;
16183
- if (Date.now() - lastChat < PER_CHAT_INTERVAL_MS) return void 0;
16217
+ if (Date.now() - lastChat < perChatInterval(chatId)) return void 0;
16184
16218
  if (Date.now() - this.lastGlobalSend < GLOBAL_INTERVAL_MS) return void 0;
16185
16219
  }
16186
16220
  try {
@@ -16236,7 +16270,7 @@ var init_telegram_throttle = __esm({
16236
16270
  }
16237
16271
  const item = this.queue[0];
16238
16272
  const lastChat = this.lastSendPerChat.get(item.chatId) ?? 0;
16239
- const chatWait = PER_CHAT_INTERVAL_MS - (Date.now() - lastChat);
16273
+ const chatWait = perChatInterval(item.chatId) - (Date.now() - lastChat);
16240
16274
  if (chatWait > 0) await sleep(chatWait);
16241
16275
  const globalWait = GLOBAL_INTERVAL_MS - (Date.now() - this.lastGlobalSend);
16242
16276
  if (globalWait > 0) await sleep(globalWait);
@@ -18708,7 +18742,7 @@ function makeLiveStatus(chatId, channel, modelLabel, verboseLevel, showThinking)
18708
18742
  };
18709
18743
  return { liveStatus, toolCb };
18710
18744
  }
18711
- var FLUSH_INTERVAL_DM_MS, FLUSH_INTERVAL_GROUP_MS, MAX_THINKING_CHARS, GLOBAL_MIN_GAP_MS, globalLastFlushAt, TRIM_THRESHOLD, MAX_ENTRIES, HEARTBEAT_FORCE_INTERVAL_MS, SPINNER_FRAMES, HEARTBEAT_TEXTS, LiveStatusMessage;
18745
+ var FLUSH_INTERVAL_DM_MS, FLUSH_INTERVAL_GROUP_MS, MAX_THINKING_CHARS, GLOBAL_MIN_GAP_MS, globalLastFlushAt, TRIM_THRESHOLD, MAX_ENTRIES, SPINNER_FRAMES, HEARTBEAT_TEXTS, LiveStatusMessage;
18712
18746
  var init_live_status = __esm({
18713
18747
  "src/router/live-status.ts"() {
18714
18748
  "use strict";
@@ -18722,7 +18756,6 @@ var init_live_status = __esm({
18722
18756
  globalLastFlushAt = 0;
18723
18757
  TRIM_THRESHOLD = 3500;
18724
18758
  MAX_ENTRIES = 200;
18725
- HEARTBEAT_FORCE_INTERVAL_MS = 15e3;
18726
18759
  SPINNER_FRAMES = ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"];
18727
18760
  HEARTBEAT_TEXTS = ["Still working\u2026", "Processing\u2026"];
18728
18761
  LiveStatusMessage = class _LiveStatusMessage {
@@ -18859,13 +18892,8 @@ var init_live_status = __esm({
18859
18892
  }
18860
18893
  if (Date.now() < this.nextFlushAllowedAt) return;
18861
18894
  const throttleState = getThrottleState();
18862
- if (throttleState?.isPaused) {
18863
- const staleSec = Date.now() - this.lastSuccessfulFlushAt;
18864
- const shouldForce = this.pendingTools.size > 0 && staleSec >= HEARTBEAT_FORCE_INTERVAL_MS;
18865
- if (!shouldForce) return;
18866
- } else {
18867
- if (!canFlushGlobally()) return;
18868
- }
18895
+ if (throttleState?.isPaused) return;
18896
+ if (!canFlushGlobally()) return;
18869
18897
  this.spinnerFrame++;
18870
18898
  const deduped = dedupThinking(this.entries);
18871
18899
  const body = renderEntries(
@@ -31580,7 +31608,7 @@ var init_telegram2 = __esm({
31580
31608
  if (!this.pollingExpected) return;
31581
31609
  const silenceMs = Date.now() - this.lastUpdateAt;
31582
31610
  if (silenceMs > _TelegramChannel.POLLING_SILENCE_THRESHOLD_MS) {
31583
- warn(
31611
+ log(
31584
31612
  `[telegram] No updates received for ${Math.round(silenceMs / 1e3)}s \u2014 triggering reconnect`
31585
31613
  );
31586
31614
  markChannelDown("telegram", `No updates for ${Math.round(silenceMs / 1e3)}s`);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cc-claw",
3
- "version": "0.24.0",
3
+ "version": "0.24.1",
4
4
  "description": "CC-Claw: Personal AI assistant on Telegram — multi-backend (Claude, Gemini, Codex, Cursor), sub-agent orchestration, MCP management",
5
5
  "type": "module",
6
6
  "main": "dist/cli.js",