@gonzih/cc-tg 0.3.14 → 0.3.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.js +8 -4
- package/dist/cron.d.ts +7 -1
- package/dist/cron.js +24 -3
- package/package.json +1 -1
package/dist/bot.js
CHANGED
|
@@ -168,9 +168,11 @@ export class CcTgBot {
|
|
|
168
168
|
this.botId = me.id;
|
|
169
169
|
console.log(`[tg] bot identity: @${this.botUsername} (id=${this.botId})`);
|
|
170
170
|
}).catch((err) => console.error("[tg] getMe failed:", err.message));
|
|
171
|
-
// Cron manager — fires each task into an isolated ClaudeProcess
|
|
172
|
-
|
|
173
|
-
|
|
171
|
+
// Cron manager — fires each task into an isolated ClaudeProcess.
|
|
172
|
+
// The `done` callback is passed through to runCronTask so the cron manager
|
|
173
|
+
// knows when a task finishes and can allow the next tick to run.
|
|
174
|
+
this.cron = new CronManager(opts.cwd ?? process.cwd(), (chatId, prompt, jobId, done) => {
|
|
175
|
+
this.runCronTask(chatId, prompt, done);
|
|
174
176
|
});
|
|
175
177
|
this.costStore = new CostStore(opts.cwd ?? process.cwd());
|
|
176
178
|
this.registerBotCommands();
|
|
@@ -722,7 +724,7 @@ export class CcTgBot {
|
|
|
722
724
|
const toolUse = content.find((b) => b.type === "tool_use");
|
|
723
725
|
return toolUse?.name ?? "";
|
|
724
726
|
}
|
|
725
|
-
runCronTask(chatId, prompt) {
|
|
727
|
+
runCronTask(chatId, prompt, done = () => { }) {
|
|
726
728
|
// Fresh isolated Claude session — never touches main conversation
|
|
727
729
|
const cronProcess = new ClaudeProcess({
|
|
728
730
|
cwd: this.opts.cwd,
|
|
@@ -783,9 +785,11 @@ export class CcTgBot {
|
|
|
783
785
|
cronProcess.on("error", (err) => {
|
|
784
786
|
console.error(`[cron] task error for chat=${chatId}:`, err.message);
|
|
785
787
|
cronProcess.kill();
|
|
788
|
+
done();
|
|
786
789
|
});
|
|
787
790
|
cronProcess.on("exit", () => {
|
|
788
791
|
console.log(`[cron] task complete for chat=${chatId}`);
|
|
792
|
+
done();
|
|
789
793
|
});
|
|
790
794
|
cronProcess.sendPrompt(taskPrompt);
|
|
791
795
|
}
|
package/dist/cron.d.ts
CHANGED
|
@@ -11,9 +11,15 @@ export interface CronJob {
|
|
|
11
11
|
createdAt: string;
|
|
12
12
|
schedule: string;
|
|
13
13
|
}
|
|
14
|
-
|
|
14
|
+
/** Called when a job fires. `done` must be called when the task completes so
|
|
15
|
+
* the next scheduled tick is allowed to run. Until `done` is called, concurrent
|
|
16
|
+
* ticks for the same job are silently skipped (prevents the resume-loop explosion
|
|
17
|
+
* where each tick spawns more agents than the last). */
|
|
18
|
+
type FireCallback = (chatId: number, prompt: string, jobId: string, done: () => void) => void;
|
|
15
19
|
export declare class CronManager {
|
|
16
20
|
private jobs;
|
|
21
|
+
/** Job IDs whose fire callback has been invoked but whose `done` hasn't fired yet. */
|
|
22
|
+
private activeJobs;
|
|
17
23
|
private storePath;
|
|
18
24
|
private fire;
|
|
19
25
|
constructor(cwd: string, fire: FireCallback);
|
package/dist/cron.js
CHANGED
|
@@ -7,6 +7,8 @@ import { readFileSync, writeFileSync, mkdirSync, existsSync } from "fs";
|
|
|
7
7
|
import { join } from "path";
|
|
8
8
|
export class CronManager {
|
|
9
9
|
jobs = new Map();
|
|
10
|
+
/** Job IDs whose fire callback has been invoked but whose `done` hasn't fired yet. */
|
|
11
|
+
activeJobs = new Set();
|
|
10
12
|
storePath;
|
|
11
13
|
fire;
|
|
12
14
|
constructor(cwd, fire) {
|
|
@@ -36,8 +38,13 @@ export class CronManager {
|
|
|
36
38
|
const id = `${Date.now()}-${Math.random().toString(36).slice(2, 6)}`;
|
|
37
39
|
const job = { id, chatId, intervalMs, prompt, schedule, createdAt: new Date().toISOString() };
|
|
38
40
|
const timer = setInterval(() => {
|
|
41
|
+
if (this.activeJobs.has(id)) {
|
|
42
|
+
console.log(`[cron:${id}] skipping tick — previous task still running`);
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
this.activeJobs.add(id);
|
|
39
46
|
console.log(`[cron:${id}] firing for chat=${chatId} prompt="${prompt}"`);
|
|
40
|
-
this.fire(chatId, prompt);
|
|
47
|
+
this.fire(chatId, prompt, id, () => { this.activeJobs.delete(id); });
|
|
41
48
|
}, intervalMs);
|
|
42
49
|
this.jobs.set(id, { ...job, timer });
|
|
43
50
|
this.persist();
|
|
@@ -48,6 +55,7 @@ export class CronManager {
|
|
|
48
55
|
if (!job || job.chatId !== chatId)
|
|
49
56
|
return false;
|
|
50
57
|
clearInterval(job.timer);
|
|
58
|
+
this.activeJobs.delete(id);
|
|
51
59
|
this.jobs.delete(id);
|
|
52
60
|
this.persist();
|
|
53
61
|
return true;
|
|
@@ -57,6 +65,7 @@ export class CronManager {
|
|
|
57
65
|
for (const [id, job] of this.jobs) {
|
|
58
66
|
if (job.chatId === chatId) {
|
|
59
67
|
clearInterval(job.timer);
|
|
68
|
+
this.activeJobs.delete(id);
|
|
60
69
|
this.jobs.delete(id);
|
|
61
70
|
count++;
|
|
62
71
|
}
|
|
@@ -86,9 +95,16 @@ export class CronManager {
|
|
|
86
95
|
}
|
|
87
96
|
// Recreate timer so it uses updated intervalMs and always reads latest job.prompt
|
|
88
97
|
clearInterval(job.timer);
|
|
98
|
+
// Also clear any active-job lock so the updated timer can fire immediately next tick
|
|
99
|
+
this.activeJobs.delete(job.id);
|
|
89
100
|
job.timer = setInterval(() => {
|
|
101
|
+
if (this.activeJobs.has(job.id)) {
|
|
102
|
+
console.log(`[cron:${job.id}] skipping tick — previous task still running`);
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
105
|
+
this.activeJobs.add(job.id);
|
|
90
106
|
console.log(`[cron:${job.id}] firing for chat=${job.chatId} prompt="${job.prompt}"`);
|
|
91
|
-
this.fire(job.chatId, job.prompt);
|
|
107
|
+
this.fire(job.chatId, job.prompt, job.id, () => { this.activeJobs.delete(job.id); });
|
|
92
108
|
}, job.intervalMs);
|
|
93
109
|
this.persist();
|
|
94
110
|
const { timer: _t, ...cronJob } = job;
|
|
@@ -113,8 +129,13 @@ export class CronManager {
|
|
|
113
129
|
const data = JSON.parse(readFileSync(this.storePath, "utf8"));
|
|
114
130
|
for (const job of data) {
|
|
115
131
|
const timer = setInterval(() => {
|
|
132
|
+
if (this.activeJobs.has(job.id)) {
|
|
133
|
+
console.log(`[cron:${job.id}] skipping tick — previous task still running`);
|
|
134
|
+
return;
|
|
135
|
+
}
|
|
136
|
+
this.activeJobs.add(job.id);
|
|
116
137
|
console.log(`[cron:${job.id}] firing for chat=${job.chatId} prompt="${job.prompt}"`);
|
|
117
|
-
this.fire(job.chatId, job.prompt);
|
|
138
|
+
this.fire(job.chatId, job.prompt, job.id, () => { this.activeJobs.delete(job.id); });
|
|
118
139
|
}, job.intervalMs);
|
|
119
140
|
this.jobs.set(job.id, { ...job, timer });
|
|
120
141
|
}
|