@gonzih/cc-tg 0.1.2 → 0.1.4
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 +3 -0
- package/dist/bot.js +57 -7
- package/package.json +1 -1
package/dist/bot.d.ts
CHANGED
|
@@ -17,7 +17,10 @@ export declare class CcTgBot {
|
|
|
17
17
|
private handleTelegram;
|
|
18
18
|
private getOrCreateSession;
|
|
19
19
|
private handleClaudeMessage;
|
|
20
|
+
private startTyping;
|
|
21
|
+
private stopTyping;
|
|
20
22
|
private flushPending;
|
|
23
|
+
private extractToolName;
|
|
21
24
|
private killSession;
|
|
22
25
|
stop(): void;
|
|
23
26
|
}
|
package/dist/bot.js
CHANGED
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
import TelegramBot from "node-telegram-bot-api";
|
|
6
6
|
import { ClaudeProcess, extractText } from "./claude.js";
|
|
7
7
|
const FLUSH_DELAY_MS = 800; // debounce streaming chunks into one Telegram message
|
|
8
|
+
const TYPING_INTERVAL_MS = 4000; // re-send typing action before Telegram's 5s expiry
|
|
8
9
|
export class CcTgBot {
|
|
9
10
|
bot;
|
|
10
11
|
sessions = new Map();
|
|
@@ -46,6 +47,7 @@ export class CcTgBot {
|
|
|
46
47
|
const session = this.getOrCreateSession(chatId);
|
|
47
48
|
try {
|
|
48
49
|
session.claude.sendPrompt(text);
|
|
50
|
+
this.startTyping(chatId, session);
|
|
49
51
|
}
|
|
50
52
|
catch (err) {
|
|
51
53
|
await this.bot.sendMessage(chatId, `Error sending to Claude: ${err.message}`);
|
|
@@ -64,21 +66,43 @@ export class CcTgBot {
|
|
|
64
66
|
claude,
|
|
65
67
|
pendingText: "",
|
|
66
68
|
flushTimer: null,
|
|
69
|
+
typingTimer: null,
|
|
67
70
|
};
|
|
68
|
-
claude.on("message", (msg) =>
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
71
|
+
claude.on("message", (msg) => {
|
|
72
|
+
// Verbose logging — log every message type and subtype
|
|
73
|
+
const subtype = msg.payload.subtype ?? "";
|
|
74
|
+
const toolName = this.extractToolName(msg);
|
|
75
|
+
const logParts = [`[claude:${chatId}] msg=${msg.type}`];
|
|
76
|
+
if (subtype)
|
|
77
|
+
logParts.push(`subtype=${subtype}`);
|
|
78
|
+
if (toolName)
|
|
79
|
+
logParts.push(`tool=${toolName}`);
|
|
80
|
+
console.log(logParts.join(" "));
|
|
81
|
+
// Surface tool activity to Telegram as a status line
|
|
82
|
+
if (msg.type === "assistant" && toolName) {
|
|
83
|
+
this.bot.sendMessage(chatId, `⚙️ ${toolName}...`).catch(() => { });
|
|
84
|
+
}
|
|
85
|
+
if (msg.type === "system" && subtype === "task_progress") {
|
|
86
|
+
const desc = msg.payload.description ?? "";
|
|
87
|
+
if (desc)
|
|
88
|
+
this.bot.sendMessage(chatId, `🔍 ${desc}`).catch(() => { });
|
|
73
89
|
}
|
|
90
|
+
this.handleClaudeMessage(chatId, session, msg);
|
|
91
|
+
});
|
|
92
|
+
claude.on("stderr", (data) => {
|
|
93
|
+
const line = data.trim();
|
|
94
|
+
if (line)
|
|
95
|
+
console.error(`[claude:${chatId}:stderr]`, line);
|
|
74
96
|
});
|
|
75
97
|
claude.on("exit", (code) => {
|
|
76
|
-
console.log(`[claude:${chatId}] exited
|
|
98
|
+
console.log(`[claude:${chatId}] exited code=${code}`);
|
|
99
|
+
this.stopTyping(session);
|
|
77
100
|
this.sessions.delete(chatId);
|
|
78
101
|
});
|
|
79
102
|
claude.on("error", (err) => {
|
|
80
|
-
console.error(`[claude:${chatId}] process error
|
|
103
|
+
console.error(`[claude:${chatId}] process error: ${err.message}`);
|
|
81
104
|
this.bot.sendMessage(chatId, `Claude process error: ${err.message}`).catch(() => { });
|
|
105
|
+
this.stopTyping(session);
|
|
82
106
|
this.sessions.delete(chatId);
|
|
83
107
|
});
|
|
84
108
|
this.sessions.set(chatId, session);
|
|
@@ -89,6 +113,7 @@ export class CcTgBot {
|
|
|
89
113
|
// Ignore `assistant` streaming chunks to avoid duplicates.
|
|
90
114
|
if (msg.type !== "result")
|
|
91
115
|
return;
|
|
116
|
+
this.stopTyping(session);
|
|
92
117
|
const text = extractText(msg);
|
|
93
118
|
if (!text)
|
|
94
119
|
return;
|
|
@@ -98,6 +123,20 @@ export class CcTgBot {
|
|
|
98
123
|
clearTimeout(session.flushTimer);
|
|
99
124
|
session.flushTimer = setTimeout(() => this.flushPending(chatId, session), FLUSH_DELAY_MS);
|
|
100
125
|
}
|
|
126
|
+
startTyping(chatId, session) {
|
|
127
|
+
this.stopTyping(session);
|
|
128
|
+
// Send immediately, then keep alive every 4s
|
|
129
|
+
this.bot.sendChatAction(chatId, "typing").catch(() => { });
|
|
130
|
+
session.typingTimer = setInterval(() => {
|
|
131
|
+
this.bot.sendChatAction(chatId, "typing").catch(() => { });
|
|
132
|
+
}, TYPING_INTERVAL_MS);
|
|
133
|
+
}
|
|
134
|
+
stopTyping(session) {
|
|
135
|
+
if (session.typingTimer) {
|
|
136
|
+
clearInterval(session.typingTimer);
|
|
137
|
+
session.typingTimer = null;
|
|
138
|
+
}
|
|
139
|
+
}
|
|
101
140
|
flushPending(chatId, session) {
|
|
102
141
|
const text = session.pendingText.trim();
|
|
103
142
|
session.pendingText = "";
|
|
@@ -113,9 +152,20 @@ export class CcTgBot {
|
|
|
113
152
|
});
|
|
114
153
|
}
|
|
115
154
|
}
|
|
155
|
+
extractToolName(msg) {
|
|
156
|
+
const message = msg.payload.message;
|
|
157
|
+
if (!message)
|
|
158
|
+
return "";
|
|
159
|
+
const content = message.content;
|
|
160
|
+
if (!Array.isArray(content))
|
|
161
|
+
return "";
|
|
162
|
+
const toolUse = content.find((b) => b.type === "tool_use");
|
|
163
|
+
return toolUse?.name ?? "";
|
|
164
|
+
}
|
|
116
165
|
killSession(chatId) {
|
|
117
166
|
const session = this.sessions.get(chatId);
|
|
118
167
|
if (session) {
|
|
168
|
+
this.stopTyping(session);
|
|
119
169
|
session.claude.kill();
|
|
120
170
|
this.sessions.delete(chatId);
|
|
121
171
|
}
|