@gonzih/cc-tg 0.2.10 → 0.2.11

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.
Files changed (2) hide show
  1. package/dist/bot.js +61 -25
  2. package/package.json +1 -1
package/dist/bot.js CHANGED
@@ -5,6 +5,7 @@
5
5
  import TelegramBot from "node-telegram-bot-api";
6
6
  import { existsSync, createWriteStream, mkdirSync } from "fs";
7
7
  import { resolve, basename, join } from "path";
8
+ import os from "os";
8
9
  import { execSync, spawn } from "child_process";
9
10
  import https from "https";
10
11
  import http from "http";
@@ -334,21 +335,44 @@ export class CcTgBot {
334
335
  if (block.type !== "tool_use")
335
336
  continue;
336
337
  const name = block.name;
337
- if (!["Write", "Edit", "NotebookEdit"].includes(name))
338
- continue;
339
338
  const input = block.input;
340
339
  if (!input)
341
340
  continue;
342
- // Write tool uses file_path, Edit uses file_path
343
- const filePath = input.file_path ?? input.path;
344
- if (!filePath)
345
- continue;
346
- // Resolve relative paths against cwd
347
- const resolved = filePath.startsWith("/")
348
- ? filePath
349
- : resolve(cwd ?? process.cwd(), filePath);
350
- console.log(`[claude:files] tracked written file: ${resolved}`);
351
- session.writtenFiles.add(resolved);
341
+ if (["Write", "Edit", "NotebookEdit"].includes(name)) {
342
+ // Write tool uses file_path, Edit uses file_path
343
+ const filePath = input.file_path ?? input.path;
344
+ if (!filePath)
345
+ continue;
346
+ // Resolve relative paths against cwd
347
+ const resolved = filePath.startsWith("/")
348
+ ? filePath
349
+ : resolve(cwd ?? process.cwd(), filePath);
350
+ console.log(`[claude:files] tracked written file: ${resolved}`);
351
+ session.writtenFiles.add(resolved);
352
+ }
353
+ else if (name === "Bash") {
354
+ const cmd = input.command ?? "";
355
+ // yt-dlp / ffmpeg -o "path"
356
+ const oFlag = cmd.match(/-o\s+["']?([^\s"']+\.[\w]{1,10})["']?/);
357
+ if (oFlag)
358
+ session.writtenFiles.add(resolve(cwd ?? process.cwd(), oFlag[1]));
359
+ // mv source dest — track dest
360
+ const mvMatch = cmd.match(/\bmv\s+\S+\s+["']?([^\s"']+)["']?$/);
361
+ if (mvMatch)
362
+ session.writtenFiles.add(resolve(cwd ?? process.cwd(), mvMatch[1]));
363
+ // cp source dest — track dest
364
+ const cpMatch = cmd.match(/\bcp\s+\S+\s+["']?([^\s"']+)["']?$/);
365
+ if (cpMatch)
366
+ session.writtenFiles.add(resolve(cwd ?? process.cwd(), cpMatch[1]));
367
+ // curl -o path or wget -O path
368
+ const curlMatch = cmd.match(/curl\s+.*?-o\s+["']?([^\s"']+)["']?/);
369
+ if (curlMatch)
370
+ session.writtenFiles.add(resolve(cwd ?? process.cwd(), curlMatch[1]));
371
+ // wget -O path
372
+ const wgetMatch = cmd.match(/wget\s+.*?-O\s+["']?([^\s"']+)["']?/);
373
+ if (wgetMatch)
374
+ session.writtenFiles.add(resolve(cwd ?? process.cwd(), wgetMatch[1]));
375
+ }
352
376
  }
353
377
  }
354
378
  isSensitiveFile(filePath) {
@@ -362,8 +386,6 @@ export class CcTgBot {
362
386
  return sensitivePatterns.some((p) => p.test(name));
363
387
  }
364
388
  uploadMentionedFiles(chatId, resultText, session) {
365
- if (session.writtenFiles.size === 0)
366
- return;
367
389
  // Extract file path candidates from result text
368
390
  // Match: /absolute/path/file.ext or relative like ./foo/bar.csv or just foo.pdf
369
391
  const pathPattern = /(?:^|[\s`'"(])(\/?[\w.\-/]+\.[\w]{1,10})(?:[\s`'")\n]|$)/gm;
@@ -372,24 +394,38 @@ export class CcTgBot {
372
394
  while ((match = pathPattern.exec(resultText)) !== null) {
373
395
  candidates.add(match[1]);
374
396
  }
397
+ const safeDirs = ["/tmp/", "/var/folders/", os.homedir() + "/Downloads/"];
398
+ const isSafeDir = (p) => safeDirs.some(d => p.startsWith(d)) || p.startsWith(this.opts.cwd ?? process.cwd());
375
399
  const toUpload = [];
400
+ if (session.writtenFiles.size > 0) {
401
+ for (const candidate of candidates) {
402
+ // Try as-is (absolute), or resolve against cwd
403
+ const resolved = candidate.startsWith("/")
404
+ ? candidate
405
+ : resolve(this.opts.cwd ?? process.cwd(), candidate);
406
+ if (session.writtenFiles.has(resolved) && existsSync(resolved)) {
407
+ toUpload.push(resolved);
408
+ }
409
+ else {
410
+ // Also check by basename — result might mention just the filename
411
+ for (const written of session.writtenFiles) {
412
+ if (basename(written) === basename(candidate) && existsSync(written)) {
413
+ toUpload.push(written);
414
+ break;
415
+ }
416
+ }
417
+ }
418
+ }
419
+ }
420
+ // Also upload files mentioned in result text that exist in safe dirs
421
+ // even if not tracked via Write tool
376
422
  for (const candidate of candidates) {
377
- // Try as-is (absolute), or resolve against cwd
378
423
  const resolved = candidate.startsWith("/")
379
424
  ? candidate
380
425
  : resolve(this.opts.cwd ?? process.cwd(), candidate);
381
- if (session.writtenFiles.has(resolved) && existsSync(resolved)) {
426
+ if (existsSync(resolved) && isSafeDir(resolved) && !toUpload.includes(resolved)) {
382
427
  toUpload.push(resolved);
383
428
  }
384
- else {
385
- // Also check by basename — result might mention just the filename
386
- for (const written of session.writtenFiles) {
387
- if (basename(written) === basename(candidate) && existsSync(written)) {
388
- toUpload.push(written);
389
- break;
390
- }
391
- }
392
- }
393
429
  }
394
430
  // Deduplicate and filter sensitive files
395
431
  const unique = [...new Set(toUpload)];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gonzih/cc-tg",
3
- "version": "0.2.10",
3
+ "version": "0.2.11",
4
4
  "description": "Claude Code Telegram bot — chat with Claude Code via Telegram",
5
5
  "type": "module",
6
6
  "bin": {