@gonzih/cc-tg 0.2.11 → 0.2.12

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 CHANGED
@@ -39,6 +39,7 @@ export declare class CcTgBot {
39
39
  private handleMcpVersion;
40
40
  private handleClearNpxCache;
41
41
  private handleRestart;
42
+ private handleGetFile;
42
43
  private killSession;
43
44
  stop(): void;
44
45
  }
package/dist/bot.js CHANGED
@@ -6,7 +6,7 @@ import TelegramBot from "node-telegram-bot-api";
6
6
  import { existsSync, createWriteStream, mkdirSync } from "fs";
7
7
  import { resolve, basename, join } from "path";
8
8
  import os from "os";
9
- import { execSync, spawn } from "child_process";
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: "Get a file from the server by path" },
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);
@@ -649,22 +655,39 @@ export class CcTgBot {
649
655
  await this.bot.sendMessage(chatId, `NPX cache cleared and MCP restarted.${pidNote} Will pick up latest npm version on next call.`);
650
656
  }
651
657
  async handleRestart(chatId) {
652
- await this.bot.sendMessage(chatId, "Restarting bot... brb.");
653
- await new Promise(resolve => setTimeout(resolve, 1000));
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
658
+ await this.bot.sendMessage(chatId, "Restarting... brb.");
659
+ await new Promise(resolve => setTimeout(resolve, 500));
666
660
  process.exit(0);
667
661
  }
662
+ async handleGetFile(chatId, text) {
663
+ const arg = text.slice("/get_file".length).trim();
664
+ if (!arg) {
665
+ await this.bot.sendMessage(chatId, "Usage: /get_file <path>");
666
+ return;
667
+ }
668
+ const filePath = resolve(arg);
669
+ const safeDirs = ["/tmp/", "/var/folders/", os.homedir() + "/Downloads/", this.opts.cwd ?? process.cwd()];
670
+ const inSafeDir = safeDirs.some(d => filePath.startsWith(d));
671
+ if (!inSafeDir) {
672
+ await this.bot.sendMessage(chatId, "Access denied: path not in allowed directories");
673
+ return;
674
+ }
675
+ if (!existsSync(filePath)) {
676
+ await this.bot.sendMessage(chatId, `File not found: ${filePath}`);
677
+ return;
678
+ }
679
+ const { statSync } = await import("fs");
680
+ const stat = statSync(filePath);
681
+ if (!stat.isFile()) {
682
+ await this.bot.sendMessage(chatId, `Not a file: ${filePath}`);
683
+ return;
684
+ }
685
+ if (this.isSensitiveFile(filePath)) {
686
+ await this.bot.sendMessage(chatId, "Access denied: sensitive file");
687
+ return;
688
+ }
689
+ await this.bot.sendDocument(chatId, filePath);
690
+ }
668
691
  killSession(chatId, keepCrons = true) {
669
692
  const session = this.sessions.get(chatId);
670
693
  if (session) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gonzih/cc-tg",
3
- "version": "0.2.11",
3
+ "version": "0.2.12",
4
4
  "description": "Claude Code Telegram bot — chat with Claude Code via Telegram",
5
5
  "type": "module",
6
6
  "bin": {