@gonzih/cc-discord 0.1.7 → 0.1.8

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
@@ -3,8 +3,8 @@
3
3
  * One ClaudeProcess per channel (or channel:thread) — sessions are isolated per channel.
4
4
  */
5
5
  import { Redis } from "ioredis";
6
- /** Prepend [MM-DD HH:mm] so Claude knows when the message was received. */
7
- export declare function stampPrompt(text: string, now?: Date): string;
6
+ /** Prepend [DayOfWeek HH:MM] username: so Claude knows when the message was received and from whom. */
7
+ export declare function stampPrompt(text: string, username?: string, now?: Date): string;
8
8
  export interface DiscordBotOptions {
9
9
  discordToken: string;
10
10
  claudeToken?: string;
package/dist/bot.js CHANGED
@@ -37,13 +37,14 @@ function computeCostUsd(usage) {
37
37
  const FLUSH_DELAY_MS = 800;
38
38
  // Discord typing indicator: re-send every 9s (indicator expires after ~10s)
39
39
  const TYPING_INTERVAL_MS = 9000;
40
- /** Prepend [MM-DD HH:mm] so Claude knows when the message was received. */
41
- export function stampPrompt(text, now = new Date()) {
42
- const mm = String(now.getMonth() + 1).padStart(2, "0");
43
- const dd = String(now.getDate()).padStart(2, "0");
40
+ const DAYS = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"];
41
+ /** Prepend [DayOfWeek HH:MM] username: so Claude knows when the message was received and from whom. */
42
+ export function stampPrompt(text, username, now = new Date()) {
43
+ const day = DAYS[now.getDay()];
44
44
  const hh = String(now.getHours()).padStart(2, "0");
45
45
  const min = String(now.getMinutes()).padStart(2, "0");
46
- return `[${mm}-${dd} ${hh}:${min}] ${text}`;
46
+ const header = username ? `[${day} ${hh}:${min}] ${username}: ` : `[${day} ${hh}:${min}] `;
47
+ return header + text;
47
48
  }
48
49
  function formatTokens(n) {
49
50
  if (n >= 1000)
@@ -285,8 +286,9 @@ export class CcDiscordBot {
285
286
  if (mappedNs && this.redis) {
286
287
  this.writeChatMessage("user", "discord", text, effectiveChannelId);
287
288
  this.opts.registerRoutedChannelId?.(mappedNs.namespace, effectiveChannelId);
289
+ const username = msg.member?.displayName ?? msg.author.username;
288
290
  try {
289
- await routeToMetaAgent(mappedNs.namespace, text, this.redis);
291
+ await routeToMetaAgent(mappedNs.namespace, stampPrompt(text, username, msg.createdAt), this.redis);
290
292
  }
291
293
  catch (err) {
292
294
  await msg.channel.send(`Failed to route to ${mappedNs.namespace}: ${err.message}`).catch(() => { });
@@ -295,9 +297,10 @@ export class CcDiscordBot {
295
297
  }
296
298
  // Local Claude session
297
299
  const session = this.getOrCreateSession(effectiveChannelId, msg.channel);
300
+ const username = msg.member?.displayName ?? msg.author.username;
298
301
  try {
299
302
  session.currentPrompt = text;
300
- session.claude.sendPrompt(stampPrompt(text));
303
+ session.claude.sendPrompt(stampPrompt(text, username, msg.createdAt));
301
304
  this.startTyping(effectiveChannelId, msg.channel, session);
302
305
  this.writeChatMessage("user", "discord", text, effectiveChannelId);
303
306
  }
@@ -317,7 +320,8 @@ export class CcDiscordBot {
317
320
  }
318
321
  const session = this.getOrCreateSession(channelId, channel);
319
322
  session.currentPrompt = transcript;
320
- session.claude.sendPrompt(stampPrompt(transcript));
323
+ const voiceUsername = msg.member?.displayName ?? msg.author.username;
324
+ session.claude.sendPrompt(stampPrompt(transcript, voiceUsername, msg.createdAt));
321
325
  this.startTyping(channelId, channel, session);
322
326
  this.writeChatMessage("user", "discord", transcript, channelId);
323
327
  }
@@ -342,8 +346,9 @@ export class CcDiscordBot {
342
346
  try {
343
347
  const base64Data = await fetchAsBase64(imageUrl);
344
348
  const caption = msg.content.trim() || "";
349
+ const imgUsername = msg.member?.displayName ?? msg.author.username;
345
350
  const session = this.getOrCreateSession(channelId, channel);
346
- session.claude.sendImage(base64Data, contentType, stampPrompt(caption));
351
+ session.claude.sendImage(base64Data, contentType, stampPrompt(caption, imgUsername, msg.createdAt));
347
352
  this.startTyping(channelId, channel, session);
348
353
  }
349
354
  catch (err) {
@@ -26,12 +26,11 @@ export interface ParsedNotification {
26
26
  }
27
27
  /**
28
28
  * Parse a notification payload.
29
- * Returns the display text plus an optional chatId for per-channel routing,
30
- * or null when the routing array excludes "discord".
29
+ * Returns the display text plus an optional chatId for per-channel routing.
31
30
  * Appends a [driver] or [driver:model] badge when present.
32
31
  * Appends " cost: $X.XXX" if a numeric cost field is present.
33
32
  */
34
- export declare function parseNotification(raw: string): ParsedNotification | null;
33
+ export declare function parseNotification(raw: string): ParsedNotification;
35
34
  /**
36
35
  * Write a message to the chat log in Redis.
37
36
  * Fire-and-forget — errors are logged but not thrown.
package/dist/notifier.js CHANGED
@@ -10,7 +10,7 @@
10
10
  * cca:chat:log:{namespace} — LPUSH + LTRIM 0 499 (last 500 messages)
11
11
  * cca:chat:outgoing:{namespace} — PUBLISH for web UI to consume
12
12
  */
13
- import { chatLogKey, chatOutgoingChannel, chatIncomingChannel, notifyChannel, notifyListKey, metaAgentStatusKey, metaInputKey, } from "@gonzih/cc-wire";
13
+ import { chatLogKey, chatOutgoingChannel, chatIncomingChannel, notifyChannel, metaAgentStatusKey, metaInputKey, } from "@gonzih/cc-wire";
14
14
  import { splitLongMessage, stripAnsi } from "./formatter.js";
15
15
  function log(level, ...args) {
16
16
  const fn = level === "error" ? console.error : level === "warn" ? console.warn : console.log;
@@ -32,8 +32,7 @@ function shortenModelName(model, driver) {
32
32
  }
33
33
  /**
34
34
  * Parse a notification payload.
35
- * Returns the display text plus an optional chatId for per-channel routing,
36
- * or null when the routing array excludes "discord".
35
+ * Returns the display text plus an optional chatId for per-channel routing.
37
36
  * Appends a [driver] or [driver:model] badge when present.
38
37
  * Appends " cost: $X.XXX" if a numeric cost field is present.
39
38
  */
@@ -45,10 +44,6 @@ export function parseNotification(raw) {
45
44
  let chatId;
46
45
  try {
47
46
  const parsed = JSON.parse(raw);
48
- // routing: absent/empty → all transports; non-empty → only listed transports
49
- if (parsed.routing && parsed.routing.length > 0 && !parsed.routing.includes("discord")) {
50
- return null;
51
- }
52
47
  if (parsed.text)
53
48
  text = parsed.text;
54
49
  driver = parsed.driver;
@@ -201,8 +196,8 @@ export function startNotifier(bot, notifyChannelId, namespace, redis, handleUser
201
196
  clearTimeout(buf.timer);
202
197
  buf.timer = setTimeout(() => flushMetaAgentBuffer(ns, targetChannelId), META_AGENT_FLUSH_DELAY_MS);
203
198
  });
204
- // Poll the notifyListKey(namespace) LIST every 5 seconds
205
- const notifyListRedisKey = notifyListKey(namespace);
199
+ // Poll the notifyChannel(namespace) LIST every 5 seconds
200
+ const notifyListKey = notifyChannel(namespace);
206
201
  const MAX_PER_CYCLE = 20;
207
202
  const pollNotifyList = async () => {
208
203
  const targetId = notifyChannelId ?? getActiveChannelId?.();
@@ -211,7 +206,7 @@ export function startNotifier(bot, notifyChannelId, namespace, redis, handleUser
211
206
  const items = [];
212
207
  try {
213
208
  for (let i = 0; i < MAX_PER_CYCLE; i++) {
214
- const item = await redis.rpop(notifyListRedisKey);
209
+ const item = await redis.rpop(notifyListKey);
215
210
  if (item === null)
216
211
  break;
217
212
  items.push(item);
@@ -226,7 +221,7 @@ export function startNotifier(bot, notifyChannelId, namespace, redis, handleUser
226
221
  let remaining = 0;
227
222
  if (items.length === MAX_PER_CYCLE) {
228
223
  try {
229
- remaining = await redis.llen(notifyListRedisKey);
224
+ remaining = await redis.llen(notifyListKey);
230
225
  }
231
226
  catch (err) {
232
227
  log("warn", "notify list llen failed:", err.message);
@@ -234,8 +229,6 @@ export function startNotifier(bot, notifyChannelId, namespace, redis, handleUser
234
229
  }
235
230
  for (const raw of items) {
236
231
  const notification = parseNotification(raw);
237
- if (notification === null)
238
- continue; // routing excludes discord
239
232
  const destChannelId = resolveNotifyChannel(notification.chatId, notifyChannelId, getActiveChannelId, reverseSnowflakeLookup) ?? targetId;
240
233
  bot.sendToChannelById(destChannelId, notification.text).catch((err) => {
241
234
  log("warn", "notify list send failed:", err.message);
@@ -258,8 +251,6 @@ export function startNotifier(bot, notifyChannelId, namespace, redis, handleUser
258
251
  const incomingCh = chatIncomingChannel(namespace);
259
252
  if (channel === notifyCh) {
260
253
  const notification = parseNotification(message);
261
- if (notification === null)
262
- return; // routing excludes discord
263
254
  const targetId = resolveNotifyChannel(notification.chatId, notifyChannelId, getActiveChannelId, reverseSnowflakeLookup);
264
255
  if (targetId != null) {
265
256
  bot.sendToChannelById(targetId, notification.text).catch((err) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gonzih/cc-discord",
3
- "version": "0.1.7",
3
+ "version": "0.1.8",
4
4
  "description": "Claude Code Discord bot — chat with Claude Code via Discord",
5
5
  "type": "module",
6
6
  "bin": {
@@ -18,7 +18,7 @@
18
18
  "dist/"
19
19
  ],
20
20
  "dependencies": {
21
- "@gonzih/cc-wire": "^0.1.6",
21
+ "@gonzih/cc-wire": "^0.1.4",
22
22
  "discord.js": "^14.0.0",
23
23
  "ioredis": "^5.0.0"
24
24
  },