@gonzih/cc-tg 0.9.0 → 0.9.1
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 +7 -0
- package/dist/index.js +17 -13
- package/dist/notifier.d.ts +3 -2
- package/dist/notifier.js +32 -22
- package/package.json +1 -1
package/dist/bot.d.ts
CHANGED
|
@@ -23,10 +23,13 @@ export declare class CcTgBot {
|
|
|
23
23
|
private botId;
|
|
24
24
|
private redis?;
|
|
25
25
|
private namespace;
|
|
26
|
+
private lastActiveChatId?;
|
|
26
27
|
constructor(opts: BotOptions);
|
|
27
28
|
private registerBotCommands;
|
|
28
29
|
/** Write a message to the Redis chat log. Fire-and-forget — no-op if Redis is not configured. */
|
|
29
30
|
private writeChatMessage;
|
|
31
|
+
/** Returns the last chatId that sent a message — used by the chat bridge when no fixed chatId is configured. */
|
|
32
|
+
getLastActiveChatId(): number | undefined;
|
|
30
33
|
/** Session key: "chatId:threadId" for topics, "chatId:main" for DMs/non-topic groups */
|
|
31
34
|
private sessionKey;
|
|
32
35
|
/**
|
package/dist/bot.js
CHANGED
|
@@ -156,6 +156,7 @@ export class CcTgBot {
|
|
|
156
156
|
botId = 0;
|
|
157
157
|
redis;
|
|
158
158
|
namespace;
|
|
159
|
+
lastActiveChatId;
|
|
159
160
|
constructor(opts) {
|
|
160
161
|
this.opts = opts;
|
|
161
162
|
this.redis = opts.redis;
|
|
@@ -192,6 +193,10 @@ export class CcTgBot {
|
|
|
192
193
|
};
|
|
193
194
|
writeChatLog(this.redis, this.namespace, msg);
|
|
194
195
|
}
|
|
196
|
+
/** Returns the last chatId that sent a message — used by the chat bridge when no fixed chatId is configured. */
|
|
197
|
+
getLastActiveChatId() {
|
|
198
|
+
return this.lastActiveChatId;
|
|
199
|
+
}
|
|
195
200
|
/** Session key: "chatId:threadId" for topics, "chatId:main" for DMs/non-topic groups */
|
|
196
201
|
sessionKey(chatId, threadId) {
|
|
197
202
|
return `${chatId}:${threadId ?? 'main'}`;
|
|
@@ -243,6 +248,8 @@ export class CcTgBot {
|
|
|
243
248
|
await this.replyToChat(chatId, "Not authorized.", threadId);
|
|
244
249
|
return;
|
|
245
250
|
}
|
|
251
|
+
// Track the last chat that sent us a message for the chat bridge
|
|
252
|
+
this.lastActiveChatId = chatId;
|
|
246
253
|
// Group chat handling
|
|
247
254
|
const isGroup = msg.chat.type === "group" || msg.chat.type === "supergroup";
|
|
248
255
|
if (isGroup) {
|
package/dist/index.js
CHANGED
|
@@ -113,20 +113,26 @@ const groupChatIds = process.env.GROUP_CHAT_IDS
|
|
|
113
113
|
? process.env.GROUP_CHAT_IDS.split(",").map((s) => parseInt(s.trim(), 10)).filter(Boolean)
|
|
114
114
|
: [];
|
|
115
115
|
const cwd = process.env.CWD ?? process.cwd();
|
|
116
|
+
// agent-ops / chat bridge — Redis is always initialized so the chat bridge works
|
|
117
|
+
// regardless of whether CC_AGENT_OPS_PORT or CC_AGENT_NOTIFY_CHAT_ID are set.
|
|
118
|
+
const redisUrl = process.env.REDIS_URL || "redis://localhost:6379";
|
|
119
|
+
const namespace = process.env.CC_AGENT_NAMESPACE || "default";
|
|
120
|
+
const sharedRedis = new Redis(redisUrl);
|
|
121
|
+
sharedRedis.on("error", (err) => {
|
|
122
|
+
// Non-fatal — Redis features (chat bridge, ops) degrade gracefully
|
|
123
|
+
console.warn("[redis] connection error:", err.message);
|
|
124
|
+
});
|
|
116
125
|
const bot = new CcTgBot({
|
|
117
126
|
telegramToken,
|
|
118
127
|
claudeToken,
|
|
119
128
|
cwd,
|
|
120
129
|
allowedUserIds,
|
|
121
130
|
groupChatIds,
|
|
131
|
+
redis: sharedRedis,
|
|
132
|
+
namespace,
|
|
122
133
|
});
|
|
123
|
-
// agent-ops: optional self-registration + HTTP control endpoint
|
|
124
|
-
const redisUrl = process.env.REDIS_URL || "redis://localhost:6379";
|
|
125
|
-
const namespace = process.env.CC_AGENT_NAMESPACE || "default";
|
|
126
|
-
let sharedRedis = null;
|
|
127
134
|
if (process.env.CC_AGENT_OPS_PORT) {
|
|
128
135
|
const botInfo = await bot.getMe();
|
|
129
|
-
sharedRedis = new Redis(redisUrl);
|
|
130
136
|
const registry = new Registry(sharedRedis);
|
|
131
137
|
await registry.register({
|
|
132
138
|
namespace,
|
|
@@ -147,17 +153,15 @@ if (process.env.CC_AGENT_OPS_PORT) {
|
|
|
147
153
|
});
|
|
148
154
|
console.log(`[ops] control server on port ${process.env.CC_AGENT_OPS_PORT}`);
|
|
149
155
|
}
|
|
150
|
-
// Notifier — subscribe to cca:notify
|
|
156
|
+
// Notifier — always subscribe to cca:notify and cca:chat:incoming channels.
|
|
157
|
+
// CC_AGENT_NOTIFY_CHAT_ID pins a fixed Telegram chatId; without it the last
|
|
158
|
+
// active chatId is used dynamically for the chat bridge.
|
|
151
159
|
const notifyChatId = process.env.CC_AGENT_NOTIFY_CHAT_ID
|
|
152
160
|
? Number(process.env.CC_AGENT_NOTIFY_CHAT_ID)
|
|
153
161
|
: null;
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
const notifierBot = new TelegramBot(telegramToken, { polling: false });
|
|
158
|
-
startNotifier(notifierBot, notifyChatId, namespace, sharedRedis, (cid, text) => bot.handleUserMessage(cid, text));
|
|
159
|
-
console.log(`[notifier] started for namespace=${namespace} chatId=${notifyChatId}`);
|
|
160
|
-
}
|
|
162
|
+
const notifierBot = new TelegramBot(telegramToken, { polling: false });
|
|
163
|
+
startNotifier(notifierBot, notifyChatId, namespace, sharedRedis, (cid, text) => bot.handleUserMessage(cid, text), () => bot.getLastActiveChatId());
|
|
164
|
+
console.log(`[notifier] started for namespace=${namespace} chatId=${notifyChatId ?? "dynamic"}`);
|
|
161
165
|
process.on("SIGINT", () => {
|
|
162
166
|
console.log("\nShutting down...");
|
|
163
167
|
bot.stop();
|
package/dist/notifier.d.ts
CHANGED
|
@@ -28,9 +28,10 @@ export declare function writeChatLog(redis: Redis, namespace: string, msg: ChatM
|
|
|
28
28
|
* Start the notifier.
|
|
29
29
|
*
|
|
30
30
|
* @param bot - Telegram bot instance (for sending messages)
|
|
31
|
-
* @param chatId - Telegram chat ID to forward notifications to
|
|
31
|
+
* @param chatId - Telegram chat ID to forward notifications to. Pass null to use getActiveChatId.
|
|
32
32
|
* @param namespace - cc-agent namespace (used to build Redis channel names)
|
|
33
33
|
* @param redis - ioredis client in normal mode (will be duplicated for pub/sub)
|
|
34
34
|
* @param handleUserMessage - Optional callback to feed UI messages into the active Claude session
|
|
35
|
+
* @param getActiveChatId - Optional callback to resolve chatId dynamically (used when chatId is null)
|
|
35
36
|
*/
|
|
36
|
-
export declare function startNotifier(bot: TelegramBot, chatId: number, namespace: string, redis: Redis, handleUserMessage?: (chatId: number, text: string) => void): void;
|
|
37
|
+
export declare function startNotifier(bot: TelegramBot, chatId: number | null, namespace: string, redis: Redis, handleUserMessage?: (chatId: number, text: string) => void, getActiveChatId?: () => number | undefined): void;
|
package/dist/notifier.js
CHANGED
|
@@ -35,12 +35,13 @@ export function writeChatLog(redis, namespace, msg) {
|
|
|
35
35
|
* Start the notifier.
|
|
36
36
|
*
|
|
37
37
|
* @param bot - Telegram bot instance (for sending messages)
|
|
38
|
-
* @param chatId - Telegram chat ID to forward notifications to
|
|
38
|
+
* @param chatId - Telegram chat ID to forward notifications to. Pass null to use getActiveChatId.
|
|
39
39
|
* @param namespace - cc-agent namespace (used to build Redis channel names)
|
|
40
40
|
* @param redis - ioredis client in normal mode (will be duplicated for pub/sub)
|
|
41
41
|
* @param handleUserMessage - Optional callback to feed UI messages into the active Claude session
|
|
42
|
+
* @param getActiveChatId - Optional callback to resolve chatId dynamically (used when chatId is null)
|
|
42
43
|
*/
|
|
43
|
-
export function startNotifier(bot, chatId, namespace, redis, handleUserMessage) {
|
|
44
|
+
export function startNotifier(bot, chatId, namespace, redis, handleUserMessage, getActiveChatId) {
|
|
44
45
|
const sub = redis.duplicate({
|
|
45
46
|
retryStrategy: (times) => {
|
|
46
47
|
const delay = Math.min(1000 * Math.pow(2, times - 1), 30_000);
|
|
@@ -76,9 +77,11 @@ export function startNotifier(bot, chatId, namespace, redis, handleUserMessage)
|
|
|
76
77
|
const notifyChannel = `cca:notify:${namespace}`;
|
|
77
78
|
const incomingChannel = `cca:chat:incoming:${namespace}`;
|
|
78
79
|
if (channel === notifyChannel) {
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
80
|
+
if (chatId !== null) {
|
|
81
|
+
bot.sendMessage(chatId, message).catch((err) => {
|
|
82
|
+
log("warn", "sendMessage failed:", err.message);
|
|
83
|
+
});
|
|
84
|
+
}
|
|
82
85
|
return;
|
|
83
86
|
}
|
|
84
87
|
if (channel === incomingChannel) {
|
|
@@ -91,23 +94,30 @@ export function startNotifier(bot, chatId, namespace, redis, handleUserMessage)
|
|
|
91
94
|
catch {
|
|
92
95
|
// raw string message — use as-is
|
|
93
96
|
}
|
|
94
|
-
//
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
97
|
+
// Resolve the target chatId: prefer the fixed chatId, fall back to last active
|
|
98
|
+
const targetChatId = chatId ?? getActiveChatId?.();
|
|
99
|
+
if (targetChatId !== undefined) {
|
|
100
|
+
// Echo to Telegram so the user sees UI messages in the chat
|
|
101
|
+
bot.sendMessage(targetChatId, `📱 [from UI]: ${content}`).catch((err) => {
|
|
102
|
+
log("warn", "sendMessage (UI echo) failed:", err.message);
|
|
103
|
+
});
|
|
104
|
+
// Log the incoming message
|
|
105
|
+
const inMsg = {
|
|
106
|
+
id: `ui-${Date.now()}-${Math.random().toString(36).slice(2, 6)}`,
|
|
107
|
+
source: "ui",
|
|
108
|
+
role: "user",
|
|
109
|
+
content,
|
|
110
|
+
timestamp: new Date().toISOString(),
|
|
111
|
+
chatId: targetChatId,
|
|
112
|
+
};
|
|
113
|
+
writeChatLog(redis, namespace, inMsg);
|
|
114
|
+
// Feed into active Claude session as if user typed it
|
|
115
|
+
if (handleUserMessage) {
|
|
116
|
+
handleUserMessage(targetChatId, content);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
else {
|
|
120
|
+
log("warn", "cca:chat:incoming: no active chatId to route message to");
|
|
111
121
|
}
|
|
112
122
|
}
|
|
113
123
|
});
|