@gonzih/cc-tg 0.2.11 → 0.2.13
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/bot.d.ts +1 -0
- package/dist/bot.js +51 -16
- package/package.json +1 -1
package/dist/bot.d.ts
CHANGED
package/dist/bot.js
CHANGED
|
@@ -3,10 +3,10 @@
|
|
|
3
3
|
* One ClaudeProcess per chat_id — sessions are isolated per user.
|
|
4
4
|
*/
|
|
5
5
|
import TelegramBot from "node-telegram-bot-api";
|
|
6
|
-
import { existsSync, createWriteStream, mkdirSync } from "fs";
|
|
6
|
+
import { existsSync, createWriteStream, mkdirSync, statSync } from "fs";
|
|
7
7
|
import { resolve, basename, join } from "path";
|
|
8
8
|
import os from "os";
|
|
9
|
-
import { execSync
|
|
9
|
+
import { execSync } from "child_process";
|
|
10
10
|
import https from "https";
|
|
11
11
|
import http from "http";
|
|
12
12
|
import { ClaudeProcess, extractText } from "./claude.js";
|
|
@@ -23,6 +23,7 @@ const BOT_COMMANDS = [
|
|
|
23
23
|
{ command: "mcp_version", description: "Show cc-agent npm version and npx cache info" },
|
|
24
24
|
{ command: "clear_npx_cache", description: "Clear npx cache and restart MCP to pick up latest version" },
|
|
25
25
|
{ command: "restart", description: "Restart the bot process in-place" },
|
|
26
|
+
{ command: "get_file", description: "Send a file from the server to this chat" },
|
|
26
27
|
];
|
|
27
28
|
const FLUSH_DELAY_MS = 800; // debounce streaming chunks into one Telegram message
|
|
28
29
|
const TYPING_INTERVAL_MS = 4000; // re-send typing action before Telegram's 5s expiry
|
|
@@ -138,6 +139,11 @@ export class CcTgBot {
|
|
|
138
139
|
await this.handleRestart(chatId);
|
|
139
140
|
return;
|
|
140
141
|
}
|
|
142
|
+
// /get_file <path> — send a file from the server to the user
|
|
143
|
+
if (text.startsWith("/get_file")) {
|
|
144
|
+
await this.handleGetFile(chatId, text);
|
|
145
|
+
return;
|
|
146
|
+
}
|
|
141
147
|
const session = this.getOrCreateSession(chatId);
|
|
142
148
|
try {
|
|
143
149
|
session.claude.sendPrompt(text);
|
|
@@ -434,6 +440,13 @@ export class CcTgBot {
|
|
|
434
440
|
console.log(`[claude:files] skipping sensitive file: ${filePath}`);
|
|
435
441
|
continue;
|
|
436
442
|
}
|
|
443
|
+
const fileSize = statSync(filePath).size;
|
|
444
|
+
const MAX_TG_FILE_BYTES = 50 * 1024 * 1024;
|
|
445
|
+
if (fileSize > MAX_TG_FILE_BYTES) {
|
|
446
|
+
const mb = (fileSize / (1024 * 1024)).toFixed(1);
|
|
447
|
+
this.bot.sendMessage(chatId, `File too large for Telegram (${mb}mb). Find it at: ${filePath}`).catch(() => { });
|
|
448
|
+
continue;
|
|
449
|
+
}
|
|
437
450
|
console.log(`[claude:files] uploading to telegram: ${filePath}`);
|
|
438
451
|
this.bot.sendDocument(chatId, filePath).catch((err) => console.error(`[tg:${chatId}] sendDocument failed for ${filePath}:`, err.message));
|
|
439
452
|
}
|
|
@@ -649,22 +662,44 @@ export class CcTgBot {
|
|
|
649
662
|
await this.bot.sendMessage(chatId, `NPX cache cleared and MCP restarted.${pidNote} Will pick up latest npm version on next call.`);
|
|
650
663
|
}
|
|
651
664
|
async handleRestart(chatId) {
|
|
652
|
-
await this.bot.sendMessage(chatId, "Restarting
|
|
653
|
-
await new Promise(resolve => setTimeout(resolve,
|
|
654
|
-
this.stop();
|
|
655
|
-
const isLaunchd = process.ppid === 1;
|
|
656
|
-
if (!isLaunchd) {
|
|
657
|
-
// Running manually — spawn a replacement process
|
|
658
|
-
const child = spawn(process.execPath, process.argv.slice(1), {
|
|
659
|
-
detached: true,
|
|
660
|
-
stdio: "ignore",
|
|
661
|
-
env: process.env,
|
|
662
|
-
});
|
|
663
|
-
child.unref();
|
|
664
|
-
}
|
|
665
|
-
// If launchd-managed, just exit — launchd will restart us
|
|
665
|
+
await this.bot.sendMessage(chatId, "Restarting... brb.");
|
|
666
|
+
await new Promise(resolve => setTimeout(resolve, 500));
|
|
666
667
|
process.exit(0);
|
|
667
668
|
}
|
|
669
|
+
async handleGetFile(chatId, text) {
|
|
670
|
+
const arg = text.slice("/get_file".length).trim();
|
|
671
|
+
if (!arg) {
|
|
672
|
+
await this.bot.sendMessage(chatId, "Usage: /get_file <path>");
|
|
673
|
+
return;
|
|
674
|
+
}
|
|
675
|
+
const filePath = resolve(arg);
|
|
676
|
+
const safeDirs = ["/tmp/", "/var/folders/", os.homedir() + "/Downloads/", this.opts.cwd ?? process.cwd()];
|
|
677
|
+
const inSafeDir = safeDirs.some(d => filePath.startsWith(d));
|
|
678
|
+
if (!inSafeDir) {
|
|
679
|
+
await this.bot.sendMessage(chatId, "Access denied: path not in allowed directories");
|
|
680
|
+
return;
|
|
681
|
+
}
|
|
682
|
+
if (!existsSync(filePath)) {
|
|
683
|
+
await this.bot.sendMessage(chatId, `File not found: ${filePath}`);
|
|
684
|
+
return;
|
|
685
|
+
}
|
|
686
|
+
if (!statSync(filePath).isFile()) {
|
|
687
|
+
await this.bot.sendMessage(chatId, `Not a file: ${filePath}`);
|
|
688
|
+
return;
|
|
689
|
+
}
|
|
690
|
+
if (this.isSensitiveFile(filePath)) {
|
|
691
|
+
await this.bot.sendMessage(chatId, "Access denied: sensitive file");
|
|
692
|
+
return;
|
|
693
|
+
}
|
|
694
|
+
const MAX_TG_FILE_BYTES = 50 * 1024 * 1024;
|
|
695
|
+
const fileSize = statSync(filePath).size;
|
|
696
|
+
if (fileSize > MAX_TG_FILE_BYTES) {
|
|
697
|
+
const mb = (fileSize / (1024 * 1024)).toFixed(1);
|
|
698
|
+
await this.bot.sendMessage(chatId, `File too large for Telegram (${mb}mb). Find it at: ${filePath}`);
|
|
699
|
+
return;
|
|
700
|
+
}
|
|
701
|
+
await this.bot.sendDocument(chatId, filePath);
|
|
702
|
+
}
|
|
668
703
|
killSession(chatId, keepCrons = true) {
|
|
669
704
|
const session = this.sessions.get(chatId);
|
|
670
705
|
if (session) {
|