@geminixiang/mama 0.1.10 → 0.2.0-beta.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.
Files changed (151) hide show
  1. package/README.md +80 -23
  2. package/dist/adapter.d.ts +11 -9
  3. package/dist/adapter.d.ts.map +1 -1
  4. package/dist/adapter.js.map +1 -1
  5. package/dist/adapters/discord/bot.d.ts +2 -2
  6. package/dist/adapters/discord/bot.d.ts.map +1 -1
  7. package/dist/adapters/discord/bot.js +33 -21
  8. package/dist/adapters/discord/bot.js.map +1 -1
  9. package/dist/adapters/discord/context.d.ts.map +1 -1
  10. package/dist/adapters/discord/context.js +20 -13
  11. package/dist/adapters/discord/context.js.map +1 -1
  12. package/dist/adapters/slack/bot.d.ts +13 -4
  13. package/dist/adapters/slack/bot.d.ts.map +1 -1
  14. package/dist/adapters/slack/bot.js +98 -43
  15. package/dist/adapters/slack/bot.js.map +1 -1
  16. package/dist/adapters/slack/context.d.ts.map +1 -1
  17. package/dist/adapters/slack/context.js +25 -20
  18. package/dist/adapters/slack/context.js.map +1 -1
  19. package/dist/adapters/telegram/bot.d.ts +4 -2
  20. package/dist/adapters/telegram/bot.d.ts.map +1 -1
  21. package/dist/adapters/telegram/bot.js +143 -58
  22. package/dist/adapters/telegram/bot.js.map +1 -1
  23. package/dist/adapters/telegram/context.d.ts +1 -1
  24. package/dist/adapters/telegram/context.d.ts.map +1 -1
  25. package/dist/adapters/telegram/context.js +124 -29
  26. package/dist/adapters/telegram/context.js.map +1 -1
  27. package/dist/agent.d.ts +7 -4
  28. package/dist/agent.d.ts.map +1 -1
  29. package/dist/agent.js +303 -89
  30. package/dist/agent.js.map +1 -1
  31. package/dist/bindings.d.ts +63 -0
  32. package/dist/bindings.d.ts.map +1 -0
  33. package/dist/bindings.js +94 -0
  34. package/dist/bindings.js.map +1 -0
  35. package/dist/config.d.ts +34 -4
  36. package/dist/config.d.ts.map +1 -1
  37. package/dist/config.js +98 -38
  38. package/dist/config.js.map +1 -1
  39. package/dist/context.d.ts +8 -6
  40. package/dist/context.d.ts.map +1 -1
  41. package/dist/context.js +23 -14
  42. package/dist/context.js.map +1 -1
  43. package/dist/events.d.ts +4 -0
  44. package/dist/events.d.ts.map +1 -1
  45. package/dist/events.js +20 -5
  46. package/dist/events.js.map +1 -1
  47. package/dist/execution-resolver.d.ts +20 -0
  48. package/dist/execution-resolver.d.ts.map +1 -0
  49. package/dist/execution-resolver.js +51 -0
  50. package/dist/execution-resolver.js.map +1 -0
  51. package/dist/instrument.d.ts +2 -0
  52. package/dist/instrument.d.ts.map +1 -0
  53. package/dist/instrument.js +14 -0
  54. package/dist/instrument.js.map +1 -0
  55. package/dist/link-server.d.ts +16 -0
  56. package/dist/link-server.d.ts.map +1 -0
  57. package/dist/link-server.js +839 -0
  58. package/dist/link-server.js.map +1 -0
  59. package/dist/link-token.d.ts +32 -0
  60. package/dist/link-token.d.ts.map +1 -0
  61. package/dist/link-token.js +68 -0
  62. package/dist/link-token.js.map +1 -0
  63. package/dist/log.d.ts +3 -2
  64. package/dist/log.d.ts.map +1 -1
  65. package/dist/log.js +10 -9
  66. package/dist/log.js.map +1 -1
  67. package/dist/login.d.ts +29 -0
  68. package/dist/login.d.ts.map +1 -0
  69. package/dist/login.js +164 -0
  70. package/dist/login.js.map +1 -0
  71. package/dist/main.d.ts +1 -1
  72. package/dist/main.d.ts.map +1 -1
  73. package/dist/main.js +322 -82
  74. package/dist/main.js.map +1 -1
  75. package/dist/provisioner.d.ts +93 -0
  76. package/dist/provisioner.d.ts.map +1 -0
  77. package/dist/provisioner.js +336 -0
  78. package/dist/provisioner.js.map +1 -0
  79. package/dist/sandbox/container.d.ts +15 -0
  80. package/dist/sandbox/container.d.ts.map +1 -0
  81. package/dist/sandbox/container.js +122 -0
  82. package/dist/sandbox/container.js.map +1 -0
  83. package/dist/sandbox/errors.d.ts +6 -0
  84. package/dist/sandbox/errors.d.ts.map +1 -0
  85. package/dist/sandbox/errors.js +11 -0
  86. package/dist/sandbox/errors.js.map +1 -0
  87. package/dist/sandbox/firecracker.d.ts +16 -0
  88. package/dist/sandbox/firecracker.d.ts.map +1 -0
  89. package/dist/sandbox/firecracker.js +206 -0
  90. package/dist/sandbox/firecracker.js.map +1 -0
  91. package/dist/sandbox/host.d.ts +12 -0
  92. package/dist/sandbox/host.d.ts.map +1 -0
  93. package/dist/sandbox/host.js +89 -0
  94. package/dist/sandbox/host.js.map +1 -0
  95. package/dist/sandbox/image.d.ts +5 -0
  96. package/dist/sandbox/image.d.ts.map +1 -0
  97. package/dist/sandbox/image.js +30 -0
  98. package/dist/sandbox/image.js.map +1 -0
  99. package/dist/sandbox/index.d.ts +20 -0
  100. package/dist/sandbox/index.d.ts.map +1 -0
  101. package/dist/sandbox/index.js +51 -0
  102. package/dist/sandbox/index.js.map +1 -0
  103. package/dist/sandbox/types.d.ts +51 -0
  104. package/dist/sandbox/types.d.ts.map +1 -0
  105. package/dist/sandbox/types.js +2 -0
  106. package/dist/sandbox/types.js.map +1 -0
  107. package/dist/sandbox/utils.d.ts +4 -0
  108. package/dist/sandbox/utils.d.ts.map +1 -0
  109. package/dist/sandbox/utils.js +51 -0
  110. package/dist/sandbox/utils.js.map +1 -0
  111. package/dist/sandbox.d.ts +1 -39
  112. package/dist/sandbox.d.ts.map +1 -1
  113. package/dist/sandbox.js +1 -286
  114. package/dist/sandbox.js.map +1 -1
  115. package/dist/sentry.d.ts +31 -0
  116. package/dist/sentry.d.ts.map +1 -0
  117. package/dist/sentry.js +205 -0
  118. package/dist/sentry.js.map +1 -0
  119. package/dist/session-store.d.ts +72 -0
  120. package/dist/session-store.d.ts.map +1 -0
  121. package/dist/session-store.js +186 -0
  122. package/dist/session-store.js.map +1 -0
  123. package/dist/store.d.ts +1 -1
  124. package/dist/store.d.ts.map +1 -1
  125. package/dist/store.js +8 -8
  126. package/dist/store.js.map +1 -1
  127. package/dist/tools/event.d.ts +21 -0
  128. package/dist/tools/event.d.ts.map +1 -0
  129. package/dist/tools/event.js +103 -0
  130. package/dist/tools/event.js.map +1 -0
  131. package/dist/tools/index.d.ts +6 -1
  132. package/dist/tools/index.d.ts.map +1 -1
  133. package/dist/tools/index.js +5 -1
  134. package/dist/tools/index.js.map +1 -1
  135. package/dist/ui-copy.d.ts +11 -0
  136. package/dist/ui-copy.d.ts.map +1 -0
  137. package/dist/ui-copy.js +33 -0
  138. package/dist/ui-copy.js.map +1 -0
  139. package/dist/vault-routing.d.ts +10 -0
  140. package/dist/vault-routing.d.ts.map +1 -0
  141. package/dist/vault-routing.js +58 -0
  142. package/dist/vault-routing.js.map +1 -0
  143. package/dist/vault.d.ts +106 -0
  144. package/dist/vault.d.ts.map +1 -0
  145. package/dist/vault.js +389 -0
  146. package/dist/vault.js.map +1 -0
  147. package/dist/vault.test.d.ts +2 -0
  148. package/dist/vault.test.d.ts.map +1 -0
  149. package/dist/vault.test.js +67 -0
  150. package/dist/vault.test.js.map +1 -0
  151. package/package.json +13 -11
@@ -3,7 +3,9 @@ import { WebClient } from "@slack/web-api";
3
3
  import { appendFileSync, existsSync, mkdirSync, readFileSync } from "fs";
4
4
  import { readFile } from "fs/promises";
5
5
  import { basename, join } from "path";
6
+ import { parseLoginCommand } from "../../login.js";
6
7
  import * as log from "../../log.js";
8
+ import { PRODUCT_NAME, formatAlreadyWorking, formatForceStopped, formatNothingRunning, } from "../../ui-copy.js";
7
9
  import { createSlackAdapters } from "./context.js";
8
10
  // ============================================================================
9
11
  // Exponential backoff utility for Slack API calls
@@ -92,6 +94,21 @@ export class SlackBot {
92
94
  setEventsWatcher(watcher) {
93
95
  this.eventsWatcher = watcher;
94
96
  }
97
+ toBotEvent(event) {
98
+ return {
99
+ type: event.type,
100
+ conversationId: event.channel,
101
+ ts: event.ts,
102
+ thread_ts: event.thread_ts,
103
+ user: event.user,
104
+ text: event.text,
105
+ attachments: event.attachments?.map((attachment) => ({
106
+ name: attachment.original,
107
+ localPath: attachment.localPath,
108
+ })),
109
+ sessionKey: event.sessionKey,
110
+ };
111
+ }
95
112
  // ==========================================================================
96
113
  // Public API
97
114
  // ==========================================================================
@@ -119,15 +136,15 @@ export class SlackBot {
119
136
  getAllChannels() {
120
137
  return Array.from(this.channels.values());
121
138
  }
122
- async postMessage(channel, text) {
139
+ async postMessage(conversationId, text) {
123
140
  return withRetry(async () => {
124
- const result = await this.webClient.chat.postMessage({ channel, text });
141
+ const result = await this.webClient.chat.postMessage({ channel: conversationId, text });
125
142
  return result.ts;
126
143
  });
127
144
  }
128
- async updateMessage(channel, ts, text) {
145
+ async updateMessage(conversationId, ts, text) {
129
146
  return withRetry(async () => {
130
- await this.webClient.chat.update({ channel, ts, text });
147
+ await this.webClient.chat.update({ channel: conversationId, ts, text });
131
148
  });
132
149
  }
133
150
  async deleteMessage(channel, ts) {
@@ -148,9 +165,6 @@ export class SlackBot {
148
165
  });
149
166
  });
150
167
  }
151
- registerThreadAlias(aliasKey, sessionKey) {
152
- this.handler.registerThreadAlias(aliasKey, sessionKey);
153
- }
154
168
  async postInThread(channel, threadTs, text) {
155
169
  return withRetry(async () => {
156
170
  // Use Block Kit section for long messages to trigger Slack's "Show more" collapsing (~700 chars)
@@ -200,10 +214,10 @@ export class SlackBot {
200
214
  * This is the ONLY place messages are written to log.jsonl
201
215
  */
202
216
  logToFile(channel, entry) {
203
- const dir = join(this.workingDir, channel);
204
- if (!existsSync(dir))
205
- mkdirSync(dir, { recursive: true });
206
- appendFileSync(join(dir, "log.jsonl"), `${JSON.stringify(entry)}\n`);
217
+ const channelDir = join(this.workingDir, channel);
218
+ if (!existsSync(channelDir))
219
+ mkdirSync(channelDir, { recursive: true });
220
+ appendFileSync(join(channelDir, "log.jsonl"), `${JSON.stringify(entry)}\n`);
207
221
  }
208
222
  /**
209
223
  * Log a bot response to log.jsonl
@@ -239,14 +253,23 @@ export class SlackBot {
239
253
  * Returns true if enqueued, false if queue is full (max 5).
240
254
  */
241
255
  enqueueEvent(event) {
242
- const queue = this.getQueue(event.channel);
256
+ const queue = this.getQueue(event.conversationId);
243
257
  if (queue.size() >= 5) {
244
- log.logWarning(`Event queue full for ${event.channel}, discarding: ${event.text.substring(0, 50)}`);
258
+ log.logWarning(`Event queue full for ${event.conversationId}, discarding: ${event.text.substring(0, 50)}`);
245
259
  return false;
246
260
  }
247
- log.logInfo(`Enqueueing event for ${event.channel}: ${event.text.substring(0, 50)}`);
261
+ log.logInfo(`Enqueueing event for ${event.conversationId}: ${event.text.substring(0, 50)}`);
248
262
  queue.enqueue(() => {
249
- const adapters = createSlackAdapters(event, this, true);
263
+ const slackEvent = {
264
+ type: "mention",
265
+ channel: event.conversationId,
266
+ ts: event.ts,
267
+ thread_ts: event.thread_ts,
268
+ user: event.user,
269
+ text: event.text,
270
+ sessionKey: event.sessionKey,
271
+ };
272
+ const adapters = createSlackAdapters(slackEvent, this, true);
250
273
  return this.handler.handleEvent(event, this, adapters, true);
251
274
  });
252
275
  return true;
@@ -270,12 +293,12 @@ export class SlackBot {
270
293
  type: "section",
271
294
  text: {
272
295
  type: "mrkdwn",
273
- text: "*Pi Agent*\nWelcome back! Start a new task or check on running work.",
296
+ text: `*${PRODUCT_NAME}*\nStart a new task or check on running work.`,
274
297
  },
275
298
  accessory: {
276
299
  type: "image",
277
300
  image_url: "https://media1.tenor.com/m/lfDATg4Bhc0AAAAC/happy-cat.gif",
278
- alt_text: "Pi Agent",
301
+ alt_text: PRODUCT_NAME,
279
302
  },
280
303
  },
281
304
  ];
@@ -364,6 +387,12 @@ export class SlackBot {
364
387
  });
365
388
  }
366
389
  else {
390
+ const timestampFormatter = new Intl.DateTimeFormat(undefined, {
391
+ month: "short",
392
+ day: "numeric",
393
+ hour: "2-digit",
394
+ minute: "2-digit",
395
+ });
367
396
  for (const ev of periodicEvents) {
368
397
  const channelLabel = ev.platform === "slack"
369
398
  ? (() => {
@@ -372,14 +401,7 @@ export class SlackBot {
372
401
  return `${ev.platform}:${channelName}`;
373
402
  })()
374
403
  : `${ev.platform}:${ev.channelId}`;
375
- const nextStr = ev.nextRun
376
- ? new Date(ev.nextRun).toLocaleString("en-US", {
377
- month: "short",
378
- day: "numeric",
379
- hour: "2-digit",
380
- minute: "2-digit",
381
- })
382
- : "—";
404
+ const nextStr = ev.nextRun ? timestampFormatter.format(new Date(ev.nextRun)) : "—";
383
405
  blocks.push({
384
406
  type: "section",
385
407
  text: {
@@ -398,6 +420,24 @@ export class SlackBot {
398
420
  });
399
421
  return { type: "home", blocks };
400
422
  }
423
+ /**
424
+ * Resolve which session key to stop.
425
+ * When stop is called from a thread, the thread session (channelId:thread_ts) might
426
+ * not be running — but the channel session (channelId) might be, because the bot's
427
+ * reply to a top-level mention creates a thread. Check both, prefer thread first.
428
+ */
429
+ resolveStopTarget(channelId, threadTs) {
430
+ if (threadTs) {
431
+ const threadKey = `${channelId}:${threadTs}`;
432
+ if (this.handler.isRunning(threadKey))
433
+ return threadKey;
434
+ // Fall back to channel session — the thread may have been spawned by a top-level run
435
+ if (this.handler.isRunning(channelId))
436
+ return channelId;
437
+ return null;
438
+ }
439
+ return this.handler.isRunning(channelId) ? channelId : null;
440
+ }
401
441
  setupEventHandlers() {
402
442
  // Channel @mentions
403
443
  this.socketClient.on("app_mention", ({ event, ack }) => {
@@ -407,9 +447,9 @@ export class SlackBot {
407
447
  ack();
408
448
  return;
409
449
  }
410
- // Derive session key from thread context (resolve alias for bot-reply-anchored threads)
411
- const rootTs = e.thread_ts ?? e.ts;
412
- const sessionKey = this.handler.resolveSessionKey(`${e.channel}:${rootTs}`);
450
+ // Top-level mentions use a persistent channel session.
451
+ // Thread replies get their own isolated session (channelId:thread_ts).
452
+ const sessionKey = e.thread_ts ? `${e.channel}:${e.thread_ts}` : e.channel;
413
453
  const slackEvent = {
414
454
  type: "mention",
415
455
  channel: e.channel,
@@ -418,6 +458,7 @@ export class SlackBot {
418
458
  user: e.user,
419
459
  text: e.text.replace(/<@[A-Z0-9]+>/gi, "").trim(),
420
460
  files: e.files,
461
+ sessionKey,
421
462
  };
422
463
  // SYNC: Log to log.jsonl (ALWAYS, even for old messages)
423
464
  // Also downloads attachments in background and stores local paths
@@ -430,23 +471,30 @@ export class SlackBot {
430
471
  }
431
472
  // Check for stop command - execute immediately, don't queue!
432
473
  if (slackEvent.text.toLowerCase().trim() === "stop") {
433
- if (this.handler.isRunning(sessionKey)) {
434
- this.handler.handleStop(sessionKey, e.channel, this);
474
+ const stopTarget = this.resolveStopTarget(e.channel, e.thread_ts);
475
+ if (stopTarget) {
476
+ this.handler.handleStop(stopTarget, e.channel, this);
435
477
  }
436
478
  else {
437
- this.postMessage(e.channel, "_Nothing running_");
479
+ this.postMessage(e.channel, formatNothingRunning("slack"));
438
480
  }
439
481
  ack();
440
482
  return;
441
483
  }
484
+ // Check for login command
485
+ if (parseLoginCommand(slackEvent.text)) {
486
+ void this.handler.handleLogin("slack", e.user, e.channel, this, slackEvent.text, false);
487
+ ack();
488
+ return;
489
+ }
442
490
  // SYNC: Check if busy (per-thread)
443
491
  if (this.handler.isRunning(sessionKey)) {
444
- this.postMessage(e.channel, "_Already working in this thread. Say `@mama stop` to cancel._");
492
+ this.postMessage(e.channel, formatAlreadyWorking("slack", "@mama stop", { scope: "thread" }));
445
493
  }
446
494
  else {
447
495
  this.getQueue(sessionKey).enqueue(() => {
448
496
  const adapters = createSlackAdapters(slackEvent, this, false);
449
- return this.handler.handleEvent(slackEvent, this, adapters, false);
497
+ return this.handler.handleEvent(this.toBotEvent(slackEvent), this, adapters, false);
450
498
  });
451
499
  }
452
500
  ack();
@@ -482,6 +530,7 @@ export class SlackBot {
482
530
  user: e.user,
483
531
  text: (e.text || "").replace(/<@[A-Z0-9]+>/gi, "").trim(),
484
532
  files: e.files,
533
+ sessionKey: isDM ? e.channel : undefined,
485
534
  };
486
535
  // SYNC: Log to log.jsonl (ALL messages - channel chatter and DMs)
487
536
  // Also downloads attachments in background and stores local paths
@@ -495,38 +544,43 @@ export class SlackBot {
495
544
  // Check for stop command in channel threads (without @mention)
496
545
  // app_mention handles "@mama stop", but bare "stop" in a thread comes here
497
546
  if (!isDM && e.thread_ts && slackEvent.text.toLowerCase().trim() === "stop") {
498
- const threadSessionKey = this.handler.resolveSessionKey(`${e.channel}:${e.thread_ts}`);
499
- if (this.handler.isRunning(threadSessionKey)) {
500
- this.handler.handleStop(threadSessionKey, e.channel, this);
547
+ const stopTarget = this.resolveStopTarget(e.channel, e.thread_ts);
548
+ if (stopTarget) {
549
+ this.handler.handleStop(stopTarget, e.channel, this);
501
550
  }
502
551
  else {
503
- this.postMessage(e.channel, "_Nothing running_");
552
+ this.postMessage(e.channel, formatNothingRunning("slack"));
504
553
  }
505
554
  ack();
506
555
  return;
507
556
  }
508
557
  // Only trigger handler for DMs
509
558
  if (isDM) {
510
- const dmRootTs = e.thread_ts ?? e.ts;
511
- const dmSessionKey = this.handler.resolveSessionKey(`${e.channel}:${dmRootTs}`);
559
+ const dmSessionKey = slackEvent.sessionKey;
512
560
  // Check for stop command - execute immediately, don't queue!
513
561
  if (slackEvent.text.toLowerCase().trim() === "stop") {
514
562
  if (this.handler.isRunning(dmSessionKey)) {
515
563
  this.handler.handleStop(dmSessionKey, e.channel, this); // Don't await, don't queue
516
564
  }
517
565
  else {
518
- this.postMessage(e.channel, "_Nothing running_");
566
+ this.postMessage(e.channel, formatNothingRunning("slack"));
519
567
  }
520
568
  ack();
521
569
  return;
522
570
  }
571
+ // Check for login command
572
+ if (parseLoginCommand(slackEvent.text)) {
573
+ void this.handler.handleLogin("slack", e.user, e.channel, this, slackEvent.text, true);
574
+ ack();
575
+ return;
576
+ }
523
577
  if (this.handler.isRunning(dmSessionKey)) {
524
- this.postMessage(e.channel, "_Already working. Say `stop` to cancel._");
578
+ this.postMessage(e.channel, formatAlreadyWorking("slack", "stop"));
525
579
  }
526
580
  else {
527
581
  this.getQueue(dmSessionKey).enqueue(() => {
528
582
  const adapters = createSlackAdapters(slackEvent, this, false);
529
- return this.handler.handleEvent(slackEvent, this, adapters, false);
583
+ return this.handler.handleEvent(this.toBotEvent(slackEvent), this, adapters, false);
530
584
  });
531
585
  }
532
586
  }
@@ -562,7 +616,8 @@ export class SlackBot {
562
616
  // Use handler's forceStop method
563
617
  this.handler.forceStop(sessionKey);
564
618
  // Notify in channel
565
- await this.postMessage(channelId, `_🔴 Force stopped by ${userId}_`);
619
+ const actorLabel = userId ? `<@${userId}>` : "someone";
620
+ await this.postMessage(channelId, formatForceStopped("slack", actorLabel));
566
621
  // Refresh home tab
567
622
  if (userId) {
568
623
  this.webClient.views
@@ -1 +1 @@
1
- {"version":3,"file":"bot.js","sourceRoot":"","sources":["../../../src/adapters/slack/bot.ts"],"names":[],"mappings":"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","sourcesContent":["import { SocketModeClient } from \"@slack/socket-mode\";\nimport { WebClient } from \"@slack/web-api\";\nimport { appendFileSync, existsSync, mkdirSync, readFileSync } from \"fs\";\nimport { readFile } from \"fs/promises\";\nimport { basename, join } from \"path\";\nimport type { Bot, BotEvent, BotHandler, PlatformInfo } from \"../../adapter.js\";\nimport type { EventsWatcher } from \"../../events.js\";\nimport * as log from \"../../log.js\";\nimport type { Attachment, ChannelStore } from \"../../store.js\";\nimport { createSlackAdapters } from \"./context.js\";\n\n// ============================================================================\n// Exponential backoff utility for Slack API calls\n// ============================================================================\n\n/**\n * Retry a function with exponential backoff on rate limit errors.\n */\nasync function withRetry<T>(\n fn: () => Promise<T>,\n maxRetries: number = 3,\n baseDelayMs: number = 1000,\n): Promise<T> {\n let lastError: Error | undefined;\n for (let attempt = 0; attempt < maxRetries; attempt++) {\n try {\n return await fn();\n } catch (err) {\n lastError = err instanceof Error ? err : new Error(String(err));\n\n // Check for rate limit errors\n let isRateLimited = false;\n\n // Check for rate_limited error code (Slack SDK)\n if (\"code\" in lastError && lastError.code === \"rate_limited\") {\n isRateLimited = true;\n }\n\n // Check for rate_limited in error response\n if (\"data\" in lastError) {\n const data = (lastError as { data?: { error?: string; response?: { status?: number } } })\n .data;\n if (data?.error === \"rate_limited\" || data?.response?.status === 429) {\n isRateLimited = true;\n }\n }\n\n if (isRateLimited) {\n const delay = baseDelayMs * Math.pow(2, attempt);\n log.logWarning(\n `Rate limited, retrying in ${delay}ms (attempt ${attempt + 1}/${maxRetries})`,\n );\n await new Promise((resolve) => setTimeout(resolve, delay));\n continue;\n }\n\n // Non-retryable error\n throw lastError;\n }\n }\n throw lastError;\n}\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport interface SlackEvent {\n type: \"mention\" | \"dm\";\n channel: string;\n ts: string;\n thread_ts?: string;\n user: string;\n text: string;\n files?: Array<{ name?: string; url_private_download?: string; url_private?: string }>;\n /** Processed attachments with local paths (populated after logUserMessage) */\n attachments?: Attachment[];\n}\n\nexport interface SlackUser {\n id: string;\n userName: string;\n displayName: string;\n}\n\nexport interface SlackChannel {\n id: string;\n name: string;\n}\n\n// Types used by agent.ts\nexport interface ChannelInfo {\n id: string;\n name: string;\n}\n\nexport interface UserInfo {\n id: string;\n userName: string;\n displayName: string;\n}\n\nexport interface SlackContext {\n message: {\n text: string;\n rawText: string;\n user: string;\n userName?: string;\n channel: string;\n ts: string;\n attachments: Array<{ local: string }>;\n };\n channelName?: string;\n channels: ChannelInfo[];\n users: UserInfo[];\n respond: (text: string, shouldLog?: boolean) => Promise<void>;\n replaceMessage: (text: string) => Promise<void>;\n respondInThread: (text: string) => Promise<void>;\n setTyping: (isTyping: boolean) => Promise<void>;\n uploadFile: (filePath: string, title?: string) => Promise<void>;\n setWorking: (working: boolean) => Promise<void>;\n deleteMessage: () => Promise<void>;\n}\n\n/** @deprecated Use BotHandler from adapter.ts instead */\nexport type MomHandler = BotHandler;\n\n// ============================================================================\n// Per-channel queue for sequential processing\n// ============================================================================\n\ntype QueuedWork = () => Promise<void>;\n\nclass ChannelQueue {\n private queue: QueuedWork[] = [];\n private processing = false;\n\n enqueue(work: QueuedWork): void {\n this.queue.push(work);\n this.processNext();\n }\n\n size(): number {\n return this.queue.length;\n }\n\n private async processNext(): Promise<void> {\n if (this.processing || this.queue.length === 0) return;\n this.processing = true;\n const work = this.queue.shift()!;\n try {\n await work();\n } catch (err) {\n log.logWarning(\"Queue error\", err instanceof Error ? err.message : String(err));\n }\n this.processing = false;\n this.processNext();\n }\n}\n\n// ============================================================================\n// SlackBot\n// ============================================================================\n\nexport class SlackBot implements Bot {\n private socketClient: SocketModeClient;\n private webClient: WebClient;\n private handler: BotHandler;\n private workingDir: string;\n private store: ChannelStore;\n private botUserId: string | null = null;\n private startupTs: string | null = null; // Messages older than this are just logged, not processed\n\n private users = new Map<string, SlackUser>();\n private channels = new Map<string, SlackChannel>();\n private queues = new Map<string, ChannelQueue>();\n private eventsWatcher: EventsWatcher | null = null;\n\n constructor(\n handler: BotHandler,\n config: { appToken: string; botToken: string; workingDir: string; store: ChannelStore },\n ) {\n this.handler = handler;\n this.workingDir = config.workingDir;\n this.store = config.store;\n this.socketClient = new SocketModeClient({ appToken: config.appToken });\n this.webClient = new WebClient(config.botToken);\n }\n\n setEventsWatcher(watcher: EventsWatcher): void {\n this.eventsWatcher = watcher;\n }\n\n // ==========================================================================\n // Public API\n // ==========================================================================\n\n async start(): Promise<void> {\n const auth = await this.webClient.auth.test();\n this.botUserId = auth.user_id as string;\n\n await Promise.all([this.fetchUsers(), this.fetchChannels()]);\n log.logInfo(`Loaded ${this.channels.size} channels, ${this.users.size} users`);\n\n await this.backfillAllChannels();\n\n this.setupEventHandlers();\n await this.socketClient.start();\n\n // Record startup time - messages older than this are just logged, not processed\n this.startupTs = (Date.now() / 1000).toFixed(6);\n\n log.logConnected();\n }\n\n getUser(userId: string): SlackUser | undefined {\n return this.users.get(userId);\n }\n\n getChannel(channelId: string): SlackChannel | undefined {\n return this.channels.get(channelId);\n }\n\n getAllUsers(): SlackUser[] {\n return Array.from(this.users.values());\n }\n\n getAllChannels(): SlackChannel[] {\n return Array.from(this.channels.values());\n }\n\n async postMessage(channel: string, text: string): Promise<string> {\n return withRetry(async () => {\n const result = await this.webClient.chat.postMessage({ channel, text });\n return result.ts as string;\n });\n }\n\n async updateMessage(channel: string, ts: string, text: string): Promise<void> {\n return withRetry(async () => {\n await this.webClient.chat.update({ channel, ts, text });\n });\n }\n\n async deleteMessage(channel: string, ts: string): Promise<void> {\n return withRetry(async () => {\n await this.webClient.chat.delete({ channel, ts });\n });\n }\n\n // ==========================================================================\n // Slack Assistant API (AI assistant experience)\n // ==========================================================================\n\n /** Set the status for an assistant thread (shows \"thinking\" state) */\n async setAssistantStatus(channel: string, threadTs: string, status: string): Promise<void> {\n return withRetry(async () => {\n await this.webClient.assistant.threads.setStatus({\n channel_id: channel,\n thread_ts: threadTs,\n status,\n });\n });\n }\n\n registerThreadAlias(aliasKey: string, sessionKey: string): void {\n this.handler.registerThreadAlias(aliasKey, sessionKey);\n }\n\n async postInThread(channel: string, threadTs: string, text: string): Promise<string> {\n return withRetry(async () => {\n // Use Block Kit section for long messages to trigger Slack's \"Show more\" collapsing (~700 chars)\n const SECTION_TEXT_LIMIT = 3000;\n if (text.length > 500) {\n const blockText =\n text.length > SECTION_TEXT_LIMIT\n ? text.substring(0, SECTION_TEXT_LIMIT - 20) + \"\\n_(truncated)_\"\n : text;\n const result = await this.webClient.chat.postMessage({\n channel,\n thread_ts: threadTs,\n text, // full text as notification fallback\n blocks: [{ type: \"section\", text: { type: \"mrkdwn\", text: blockText } }],\n });\n return result.ts as string;\n }\n const result = await this.webClient.chat.postMessage({ channel, thread_ts: threadTs, text });\n return result.ts as string;\n });\n }\n\n async postInThreadBlocks(\n channel: string,\n threadTs: string,\n text: string,\n blocks: object[],\n ): Promise<string> {\n return withRetry(async () => {\n const result = await this.webClient.chat.postMessage({\n channel,\n thread_ts: threadTs,\n text, // fallback for notifications\n blocks: blocks as any,\n });\n return result.ts as string;\n });\n }\n\n async uploadFile(\n channel: string,\n filePath: string,\n title?: string,\n threadTs?: string,\n ): Promise<void> {\n return withRetry(async () => {\n const fileName = title || basename(filePath);\n const fileContent = readFileSync(filePath);\n await this.webClient.files.uploadV2({\n channel_id: channel,\n file: fileContent,\n filename: fileName,\n title: fileName,\n ...(threadTs ? { thread_ts: threadTs } : {}),\n } as Parameters<typeof this.webClient.files.uploadV2>[0]);\n });\n }\n\n /**\n * Log a message to log.jsonl (SYNC)\n * This is the ONLY place messages are written to log.jsonl\n */\n logToFile(channel: string, entry: object): void {\n const dir = join(this.workingDir, channel);\n if (!existsSync(dir)) mkdirSync(dir, { recursive: true });\n appendFileSync(join(dir, \"log.jsonl\"), `${JSON.stringify(entry)}\\n`);\n }\n\n /**\n * Log a bot response to log.jsonl\n */\n logBotResponse(channel: string, text: string, ts: string, threadTs?: string): void {\n this.logToFile(channel, {\n date: new Date().toISOString(),\n ts,\n threadTs,\n user: \"bot\",\n text,\n attachments: [],\n isBot: true,\n });\n }\n\n getPlatformInfo(): PlatformInfo {\n return {\n name: \"slack\",\n formattingGuide:\n \"## Slack Formatting (mrkdwn, NOT Markdown)\\nBold: *text*, Italic: _text_, Code: `code`, Block: ```code```, Links: <url|text>\\nDo NOT use **double asterisks** or [markdown](links).\",\n channels: this.getAllChannels().map((c) => ({ id: c.id, name: c.name })),\n users: this.getAllUsers().map((u) => ({\n id: u.id,\n userName: u.userName,\n displayName: u.displayName,\n })),\n };\n }\n\n // ==========================================================================\n // Events Integration\n // ==========================================================================\n\n /**\n * Enqueue an event for processing. Always queues (no \"already working\" rejection).\n * Returns true if enqueued, false if queue is full (max 5).\n */\n enqueueEvent(event: BotEvent): boolean {\n const queue = this.getQueue(event.channel);\n if (queue.size() >= 5) {\n log.logWarning(\n `Event queue full for ${event.channel}, discarding: ${event.text.substring(0, 50)}`,\n );\n return false;\n }\n log.logInfo(`Enqueueing event for ${event.channel}: ${event.text.substring(0, 50)}`);\n queue.enqueue(() => {\n const adapters = createSlackAdapters(event as unknown as SlackEvent, this, true);\n return this.handler.handleEvent(event, this, adapters, true);\n });\n return true;\n }\n\n // ==========================================================================\n // Private - Event Handlers\n // ==========================================================================\n\n private getQueue(channelId: string): ChannelQueue {\n let queue = this.queues.get(channelId);\n if (!queue) {\n queue = new ChannelQueue();\n this.queues.set(channelId, queue);\n }\n return queue;\n }\n\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n private buildHomeView(): { type: \"home\"; blocks: any[] } {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const blocks: any[] = [\n {\n type: \"section\",\n text: {\n type: \"mrkdwn\",\n text: \"*Pi Agent*\\nWelcome back! Start a new task or check on running work.\",\n },\n accessory: {\n type: \"image\",\n image_url: \"https://media1.tenor.com/m/lfDATg4Bhc0AAAAC/happy-cat.gif\",\n alt_text: \"Pi Agent\",\n },\n },\n ];\n\n // --- Running tasks ---\n const runningSessions = this.handler.getRunningSessions();\n\n blocks.push(\n { type: \"divider\" },\n {\n type: \"header\",\n text: {\n type: \"plain_text\",\n text: `Running Tasks (${runningSessions.length})`,\n emoji: true,\n },\n },\n );\n\n if (runningSessions.length === 0) {\n blocks.push({\n type: \"context\",\n elements: [{ type: \"mrkdwn\", text: \"_No tasks running right now._\" }],\n });\n } else {\n // Threshold for \"stuck\" detection (10 minutes)\n const STUCK_THRESHOLD_MS = 10 * 60 * 1000;\n\n for (const session of runningSessions) {\n const channelId = session.sessionKey.split(\":\")[0];\n const channel = this.channels.get(channelId);\n const channelName = channel ? `#${channel.name}` : channelId;\n const elapsed = Math.floor((Date.now() - session.startedAt) / 60000);\n const elapsedStr = elapsed < 1 ? \"<1 min\" : `${elapsed} min`;\n\n // Check if task might be stuck\n const lastActivity = session.lastActivityAt ? Date.now() - session.lastActivityAt : 0;\n const isStuck = lastActivity > STUCK_THRESHOLD_MS;\n const statusText = isStuck ? \"_stuck_\" : \"_running_\";\n\n // Build status line: channel · status · time · step\n let statusLine = `${statusText} · ${elapsedStr}`;\n if (session.currentTool) {\n statusLine += ` · ${session.currentTool}`;\n }\n if (isStuck && lastActivity > 0) {\n const inactiveMin = Math.floor(lastActivity / 60000);\n statusLine += ` · idle ${inactiveMin}m`;\n }\n\n // Use context block for gray small text (like \"No scheduled jobs.\")\n blocks.push({\n type: \"context\",\n elements: [\n {\n type: \"mrkdwn\",\n text: `*${channelName}* · ${statusLine}`,\n },\n ],\n });\n\n // Add Force Stop button as separate element if stuck\n if (isStuck) {\n blocks.push({\n type: \"context\",\n elements: [\n {\n type: \"mrkdwn\",\n text: \" \",\n },\n {\n type: \"button\",\n text: { type: \"plain_text\", text: \"Force Stop\", emoji: true },\n action_id: `force_stop_${session.sessionKey.replace(/:/g, \"_\")}`,\n style: \"danger\",\n },\n ],\n });\n }\n }\n }\n\n // --- Cron jobs ---\n const periodicEvents = this.eventsWatcher?.getPeriodicEvents() ?? [];\n\n blocks.push(\n { type: \"divider\" },\n {\n type: \"header\",\n text: {\n type: \"plain_text\",\n text: `Scheduled Jobs (${periodicEvents.length})`,\n emoji: true,\n },\n },\n );\n\n if (periodicEvents.length === 0) {\n blocks.push({\n type: \"context\",\n elements: [{ type: \"mrkdwn\", text: \"_No scheduled jobs._\" }],\n });\n } else {\n for (const ev of periodicEvents) {\n const channelLabel =\n ev.platform === \"slack\"\n ? (() => {\n const channel = this.channels.get(ev.channelId);\n const channelName = channel ? `#${channel.name}` : ev.channelId;\n return `${ev.platform}:${channelName}`;\n })()\n : `${ev.platform}:${ev.channelId}`;\n const nextStr = ev.nextRun\n ? new Date(ev.nextRun).toLocaleString(\"en-US\", {\n month: \"short\",\n day: \"numeric\",\n hour: \"2-digit\",\n minute: \"2-digit\",\n })\n : \"—\";\n blocks.push({\n type: \"section\",\n text: {\n type: \"mrkdwn\",\n text: `*${ev.text}*\\n└ \\`${ev.schedule}\\` · ${channelLabel} · Next: ${nextStr}`,\n },\n });\n }\n }\n\n // --- Footer ---\n blocks.push(\n { type: \"divider\" },\n {\n type: \"context\",\n elements: [\n { type: \"mrkdwn\", text: \"💡 @mention in a channel or send a DM to start a new task\" },\n ],\n },\n );\n\n return { type: \"home\", blocks };\n }\n\n private setupEventHandlers(): void {\n // Channel @mentions\n this.socketClient.on(\"app_mention\", ({ event, ack }) => {\n const e = event as {\n text: string;\n channel: string;\n user: string;\n ts: string;\n thread_ts?: string;\n files?: Array<{ name: string; url_private_download?: string; url_private?: string }>;\n };\n\n // Skip DMs (handled by message event)\n if (e.channel.startsWith(\"D\")) {\n ack();\n return;\n }\n\n // Derive session key from thread context (resolve alias for bot-reply-anchored threads)\n const rootTs = e.thread_ts ?? e.ts;\n const sessionKey = this.handler.resolveSessionKey(`${e.channel}:${rootTs}`);\n\n const slackEvent: SlackEvent = {\n type: \"mention\",\n channel: e.channel,\n ts: e.ts,\n thread_ts: e.thread_ts,\n user: e.user,\n text: e.text.replace(/<@[A-Z0-9]+>/gi, \"\").trim(),\n files: e.files,\n };\n\n // SYNC: Log to log.jsonl (ALWAYS, even for old messages)\n // Also downloads attachments in background and stores local paths\n slackEvent.attachments = this.logUserMessage(slackEvent);\n\n // Only trigger processing for messages AFTER startup (not replayed old messages)\n if (this.startupTs && e.ts < this.startupTs) {\n log.logInfo(\n `[${e.channel}] Logged old message (pre-startup), not triggering: ${slackEvent.text.substring(0, 30)}`,\n );\n ack();\n return;\n }\n\n // Check for stop command - execute immediately, don't queue!\n if (slackEvent.text.toLowerCase().trim() === \"stop\") {\n if (this.handler.isRunning(sessionKey)) {\n this.handler.handleStop(sessionKey, e.channel, this);\n } else {\n this.postMessage(e.channel, \"_Nothing running_\");\n }\n ack();\n return;\n }\n\n // SYNC: Check if busy (per-thread)\n if (this.handler.isRunning(sessionKey)) {\n this.postMessage(\n e.channel,\n \"_Already working in this thread. Say `@mama stop` to cancel._\",\n );\n } else {\n this.getQueue(sessionKey).enqueue(() => {\n const adapters = createSlackAdapters(slackEvent, this, false);\n return this.handler.handleEvent(\n slackEvent as unknown as import(\"../../adapter.js\").BotEvent,\n this,\n adapters,\n false,\n );\n });\n }\n\n ack();\n });\n\n // All messages (for logging) + DMs (for triggering)\n this.socketClient.on(\"message\", ({ event, ack }) => {\n const e = event as {\n text?: string;\n channel: string;\n user?: string;\n ts: string;\n thread_ts?: string;\n channel_type?: string;\n subtype?: string;\n bot_id?: string;\n files?: Array<{ name: string; url_private_download?: string; url_private?: string }>;\n };\n\n // Skip bot messages, edits, etc.\n if (e.bot_id || !e.user || e.user === this.botUserId) {\n ack();\n return;\n }\n if (e.subtype !== undefined && e.subtype !== \"file_share\") {\n ack();\n return;\n }\n if (!e.text && (!e.files || e.files.length === 0)) {\n ack();\n return;\n }\n\n const isDM = e.channel_type === \"im\";\n const isBotMention = e.text?.includes(`<@${this.botUserId}>`);\n\n // Skip channel @mentions - already handled by app_mention event\n if (!isDM && isBotMention) {\n ack();\n return;\n }\n\n const slackEvent: SlackEvent = {\n type: isDM ? \"dm\" : \"mention\",\n channel: e.channel,\n ts: e.ts,\n thread_ts: e.thread_ts,\n user: e.user,\n text: (e.text || \"\").replace(/<@[A-Z0-9]+>/gi, \"\").trim(),\n files: e.files,\n };\n\n // SYNC: Log to log.jsonl (ALL messages - channel chatter and DMs)\n // Also downloads attachments in background and stores local paths\n slackEvent.attachments = this.logUserMessage(slackEvent);\n\n // Only trigger processing for messages AFTER startup (not replayed old messages)\n if (this.startupTs && e.ts < this.startupTs) {\n log.logInfo(\n `[${e.channel}] Skipping old message (pre-startup): ${slackEvent.text.substring(0, 30)}`,\n );\n ack();\n return;\n }\n\n // Check for stop command in channel threads (without @mention)\n // app_mention handles \"@mama stop\", but bare \"stop\" in a thread comes here\n if (!isDM && e.thread_ts && slackEvent.text.toLowerCase().trim() === \"stop\") {\n const threadSessionKey = this.handler.resolveSessionKey(`${e.channel}:${e.thread_ts}`);\n if (this.handler.isRunning(threadSessionKey)) {\n this.handler.handleStop(threadSessionKey, e.channel, this);\n } else {\n this.postMessage(e.channel, \"_Nothing running_\");\n }\n ack();\n return;\n }\n\n // Only trigger handler for DMs\n if (isDM) {\n const dmRootTs = e.thread_ts ?? e.ts;\n const dmSessionKey = this.handler.resolveSessionKey(`${e.channel}:${dmRootTs}`);\n\n // Check for stop command - execute immediately, don't queue!\n if (slackEvent.text.toLowerCase().trim() === \"stop\") {\n if (this.handler.isRunning(dmSessionKey)) {\n this.handler.handleStop(dmSessionKey, e.channel, this); // Don't await, don't queue\n } else {\n this.postMessage(e.channel, \"_Nothing running_\");\n }\n ack();\n return;\n }\n\n if (this.handler.isRunning(dmSessionKey)) {\n this.postMessage(e.channel, \"_Already working. Say `stop` to cancel._\");\n } else {\n this.getQueue(dmSessionKey).enqueue(() => {\n const adapters = createSlackAdapters(slackEvent, this, false);\n return this.handler.handleEvent(\n slackEvent as unknown as import(\"../../adapter.js\").BotEvent,\n this,\n adapters,\n false,\n );\n });\n }\n }\n\n ack();\n });\n\n // App Home tab\n this.socketClient.on(\"app_home_opened\", ({ event, ack }) => {\n const e = event as { user: string; tab: string };\n ack();\n if (e.tab !== \"home\") return;\n\n this.webClient.views\n .publish({\n user_id: e.user,\n view: this.buildHomeView(),\n })\n .catch((err) => {\n log.logWarning(`Failed to publish App Home view`, String(err));\n });\n });\n\n // Handle button clicks (Force Stop)\n this.socketClient.on(\"block_actions\", async ({ body, ack }) => {\n const action = body.actions?.[0];\n if (!action || !action.action_id?.startsWith(\"force_stop_\")) {\n ack();\n return;\n }\n\n ack();\n const sessionKey = action.action_id.replace(\"force_stop_\", \"\").replace(/_/g, \":\");\n const userId = body.user?.id;\n const channelId = body.container?.channel_id || sessionKey.split(\":\")[0];\n\n log.logInfo(`[Force Stop] User ${userId} requested force stop for ${sessionKey}`);\n\n // Use handler's forceStop method\n this.handler.forceStop(sessionKey);\n\n // Notify in channel\n await this.postMessage(channelId, `_🔴 Force stopped by ${userId}_`);\n\n // Refresh home tab\n if (userId) {\n this.webClient.views\n .publish({\n user_id: userId,\n view: this.buildHomeView(),\n })\n .catch((err) => {\n log.logWarning(`Failed to refresh App Home view`, String(err));\n });\n }\n });\n }\n\n /**\n * Log a user message to log.jsonl (SYNC)\n * Downloads attachments in background via store\n */\n private logUserMessage(event: SlackEvent): Attachment[] {\n const user = this.users.get(event.user);\n // Process attachments - queues downloads in background\n const attachments = event.files\n ? this.store.processAttachments(event.channel, event.files, event.ts)\n : [];\n this.logToFile(event.channel, {\n date: new Date(parseFloat(event.ts) * 1000).toISOString(),\n ts: event.ts,\n threadTs: event.thread_ts,\n user: event.user,\n userName: user?.userName,\n displayName: user?.displayName,\n text: event.text,\n attachments,\n isBot: false,\n });\n return attachments;\n }\n\n // ==========================================================================\n // Private - Backfill\n // ==========================================================================\n\n private async getExistingTimestamps(channelId: string): Promise<Set<string>> {\n const logPath = join(this.workingDir, channelId, \"log.jsonl\");\n const timestamps = new Set<string>();\n if (!existsSync(logPath)) return timestamps;\n\n const content = await readFile(logPath, \"utf-8\");\n const lines = content.trim().split(\"\\n\").filter(Boolean);\n for (const line of lines) {\n try {\n const entry = JSON.parse(line);\n if (entry.ts) timestamps.add(entry.ts);\n } catch {}\n }\n return timestamps;\n }\n\n private async backfillChannel(channelId: string): Promise<number> {\n const existingTs = await this.getExistingTimestamps(channelId);\n\n // Find the biggest ts in log.jsonl\n let latestTs: string | undefined;\n for (const ts of existingTs) {\n if (!latestTs || parseFloat(ts) > parseFloat(latestTs)) latestTs = ts;\n }\n\n type Message = {\n user?: string;\n bot_id?: string;\n text?: string;\n ts?: string;\n subtype?: string;\n files?: Array<{ name: string }>;\n };\n const allMessages: Message[] = [];\n\n let cursor: string | undefined;\n let pageCount = 0;\n const maxPages = 3;\n\n do {\n const result = await this.webClient.conversations.history({\n channel: channelId,\n oldest: latestTs, // Only fetch messages newer than what we have\n inclusive: false,\n limit: 1000,\n cursor,\n });\n if (result.messages) {\n allMessages.push(...(result.messages as Message[]));\n }\n cursor = result.response_metadata?.next_cursor;\n pageCount++;\n } while (cursor && pageCount < maxPages);\n\n // Filter: include mama's messages, exclude other bots, skip already logged\n const relevantMessages = allMessages.filter((msg) => {\n if (!msg.ts || existingTs.has(msg.ts)) return false; // Skip duplicates\n if (msg.user === this.botUserId) return true;\n if (msg.bot_id) return false;\n if (msg.subtype !== undefined && msg.subtype !== \"file_share\") return false;\n if (!msg.user) return false;\n if (!msg.text && (!msg.files || msg.files.length === 0)) return false;\n return true;\n });\n\n // Reverse to chronological order\n relevantMessages.reverse();\n\n // Log each message to log.jsonl\n for (const msg of relevantMessages) {\n const isMamaMessage = msg.user === this.botUserId;\n const user = this.users.get(msg.user!);\n // Strip @mentions from text (same as live messages)\n const text = (msg.text || \"\").replace(/<@[A-Z0-9]+>/gi, \"\").trim();\n // Process attachments - queues downloads in background\n const attachments = msg.files\n ? this.store.processAttachments(channelId, msg.files, msg.ts!)\n : [];\n\n this.logToFile(channelId, {\n date: new Date(parseFloat(msg.ts!) * 1000).toISOString(),\n ts: msg.ts!,\n user: isMamaMessage ? \"bot\" : msg.user!,\n userName: isMamaMessage ? undefined : user?.userName,\n displayName: isMamaMessage ? undefined : user?.displayName,\n text,\n attachments,\n isBot: isMamaMessage,\n });\n }\n\n return relevantMessages.length;\n }\n\n private async backfillAllChannels(): Promise<void> {\n const startTime = Date.now();\n\n // Only backfill channels that already have a log.jsonl (mama has interacted with them before)\n const channelsToBackfill: Array<[string, SlackChannel]> = [];\n for (const [channelId, channel] of this.channels) {\n const logPath = join(this.workingDir, channelId, \"log.jsonl\");\n if (existsSync(logPath)) {\n channelsToBackfill.push([channelId, channel]);\n }\n }\n\n log.logBackfillStart(channelsToBackfill.length);\n\n let totalMessages = 0;\n for (const [channelId, channel] of channelsToBackfill) {\n try {\n const count = await this.backfillChannel(channelId);\n if (count > 0) log.logBackfillChannel(channel.name, count);\n totalMessages += count;\n } catch (error) {\n log.logWarning(`Failed to backfill #${channel.name}`, String(error));\n }\n\n // Add delay between channels to avoid hitting Slack rate limits\n if (channelId !== channelsToBackfill[channelsToBackfill.length - 1][0]) {\n await new Promise((resolve) => setTimeout(resolve, 500));\n }\n }\n\n const durationMs = Date.now() - startTime;\n log.logBackfillComplete(totalMessages, durationMs);\n }\n\n // ==========================================================================\n // Private - Fetch Users/Channels\n // ==========================================================================\n\n private async fetchUsers(): Promise<void> {\n let cursor: string | undefined;\n do {\n const result = await this.webClient.users.list({ limit: 200, cursor });\n const members = result.members as\n | Array<{ id?: string; name?: string; real_name?: string; deleted?: boolean }>\n | undefined;\n if (members) {\n for (const u of members) {\n if (u.id && u.name && !u.deleted) {\n this.users.set(u.id, {\n id: u.id,\n userName: u.name,\n displayName: u.real_name || u.name,\n });\n }\n }\n }\n cursor = result.response_metadata?.next_cursor;\n } while (cursor);\n }\n\n private async fetchChannels(): Promise<void> {\n // Fetch public/private channels\n let cursor: string | undefined;\n do {\n const result = await this.webClient.conversations.list({\n types: \"public_channel,private_channel\",\n exclude_archived: true,\n limit: 200,\n cursor,\n });\n const channels = result.channels as\n | Array<{ id?: string; name?: string; is_member?: boolean }>\n | undefined;\n if (channels) {\n for (const c of channels) {\n if (c.id && c.name && c.is_member) {\n this.channels.set(c.id, { id: c.id, name: c.name });\n }\n }\n }\n cursor = result.response_metadata?.next_cursor;\n } while (cursor);\n\n // Also fetch DM channels (IMs)\n cursor = undefined;\n do {\n const result = await this.webClient.conversations.list({\n types: \"im\",\n limit: 200,\n cursor,\n });\n const ims = result.channels as Array<{ id?: string; user?: string }> | undefined;\n if (ims) {\n for (const im of ims) {\n if (im.id) {\n // Use user's name as channel name for DMs\n const user = im.user ? this.users.get(im.user) : undefined;\n const name = user ? `DM:${user.userName}` : `DM:${im.id}`;\n this.channels.set(im.id, { id: im.id, name });\n }\n }\n }\n cursor = result.response_metadata?.next_cursor;\n } while (cursor);\n }\n}\n"]}
1
+ {"version":3,"file":"bot.js","sourceRoot":"","sources":["../../../src/adapters/slack/bot.ts"],"names":[],"mappings":"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","sourcesContent":["import { SocketModeClient } from \"@slack/socket-mode\";\nimport { WebClient } from \"@slack/web-api\";\nimport { appendFileSync, existsSync, mkdirSync, readFileSync } from \"fs\";\nimport { readFile } from \"fs/promises\";\nimport { basename, join } from \"path\";\nimport type { Bot, BotEvent, BotHandler, PlatformInfo } from \"../../adapter.js\";\nimport type { EventsWatcher } from \"../../events.js\";\nimport { parseLoginCommand } from \"../../login.js\";\nimport * as log from \"../../log.js\";\nimport type { Attachment, ChannelStore } from \"../../store.js\";\nimport {\n PRODUCT_NAME,\n formatAlreadyWorking,\n formatForceStopped,\n formatNothingRunning,\n} from \"../../ui-copy.js\";\nimport { createSlackAdapters } from \"./context.js\";\n\n// ============================================================================\n// Exponential backoff utility for Slack API calls\n// ============================================================================\n\n/**\n * Retry a function with exponential backoff on rate limit errors.\n */\nasync function withRetry<T>(\n fn: () => Promise<T>,\n maxRetries: number = 3,\n baseDelayMs: number = 1000,\n): Promise<T> {\n let lastError: Error | undefined;\n for (let attempt = 0; attempt < maxRetries; attempt++) {\n try {\n return await fn();\n } catch (err) {\n lastError = err instanceof Error ? err : new Error(String(err));\n\n // Check for rate limit errors\n let isRateLimited = false;\n\n // Check for rate_limited error code (Slack SDK)\n if (\"code\" in lastError && lastError.code === \"rate_limited\") {\n isRateLimited = true;\n }\n\n // Check for rate_limited in error response\n if (\"data\" in lastError) {\n const data = (lastError as { data?: { error?: string; response?: { status?: number } } })\n .data;\n if (data?.error === \"rate_limited\" || data?.response?.status === 429) {\n isRateLimited = true;\n }\n }\n\n if (isRateLimited) {\n const delay = baseDelayMs * Math.pow(2, attempt);\n log.logWarning(\n `Rate limited, retrying in ${delay}ms (attempt ${attempt + 1}/${maxRetries})`,\n );\n await new Promise((resolve) => setTimeout(resolve, delay));\n continue;\n }\n\n // Non-retryable error\n throw lastError;\n }\n }\n throw lastError;\n}\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport interface SlackEvent {\n type: \"mention\" | \"dm\";\n channel: string;\n ts: string;\n thread_ts?: string;\n user: string;\n text: string;\n files?: Array<{ name?: string; url_private_download?: string; url_private?: string }>;\n /** Processed attachments with local paths (populated after logUserMessage) */\n attachments?: Attachment[];\n /** Session key passed through to BotEvent so handleEvent uses the correct persistent session */\n sessionKey?: string;\n}\n\nexport interface SlackUser {\n id: string;\n userName: string;\n displayName: string;\n}\n\nexport interface SlackChannel {\n id: string;\n name: string;\n}\n\n// Types used by agent.ts\nexport interface ChannelInfo {\n id: string;\n name: string;\n}\n\nexport interface UserInfo {\n id: string;\n userName: string;\n displayName: string;\n}\n\nexport interface SlackContext {\n message: {\n text: string;\n rawText: string;\n user: string;\n userName?: string;\n channel: string;\n ts: string;\n attachments: Array<{ localPath: string }>;\n };\n channelName?: string;\n channels: ChannelInfo[];\n users: UserInfo[];\n respond: (text: string, shouldLog?: boolean) => Promise<void>;\n replaceMessage: (text: string) => Promise<void>;\n respondInThread: (text: string) => Promise<void>;\n setTyping: (isTyping: boolean) => Promise<void>;\n uploadFile: (filePath: string, title?: string) => Promise<void>;\n setWorking: (working: boolean) => Promise<void>;\n deleteMessage: () => Promise<void>;\n}\n\n/** @deprecated Use BotHandler from adapter.ts instead */\nexport type MomHandler = BotHandler;\n\n// ============================================================================\n// Per-channel queue for sequential processing\n// ============================================================================\n\ntype QueuedWork = () => Promise<void>;\n\nclass ChannelQueue {\n private queue: QueuedWork[] = [];\n private processing = false;\n\n enqueue(work: QueuedWork): void {\n this.queue.push(work);\n this.processNext();\n }\n\n size(): number {\n return this.queue.length;\n }\n\n private async processNext(): Promise<void> {\n if (this.processing || this.queue.length === 0) return;\n this.processing = true;\n const work = this.queue.shift()!;\n try {\n await work();\n } catch (err) {\n log.logWarning(\"Queue error\", err instanceof Error ? err.message : String(err));\n }\n this.processing = false;\n this.processNext();\n }\n}\n\n// ============================================================================\n// SlackBot\n// ============================================================================\n\nexport class SlackBot implements Bot {\n private socketClient: SocketModeClient;\n private webClient: WebClient;\n private handler: BotHandler;\n private workingDir: string;\n private store: ChannelStore;\n private botUserId: string | null = null;\n private startupTs: string | null = null; // Messages older than this are just logged, not processed\n\n private users = new Map<string, SlackUser>();\n private channels = new Map<string, SlackChannel>();\n private queues = new Map<string, ChannelQueue>();\n private eventsWatcher: EventsWatcher | null = null;\n\n constructor(\n handler: BotHandler,\n config: { appToken: string; botToken: string; workingDir: string; store: ChannelStore },\n ) {\n this.handler = handler;\n this.workingDir = config.workingDir;\n this.store = config.store;\n this.socketClient = new SocketModeClient({ appToken: config.appToken });\n this.webClient = new WebClient(config.botToken);\n }\n\n setEventsWatcher(watcher: EventsWatcher): void {\n this.eventsWatcher = watcher;\n }\n\n private toBotEvent(event: SlackEvent): BotEvent {\n return {\n type: event.type,\n conversationId: event.channel,\n ts: event.ts,\n thread_ts: event.thread_ts,\n user: event.user,\n text: event.text,\n attachments: event.attachments?.map((attachment) => ({\n name: attachment.original,\n localPath: attachment.localPath,\n })),\n sessionKey: event.sessionKey,\n };\n }\n\n // ==========================================================================\n // Public API\n // ==========================================================================\n\n async start(): Promise<void> {\n const auth = await this.webClient.auth.test();\n this.botUserId = auth.user_id as string;\n\n await Promise.all([this.fetchUsers(), this.fetchChannels()]);\n log.logInfo(`Loaded ${this.channels.size} channels, ${this.users.size} users`);\n\n await this.backfillAllChannels();\n\n this.setupEventHandlers();\n await this.socketClient.start();\n\n // Record startup time - messages older than this are just logged, not processed\n this.startupTs = (Date.now() / 1000).toFixed(6);\n\n log.logConnected();\n }\n\n getUser(userId: string): SlackUser | undefined {\n return this.users.get(userId);\n }\n\n getChannel(channelId: string): SlackChannel | undefined {\n return this.channels.get(channelId);\n }\n\n getAllUsers(): SlackUser[] {\n return Array.from(this.users.values());\n }\n\n getAllChannels(): SlackChannel[] {\n return Array.from(this.channels.values());\n }\n\n async postMessage(conversationId: string, text: string): Promise<string> {\n return withRetry(async () => {\n const result = await this.webClient.chat.postMessage({ channel: conversationId, text });\n return result.ts as string;\n });\n }\n\n async updateMessage(conversationId: string, ts: string, text: string): Promise<void> {\n return withRetry(async () => {\n await this.webClient.chat.update({ channel: conversationId, ts, text });\n });\n }\n\n async deleteMessage(channel: string, ts: string): Promise<void> {\n return withRetry(async () => {\n await this.webClient.chat.delete({ channel, ts });\n });\n }\n\n // ==========================================================================\n // Slack Assistant API (AI assistant experience)\n // ==========================================================================\n\n /** Set the status for an assistant thread (shows \"thinking\" state) */\n async setAssistantStatus(channel: string, threadTs: string, status: string): Promise<void> {\n return withRetry(async () => {\n await this.webClient.assistant.threads.setStatus({\n channel_id: channel,\n thread_ts: threadTs,\n status,\n });\n });\n }\n\n async postInThread(channel: string, threadTs: string, text: string): Promise<string> {\n return withRetry(async () => {\n // Use Block Kit section for long messages to trigger Slack's \"Show more\" collapsing (~700 chars)\n const SECTION_TEXT_LIMIT = 3000;\n if (text.length > 500) {\n const blockText =\n text.length > SECTION_TEXT_LIMIT\n ? text.substring(0, SECTION_TEXT_LIMIT - 20) + \"\\n_(truncated)_\"\n : text;\n const result = await this.webClient.chat.postMessage({\n channel,\n thread_ts: threadTs,\n text, // full text as notification fallback\n blocks: [{ type: \"section\", text: { type: \"mrkdwn\", text: blockText } }],\n });\n return result.ts as string;\n }\n const result = await this.webClient.chat.postMessage({ channel, thread_ts: threadTs, text });\n return result.ts as string;\n });\n }\n\n async postInThreadBlocks(\n channel: string,\n threadTs: string,\n text: string,\n blocks: object[],\n ): Promise<string> {\n return withRetry(async () => {\n const result = await this.webClient.chat.postMessage({\n channel,\n thread_ts: threadTs,\n text, // fallback for notifications\n blocks: blocks as any,\n });\n return result.ts as string;\n });\n }\n\n async uploadFile(\n channel: string,\n filePath: string,\n title?: string,\n threadTs?: string,\n ): Promise<void> {\n return withRetry(async () => {\n const fileName = title || basename(filePath);\n const fileContent = readFileSync(filePath);\n await this.webClient.files.uploadV2({\n channel_id: channel,\n file: fileContent,\n filename: fileName,\n title: fileName,\n ...(threadTs ? { thread_ts: threadTs } : {}),\n } as Parameters<typeof this.webClient.files.uploadV2>[0]);\n });\n }\n\n /**\n * Log a message to log.jsonl (SYNC)\n * This is the ONLY place messages are written to log.jsonl\n */\n logToFile(channel: string, entry: object): void {\n const channelDir = join(this.workingDir, channel);\n if (!existsSync(channelDir)) mkdirSync(channelDir, { recursive: true });\n appendFileSync(join(channelDir, \"log.jsonl\"), `${JSON.stringify(entry)}\\n`);\n }\n\n /**\n * Log a bot response to log.jsonl\n */\n logBotResponse(channel: string, text: string, ts: string, threadTs?: string): void {\n this.logToFile(channel, {\n date: new Date().toISOString(),\n ts,\n threadTs,\n user: \"bot\",\n text,\n attachments: [],\n isBot: true,\n });\n }\n\n getPlatformInfo(): PlatformInfo {\n return {\n name: \"slack\",\n formattingGuide:\n \"## Slack Formatting (mrkdwn, NOT Markdown)\\nBold: *text*, Italic: _text_, Code: `code`, Block: ```code```, Links: <url|text>\\nDo NOT use **double asterisks** or [markdown](links).\",\n channels: this.getAllChannels().map((c) => ({ id: c.id, name: c.name })),\n users: this.getAllUsers().map((u) => ({\n id: u.id,\n userName: u.userName,\n displayName: u.displayName,\n })),\n };\n }\n\n // ==========================================================================\n // Events Integration\n // ==========================================================================\n\n /**\n * Enqueue an event for processing. Always queues (no \"already working\" rejection).\n * Returns true if enqueued, false if queue is full (max 5).\n */\n enqueueEvent(event: BotEvent): boolean {\n const queue = this.getQueue(event.conversationId);\n if (queue.size() >= 5) {\n log.logWarning(\n `Event queue full for ${event.conversationId}, discarding: ${event.text.substring(0, 50)}`,\n );\n return false;\n }\n log.logInfo(`Enqueueing event for ${event.conversationId}: ${event.text.substring(0, 50)}`);\n queue.enqueue(() => {\n const slackEvent: SlackEvent = {\n type: \"mention\",\n channel: event.conversationId,\n ts: event.ts,\n thread_ts: event.thread_ts,\n user: event.user,\n text: event.text,\n sessionKey: event.sessionKey,\n };\n const adapters = createSlackAdapters(slackEvent, this, true);\n return this.handler.handleEvent(event, this, adapters, true);\n });\n return true;\n }\n\n // ==========================================================================\n // Private - Event Handlers\n // ==========================================================================\n\n private getQueue(channelId: string): ChannelQueue {\n let queue = this.queues.get(channelId);\n if (!queue) {\n queue = new ChannelQueue();\n this.queues.set(channelId, queue);\n }\n return queue;\n }\n\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n private buildHomeView(): { type: \"home\"; blocks: any[] } {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const blocks: any[] = [\n {\n type: \"section\",\n text: {\n type: \"mrkdwn\",\n text: `*${PRODUCT_NAME}*\\nStart a new task or check on running work.`,\n },\n accessory: {\n type: \"image\",\n image_url: \"https://media1.tenor.com/m/lfDATg4Bhc0AAAAC/happy-cat.gif\",\n alt_text: PRODUCT_NAME,\n },\n },\n ];\n\n // --- Running tasks ---\n const runningSessions = this.handler.getRunningSessions();\n\n blocks.push(\n { type: \"divider\" },\n {\n type: \"header\",\n text: {\n type: \"plain_text\",\n text: `Running Tasks (${runningSessions.length})`,\n emoji: true,\n },\n },\n );\n\n if (runningSessions.length === 0) {\n blocks.push({\n type: \"context\",\n elements: [{ type: \"mrkdwn\", text: \"_No tasks running right now._\" }],\n });\n } else {\n // Threshold for \"stuck\" detection (10 minutes)\n const STUCK_THRESHOLD_MS = 10 * 60 * 1000;\n\n for (const session of runningSessions) {\n const channelId = session.sessionKey.split(\":\")[0];\n const channel = this.channels.get(channelId);\n const channelName = channel ? `#${channel.name}` : channelId;\n const elapsed = Math.floor((Date.now() - session.startedAt) / 60000);\n const elapsedStr = elapsed < 1 ? \"<1 min\" : `${elapsed} min`;\n\n // Check if task might be stuck\n const lastActivity = session.lastActivityAt ? Date.now() - session.lastActivityAt : 0;\n const isStuck = lastActivity > STUCK_THRESHOLD_MS;\n const statusText = isStuck ? \"_stuck_\" : \"_running_\";\n\n // Build status line: channel · status · time · step\n let statusLine = `${statusText} · ${elapsedStr}`;\n if (session.currentTool) {\n statusLine += ` · ${session.currentTool}`;\n }\n if (isStuck && lastActivity > 0) {\n const inactiveMin = Math.floor(lastActivity / 60000);\n statusLine += ` · idle ${inactiveMin}m`;\n }\n\n // Use context block for gray small text (like \"No scheduled jobs.\")\n blocks.push({\n type: \"context\",\n elements: [\n {\n type: \"mrkdwn\",\n text: `*${channelName}* · ${statusLine}`,\n },\n ],\n });\n\n // Add Force Stop button as separate element if stuck\n if (isStuck) {\n blocks.push({\n type: \"context\",\n elements: [\n {\n type: \"mrkdwn\",\n text: \" \",\n },\n {\n type: \"button\",\n text: { type: \"plain_text\", text: \"Force Stop\", emoji: true },\n action_id: `force_stop_${session.sessionKey.replace(/:/g, \"_\")}`,\n style: \"danger\",\n },\n ],\n });\n }\n }\n }\n\n // --- Cron jobs ---\n const periodicEvents = this.eventsWatcher?.getPeriodicEvents() ?? [];\n\n blocks.push(\n { type: \"divider\" },\n {\n type: \"header\",\n text: {\n type: \"plain_text\",\n text: `Scheduled Jobs (${periodicEvents.length})`,\n emoji: true,\n },\n },\n );\n\n if (periodicEvents.length === 0) {\n blocks.push({\n type: \"context\",\n elements: [{ type: \"mrkdwn\", text: \"_No scheduled jobs._\" }],\n });\n } else {\n const timestampFormatter = new Intl.DateTimeFormat(undefined, {\n month: \"short\",\n day: \"numeric\",\n hour: \"2-digit\",\n minute: \"2-digit\",\n });\n for (const ev of periodicEvents) {\n const channelLabel =\n ev.platform === \"slack\"\n ? (() => {\n const channel = this.channels.get(ev.channelId);\n const channelName = channel ? `#${channel.name}` : ev.channelId;\n return `${ev.platform}:${channelName}`;\n })()\n : `${ev.platform}:${ev.channelId}`;\n const nextStr = ev.nextRun ? timestampFormatter.format(new Date(ev.nextRun)) : \"—\";\n blocks.push({\n type: \"section\",\n text: {\n type: \"mrkdwn\",\n text: `*${ev.text}*\\n└ \\`${ev.schedule}\\` · ${channelLabel} · Next: ${nextStr}`,\n },\n });\n }\n }\n\n // --- Footer ---\n blocks.push(\n { type: \"divider\" },\n {\n type: \"context\",\n elements: [\n { type: \"mrkdwn\", text: \"💡 @mention in a channel or send a DM to start a new task\" },\n ],\n },\n );\n\n return { type: \"home\", blocks };\n }\n\n /**\n * Resolve which session key to stop.\n * When stop is called from a thread, the thread session (channelId:thread_ts) might\n * not be running — but the channel session (channelId) might be, because the bot's\n * reply to a top-level mention creates a thread. Check both, prefer thread first.\n */\n private resolveStopTarget(channelId: string, threadTs?: string): string | null {\n if (threadTs) {\n const threadKey = `${channelId}:${threadTs}`;\n if (this.handler.isRunning(threadKey)) return threadKey;\n // Fall back to channel session — the thread may have been spawned by a top-level run\n if (this.handler.isRunning(channelId)) return channelId;\n return null;\n }\n return this.handler.isRunning(channelId) ? channelId : null;\n }\n\n private setupEventHandlers(): void {\n // Channel @mentions\n this.socketClient.on(\"app_mention\", ({ event, ack }) => {\n const e = event as {\n text: string;\n channel: string;\n user: string;\n ts: string;\n thread_ts?: string;\n files?: Array<{ name: string; url_private_download?: string; url_private?: string }>;\n };\n\n // Skip DMs (handled by message event)\n if (e.channel.startsWith(\"D\")) {\n ack();\n return;\n }\n\n // Top-level mentions use a persistent channel session.\n // Thread replies get their own isolated session (channelId:thread_ts).\n const sessionKey = e.thread_ts ? `${e.channel}:${e.thread_ts}` : e.channel;\n\n const slackEvent: SlackEvent = {\n type: \"mention\",\n channel: e.channel,\n ts: e.ts,\n thread_ts: e.thread_ts,\n user: e.user,\n text: e.text.replace(/<@[A-Z0-9]+>/gi, \"\").trim(),\n files: e.files,\n sessionKey,\n };\n\n // SYNC: Log to log.jsonl (ALWAYS, even for old messages)\n // Also downloads attachments in background and stores local paths\n slackEvent.attachments = this.logUserMessage(slackEvent);\n\n // Only trigger processing for messages AFTER startup (not replayed old messages)\n if (this.startupTs && e.ts < this.startupTs) {\n log.logInfo(\n `[${e.channel}] Logged old message (pre-startup), not triggering: ${slackEvent.text.substring(0, 30)}`,\n );\n ack();\n return;\n }\n\n // Check for stop command - execute immediately, don't queue!\n if (slackEvent.text.toLowerCase().trim() === \"stop\") {\n const stopTarget = this.resolveStopTarget(e.channel, e.thread_ts);\n if (stopTarget) {\n this.handler.handleStop(stopTarget, e.channel, this);\n } else {\n this.postMessage(e.channel, formatNothingRunning(\"slack\"));\n }\n ack();\n return;\n }\n\n // Check for login command\n if (parseLoginCommand(slackEvent.text)) {\n void this.handler.handleLogin(\"slack\", e.user, e.channel, this, slackEvent.text, false);\n ack();\n return;\n }\n\n // SYNC: Check if busy (per-thread)\n if (this.handler.isRunning(sessionKey)) {\n this.postMessage(\n e.channel,\n formatAlreadyWorking(\"slack\", \"@mama stop\", { scope: \"thread\" }),\n );\n } else {\n this.getQueue(sessionKey).enqueue(() => {\n const adapters = createSlackAdapters(slackEvent, this, false);\n return this.handler.handleEvent(this.toBotEvent(slackEvent), this, adapters, false);\n });\n }\n\n ack();\n });\n\n // All messages (for logging) + DMs (for triggering)\n this.socketClient.on(\"message\", ({ event, ack }) => {\n const e = event as {\n text?: string;\n channel: string;\n user?: string;\n ts: string;\n thread_ts?: string;\n channel_type?: string;\n subtype?: string;\n bot_id?: string;\n files?: Array<{ name: string; url_private_download?: string; url_private?: string }>;\n };\n\n // Skip bot messages, edits, etc.\n if (e.bot_id || !e.user || e.user === this.botUserId) {\n ack();\n return;\n }\n if (e.subtype !== undefined && e.subtype !== \"file_share\") {\n ack();\n return;\n }\n if (!e.text && (!e.files || e.files.length === 0)) {\n ack();\n return;\n }\n\n const isDM = e.channel_type === \"im\";\n const isBotMention = e.text?.includes(`<@${this.botUserId}>`);\n\n // Skip channel @mentions - already handled by app_mention event\n if (!isDM && isBotMention) {\n ack();\n return;\n }\n\n const slackEvent: SlackEvent = {\n type: isDM ? \"dm\" : \"mention\",\n channel: e.channel,\n ts: e.ts,\n thread_ts: e.thread_ts,\n user: e.user,\n text: (e.text || \"\").replace(/<@[A-Z0-9]+>/gi, \"\").trim(),\n files: e.files,\n sessionKey: isDM ? e.channel : undefined,\n };\n\n // SYNC: Log to log.jsonl (ALL messages - channel chatter and DMs)\n // Also downloads attachments in background and stores local paths\n slackEvent.attachments = this.logUserMessage(slackEvent);\n\n // Only trigger processing for messages AFTER startup (not replayed old messages)\n if (this.startupTs && e.ts < this.startupTs) {\n log.logInfo(\n `[${e.channel}] Skipping old message (pre-startup): ${slackEvent.text.substring(0, 30)}`,\n );\n ack();\n return;\n }\n\n // Check for stop command in channel threads (without @mention)\n // app_mention handles \"@mama stop\", but bare \"stop\" in a thread comes here\n if (!isDM && e.thread_ts && slackEvent.text.toLowerCase().trim() === \"stop\") {\n const stopTarget = this.resolveStopTarget(e.channel, e.thread_ts);\n if (stopTarget) {\n this.handler.handleStop(stopTarget, e.channel, this);\n } else {\n this.postMessage(e.channel, formatNothingRunning(\"slack\"));\n }\n ack();\n return;\n }\n\n // Only trigger handler for DMs\n if (isDM) {\n const dmSessionKey = slackEvent.sessionKey!;\n // Check for stop command - execute immediately, don't queue!\n if (slackEvent.text.toLowerCase().trim() === \"stop\") {\n if (this.handler.isRunning(dmSessionKey)) {\n this.handler.handleStop(dmSessionKey, e.channel, this); // Don't await, don't queue\n } else {\n this.postMessage(e.channel, formatNothingRunning(\"slack\"));\n }\n ack();\n return;\n }\n\n // Check for login command\n if (parseLoginCommand(slackEvent.text)) {\n void this.handler.handleLogin(\"slack\", e.user, e.channel, this, slackEvent.text, true);\n ack();\n return;\n }\n\n if (this.handler.isRunning(dmSessionKey)) {\n this.postMessage(e.channel, formatAlreadyWorking(\"slack\", \"stop\"));\n } else {\n this.getQueue(dmSessionKey).enqueue(() => {\n const adapters = createSlackAdapters(slackEvent, this, false);\n return this.handler.handleEvent(this.toBotEvent(slackEvent), this, adapters, false);\n });\n }\n }\n\n ack();\n });\n\n // App Home tab\n this.socketClient.on(\"app_home_opened\", ({ event, ack }) => {\n const e = event as { user: string; tab: string };\n ack();\n if (e.tab !== \"home\") return;\n\n this.webClient.views\n .publish({\n user_id: e.user,\n view: this.buildHomeView(),\n })\n .catch((err) => {\n log.logWarning(`Failed to publish App Home view`, String(err));\n });\n });\n\n // Handle button clicks (Force Stop)\n this.socketClient.on(\"block_actions\", async ({ body, ack }) => {\n const action = body.actions?.[0];\n if (!action || !action.action_id?.startsWith(\"force_stop_\")) {\n ack();\n return;\n }\n\n ack();\n const sessionKey = action.action_id.replace(\"force_stop_\", \"\").replace(/_/g, \":\");\n const userId = body.user?.id;\n const channelId = body.container?.channel_id || sessionKey.split(\":\")[0];\n\n log.logInfo(`[Force Stop] User ${userId} requested force stop for ${sessionKey}`);\n\n // Use handler's forceStop method\n this.handler.forceStop(sessionKey);\n\n // Notify in channel\n const actorLabel = userId ? `<@${userId}>` : \"someone\";\n await this.postMessage(channelId, formatForceStopped(\"slack\", actorLabel));\n\n // Refresh home tab\n if (userId) {\n this.webClient.views\n .publish({\n user_id: userId,\n view: this.buildHomeView(),\n })\n .catch((err) => {\n log.logWarning(`Failed to refresh App Home view`, String(err));\n });\n }\n });\n }\n\n /**\n * Log a user message to log.jsonl (SYNC)\n * Downloads attachments in background via store\n */\n private logUserMessage(event: SlackEvent): Attachment[] {\n const user = this.users.get(event.user);\n // Process attachments - queues downloads in background\n const attachments = event.files\n ? this.store.processAttachments(event.channel, event.files, event.ts)\n : [];\n this.logToFile(event.channel, {\n date: new Date(parseFloat(event.ts) * 1000).toISOString(),\n ts: event.ts,\n threadTs: event.thread_ts,\n user: event.user,\n userName: user?.userName,\n displayName: user?.displayName,\n text: event.text,\n attachments,\n isBot: false,\n });\n return attachments;\n }\n\n // ==========================================================================\n // Private - Backfill\n // ==========================================================================\n\n private async getExistingTimestamps(channelId: string): Promise<Set<string>> {\n const logPath = join(this.workingDir, channelId, \"log.jsonl\");\n const timestamps = new Set<string>();\n if (!existsSync(logPath)) return timestamps;\n\n const content = await readFile(logPath, \"utf-8\");\n const lines = content.trim().split(\"\\n\").filter(Boolean);\n for (const line of lines) {\n try {\n const entry = JSON.parse(line);\n if (entry.ts) timestamps.add(entry.ts);\n } catch {}\n }\n return timestamps;\n }\n\n private async backfillChannel(channelId: string): Promise<number> {\n const existingTs = await this.getExistingTimestamps(channelId);\n\n // Find the biggest ts in log.jsonl\n let latestTs: string | undefined;\n for (const ts of existingTs) {\n if (!latestTs || parseFloat(ts) > parseFloat(latestTs)) latestTs = ts;\n }\n\n type Message = {\n user?: string;\n bot_id?: string;\n text?: string;\n ts?: string;\n subtype?: string;\n files?: Array<{ name: string }>;\n };\n const allMessages: Message[] = [];\n\n let cursor: string | undefined;\n let pageCount = 0;\n const maxPages = 3;\n\n do {\n const result = await this.webClient.conversations.history({\n channel: channelId,\n oldest: latestTs, // Only fetch messages newer than what we have\n inclusive: false,\n limit: 1000,\n cursor,\n });\n if (result.messages) {\n allMessages.push(...(result.messages as Message[]));\n }\n cursor = result.response_metadata?.next_cursor;\n pageCount++;\n } while (cursor && pageCount < maxPages);\n\n // Filter: include mama's messages, exclude other bots, skip already logged\n const relevantMessages = allMessages.filter((msg) => {\n if (!msg.ts || existingTs.has(msg.ts)) return false; // Skip duplicates\n if (msg.user === this.botUserId) return true;\n if (msg.bot_id) return false;\n if (msg.subtype !== undefined && msg.subtype !== \"file_share\") return false;\n if (!msg.user) return false;\n if (!msg.text && (!msg.files || msg.files.length === 0)) return false;\n return true;\n });\n\n // Reverse to chronological order\n relevantMessages.reverse();\n\n // Log each message to log.jsonl\n for (const msg of relevantMessages) {\n const isMamaMessage = msg.user === this.botUserId;\n const user = this.users.get(msg.user!);\n // Strip @mentions from text (same as live messages)\n const text = (msg.text || \"\").replace(/<@[A-Z0-9]+>/gi, \"\").trim();\n // Process attachments - queues downloads in background\n const attachments = msg.files\n ? this.store.processAttachments(channelId, msg.files, msg.ts!)\n : [];\n\n this.logToFile(channelId, {\n date: new Date(parseFloat(msg.ts!) * 1000).toISOString(),\n ts: msg.ts!,\n user: isMamaMessage ? \"bot\" : msg.user!,\n userName: isMamaMessage ? undefined : user?.userName,\n displayName: isMamaMessage ? undefined : user?.displayName,\n text,\n attachments,\n isBot: isMamaMessage,\n });\n }\n\n return relevantMessages.length;\n }\n\n private async backfillAllChannels(): Promise<void> {\n const startTime = Date.now();\n\n // Only backfill channels that already have a log.jsonl (mama has interacted with them before)\n const channelsToBackfill: Array<[string, SlackChannel]> = [];\n for (const [channelId, channel] of this.channels) {\n const logPath = join(this.workingDir, channelId, \"log.jsonl\");\n if (existsSync(logPath)) {\n channelsToBackfill.push([channelId, channel]);\n }\n }\n\n log.logBackfillStart(channelsToBackfill.length);\n\n let totalMessages = 0;\n for (const [channelId, channel] of channelsToBackfill) {\n try {\n const count = await this.backfillChannel(channelId);\n if (count > 0) log.logBackfillChannel(channel.name, count);\n totalMessages += count;\n } catch (error) {\n log.logWarning(`Failed to backfill #${channel.name}`, String(error));\n }\n\n // Add delay between channels to avoid hitting Slack rate limits\n if (channelId !== channelsToBackfill[channelsToBackfill.length - 1][0]) {\n await new Promise((resolve) => setTimeout(resolve, 500));\n }\n }\n\n const durationMs = Date.now() - startTime;\n log.logBackfillComplete(totalMessages, durationMs);\n }\n\n // ==========================================================================\n // Private - Fetch Users/Channels\n // ==========================================================================\n\n private async fetchUsers(): Promise<void> {\n let cursor: string | undefined;\n do {\n const result = await this.webClient.users.list({ limit: 200, cursor });\n const members = result.members as\n | Array<{ id?: string; name?: string; real_name?: string; deleted?: boolean }>\n | undefined;\n if (members) {\n for (const u of members) {\n if (u.id && u.name && !u.deleted) {\n this.users.set(u.id, {\n id: u.id,\n userName: u.name,\n displayName: u.real_name || u.name,\n });\n }\n }\n }\n cursor = result.response_metadata?.next_cursor;\n } while (cursor);\n }\n\n private async fetchChannels(): Promise<void> {\n // Fetch public/private channels\n let cursor: string | undefined;\n do {\n const result = await this.webClient.conversations.list({\n types: \"public_channel,private_channel\",\n exclude_archived: true,\n limit: 200,\n cursor,\n });\n const channels = result.channels as\n | Array<{ id?: string; name?: string; is_member?: boolean }>\n | undefined;\n if (channels) {\n for (const c of channels) {\n if (c.id && c.name && c.is_member) {\n this.channels.set(c.id, { id: c.id, name: c.name });\n }\n }\n }\n cursor = result.response_metadata?.next_cursor;\n } while (cursor);\n\n // Also fetch DM channels (IMs)\n cursor = undefined;\n do {\n const result = await this.webClient.conversations.list({\n types: \"im\",\n limit: 200,\n cursor,\n });\n const ims = result.channels as Array<{ id?: string; user?: string }> | undefined;\n if (ims) {\n for (const im of ims) {\n if (im.id) {\n // Use user's name as channel name for DMs\n const user = im.user ? this.users.get(im.user) : undefined;\n const name = user ? `DM:${user.userName}` : `DM:${im.id}`;\n this.channels.set(im.id, { id: im.id, name });\n }\n }\n }\n cursor = result.response_metadata?.next_cursor;\n } while (cursor);\n }\n}\n"]}