@gonzih/cc-tg 0.2.13 → 0.2.15

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
@@ -43,3 +43,4 @@ export declare class CcTgBot {
43
43
  private killSession;
44
44
  stop(): void;
45
45
  }
46
+ export declare function splitMessage(text: string, maxLen?: number): string[];
package/dist/bot.js CHANGED
@@ -3,7 +3,7 @@
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, statSync } from "fs";
6
+ import { existsSync, createWriteStream, mkdirSync, statSync, readdirSync } from "fs";
7
7
  import { resolve, basename, join } from "path";
8
8
  import os from "os";
9
9
  import { execSync } from "child_process";
@@ -358,10 +358,45 @@ export class CcTgBot {
358
358
  }
359
359
  else if (name === "Bash") {
360
360
  const cmd = input.command ?? "";
361
- // yt-dlp / ffmpeg -o "path"
362
- const oFlag = cmd.match(/-o\s+["']?([^\s"']+\.[\w]{1,10})["']?/);
363
- if (oFlag)
364
- session.writtenFiles.add(resolve(cwd ?? process.cwd(), oFlag[1]));
361
+ if (/\byt-dlp\b|\bffmpeg\b/.test(cmd)) {
362
+ // Scan output dir for recently modified media files (template paths like /tmp/%(title)s.%(ext)s
363
+ // make the actual filename unknowable at tracking time)
364
+ const oFlagMatch = cmd.match(/-o\s+["']?([^\s"']+)/);
365
+ let scanDir = "/tmp/";
366
+ if (oFlagMatch) {
367
+ const oPath = oFlagMatch[1].replace(/["'].*$/, "");
368
+ const dirEnd = oPath.lastIndexOf("/");
369
+ if (dirEnd > 0)
370
+ scanDir = oPath.slice(0, dirEnd + 1);
371
+ }
372
+ const MEDIA_EXTS = new Set([".mp3", ".mp4", ".wav", ".ogg", ".flac", ".webm", ".m4a", ".aac"]);
373
+ const nowMs = Date.now();
374
+ try {
375
+ for (const entry of readdirSync(scanDir)) {
376
+ const dotIdx = entry.lastIndexOf(".");
377
+ if (dotIdx < 0)
378
+ continue;
379
+ const ext = entry.slice(dotIdx).toLowerCase();
380
+ if (!MEDIA_EXTS.has(ext))
381
+ continue;
382
+ const full = join(scanDir, entry);
383
+ try {
384
+ if (nowMs - statSync(full).mtimeMs <= 90_000) {
385
+ console.log(`[claude:files] tracked yt-dlp/ffmpeg output: ${full}`);
386
+ session.writtenFiles.add(full);
387
+ }
388
+ }
389
+ catch { /* skip unreadable entries */ }
390
+ }
391
+ }
392
+ catch { /* scanDir doesn't exist or unreadable */ }
393
+ }
394
+ else {
395
+ // Other bash commands: try to extract output path from -o flag
396
+ const oFlag = cmd.match(/-o\s+["']?([^\s"']+\.[\w]{1,10})["']?/);
397
+ if (oFlag)
398
+ session.writtenFiles.add(resolve(cwd ?? process.cwd(), oFlag[1]));
399
+ }
365
400
  // mv source dest — track dest
366
401
  const mvMatch = cmd.match(/\bmv\s+\S+\s+["']?([^\s"']+)["']?$/);
367
402
  if (mvMatch)
@@ -387,7 +422,7 @@ export class CcTgBot {
387
422
  /credential/i, /secret/i, /password/i, /passwd/i, /\.env/i,
388
423
  /api[_-]?key/i, /token/i, /private[_-]?key/i, /id_rsa/i,
389
424
  /\.pem$/i, /\.key$/i, /\.pfx$/i, /\.p12$/i,
390
- /gmail/i, /oauth/i, /auth/i,
425
+ /gmail/i, /oauth/i, /\bauth\b/i,
391
426
  ];
392
427
  return sensitivePatterns.some((p) => p.test(name));
393
428
  }
@@ -395,11 +430,15 @@ export class CcTgBot {
395
430
  // Extract file path candidates from result text
396
431
  // Match: /absolute/path/file.ext or relative like ./foo/bar.csv or just foo.pdf
397
432
  const pathPattern = /(?:^|[\s`'"(])(\/?[\w.\-/]+\.[\w]{1,10})(?:[\s`'")\n]|$)/gm;
433
+ const quotedPattern = /"([^"]+\.[a-zA-Z0-9]{1,10})"|'([^']+\.[a-zA-Z0-9]{1,10})'/g;
398
434
  const candidates = new Set();
399
435
  let match;
400
436
  while ((match = pathPattern.exec(resultText)) !== null) {
401
437
  candidates.add(match[1]);
402
438
  }
439
+ while ((match = quotedPattern.exec(resultText)) !== null) {
440
+ candidates.add(match[1] ?? match[2]);
441
+ }
403
442
  const safeDirs = ["/tmp/", "/var/folders/", os.homedir() + "/Downloads/"];
404
443
  const isSafeDir = (p) => safeDirs.some(d => p.startsWith(d)) || p.startsWith(this.opts.cwd ?? process.cwd());
405
444
  const toUpload = [];
@@ -741,7 +780,7 @@ function downloadToFile(url, destPath) {
741
780
  }).on("error", reject);
742
781
  });
743
782
  }
744
- function splitMessage(text, maxLen = 4096) {
783
+ export function splitMessage(text, maxLen = 4096) {
745
784
  if (text.length <= maxLen)
746
785
  return [text];
747
786
  const chunks = [];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gonzih/cc-tg",
3
- "version": "0.2.13",
3
+ "version": "0.2.15",
4
4
  "description": "Claude Code Telegram bot — chat with Claude Code via Telegram",
5
5
  "type": "module",
6
6
  "bin": {
@@ -9,7 +9,10 @@
9
9
  "scripts": {
10
10
  "build": "tsc",
11
11
  "start": "node dist/index.js",
12
- "dev": "node --loader ts-node/esm src/index.ts"
12
+ "dev": "node --loader ts-node/esm src/index.ts",
13
+ "test": "vitest run",
14
+ "test:watch": "vitest",
15
+ "test:coverage": "vitest run --coverage"
13
16
  },
14
17
  "files": [
15
18
  "dist/"
@@ -20,7 +23,9 @@
20
23
  "devDependencies": {
21
24
  "@types/node": "^22.0.0",
22
25
  "@types/node-telegram-bot-api": "^0.64.0",
23
- "typescript": "^5.5.0"
26
+ "@vitest/coverage-v8": "^4.1.0",
27
+ "typescript": "^5.5.0",
28
+ "vitest": "^4.1.0"
24
29
  },
25
30
  "repository": {
26
31
  "type": "git",