@gonzih/cc-tg 0.9.42 → 0.9.44

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
@@ -12,6 +12,9 @@ export interface BotOptions {
12
12
  groupChatIds?: number[];
13
13
  redis?: Redis;
14
14
  namespace?: string;
15
+ /** Called when a message is routed to a non-default namespace so the notifier
16
+ * can forward the response back to the originating Telegram chat. */
17
+ registerRoutedChatId?: (namespace: string, chatId: number) => void;
15
18
  }
16
19
  /** Prepend [MM-DD HH:mm] so Claude knows when the message was received. Not shown in Telegram. */
17
20
  export declare function stampPrompt(text: string, now?: Date): string;
package/dist/bot.js CHANGED
@@ -454,6 +454,8 @@ export class CcTgBot {
454
454
  // Acknowledge routing immediately so user knows the message was delegated
455
455
  await this.replyToChat(chatId, `→ #${routing.namespace}`, threadId);
456
456
  this.writeChatMessage("user", "telegram", text, chatId);
457
+ // Register the originating chatId so responses come back to this chat
458
+ this.opts.registerRoutedChatId?.(routing.namespace, chatId);
457
459
  try {
458
460
  await ensureMetaAgent(routing.namespace, routing.repoUrl, (toolName, args) => this.callCcAgentTool(toolName, args ?? {}), this.redis);
459
461
  await routeToMetaAgent(routing.namespace, routing.strippedMessage, this.redis);
@@ -478,6 +480,8 @@ export class CcTgBot {
478
480
  const repoUrl = `https://github.com/${defaultOrg}/${namespace}`;
479
481
  await this.replyToChat(chatId, `→ #${namespace} (meta-agent)`, threadId);
480
482
  this.writeChatMessage("user", "telegram", text, chatId);
483
+ // Register the originating chatId so responses come back to this chat
484
+ this.opts.registerRoutedChatId?.(namespace, chatId);
481
485
  try {
482
486
  await ensureMetaAgent(namespace, repoUrl, (toolName, args) => this.callCcAgentTool(toolName, args ?? {}), this.redis);
483
487
  await routeToMetaAgent(namespace, text, this.redis);
package/dist/index.js CHANGED
@@ -130,6 +130,20 @@ sharedRedis.once("ready", () => {
130
130
  });
131
131
  console.log(`[cc-tg] version:reported ${pkg.version}`);
132
132
  });
133
+ // Notifier — always subscribe to cca:notify and cca:chat:incoming channels.
134
+ // CC_AGENT_NOTIFY_CHAT_ID pins a fixed Telegram chatId; without it the last
135
+ // active chatId is used dynamically for the chat bridge.
136
+ // Created before the bot so we can pass registerRoutedChatId into BotOptions.
137
+ // Callbacks are wired via closures that delegate to the bot after it is created.
138
+ const notifyChatId = process.env.CC_AGENT_NOTIFY_CHAT_ID
139
+ ? Number(process.env.CC_AGENT_NOTIFY_CHAT_ID)
140
+ : null;
141
+ // Mutable placeholder closures — filled in once `bot` is created below.
142
+ let getLastActiveChatIdFn = () => undefined;
143
+ let handleUserMessageFn;
144
+ const notifierBot = new TelegramBot(telegramToken, { polling: false });
145
+ const notifier = startNotifier(notifierBot, notifyChatId, namespace, sharedRedis, (cid, text) => handleUserMessageFn?.(cid, text), () => getLastActiveChatIdFn());
146
+ console.log(`[notifier] started for namespace=${namespace} chatId=${notifyChatId ?? "dynamic"}`);
133
147
  const bot = new CcTgBot({
134
148
  telegramToken,
135
149
  claudeToken,
@@ -138,7 +152,11 @@ const bot = new CcTgBot({
138
152
  groupChatIds,
139
153
  redis: sharedRedis,
140
154
  namespace,
155
+ registerRoutedChatId: (ns, chatId) => notifier.registerRoutedChatId(ns, chatId),
141
156
  });
157
+ // Wire closures now that bot is constructed
158
+ getLastActiveChatIdFn = () => bot.getLastActiveChatId();
159
+ handleUserMessageFn = (cid, text) => { void bot.handleUserMessage(cid, text); };
142
160
  if (process.env.CC_AGENT_OPS_PORT) {
143
161
  const botInfo = await bot.getMe();
144
162
  const registry = new Registry(sharedRedis);
@@ -161,15 +179,6 @@ if (process.env.CC_AGENT_OPS_PORT) {
161
179
  });
162
180
  console.log(`[ops] control server on port ${process.env.CC_AGENT_OPS_PORT}`);
163
181
  }
164
- // Notifier — always subscribe to cca:notify and cca:chat:incoming channels.
165
- // CC_AGENT_NOTIFY_CHAT_ID pins a fixed Telegram chatId; without it the last
166
- // active chatId is used dynamically for the chat bridge.
167
- const notifyChatId = process.env.CC_AGENT_NOTIFY_CHAT_ID
168
- ? Number(process.env.CC_AGENT_NOTIFY_CHAT_ID)
169
- : null;
170
- const notifierBot = new TelegramBot(telegramToken, { polling: false });
171
- startNotifier(notifierBot, notifyChatId, namespace, sharedRedis, (cid, text) => bot.handleUserMessage(cid, text), () => bot.getLastActiveChatId());
172
- console.log(`[notifier] started for namespace=${namespace} chatId=${notifyChatId ?? "dynamic"}`);
173
182
  process.on("SIGINT", () => {
174
183
  console.log("\nShutting down...");
175
184
  bot.stop();
@@ -34,6 +34,16 @@ export declare function parseNotification(raw: string): string;
34
34
  * Fire-and-forget — errors are logged but not thrown.
35
35
  */
36
36
  export declare function writeChatLog(redis: Redis, namespace: string, msg: ChatMessage): void;
37
+ export interface NotifierHandle {
38
+ /**
39
+ * Register the originating Telegram chat ID for a routed namespace.
40
+ * When the meta-agent for `namespace` publishes a response, it will be
41
+ * forwarded to `chatId` instead of the global fixed/dynamic chatId.
42
+ * Call this before routing each message to ensure the response returns
43
+ * to the correct chat.
44
+ */
45
+ registerRoutedChatId: (namespace: string, chatId: number) => void;
46
+ }
37
47
  /**
38
48
  * Start the notifier.
39
49
  *
@@ -43,5 +53,7 @@ export declare function writeChatLog(redis: Redis, namespace: string, msg: ChatM
43
53
  * @param redis - ioredis client in normal mode (will be duplicated for pub/sub)
44
54
  * @param handleUserMessage - Optional callback to feed UI messages into the active Claude session
45
55
  * @param getActiveChatId - Optional callback to resolve chatId dynamically (used when chatId is null)
56
+ *
57
+ * @returns NotifierHandle with registerRoutedChatId for per-namespace response routing
46
58
  */
47
- export declare function startNotifier(bot: TelegramBot, chatId: number | null, namespace: string, redis: Redis, handleUserMessage?: (chatId: number, text: string) => void, getActiveChatId?: () => number | undefined): void;
59
+ export declare function startNotifier(bot: TelegramBot, chatId: number | null, namespace: string, redis: Redis, handleUserMessage?: (chatId: number, text: string) => void, getActiveChatId?: () => number | undefined): NotifierHandle;
package/dist/notifier.js CHANGED
@@ -99,8 +99,13 @@ export function writeChatLog(redis, namespace, msg) {
99
99
  * @param redis - ioredis client in normal mode (will be duplicated for pub/sub)
100
100
  * @param handleUserMessage - Optional callback to feed UI messages into the active Claude session
101
101
  * @param getActiveChatId - Optional callback to resolve chatId dynamically (used when chatId is null)
102
+ *
103
+ * @returns NotifierHandle with registerRoutedChatId for per-namespace response routing
102
104
  */
103
105
  export function startNotifier(bot, chatId, namespace, redis, handleUserMessage, getActiveChatId) {
106
+ // Per-namespace chatId registry: when a message is routed to a non-default namespace,
107
+ // the originating Telegram chatId is registered here so responses go back to the right chat.
108
+ const routedChatIds = new Map();
104
109
  const sub = redis.duplicate({
105
110
  retryStrategy: (times) => {
106
111
  const delay = Math.min(1000 * Math.pow(2, times - 1), 30_000);
@@ -177,7 +182,9 @@ export function startNotifier(bot, chatId, namespace, redis, handleUserMessage,
177
182
  const content = parsed.content;
178
183
  if (!content)
179
184
  return;
180
- const targetChatId = chatId ?? getActiveChatId?.();
185
+ // Per-namespace chatId wins (set by registerRoutedChatId when a message is routed).
186
+ // Falls back to the global fixed chatId or the last-active dynamic chatId.
187
+ const targetChatId = routedChatIds.get(ns) ?? chatId ?? getActiveChatId?.();
181
188
  if (targetChatId == null) {
182
189
  log("warn", `meta-agent output: no chatId for namespace=${ns}, dropping line`);
183
190
  return;
@@ -326,4 +333,9 @@ export function startNotifier(bot, chatId, namespace, redis, handleUserMessage,
326
333
  }
327
334
  }
328
335
  });
336
+ return {
337
+ registerRoutedChatId: (ns, cid) => {
338
+ routedChatIds.set(ns, cid);
339
+ },
340
+ };
329
341
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gonzih/cc-tg",
3
- "version": "0.9.42",
3
+ "version": "0.9.44",
4
4
  "description": "Claude Code Telegram bot — chat with Claude Code via Telegram",
5
5
  "type": "module",
6
6
  "bin": {