@gonzih/cc-tg 0.9.21 → 0.9.22
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 +36 -0
- package/dist/bot.d.ts +36 -4
- package/dist/bot.js +592 -347
- package/dist/cron.d.ts +7 -1
- package/dist/cron.js +24 -3
- package/dist/formatter.d.ts +14 -12
- package/dist/formatter.js +72 -36
- package/dist/index.js +77 -21
- package/dist/notifier.d.ts +45 -0
- package/dist/notifier.js +230 -0
- package/dist/tokens.d.ts +22 -0
- package/dist/tokens.js +56 -0
- package/dist/usage-limit.js +2 -3
- package/dist/voice.js +29 -34
- package/package.json +4 -3
package/README.md
CHANGED
|
@@ -25,9 +25,11 @@ Open your bot in Telegram and start chatting.
|
|
|
25
25
|
| `TELEGRAM_BOT_TOKEN` | yes | From @BotFather |
|
|
26
26
|
| `CLAUDE_CODE_TOKEN` | yes* | Claude Code OAuth token (starts with `sk-ant-oat`) |
|
|
27
27
|
| `CLAUDE_CODE_OAUTH_TOKEN` | yes* | Alias for `CLAUDE_CODE_TOKEN` |
|
|
28
|
+
| `CLAUDE_CODE_OAUTH_TOKENS` | no | Comma-separated OAuth tokens for rotation — e.g. `token1,token2,token3`. When one account hits its usage limit, automatically switches to the next token instead of sleeping. |
|
|
28
29
|
| `ANTHROPIC_API_KEY` | yes* | Alternative — API key from console.anthropic.com |
|
|
29
30
|
| `ALLOWED_USER_IDS` | no | Comma-separated Telegram user IDs. Leave empty to allow anyone |
|
|
30
31
|
| `CWD` | no | Working directory for Claude Code. Defaults to current directory |
|
|
32
|
+
| `THREAD_CWD_MAP` | no | JSON mapping of forum topic names or IDs to CWD paths (see [Multi-topic sessions](#multi-topic-sessions)) |
|
|
31
33
|
|
|
32
34
|
*One of `CLAUDE_CODE_TOKEN`, `CLAUDE_CODE_OAUTH_TOKEN`, or `ANTHROPIC_API_KEY` required.
|
|
33
35
|
|
|
@@ -117,6 +119,37 @@ Manage the cc-agent MCP server from Telegram without SSH:
|
|
|
117
119
|
### Self-restart
|
|
118
120
|
`/restart` — spawns a detached child process with the same Node binary and args, sends you a confirmation message, then exits. The new process inherits all environment variables. No SSH required to restart the bot after updates.
|
|
119
121
|
|
|
122
|
+
### Multi-topic sessions
|
|
123
|
+
|
|
124
|
+
When you use cc-tg in a **Telegram group with Topics enabled** (a "Forum" group), each topic gets its own **isolated Claude Code session**. One bot token, one daemon, unlimited isolated project contexts.
|
|
125
|
+
|
|
126
|
+
**How it works:**
|
|
127
|
+
- Session key = `chatId:threadId` for forum topics
|
|
128
|
+
- Session key = `chatId:main` for direct messages and non-topic groups (backward compatible)
|
|
129
|
+
- Commands like `/reset`, `/stop`, `/status` are scoped to the current topic
|
|
130
|
+
|
|
131
|
+
**Setup:**
|
|
132
|
+
1. Create a Telegram group → Settings → Topics → Enable
|
|
133
|
+
2. Create topics for each project (e.g. "Simorgh", "LeWM", "EcoClaw")
|
|
134
|
+
3. Each topic now has its own isolated Claude context
|
|
135
|
+
|
|
136
|
+
**Optional: route topics to different working directories**
|
|
137
|
+
|
|
138
|
+
Set `THREAD_CWD_MAP` to a JSON string mapping topic names (or thread IDs) to absolute paths:
|
|
139
|
+
|
|
140
|
+
```bash
|
|
141
|
+
THREAD_CWD_MAP='{"Simorgh":"/Users/you/simorgh-app","LeWM":"/Users/you/le-wm","EcoClaw":"/Users/you/ecoclaw"}'
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
When cc-tg creates a new session for a topic, it looks up the topic name in this map and starts Claude in the corresponding directory. If no match is found, falls back to `CWD`.
|
|
145
|
+
|
|
146
|
+
You can also map by numeric thread ID:
|
|
147
|
+
```bash
|
|
148
|
+
THREAD_CWD_MAP='{"12345":"/Users/you/project-a","67890":"/Users/you/project-b"}'
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
If `THREAD_CWD_MAP` is not set, all topics share the same CWD — context isolation still works, just without directory routing.
|
|
152
|
+
|
|
120
153
|
### Typing indicator
|
|
121
154
|
While Claude is working, the bot sends a continuous typing indicator. Works for both regular messages and cron job execution.
|
|
122
155
|
|
|
@@ -157,6 +190,9 @@ cc-tg works with the [cc-agent](https://github.com/Gonzih/cc-agent) MCP server t
|
|
|
157
190
|
<string>your_token</string>
|
|
158
191
|
<key>CLAUDE_CODE_TOKEN</key>
|
|
159
192
|
<string>your_claude_token</string>
|
|
193
|
+
<!-- Optional: comma-separated OAuth tokens for automatic rotation on usage limit -->
|
|
194
|
+
<!-- <key>CLAUDE_CODE_OAUTH_TOKENS</key> -->
|
|
195
|
+
<!-- <string>token1,token2,token3</string> -->
|
|
160
196
|
<key>ALLOWED_USER_IDS</key>
|
|
161
197
|
<string>your_telegram_id</string>
|
|
162
198
|
<key>CWD</key>
|
package/dist/bot.d.ts
CHANGED
|
@@ -2,27 +2,54 @@
|
|
|
2
2
|
* Telegram bot that routes messages to/from a Claude Code subprocess.
|
|
3
3
|
* One ClaudeProcess per chat_id — sessions are isolated per user.
|
|
4
4
|
*/
|
|
5
|
+
import TelegramBot from "node-telegram-bot-api";
|
|
6
|
+
import { Redis } from "ioredis";
|
|
5
7
|
export interface BotOptions {
|
|
6
8
|
telegramToken: string;
|
|
7
9
|
claudeToken?: string;
|
|
8
10
|
cwd?: string;
|
|
9
11
|
allowedUserIds?: number[];
|
|
10
12
|
groupChatIds?: number[];
|
|
13
|
+
redis?: Redis;
|
|
14
|
+
namespace?: string;
|
|
11
15
|
}
|
|
12
16
|
export declare class CcTgBot {
|
|
13
17
|
private bot;
|
|
14
18
|
private sessions;
|
|
15
19
|
private pendingRetries;
|
|
16
20
|
private opts;
|
|
17
|
-
private cron;
|
|
18
21
|
private costStore;
|
|
19
22
|
private botUsername;
|
|
20
23
|
private botId;
|
|
24
|
+
private redis?;
|
|
25
|
+
private namespace;
|
|
26
|
+
private lastActiveChatId?;
|
|
27
|
+
private cron;
|
|
21
28
|
constructor(opts: BotOptions);
|
|
22
29
|
private registerBotCommands;
|
|
30
|
+
/** Write a message to the Redis chat log. Fire-and-forget — no-op if Redis is not configured. */
|
|
31
|
+
private writeChatMessage;
|
|
32
|
+
/** Returns the last chatId that sent a message — used by the chat bridge when no fixed chatId is configured. */
|
|
33
|
+
getLastActiveChatId(): number | undefined;
|
|
34
|
+
/** Session key: "chatId:threadId" for topics, "chatId:main" for DMs/non-topic groups */
|
|
35
|
+
private sessionKey;
|
|
36
|
+
/**
|
|
37
|
+
* Send a message back to the correct thread (or plain chat if no thread).
|
|
38
|
+
* When threadId is undefined, calls sendMessage with exactly 2 args to preserve
|
|
39
|
+
* backward-compatible call signatures (no extra options object).
|
|
40
|
+
*/
|
|
41
|
+
private replyToChat;
|
|
42
|
+
/** Parse THREAD_CWD_MAP env var — maps thread name or thread_id to a CWD path */
|
|
43
|
+
private getThreadCwdMap;
|
|
23
44
|
private isAllowed;
|
|
24
45
|
private handleTelegram;
|
|
46
|
+
/**
|
|
47
|
+
* Feed a text message into the active Claude session for the given chat.
|
|
48
|
+
* Called by the notifier when a UI message arrives via Redis pub/sub.
|
|
49
|
+
*/
|
|
50
|
+
handleUserMessage(chatId: number, text: string): Promise<void>;
|
|
25
51
|
private handleVoice;
|
|
52
|
+
private handleVoiceRetry;
|
|
26
53
|
private handlePhoto;
|
|
27
54
|
private handleDocument;
|
|
28
55
|
private getOrCreateSession;
|
|
@@ -34,9 +61,6 @@ export declare class CcTgBot {
|
|
|
34
61
|
private isSensitiveFile;
|
|
35
62
|
private uploadMentionedFiles;
|
|
36
63
|
private extractToolName;
|
|
37
|
-
private runCronTask;
|
|
38
|
-
private handleCron;
|
|
39
|
-
private handleCronEdit;
|
|
40
64
|
/** Find cc-agent PIDs via pgrep. Returns array of numeric PIDs. */
|
|
41
65
|
private findCcAgentPids;
|
|
42
66
|
/** Kill cc-agent PIDs with SIGTERM. Returns the list of killed PIDs. */
|
|
@@ -46,9 +70,17 @@ export declare class CcTgBot {
|
|
|
46
70
|
private handleMcpVersion;
|
|
47
71
|
private handleClearNpxCache;
|
|
48
72
|
private handleRestart;
|
|
73
|
+
private handleCron;
|
|
74
|
+
private runCronTask;
|
|
49
75
|
private handleGetFile;
|
|
76
|
+
private handleDrivers;
|
|
50
77
|
private callCcAgentTool;
|
|
51
78
|
private killSession;
|
|
79
|
+
getMe(): Promise<TelegramBot.User>;
|
|
52
80
|
stop(): void;
|
|
53
81
|
}
|
|
82
|
+
/** Detect URLs in text, fetch each via Jina Reader, and prepend content to the prompt */
|
|
83
|
+
export declare function enrichPromptWithUrls(text: string): Promise<string>;
|
|
84
|
+
/** List available skills from ~/.claude/skills/ */
|
|
85
|
+
export declare function listSkills(): string;
|
|
54
86
|
export declare function splitMessage(text: string, maxLen?: number): string[];
|