@gonzih/cc-tg 0.2.15 → 0.2.17
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 +63 -17
- package/package.json +1 -1
package/dist/bot.d.ts
CHANGED
|
@@ -29,6 +29,7 @@ export declare class CcTgBot {
|
|
|
29
29
|
private isSensitiveFile;
|
|
30
30
|
private uploadMentionedFiles;
|
|
31
31
|
private extractToolName;
|
|
32
|
+
private runCronTask;
|
|
32
33
|
private handleCron;
|
|
33
34
|
private handleCronEdit;
|
|
34
35
|
/** Find cc-agent PIDs via pgrep. Returns array of numeric PIDs. */
|
package/dist/bot.js
CHANGED
|
@@ -37,18 +37,9 @@ export class CcTgBot {
|
|
|
37
37
|
this.bot = new TelegramBot(opts.telegramToken, { polling: true });
|
|
38
38
|
this.bot.on("message", (msg) => this.handleTelegram(msg));
|
|
39
39
|
this.bot.on("polling_error", (err) => console.error("[tg]", err.message));
|
|
40
|
-
// Cron manager — fires
|
|
40
|
+
// Cron manager — fires each task into an isolated ClaudeProcess
|
|
41
41
|
this.cron = new CronManager(opts.cwd ?? process.cwd(), (chatId, prompt) => {
|
|
42
|
-
|
|
43
|
-
try {
|
|
44
|
-
session.claude.sendPrompt(`[CRON: ${prompt}]\n\n${prompt}`);
|
|
45
|
-
this.startTyping(chatId, session);
|
|
46
|
-
// Tag result with cron prefix
|
|
47
|
-
session.pendingPrefix = `CRON: ${prompt}\n\n`;
|
|
48
|
-
}
|
|
49
|
-
catch (err) {
|
|
50
|
-
console.error(`[cron] failed to fire for chat=${chatId}:`, err.message);
|
|
51
|
-
}
|
|
42
|
+
this.runCronTask(chatId, prompt);
|
|
52
43
|
});
|
|
53
44
|
this.registerBotCommands();
|
|
54
45
|
console.log("cc-tg bot started");
|
|
@@ -146,7 +137,7 @@ export class CcTgBot {
|
|
|
146
137
|
}
|
|
147
138
|
const session = this.getOrCreateSession(chatId);
|
|
148
139
|
try {
|
|
149
|
-
session.claude.sendPrompt(text);
|
|
140
|
+
session.claude.sendPrompt(buildPromptWithReplyContext(text, msg));
|
|
150
141
|
this.startTyping(chatId, session);
|
|
151
142
|
}
|
|
152
143
|
catch (err) {
|
|
@@ -171,7 +162,7 @@ export class CcTgBot {
|
|
|
171
162
|
// Feed transcript into Claude as if user typed it
|
|
172
163
|
const session = this.getOrCreateSession(chatId);
|
|
173
164
|
try {
|
|
174
|
-
session.claude.sendPrompt(transcript);
|
|
165
|
+
session.claude.sendPrompt(buildPromptWithReplyContext(transcript, msg));
|
|
175
166
|
this.startTyping(chatId, session);
|
|
176
167
|
}
|
|
177
168
|
catch (err) {
|
|
@@ -240,7 +231,6 @@ export class CcTgBot {
|
|
|
240
231
|
const session = {
|
|
241
232
|
claude,
|
|
242
233
|
pendingText: "",
|
|
243
|
-
pendingPrefix: "",
|
|
244
234
|
flushTimer: null,
|
|
245
235
|
typingTimer: null,
|
|
246
236
|
writtenFiles: new Set(),
|
|
@@ -309,13 +299,11 @@ export class CcTgBot {
|
|
|
309
299
|
}
|
|
310
300
|
flushPending(chatId, session) {
|
|
311
301
|
const raw = session.pendingText.trim();
|
|
312
|
-
const prefix = session.pendingPrefix;
|
|
313
302
|
session.pendingText = "";
|
|
314
|
-
session.pendingPrefix = "";
|
|
315
303
|
session.flushTimer = null;
|
|
316
304
|
if (!raw)
|
|
317
305
|
return;
|
|
318
|
-
const text =
|
|
306
|
+
const text = raw;
|
|
319
307
|
// Telegram max message length is 4096 chars — split if needed
|
|
320
308
|
const chunks = splitMessage(text);
|
|
321
309
|
for (const chunk of chunks) {
|
|
@@ -502,6 +490,52 @@ export class CcTgBot {
|
|
|
502
490
|
const toolUse = content.find((b) => b.type === "tool_use");
|
|
503
491
|
return toolUse?.name ?? "";
|
|
504
492
|
}
|
|
493
|
+
runCronTask(chatId, prompt) {
|
|
494
|
+
// Fresh isolated Claude session — never touches main conversation
|
|
495
|
+
const cronProcess = new ClaudeProcess({
|
|
496
|
+
cwd: this.opts.cwd,
|
|
497
|
+
token: this.opts.claudeToken,
|
|
498
|
+
});
|
|
499
|
+
const taskPrompt = [
|
|
500
|
+
"You are handling a scheduled background task.",
|
|
501
|
+
"This is NOT part of the user's ongoing conversation.",
|
|
502
|
+
"Be concise. Report results only. No greetings or pleasantries.",
|
|
503
|
+
"If there is nothing to report, say so in one sentence.",
|
|
504
|
+
"",
|
|
505
|
+
`SCHEDULED TASK: ${prompt}`,
|
|
506
|
+
].join("\n");
|
|
507
|
+
let output = "";
|
|
508
|
+
cronProcess.on("message", (msg) => {
|
|
509
|
+
if (msg.type === "result") {
|
|
510
|
+
const text = extractText(msg);
|
|
511
|
+
if (text)
|
|
512
|
+
output += text;
|
|
513
|
+
const result = output.trim();
|
|
514
|
+
if (result) {
|
|
515
|
+
const chunks = splitMessage(`🕐 ${result}`);
|
|
516
|
+
(async () => {
|
|
517
|
+
for (const chunk of chunks) {
|
|
518
|
+
try {
|
|
519
|
+
await this.bot.sendMessage(chatId, chunk);
|
|
520
|
+
}
|
|
521
|
+
catch (err) {
|
|
522
|
+
console.error(`[cron] failed to send result to chat=${chatId}:`, err.message);
|
|
523
|
+
}
|
|
524
|
+
}
|
|
525
|
+
})();
|
|
526
|
+
}
|
|
527
|
+
cronProcess.kill();
|
|
528
|
+
}
|
|
529
|
+
});
|
|
530
|
+
cronProcess.on("error", (err) => {
|
|
531
|
+
console.error(`[cron] task error for chat=${chatId}:`, err.message);
|
|
532
|
+
cronProcess.kill();
|
|
533
|
+
});
|
|
534
|
+
cronProcess.on("exit", () => {
|
|
535
|
+
console.log(`[cron] task complete for chat=${chatId}`);
|
|
536
|
+
});
|
|
537
|
+
cronProcess.sendPrompt(taskPrompt);
|
|
538
|
+
}
|
|
505
539
|
async handleCron(chatId, text) {
|
|
506
540
|
const args = text.slice("/cron".length).trim();
|
|
507
541
|
// /cron list
|
|
@@ -756,6 +790,18 @@ export class CcTgBot {
|
|
|
756
790
|
}
|
|
757
791
|
}
|
|
758
792
|
}
|
|
793
|
+
function buildPromptWithReplyContext(text, msg) {
|
|
794
|
+
const reply = msg.reply_to_message;
|
|
795
|
+
if (!reply)
|
|
796
|
+
return text;
|
|
797
|
+
const quotedText = reply.text || reply.caption || null;
|
|
798
|
+
if (!quotedText)
|
|
799
|
+
return text;
|
|
800
|
+
const truncated = quotedText.length > 500
|
|
801
|
+
? quotedText.slice(0, 500) + "... [truncated]"
|
|
802
|
+
: quotedText;
|
|
803
|
+
return `[Replying to: "${truncated}"]\n\n${text}`;
|
|
804
|
+
}
|
|
759
805
|
/** Download a URL and return its contents as a base64 string */
|
|
760
806
|
function fetchAsBase64(url) {
|
|
761
807
|
return new Promise((resolve, reject) => {
|