@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.
- package/dist/bot.js +61 -25
- 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
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
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 (
|
|
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)];
|