@gonzih/cc-tg 0.9.53 → 0.9.54

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/README.md CHANGED
@@ -32,6 +32,8 @@ Open your bot in Telegram and start chatting.
32
32
  | `ALLOWED_USER_IDS` | no | Comma-separated Telegram user IDs. Leave empty to allow anyone |
33
33
  | `CWD` | no | Working directory for Claude Code. Defaults to current directory |
34
34
  | `THREAD_CWD_MAP` | no | JSON mapping of forum topic names or IDs to CWD paths (see [Multi-topic sessions](#multi-topic-sessions)) |
35
+ | `CC_TG_AUTO_COMPACT_MESSAGES` | no | Automatically send `/compact` after this many messages in a session (default: 40, set to 0 to disable) |
36
+ | `CC_TG_COST_WARN_USD` | no | Send a cost warning notification when session cost exceeds this USD amount (default: 5.0, set to 0 to disable) |
35
37
 
36
38
  *One of `CLAUDE_CODE_TOKEN`, `CLAUDE_CODE_OAUTH_TOKEN`, or `ANTHROPIC_API_KEY` required.
37
39
 
@@ -66,6 +68,8 @@ Message [@userinfobot](https://t.me/userinfobot) — it replies with your numeri
66
68
  | `/mcp_version` | Show latest published cc-agent npm version and current cache |
67
69
  | `/clear_npx_cache` | Clear npx cache and reload cc-agent (upgrades to latest version) |
68
70
  | `/get_file <path>` | Send a file from the server to this chat |
71
+ | `/effort <level>` | Set Claude effort level (`low` / `medium` / `high` / `xhigh` / `max` / `auto`) |
72
+ | `/compact` | Compact context history to free tokens |
69
73
  | `/restart` | Self-restart the cc-tg bot process (no SSH needed) |
70
74
  | Any text | Sent directly to Claude Code |
71
75
  | Voice message | Transcribed via whisper.cpp and sent to Claude |
package/dist/bot.d.ts CHANGED
@@ -105,6 +105,13 @@ export declare class CcTgBot {
105
105
  private handleWikiSync;
106
106
  private callCcAgentTool;
107
107
  private killSession;
108
+ private handleEffort;
109
+ private handleCompact;
110
+ /**
111
+ * If CC_TG_AUTO_COMPACT_MESSAGES threshold is reached, send /compact to the active Claude
112
+ * session before the next user message. Resets the per-session counter on fire.
113
+ */
114
+ private maybeSendAutoCompact;
108
115
  getMe(): Promise<TelegramBot.User>;
109
116
  stop(): void;
110
117
  }
package/dist/bot.js CHANGED
@@ -37,6 +37,8 @@ const BOT_COMMANDS = [
37
37
  { command: "drivers", description: "List available agent drivers" },
38
38
  { command: "agents", description: "Show running meta-agents and their live status" },
39
39
  { command: "wiki", description: "Manage wiki pages — list/show/update/delete/sync" },
40
+ { command: "effort", description: "Set effort level: low / medium / high / xhigh / max / auto" },
41
+ { command: "compact", description: "Compact context history to free tokens" },
40
42
  ];
41
43
  // Debounces streaming chunks. Resets on each chunk. Fires 800ms after last chunk.
42
44
  const FLUSH_DELAY_MS = 800;
@@ -463,6 +465,16 @@ export class CcTgBot {
463
465
  await this.handleWiki(chatId, text, threadId);
464
466
  return;
465
467
  }
468
+ // /effort <level> — forward effort level to active Claude session
469
+ if (text.startsWith("/effort")) {
470
+ await this.handleEffort(chatId, text, threadId);
471
+ return;
472
+ }
473
+ // /compact — compact context history in active Claude session
474
+ if (text === "/compact") {
475
+ await this.handleCompact(chatId, threadId);
476
+ return;
477
+ }
466
478
  // #tag / #org/repo routing — delegate to meta-agent instead of local Claude session
467
479
  if (this.redis) {
468
480
  const routing = parseRoutingTag(text);
@@ -514,6 +526,7 @@ export class CcTgBot {
514
526
  const enriched = await enrichPromptWithUrls(text);
515
527
  const prompt = buildPromptWithReplyContext(enriched, msg);
516
528
  session.currentPrompt = prompt;
529
+ this.maybeSendAutoCompact(session, chatId, threadId);
517
530
  session.claude.sendPrompt(stampPrompt(prompt));
518
531
  this.startTyping(chatId, session);
519
532
  this.writeChatMessage("user", "telegram", text, chatId);
@@ -789,6 +802,8 @@ export class CcTgBot {
789
802
  currentPrompt: "",
790
803
  isRetry: false,
791
804
  threadId,
805
+ messagesSinceCompact: 0,
806
+ costWarnSent: false,
792
807
  };
793
808
  claude.on("usage", (usage) => {
794
809
  this.costStore.addUsage(chatId, usage);
@@ -847,6 +862,7 @@ export class CcTgBot {
847
862
  return;
848
863
  this.stopTyping(session);
849
864
  this.costStore.incrementMessages(chatId);
865
+ session.messagesSinceCompact++;
850
866
  const text = extractText(msg);
851
867
  if (!text)
852
868
  return;
@@ -955,6 +971,17 @@ export class CcTgBot {
955
971
  catch (err) {
956
972
  console.error(`[tg:${chatId}] uploadMentionedFiles error:`, err.message);
957
973
  }
974
+ // Cost threshold warning — fires once per session when cost first exceeds the limit
975
+ if (!session.costWarnSent) {
976
+ const warnThreshold = parseFloat(process.env.CC_TG_COST_WARN_USD ?? "5.0");
977
+ if (!isNaN(warnThreshold) && warnThreshold > 0) {
978
+ const cost = this.costStore.get(chatId);
979
+ if (cost.totalCostUsd >= warnThreshold) {
980
+ session.costWarnSent = true;
981
+ this.replyToChat(chatId, `⚠️ Session cost: $${cost.totalCostUsd.toFixed(2)} — consider /compact or /reset`, threadId).catch(() => { });
982
+ }
983
+ }
984
+ }
958
985
  }
959
986
  trackWrittenFiles(msg, session, cwd) {
960
987
  // Only look at assistant messages with tool_use blocks
@@ -1664,6 +1691,49 @@ export class CcTgBot {
1664
1691
  this.sessions.delete(key);
1665
1692
  }
1666
1693
  }
1694
+ async handleEffort(chatId, text, threadId) {
1695
+ const VALID_LEVELS = new Set(["low", "medium", "high", "xhigh", "max", "auto"]);
1696
+ const parts = text.trim().split(/\s+/);
1697
+ const level = parts[1]?.toLowerCase();
1698
+ if (!level || !VALID_LEVELS.has(level)) {
1699
+ await this.replyToChat(chatId, "Usage: /effort <level>\nValid levels: low, medium, high, xhigh, max, auto", threadId);
1700
+ return;
1701
+ }
1702
+ const sessionKey = this.sessionKey(chatId, threadId);
1703
+ const session = this.sessions.get(sessionKey);
1704
+ if (!session || session.claude.exited) {
1705
+ await this.replyToChat(chatId, `No active session. Start one, then use /effort ${level} to set the effort level.`, threadId);
1706
+ return;
1707
+ }
1708
+ session.claude.sendPrompt(`/effort ${level}`);
1709
+ await this.replyToChat(chatId, `⚡ Effort set to: ${level}`, threadId);
1710
+ }
1711
+ async handleCompact(chatId, threadId) {
1712
+ const sessionKey = this.sessionKey(chatId, threadId);
1713
+ const session = this.sessions.get(sessionKey);
1714
+ if (!session || session.claude.exited) {
1715
+ await this.replyToChat(chatId, "No active session.", threadId);
1716
+ return;
1717
+ }
1718
+ session.claude.sendPrompt("/compact");
1719
+ session.messagesSinceCompact = 0;
1720
+ await this.replyToChat(chatId, "🗜️ Compacting context history...", threadId);
1721
+ }
1722
+ /**
1723
+ * If CC_TG_AUTO_COMPACT_MESSAGES threshold is reached, send /compact to the active Claude
1724
+ * session before the next user message. Resets the per-session counter on fire.
1725
+ */
1726
+ maybeSendAutoCompact(session, chatId, threadId) {
1727
+ const threshold = parseInt(process.env.CC_TG_AUTO_COMPACT_MESSAGES ?? "40", 10);
1728
+ if (isNaN(threshold) || threshold <= 0)
1729
+ return;
1730
+ if (session.messagesSinceCompact >= threshold) {
1731
+ console.log(`[auto-compact:${chatId}] firing after ${session.messagesSinceCompact} messages`);
1732
+ session.messagesSinceCompact = 0;
1733
+ session.claude.sendPrompt("/compact");
1734
+ this.replyToChat(chatId, `🗜️ Auto-compacting context (${threshold} message limit reached)...`, threadId).catch(() => { });
1735
+ }
1736
+ }
1667
1737
  getMe() {
1668
1738
  return this.bot.getMe();
1669
1739
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gonzih/cc-tg",
3
- "version": "0.9.53",
3
+ "version": "0.9.54",
4
4
  "description": "Claude Code Telegram bot — chat with Claude Code via Telegram",
5
5
  "type": "module",
6
6
  "bin": {