@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 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) => this.handleClaudeMessage(chatId, session, msg));
69
- claude.on("stderr", (data) => {
70
- // Only surface non-noise stderr
71
- if (data.includes("Error") || data.includes("error")) {
72
- console.error(`[claude:${chatId}]`, data.trim());
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 with code ${code}`);
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:`, err.message);
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
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gonzih/cc-tg",
3
- "version": "0.1.2",
3
+ "version": "0.1.4",
4
4
  "description": "Claude Code Telegram bot — chat with Claude Code via Telegram",
5
5
  "type": "module",
6
6
  "bin": {