@gonzih/cc-tg 0.8.2 → 0.9.0
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 +0 -3
- package/dist/bot.js +0 -7
- package/dist/index.js +13 -17
- package/dist/notifier.d.ts +2 -3
- package/dist/notifier.js +22 -32
- package/package.json +1 -1
package/dist/bot.d.ts
CHANGED
|
@@ -23,13 +23,10 @@ export declare class CcTgBot {
|
|
|
23
23
|
private botId;
|
|
24
24
|
private redis?;
|
|
25
25
|
private namespace;
|
|
26
|
-
private lastActiveChatId?;
|
|
27
26
|
constructor(opts: BotOptions);
|
|
28
27
|
private registerBotCommands;
|
|
29
28
|
/** Write a message to the Redis chat log. Fire-and-forget — no-op if Redis is not configured. */
|
|
30
29
|
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;
|
|
33
30
|
/** Session key: "chatId:threadId" for topics, "chatId:main" for DMs/non-topic groups */
|
|
34
31
|
private sessionKey;
|
|
35
32
|
/**
|
package/dist/bot.js
CHANGED
|
@@ -156,7 +156,6 @@ export class CcTgBot {
|
|
|
156
156
|
botId = 0;
|
|
157
157
|
redis;
|
|
158
158
|
namespace;
|
|
159
|
-
lastActiveChatId;
|
|
160
159
|
constructor(opts) {
|
|
161
160
|
this.opts = opts;
|
|
162
161
|
this.redis = opts.redis;
|
|
@@ -193,10 +192,6 @@ export class CcTgBot {
|
|
|
193
192
|
};
|
|
194
193
|
writeChatLog(this.redis, this.namespace, msg);
|
|
195
194
|
}
|
|
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
|
-
}
|
|
200
195
|
/** Session key: "chatId:threadId" for topics, "chatId:main" for DMs/non-topic groups */
|
|
201
196
|
sessionKey(chatId, threadId) {
|
|
202
197
|
return `${chatId}:${threadId ?? 'main'}`;
|
|
@@ -248,8 +243,6 @@ export class CcTgBot {
|
|
|
248
243
|
await this.replyToChat(chatId, "Not authorized.", threadId);
|
|
249
244
|
return;
|
|
250
245
|
}
|
|
251
|
-
// Track the last chat that sent us a message for the chat bridge
|
|
252
|
-
this.lastActiveChatId = chatId;
|
|
253
246
|
// Group chat handling
|
|
254
247
|
const isGroup = msg.chat.type === "group" || msg.chat.type === "supergroup";
|
|
255
248
|
if (isGroup) {
|
package/dist/index.js
CHANGED
|
@@ -113,26 +113,20 @@ 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
|
-
});
|
|
125
116
|
const bot = new CcTgBot({
|
|
126
117
|
telegramToken,
|
|
127
118
|
claudeToken,
|
|
128
119
|
cwd,
|
|
129
120
|
allowedUserIds,
|
|
130
121
|
groupChatIds,
|
|
131
|
-
redis: sharedRedis,
|
|
132
|
-
namespace,
|
|
133
122
|
});
|
|
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;
|
|
134
127
|
if (process.env.CC_AGENT_OPS_PORT) {
|
|
135
128
|
const botInfo = await bot.getMe();
|
|
129
|
+
sharedRedis = new Redis(redisUrl);
|
|
136
130
|
const registry = new Registry(sharedRedis);
|
|
137
131
|
await registry.register({
|
|
138
132
|
namespace,
|
|
@@ -153,15 +147,17 @@ if (process.env.CC_AGENT_OPS_PORT) {
|
|
|
153
147
|
});
|
|
154
148
|
console.log(`[ops] control server on port ${process.env.CC_AGENT_OPS_PORT}`);
|
|
155
149
|
}
|
|
156
|
-
// Notifier —
|
|
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.
|
|
150
|
+
// Notifier — subscribe to cca:notify:{namespace} and cca:chat:incoming:{namespace}
|
|
159
151
|
const notifyChatId = process.env.CC_AGENT_NOTIFY_CHAT_ID
|
|
160
152
|
? Number(process.env.CC_AGENT_NOTIFY_CHAT_ID)
|
|
161
153
|
: null;
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
154
|
+
if (notifyChatId) {
|
|
155
|
+
if (!sharedRedis)
|
|
156
|
+
sharedRedis = new Redis(redisUrl);
|
|
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
|
+
}
|
|
165
161
|
process.on("SIGINT", () => {
|
|
166
162
|
console.log("\nShutting down...");
|
|
167
163
|
bot.stop();
|
package/dist/notifier.d.ts
CHANGED
|
@@ -28,10 +28,9 @@ 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
|
|
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)
|
|
36
35
|
*/
|
|
37
|
-
export declare function startNotifier(bot: TelegramBot, chatId: number
|
|
36
|
+
export declare function startNotifier(bot: TelegramBot, chatId: number, namespace: string, redis: Redis, handleUserMessage?: (chatId: number, text: string) => void): void;
|
package/dist/notifier.js
CHANGED
|
@@ -35,13 +35,12 @@ 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
|
|
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)
|
|
43
42
|
*/
|
|
44
|
-
export function startNotifier(bot, chatId, namespace, redis, handleUserMessage
|
|
43
|
+
export function startNotifier(bot, chatId, namespace, redis, handleUserMessage) {
|
|
45
44
|
const sub = redis.duplicate({
|
|
46
45
|
retryStrategy: (times) => {
|
|
47
46
|
const delay = Math.min(1000 * Math.pow(2, times - 1), 30_000);
|
|
@@ -77,11 +76,9 @@ export function startNotifier(bot, chatId, namespace, redis, handleUserMessage,
|
|
|
77
76
|
const notifyChannel = `cca:notify:${namespace}`;
|
|
78
77
|
const incomingChannel = `cca:chat:incoming:${namespace}`;
|
|
79
78
|
if (channel === notifyChannel) {
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
});
|
|
84
|
-
}
|
|
79
|
+
bot.sendMessage(chatId, message).catch((err) => {
|
|
80
|
+
log("warn", "sendMessage failed:", err.message);
|
|
81
|
+
});
|
|
85
82
|
return;
|
|
86
83
|
}
|
|
87
84
|
if (channel === incomingChannel) {
|
|
@@ -94,30 +91,23 @@ export function startNotifier(bot, chatId, namespace, redis, handleUserMessage,
|
|
|
94
91
|
catch {
|
|
95
92
|
// raw string message — use as-is
|
|
96
93
|
}
|
|
97
|
-
//
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
})
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
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");
|
|
94
|
+
// Echo to Telegram so the user sees UI messages in the chat
|
|
95
|
+
bot.sendMessage(chatId, `📱 [from UI]: ${content}`).catch((err) => {
|
|
96
|
+
log("warn", "sendMessage (UI echo) failed:", err.message);
|
|
97
|
+
});
|
|
98
|
+
// Log the incoming message
|
|
99
|
+
const inMsg = {
|
|
100
|
+
id: `ui-${Date.now()}-${Math.random().toString(36).slice(2, 6)}`,
|
|
101
|
+
source: "ui",
|
|
102
|
+
role: "user",
|
|
103
|
+
content,
|
|
104
|
+
timestamp: new Date().toISOString(),
|
|
105
|
+
chatId,
|
|
106
|
+
};
|
|
107
|
+
writeChatLog(redis, namespace, inMsg);
|
|
108
|
+
// Feed into active Claude session as if user typed it
|
|
109
|
+
if (handleUserMessage) {
|
|
110
|
+
handleUserMessage(chatId, content);
|
|
121
111
|
}
|
|
122
112
|
}
|
|
123
113
|
});
|