@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 +4 -0
- package/dist/bot.d.ts +7 -0
- package/dist/bot.js +70 -0
- package/package.json +1 -1
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
|
}
|