@geminixiang/mikan 0.3.0-beta.0 → 0.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +31 -0
- package/dist/adapter.d.ts +5 -0
- package/dist/adapter.d.ts.map +1 -1
- package/dist/adapter.js.map +1 -1
- package/dist/adapters/discord/context.d.ts +0 -1
- package/dist/adapters/discord/context.d.ts.map +1 -1
- package/dist/adapters/discord/context.js +62 -84
- package/dist/adapters/discord/context.js.map +1 -1
- package/dist/adapters/shared.d.ts +1 -2
- package/dist/adapters/shared.d.ts.map +1 -1
- package/dist/adapters/shared.js +3 -2
- package/dist/adapters/shared.js.map +1 -1
- package/dist/adapters/slack/bot.d.ts +9 -34
- package/dist/adapters/slack/bot.d.ts.map +1 -1
- package/dist/adapters/slack/bot.js +374 -358
- package/dist/adapters/slack/bot.js.map +1 -1
- package/dist/adapters/slack/context.d.ts +0 -1
- package/dist/adapters/slack/context.d.ts.map +1 -1
- package/dist/adapters/slack/context.js +110 -113
- package/dist/adapters/slack/context.js.map +1 -1
- package/dist/adapters/slack/session.d.ts +0 -3
- package/dist/adapters/slack/session.d.ts.map +1 -1
- package/dist/adapters/slack/session.js +2 -8
- package/dist/adapters/slack/session.js.map +1 -1
- package/dist/adapters/slack/thread-manager.d.ts +0 -1
- package/dist/adapters/slack/thread-manager.d.ts.map +1 -1
- package/dist/adapters/slack/thread-manager.js +1 -4
- package/dist/adapters/slack/thread-manager.js.map +1 -1
- package/dist/adapters/slack/tools/block-kit.d.ts +16 -0
- package/dist/adapters/slack/tools/block-kit.d.ts.map +1 -0
- package/dist/adapters/slack/tools/block-kit.js +105 -0
- package/dist/adapters/slack/tools/block-kit.js.map +1 -0
- package/dist/adapters/telegram/context.d.ts +0 -1
- package/dist/adapters/telegram/context.d.ts.map +1 -1
- package/dist/adapters/telegram/context.js +44 -54
- package/dist/adapters/telegram/context.js.map +1 -1
- package/dist/admin/portal.d.ts.map +1 -1
- package/dist/admin/portal.js +2 -3
- package/dist/admin/portal.js.map +1 -1
- package/dist/agent.d.ts +0 -1
- package/dist/agent.d.ts.map +1 -1
- package/dist/agent.js +47 -80
- package/dist/agent.js.map +1 -1
- package/dist/commands/admin.d.ts +0 -3
- package/dist/commands/admin.d.ts.map +1 -1
- package/dist/commands/admin.js +5 -30
- package/dist/commands/admin.js.map +1 -1
- package/dist/commands/session-view.d.ts.map +1 -1
- package/dist/commands/session-view.js +4 -17
- package/dist/commands/session-view.js.map +1 -1
- package/dist/commands/types.d.ts +3 -2
- package/dist/commands/types.d.ts.map +1 -1
- package/dist/commands/types.js.map +1 -1
- package/dist/commands/utils.d.ts +3 -1
- package/dist/commands/utils.d.ts.map +1 -1
- package/dist/commands/utils.js +15 -5
- package/dist/commands/utils.js.map +1 -1
- package/dist/context.d.ts +0 -1
- package/dist/context.d.ts.map +1 -1
- package/dist/context.js +1 -23
- package/dist/context.js.map +1 -1
- package/dist/html.d.ts +2 -0
- package/dist/html.d.ts.map +1 -0
- package/dist/html.js +4 -0
- package/dist/html.js.map +1 -0
- package/dist/login/index.d.ts +2 -1
- package/dist/login/index.d.ts.map +1 -1
- package/dist/login/index.js.map +1 -1
- package/dist/login/portal.d.ts +1 -1
- package/dist/login/portal.d.ts.map +1 -1
- package/dist/login/portal.js +2 -3
- package/dist/login/portal.js.map +1 -1
- package/dist/login/{session.d.ts → store.d.ts} +1 -1
- package/dist/login/store.d.ts.map +1 -0
- package/dist/login/{session.js → store.js} +1 -1
- package/dist/login/store.js.map +1 -0
- package/dist/main.d.ts.map +1 -1
- package/dist/main.js +1 -1
- package/dist/main.js.map +1 -1
- package/dist/portal-shell.d.ts +2 -2
- package/dist/portal-shell.d.ts.map +1 -1
- package/dist/portal-shell.js +11 -16
- package/dist/portal-shell.js.map +1 -1
- package/dist/sandbox/cloudflare.d.ts +0 -2
- package/dist/sandbox/cloudflare.d.ts.map +1 -1
- package/dist/sandbox/cloudflare.js +2 -2
- package/dist/sandbox/cloudflare.js.map +1 -1
- package/dist/sandbox/container.d.ts +0 -3
- package/dist/sandbox/container.d.ts.map +1 -1
- package/dist/sandbox/container.js +3 -3
- package/dist/sandbox/container.js.map +1 -1
- package/dist/sandbox/firecracker.d.ts +0 -2
- package/dist/sandbox/firecracker.d.ts.map +1 -1
- package/dist/sandbox/firecracker.js +2 -2
- package/dist/sandbox/firecracker.js.map +1 -1
- package/dist/sandbox/host.d.ts +0 -2
- package/dist/sandbox/host.d.ts.map +1 -1
- package/dist/sandbox/host.js +2 -2
- package/dist/sandbox/host.js.map +1 -1
- package/dist/sandbox/image.d.ts +0 -2
- package/dist/sandbox/image.d.ts.map +1 -1
- package/dist/sandbox/image.js +2 -2
- package/dist/sandbox/image.js.map +1 -1
- package/dist/sandbox/index.d.ts +1 -6
- package/dist/sandbox/index.d.ts.map +1 -1
- package/dist/sandbox/index.js +0 -5
- package/dist/sandbox/index.js.map +1 -1
- package/dist/sandbox/path-context.d.ts +0 -1
- package/dist/sandbox/path-context.d.ts.map +1 -1
- package/dist/sandbox/path-context.js +1 -1
- package/dist/sandbox/path-context.js.map +1 -1
- package/dist/sentry.d.ts +2 -2
- package/dist/sentry.d.ts.map +1 -1
- package/dist/sentry.js.map +1 -1
- package/dist/session-view/portal.d.ts.map +1 -1
- package/dist/session-view/portal.js +2 -8
- package/dist/session-view/portal.js.map +1 -1
- package/dist/sessions/chat-session-manager.d.ts.map +1 -1
- package/dist/sessions/chat-session-manager.js +5 -9
- package/dist/sessions/chat-session-manager.js.map +1 -1
- package/dist/tools/index.d.ts +2 -0
- package/dist/tools/index.d.ts.map +1 -1
- package/dist/tools/index.js +4 -0
- package/dist/tools/index.js.map +1 -1
- package/dist/vault-routing.d.ts +0 -1
- package/dist/vault-routing.d.ts.map +1 -1
- package/dist/vault-routing.js +1 -4
- package/dist/vault-routing.js.map +1 -1
- package/dist/vault.d.ts +2 -1
- package/dist/vault.d.ts.map +1 -1
- package/dist/vault.js.map +1 -1
- package/package.json +3 -1
- package/dist/login/session.d.ts.map +0 -1
- package/dist/login/session.js.map +0 -1
|
@@ -238,6 +238,16 @@ export class SlackBot {
|
|
|
238
238
|
return result.ts;
|
|
239
239
|
});
|
|
240
240
|
}
|
|
241
|
+
async postBlocks(channel, text, blocks) {
|
|
242
|
+
return slackRetry(async () => {
|
|
243
|
+
const result = await this.webClient.chat.postMessage({
|
|
244
|
+
channel,
|
|
245
|
+
text,
|
|
246
|
+
blocks: blocks,
|
|
247
|
+
});
|
|
248
|
+
return result.ts;
|
|
249
|
+
});
|
|
250
|
+
}
|
|
241
251
|
async uploadFile(channel, filePath, title, threadTs) {
|
|
242
252
|
return slackRetry(async () => {
|
|
243
253
|
const fileName = title || basename(filePath);
|
|
@@ -254,8 +264,11 @@ export class SlackBot {
|
|
|
254
264
|
logToFile(channel, entry) {
|
|
255
265
|
appendChannelLog(this.workingDir, channel, entry);
|
|
256
266
|
}
|
|
257
|
-
logBotResponse(channel, text, ts, threadTs) {
|
|
258
|
-
appendBotResponseLog(this.workingDir, channel, text, ts, threadTs
|
|
267
|
+
logBotResponse(channel, text, ts, threadTs, slackBlocks) {
|
|
268
|
+
appendBotResponseLog(this.workingDir, channel, text, ts, threadTs, {
|
|
269
|
+
platform: "slack",
|
|
270
|
+
...(slackBlocks ? { slackBlocks } : {}),
|
|
271
|
+
});
|
|
259
272
|
}
|
|
260
273
|
getPlatformInfo() {
|
|
261
274
|
return {
|
|
@@ -370,14 +383,6 @@ export class SlackBot {
|
|
|
370
383
|
sessionKey,
|
|
371
384
|
});
|
|
372
385
|
}
|
|
373
|
-
shouldTriggerSharedThreadReply(channelId, threadTs) {
|
|
374
|
-
if (!threadTs)
|
|
375
|
-
return false;
|
|
376
|
-
const sessionKey = resolveSlackSessionKey(channelId, threadTs);
|
|
377
|
-
if (this.handler.isRunning(sessionKey))
|
|
378
|
-
return true;
|
|
379
|
-
return this.hasKnownThreadSession(channelId, sessionKey);
|
|
380
|
-
}
|
|
381
386
|
buildHomeView() {
|
|
382
387
|
const blocks = [
|
|
383
388
|
{
|
|
@@ -586,31 +591,19 @@ export class SlackBot {
|
|
|
586
591
|
platform: this.getPlatformInfo(),
|
|
587
592
|
};
|
|
588
593
|
}
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
postMessage: async (_channel, text) => {
|
|
593
|
-
if (threadTs) {
|
|
594
|
-
return this.postInThread(conversationId, threadTs, text);
|
|
595
|
-
}
|
|
596
|
-
return this.postMessage(conversationId, text);
|
|
597
|
-
},
|
|
598
|
-
updateMessage: async (channel, ts, text) => {
|
|
599
|
-
await this.updateMessage(channel, ts, text);
|
|
600
|
-
},
|
|
601
|
-
enqueueEvent: (event) => this.enqueueEvent(event),
|
|
602
|
-
getPlatformInfo: () => this.getPlatformInfo(),
|
|
603
|
-
};
|
|
604
|
-
}
|
|
605
|
-
async routeSlashLoginCommand(payload) {
|
|
606
|
-
const commandSuffix = payload.text?.trim();
|
|
607
|
-
const commandText = commandSuffix ? `${payload.command} ${commandSuffix}` : payload.command;
|
|
594
|
+
buildSlashCommandEvent(payload, options = {}) {
|
|
595
|
+
const conversationId = payload.channel_id;
|
|
596
|
+
const isDirectMessage = conversationId.startsWith("D");
|
|
608
597
|
const createdAt = new Date();
|
|
609
598
|
const eventTs = (createdAt.getTime() / 1000).toFixed(6);
|
|
610
|
-
const sourceChannelId = payload.channel_id;
|
|
611
|
-
const isDirectMessage = sourceChannelId.startsWith("D");
|
|
612
599
|
const userName = payload.user_name ?? this.getUser(payload.user_id)?.userName;
|
|
613
|
-
|
|
600
|
+
const commandSuffix = options.includeText ? payload.text?.trim() : undefined;
|
|
601
|
+
const commandText = commandSuffix ? `${payload.command} ${commandSuffix}` : payload.command;
|
|
602
|
+
const threadTs = options.thread ? payload.thread_ts : undefined;
|
|
603
|
+
const sessionKey = options.thread
|
|
604
|
+
? resolveSlackSessionKey(conversationId, threadTs)
|
|
605
|
+
: conversationId;
|
|
606
|
+
this.logToFile(conversationId, {
|
|
614
607
|
date: createdAt.toISOString(),
|
|
615
608
|
ts: eventTs,
|
|
616
609
|
user: payload.user_id,
|
|
@@ -618,18 +611,43 @@ export class SlackBot {
|
|
|
618
611
|
text: commandText,
|
|
619
612
|
attachments: [],
|
|
620
613
|
isBot: false,
|
|
614
|
+
...(threadTs ? { threadTs } : {}),
|
|
621
615
|
});
|
|
622
616
|
const event = {
|
|
623
|
-
type: isDirectMessage ? "dm" : "
|
|
624
|
-
conversationId
|
|
617
|
+
type: options.type ?? (isDirectMessage ? "dm" : "mention"),
|
|
618
|
+
conversationId,
|
|
625
619
|
conversationKind: isDirectMessage ? "direct" : "shared",
|
|
626
620
|
ts: eventTs,
|
|
627
621
|
user: payload.user_id,
|
|
628
622
|
text: commandText,
|
|
629
623
|
attachments: [],
|
|
630
|
-
|
|
624
|
+
...(threadTs ? { thread_ts: threadTs } : {}),
|
|
625
|
+
sessionKey,
|
|
631
626
|
};
|
|
632
|
-
const adapters = this.createCommandAdapters(
|
|
627
|
+
const adapters = this.createCommandAdapters(conversationId, payload.user_id, userName, commandText, eventTs, isDirectMessage ? { threadTs } : { ephemeralChannelId: conversationId, threadTs });
|
|
628
|
+
return { event, adapters };
|
|
629
|
+
}
|
|
630
|
+
createSlashCommandBot(conversationId, threadTs) {
|
|
631
|
+
return {
|
|
632
|
+
start: async () => { },
|
|
633
|
+
postMessage: async (_channel, text) => {
|
|
634
|
+
if (threadTs) {
|
|
635
|
+
return this.postInThread(conversationId, threadTs, text);
|
|
636
|
+
}
|
|
637
|
+
return this.postMessage(conversationId, text);
|
|
638
|
+
},
|
|
639
|
+
updateMessage: async (channel, ts, text) => {
|
|
640
|
+
await this.updateMessage(channel, ts, text);
|
|
641
|
+
},
|
|
642
|
+
enqueueEvent: (event) => this.enqueueEvent(event),
|
|
643
|
+
getPlatformInfo: () => this.getPlatformInfo(),
|
|
644
|
+
};
|
|
645
|
+
}
|
|
646
|
+
async routeSlashLoginCommand(payload) {
|
|
647
|
+
const { event, adapters } = this.buildSlashCommandEvent(payload, {
|
|
648
|
+
type: payload.channel_id.startsWith("D") ? "dm" : "private_command",
|
|
649
|
+
includeText: true,
|
|
650
|
+
});
|
|
633
651
|
await this.handler.handleEvent(event, this, adapters);
|
|
634
652
|
}
|
|
635
653
|
async routeSlashNewCommand(payload) {
|
|
@@ -654,34 +672,7 @@ export class SlackBot {
|
|
|
654
672
|
await this.handler.handleNewCommand(conversationId, conversationId, commandBot);
|
|
655
673
|
}
|
|
656
674
|
async routeSlashModelCommand(payload) {
|
|
657
|
-
const
|
|
658
|
-
const isDirectMessage = conversationId.startsWith("D");
|
|
659
|
-
const createdAt = new Date();
|
|
660
|
-
const eventTs = (createdAt.getTime() / 1000).toFixed(6);
|
|
661
|
-
const userName = payload.user_name ?? this.getUser(payload.user_id)?.userName;
|
|
662
|
-
const commandSuffix = payload.text?.trim();
|
|
663
|
-
const commandText = commandSuffix ? `${payload.command} ${commandSuffix}` : payload.command;
|
|
664
|
-
this.logToFile(conversationId, {
|
|
665
|
-
date: createdAt.toISOString(),
|
|
666
|
-
ts: eventTs,
|
|
667
|
-
user: payload.user_id,
|
|
668
|
-
userName,
|
|
669
|
-
text: commandText,
|
|
670
|
-
attachments: [],
|
|
671
|
-
isBot: false,
|
|
672
|
-
});
|
|
673
|
-
const sessionKey = conversationId;
|
|
674
|
-
const event = {
|
|
675
|
-
type: isDirectMessage ? "dm" : "mention",
|
|
676
|
-
conversationId,
|
|
677
|
-
conversationKind: isDirectMessage ? "direct" : "shared",
|
|
678
|
-
ts: eventTs,
|
|
679
|
-
user: payload.user_id,
|
|
680
|
-
text: commandText,
|
|
681
|
-
attachments: [],
|
|
682
|
-
sessionKey,
|
|
683
|
-
};
|
|
684
|
-
const adapters = this.createCommandAdapters(conversationId, payload.user_id, userName, commandText, eventTs, isDirectMessage ? {} : { ephemeralChannelId: conversationId });
|
|
675
|
+
const { event, adapters } = this.buildSlashCommandEvent(payload, { includeText: true });
|
|
685
676
|
await this.handler.handleEvent(event, this, adapters);
|
|
686
677
|
}
|
|
687
678
|
async routeSlashSandboxCommand(payload) {
|
|
@@ -691,71 +682,11 @@ export class SlackBot {
|
|
|
691
682
|
await this.routeSlashModelCommand(payload);
|
|
692
683
|
}
|
|
693
684
|
async routeSlashSessionCommand(payload) {
|
|
694
|
-
const
|
|
695
|
-
const isDirectMessage = conversationId.startsWith("D");
|
|
696
|
-
const createdAt = new Date();
|
|
697
|
-
const eventTs = (createdAt.getTime() / 1000).toFixed(6);
|
|
698
|
-
const userName = payload.user_name ?? this.getUser(payload.user_id)?.userName;
|
|
699
|
-
const commandText = payload.command;
|
|
700
|
-
this.logToFile(conversationId, {
|
|
701
|
-
date: createdAt.toISOString(),
|
|
702
|
-
ts: eventTs,
|
|
703
|
-
user: payload.user_id,
|
|
704
|
-
userName,
|
|
705
|
-
text: commandText,
|
|
706
|
-
attachments: [],
|
|
707
|
-
isBot: false,
|
|
708
|
-
threadTs: payload.thread_ts,
|
|
709
|
-
});
|
|
710
|
-
const sessionKey = resolveSlackSessionKey(conversationId, payload.thread_ts);
|
|
711
|
-
const event = {
|
|
712
|
-
type: isDirectMessage ? "dm" : "mention",
|
|
713
|
-
conversationId,
|
|
714
|
-
conversationKind: isDirectMessage ? "direct" : "shared",
|
|
715
|
-
ts: eventTs,
|
|
716
|
-
user: payload.user_id,
|
|
717
|
-
text: commandText,
|
|
718
|
-
attachments: [],
|
|
719
|
-
thread_ts: payload.thread_ts,
|
|
720
|
-
sessionKey,
|
|
721
|
-
};
|
|
722
|
-
const adapters = this.createCommandAdapters(conversationId, payload.user_id, userName, commandText, eventTs, isDirectMessage
|
|
723
|
-
? { threadTs: payload.thread_ts }
|
|
724
|
-
: { ephemeralChannelId: conversationId, threadTs: payload.thread_ts });
|
|
685
|
+
const { event, adapters } = this.buildSlashCommandEvent(payload, { thread: true });
|
|
725
686
|
await this.handler.handleEvent(event, this, adapters);
|
|
726
687
|
}
|
|
727
688
|
async routeSlashAdminCommand(payload) {
|
|
728
|
-
const
|
|
729
|
-
const isDirectMessage = conversationId.startsWith("D");
|
|
730
|
-
const createdAt = new Date();
|
|
731
|
-
const eventTs = (createdAt.getTime() / 1000).toFixed(6);
|
|
732
|
-
const userName = payload.user_name ?? this.getUser(payload.user_id)?.userName;
|
|
733
|
-
const commandText = payload.command;
|
|
734
|
-
this.logToFile(conversationId, {
|
|
735
|
-
date: createdAt.toISOString(),
|
|
736
|
-
ts: eventTs,
|
|
737
|
-
user: payload.user_id,
|
|
738
|
-
userName,
|
|
739
|
-
text: commandText,
|
|
740
|
-
attachments: [],
|
|
741
|
-
isBot: false,
|
|
742
|
-
threadTs: payload.thread_ts,
|
|
743
|
-
});
|
|
744
|
-
const sessionKey = resolveSlackSessionKey(conversationId, payload.thread_ts);
|
|
745
|
-
const event = {
|
|
746
|
-
type: isDirectMessage ? "dm" : "mention",
|
|
747
|
-
conversationId,
|
|
748
|
-
conversationKind: isDirectMessage ? "direct" : "shared",
|
|
749
|
-
ts: eventTs,
|
|
750
|
-
user: payload.user_id,
|
|
751
|
-
text: commandText,
|
|
752
|
-
attachments: [],
|
|
753
|
-
thread_ts: payload.thread_ts,
|
|
754
|
-
sessionKey,
|
|
755
|
-
};
|
|
756
|
-
const adapters = this.createCommandAdapters(conversationId, payload.user_id, userName, commandText, eventTs, isDirectMessage
|
|
757
|
-
? { threadTs: payload.thread_ts }
|
|
758
|
-
: { ephemeralChannelId: conversationId, threadTs: payload.thread_ts });
|
|
689
|
+
const { event, adapters } = this.buildSlashCommandEvent(payload, { thread: true });
|
|
759
690
|
await this.handler.handleEvent(event, this, adapters);
|
|
760
691
|
}
|
|
761
692
|
setupEventHandlers() {
|
|
@@ -768,92 +699,80 @@ export class SlackBot {
|
|
|
768
699
|
this.socketClient.on("unable_to_socket_mode_start", (err) => {
|
|
769
700
|
log.logWarning("Slack socket unable_to_start", err ? String(err) : "");
|
|
770
701
|
});
|
|
771
|
-
|
|
772
|
-
this.socketClient.on("
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
702
|
+
this.socketClient.on("app_mention", (payload) => this.handleAppMention(payload));
|
|
703
|
+
this.socketClient.on("message", (payload) => this.handleMessageEvent(payload));
|
|
704
|
+
this.socketClient.on("slash_commands", (payload) => void this.handleSlashCommand(payload));
|
|
705
|
+
this.socketClient.on("app_home_opened", (payload) => this.handleAppHomeOpened(payload));
|
|
706
|
+
this.socketClient.on("block_actions", (payload) => void this.handleBlockAction(payload));
|
|
707
|
+
this.socketClient.on("interactive", (payload) => void this.handleBlockAction(payload));
|
|
708
|
+
}
|
|
709
|
+
handleAppMention({ event, ack }) {
|
|
710
|
+
const e = event;
|
|
711
|
+
// Skip DMs (handled by message event)
|
|
712
|
+
if (e.channel.startsWith("D")) {
|
|
713
|
+
ack();
|
|
714
|
+
return;
|
|
715
|
+
}
|
|
716
|
+
// Top-level mentions use a persistent channel session.
|
|
717
|
+
// Thread replies get their own isolated session (channelId:thread_ts).
|
|
718
|
+
const sessionKey = resolveSlackSessionKey(e.channel, e.thread_ts);
|
|
719
|
+
const mentionText = this.stripOwnMention(e.text);
|
|
720
|
+
const slackEvent = {
|
|
721
|
+
type: "mention",
|
|
722
|
+
conversationId: e.channel,
|
|
723
|
+
conversationKind: "shared",
|
|
724
|
+
channel: e.channel,
|
|
725
|
+
ts: e.ts,
|
|
726
|
+
thread_ts: e.thread_ts,
|
|
727
|
+
user: e.user,
|
|
728
|
+
text: mentionText || "Please respond to the recent conversation context.",
|
|
729
|
+
files: e.files,
|
|
730
|
+
sessionKey,
|
|
731
|
+
};
|
|
732
|
+
const attachmentsPromise = this.logUserMessage(slackEvent);
|
|
733
|
+
// Only trigger processing for messages AFTER startup (not replayed old messages)
|
|
734
|
+
if (this.startupTs && e.ts < this.startupTs) {
|
|
735
|
+
log.logInfo(`[${e.channel}] Logged old message (pre-startup), not triggering: ${slackEvent.text.substring(0, 30)}`);
|
|
736
|
+
void attachmentsPromise.catch((err) => {
|
|
737
|
+
log.logWarning("Failed to log Slack message", String(err));
|
|
738
|
+
});
|
|
739
|
+
ack();
|
|
740
|
+
return;
|
|
741
|
+
}
|
|
742
|
+
// Check for stop command - execute immediately, don't queue!
|
|
743
|
+
if (this.isStopText(slackEvent.text)) {
|
|
744
|
+
const stopTarget = this.resolveStopTarget(e.channel, e.thread_ts);
|
|
745
|
+
if (stopTarget) {
|
|
746
|
+
this.handler.handleStop(stopTarget, e.channel, this);
|
|
803
747
|
}
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
const stopTarget = this.resolveStopTarget(e.channel, e.thread_ts);
|
|
807
|
-
if (stopTarget) {
|
|
808
|
-
this.handler.handleStop(stopTarget, e.channel, this);
|
|
809
|
-
}
|
|
810
|
-
else {
|
|
811
|
-
this.postMessage(e.channel, formatNothingRunning("slack"));
|
|
812
|
-
}
|
|
813
|
-
void attachmentsPromise.catch((err) => {
|
|
814
|
-
log.logWarning("Failed to log Slack message", String(err));
|
|
815
|
-
});
|
|
816
|
-
ack();
|
|
817
|
-
return;
|
|
748
|
+
else {
|
|
749
|
+
this.postMessage(e.channel, formatNothingRunning("slack"));
|
|
818
750
|
}
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
const adapters = createSlackAdapters(slackEvent, this);
|
|
822
|
-
return this.handler.handleEvent(slackEvent, this, adapters);
|
|
751
|
+
void attachmentsPromise.catch((err) => {
|
|
752
|
+
log.logWarning("Failed to log Slack message", String(err));
|
|
823
753
|
});
|
|
824
754
|
ack();
|
|
755
|
+
return;
|
|
756
|
+
}
|
|
757
|
+
this.getQueue(this.resolveQueueKey(e.channel, sessionKey)).enqueue(async () => {
|
|
758
|
+
slackEvent.attachments = await attachmentsPromise;
|
|
759
|
+
const adapters = createSlackAdapters(slackEvent, this);
|
|
760
|
+
return this.handler.handleEvent(slackEvent, this, adapters);
|
|
825
761
|
});
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
return;
|
|
841
|
-
}
|
|
842
|
-
if (!hasSlackContent) {
|
|
843
|
-
ack();
|
|
844
|
-
return;
|
|
845
|
-
}
|
|
846
|
-
void this.logExternalBotMessage(e).catch((err) => {
|
|
847
|
-
log.logWarning("Failed to log Slack bot message", String(err));
|
|
848
|
-
});
|
|
849
|
-
ack();
|
|
850
|
-
return;
|
|
851
|
-
}
|
|
852
|
-
if (!e.user) {
|
|
853
|
-
ack();
|
|
854
|
-
return;
|
|
855
|
-
}
|
|
856
|
-
if (e.subtype !== undefined && e.subtype !== "file_share") {
|
|
762
|
+
ack();
|
|
763
|
+
}
|
|
764
|
+
handleMessageEvent({ event, ack }) {
|
|
765
|
+
const e = event;
|
|
766
|
+
const hasFiles = !!e.files && e.files.length > 0;
|
|
767
|
+
const hasSlackContent = !!e.text || hasFiles || !!e.blocks?.length || !!e.attachments?.length;
|
|
768
|
+
const isOwnBotMessage = (!!e.user && e.user === this.botUserId) || (!!this.botId && e.bot_id === this.botId);
|
|
769
|
+
if (isOwnBotMessage) {
|
|
770
|
+
ack();
|
|
771
|
+
return;
|
|
772
|
+
}
|
|
773
|
+
const isExternalBotMessage = !!e.bot_id || e.subtype === "bot_message";
|
|
774
|
+
if (isExternalBotMessage) {
|
|
775
|
+
if (e.subtype !== undefined && e.subtype !== "bot_message" && e.subtype !== "file_share") {
|
|
857
776
|
ack();
|
|
858
777
|
return;
|
|
859
778
|
}
|
|
@@ -861,203 +780,300 @@ export class SlackBot {
|
|
|
861
780
|
ack();
|
|
862
781
|
return;
|
|
863
782
|
}
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
783
|
+
void this.logExternalBotMessage(e).catch((err) => {
|
|
784
|
+
log.logWarning("Failed to log Slack bot message", String(err));
|
|
785
|
+
});
|
|
786
|
+
ack();
|
|
787
|
+
return;
|
|
788
|
+
}
|
|
789
|
+
if (!e.user) {
|
|
790
|
+
ack();
|
|
791
|
+
return;
|
|
792
|
+
}
|
|
793
|
+
if (e.subtype !== undefined && e.subtype !== "file_share") {
|
|
794
|
+
ack();
|
|
795
|
+
return;
|
|
796
|
+
}
|
|
797
|
+
if (!hasSlackContent) {
|
|
798
|
+
ack();
|
|
799
|
+
return;
|
|
800
|
+
}
|
|
801
|
+
const isDM = e.channel_type === "im";
|
|
802
|
+
const conversationKind = isDM ? "direct" : "shared";
|
|
803
|
+
const isBotMention = e.text?.includes(`<@${this.botUserId}>`);
|
|
804
|
+
// Skip channel @mentions - already handled by app_mention event
|
|
805
|
+
if (!isDM && isBotMention) {
|
|
806
|
+
ack();
|
|
807
|
+
return;
|
|
808
|
+
}
|
|
809
|
+
const isThreadReply = !!e.thread_ts;
|
|
810
|
+
const sessionKey = isDM ? resolveSlackSessionKey(e.channel, e.thread_ts) : undefined;
|
|
811
|
+
const slackEvent = {
|
|
812
|
+
type: isDM ? "dm" : "mention",
|
|
813
|
+
conversationId: e.channel,
|
|
814
|
+
conversationKind,
|
|
815
|
+
channel: e.channel,
|
|
816
|
+
ts: e.ts,
|
|
817
|
+
thread_ts: e.thread_ts,
|
|
818
|
+
user: e.user,
|
|
819
|
+
text: this.stripOwnMention(e.text),
|
|
820
|
+
files: e.files,
|
|
821
|
+
sessionKey,
|
|
822
|
+
};
|
|
823
|
+
const attachmentsPromise = this.logUserMessage(slackEvent);
|
|
824
|
+
// Only trigger processing for messages AFTER startup (not replayed old messages)
|
|
825
|
+
if (this.startupTs && e.ts < this.startupTs) {
|
|
826
|
+
log.logInfo(`[${e.channel}] Skipping old message (pre-startup): ${slackEvent.text.substring(0, 30)}`);
|
|
827
|
+
void attachmentsPromise.catch((err) => {
|
|
828
|
+
log.logWarning("Failed to log Slack message", String(err));
|
|
829
|
+
});
|
|
830
|
+
ack();
|
|
831
|
+
return;
|
|
832
|
+
}
|
|
833
|
+
// Stop command for DM only (app_mention handles shared-channel "@mikan stop").
|
|
834
|
+
if (isDM && this.isStopText(slackEvent.text)) {
|
|
835
|
+
const stopTarget = this.resolveStopTarget(e.channel, e.thread_ts);
|
|
836
|
+
if (stopTarget) {
|
|
837
|
+
this.handler.handleStop(stopTarget, e.channel, this);
|
|
910
838
|
}
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
// Auto-reply top-level channel messages start with no sessionKey because
|
|
914
|
-
// they are only candidates until the policy allows them. Once triggered,
|
|
915
|
-
// persist the resolved key on the event; otherwise the runtime fallback
|
|
916
|
-
// treats the message ts as a thread session (`channel:ts`) instead of the
|
|
917
|
-
// persistent top-level channel session.
|
|
918
|
-
slackEvent.sessionKey = activeSessionKey;
|
|
919
|
-
this.getQueue(this.resolveQueueKey(e.channel, activeSessionKey)).enqueue(async () => {
|
|
920
|
-
slackEvent.attachments = await attachmentsPromise;
|
|
921
|
-
const adapters = createSlackAdapters(slackEvent, this);
|
|
922
|
-
return this.handler.handleEvent(slackEvent, this, adapters);
|
|
923
|
-
});
|
|
924
|
-
};
|
|
925
|
-
const logOnly = () => {
|
|
926
|
-
void attachmentsPromise.catch((err) => {
|
|
927
|
-
log.logWarning("Failed to log Slack message", String(err));
|
|
928
|
-
});
|
|
929
|
-
};
|
|
930
|
-
if (isDM || isSharedThreadReply) {
|
|
931
|
-
enqueueTriggered();
|
|
932
|
-
ack();
|
|
933
|
-
return;
|
|
839
|
+
else {
|
|
840
|
+
this.postMessage(e.channel, formatNothingRunning("slack"));
|
|
934
841
|
}
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
842
|
+
void attachmentsPromise.catch((err) => {
|
|
843
|
+
log.logWarning("Failed to log Slack message", String(err));
|
|
844
|
+
});
|
|
845
|
+
ack();
|
|
846
|
+
return;
|
|
847
|
+
}
|
|
848
|
+
const enqueueTriggered = () => {
|
|
849
|
+
const activeSessionKey = slackEvent.sessionKey ?? resolveSlackSessionKey(e.channel, e.thread_ts);
|
|
850
|
+
// Auto-reply top-level channel messages start with no sessionKey because
|
|
851
|
+
// they are only candidates until the policy allows them. Once triggered,
|
|
852
|
+
// persist the resolved key on the event; otherwise the runtime fallback
|
|
853
|
+
// treats the message ts as a thread session (`channel:ts`) instead of the
|
|
854
|
+
// persistent top-level channel session.
|
|
855
|
+
slackEvent.sessionKey = activeSessionKey;
|
|
856
|
+
this.getQueue(this.resolveQueueKey(e.channel, activeSessionKey)).enqueue(async () => {
|
|
857
|
+
slackEvent.attachments = await attachmentsPromise;
|
|
858
|
+
const adapters = createSlackAdapters(slackEvent, this);
|
|
859
|
+
return this.handler.handleEvent(slackEvent, this, adapters);
|
|
947
860
|
});
|
|
861
|
+
};
|
|
862
|
+
const logOnly = () => {
|
|
863
|
+
void attachmentsPromise.catch((err) => {
|
|
864
|
+
log.logWarning("Failed to log Slack message", String(err));
|
|
865
|
+
});
|
|
866
|
+
};
|
|
867
|
+
if (isDM) {
|
|
868
|
+
enqueueTriggered();
|
|
869
|
+
ack();
|
|
870
|
+
return;
|
|
871
|
+
}
|
|
872
|
+
if (isThreadReply) {
|
|
873
|
+
logOnly();
|
|
948
874
|
ack();
|
|
875
|
+
return;
|
|
876
|
+
}
|
|
877
|
+
// Shared-channel non-mention top-level messages: gate via auto-reply policy.
|
|
878
|
+
// evaluateAutoReplyPolicy never throws — judge errors/timeouts surface as
|
|
879
|
+
// trigger:false with a distinct reason, and the user message has already
|
|
880
|
+
// been queued for logging via logUserMessage above.
|
|
881
|
+
evaluateAutoReplyPolicy({
|
|
882
|
+
event: slackEvent,
|
|
883
|
+
workingDir: this.workingDir,
|
|
884
|
+
}).then((triggerResult) => {
|
|
885
|
+
if (triggerResult.trigger)
|
|
886
|
+
enqueueTriggered();
|
|
887
|
+
else
|
|
888
|
+
logOnly();
|
|
949
889
|
});
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
890
|
+
ack();
|
|
891
|
+
}
|
|
892
|
+
async handleSlashCommand({ body, ack, }) {
|
|
893
|
+
const payload = body;
|
|
894
|
+
await ack();
|
|
895
|
+
if (!payload.command || !payload.channel_id || !payload.user_id) {
|
|
896
|
+
return;
|
|
897
|
+
}
|
|
898
|
+
const handlerPromise = payload.command === "/pi-login"
|
|
899
|
+
? this.routeSlashLoginCommand({
|
|
900
|
+
command: payload.command,
|
|
901
|
+
text: payload.text,
|
|
902
|
+
channel_id: payload.channel_id,
|
|
903
|
+
user_id: payload.user_id,
|
|
904
|
+
user_name: payload.user_name,
|
|
905
|
+
})
|
|
906
|
+
: payload.command === "/pi-new"
|
|
907
|
+
? this.routeSlashNewCommand({
|
|
958
908
|
command: payload.command,
|
|
959
|
-
text: payload.text,
|
|
960
909
|
channel_id: payload.channel_id,
|
|
961
910
|
user_id: payload.user_id,
|
|
962
911
|
user_name: payload.user_name,
|
|
963
912
|
})
|
|
964
|
-
: payload.command === "/pi-
|
|
965
|
-
? this.
|
|
913
|
+
: payload.command === "/pi-session"
|
|
914
|
+
? this.routeSlashSessionCommand({
|
|
966
915
|
command: payload.command,
|
|
967
916
|
channel_id: payload.channel_id,
|
|
968
917
|
user_id: payload.user_id,
|
|
969
918
|
user_name: payload.user_name,
|
|
919
|
+
thread_ts: payload.thread_ts,
|
|
970
920
|
})
|
|
971
|
-
: payload.command === "/pi-
|
|
972
|
-
? this.
|
|
921
|
+
: payload.command === "/pi-model"
|
|
922
|
+
? this.routeSlashModelCommand({
|
|
973
923
|
command: payload.command,
|
|
924
|
+
text: payload.text,
|
|
974
925
|
channel_id: payload.channel_id,
|
|
975
926
|
user_id: payload.user_id,
|
|
976
927
|
user_name: payload.user_name,
|
|
977
|
-
thread_ts: payload.thread_ts,
|
|
978
928
|
})
|
|
979
|
-
: payload.command === "/pi-
|
|
980
|
-
? this.
|
|
929
|
+
: payload.command === "/pi-sandbox"
|
|
930
|
+
? this.routeSlashSandboxCommand({
|
|
981
931
|
command: payload.command,
|
|
982
932
|
text: payload.text,
|
|
983
933
|
channel_id: payload.channel_id,
|
|
984
934
|
user_id: payload.user_id,
|
|
985
935
|
user_name: payload.user_name,
|
|
986
936
|
})
|
|
987
|
-
: payload.command === "/pi-
|
|
988
|
-
? this.
|
|
937
|
+
: payload.command === "/pi-auto-reply"
|
|
938
|
+
? this.routeSlashAutoReplyCommand({
|
|
989
939
|
command: payload.command,
|
|
990
940
|
text: payload.text,
|
|
991
941
|
channel_id: payload.channel_id,
|
|
992
942
|
user_id: payload.user_id,
|
|
993
943
|
user_name: payload.user_name,
|
|
994
944
|
})
|
|
995
|
-
: payload.command === "/pi-
|
|
996
|
-
? this.
|
|
945
|
+
: payload.command === "/pi-admin"
|
|
946
|
+
? this.routeSlashAdminCommand({
|
|
997
947
|
command: payload.command,
|
|
998
|
-
text: payload.text,
|
|
999
948
|
channel_id: payload.channel_id,
|
|
1000
949
|
user_id: payload.user_id,
|
|
1001
950
|
user_name: payload.user_name,
|
|
951
|
+
thread_ts: payload.thread_ts,
|
|
1002
952
|
})
|
|
1003
|
-
:
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
thread_ts: payload.thread_ts,
|
|
1010
|
-
})
|
|
1011
|
-
: null;
|
|
1012
|
-
if (!handlerPromise) {
|
|
1013
|
-
return;
|
|
1014
|
-
}
|
|
1015
|
-
handlerPromise.catch((err) => {
|
|
1016
|
-
log.logWarning("Slack slash command error", err instanceof Error ? err.message : String(err));
|
|
1017
|
-
});
|
|
953
|
+
: null;
|
|
954
|
+
if (!handlerPromise) {
|
|
955
|
+
return;
|
|
956
|
+
}
|
|
957
|
+
handlerPromise.catch((err) => {
|
|
958
|
+
log.logWarning("Slack slash command error", err instanceof Error ? err.message : String(err));
|
|
1018
959
|
});
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
960
|
+
}
|
|
961
|
+
handleAppHomeOpened({ event, ack }) {
|
|
962
|
+
const e = event;
|
|
963
|
+
ack();
|
|
964
|
+
if (e.tab !== "home")
|
|
965
|
+
return;
|
|
966
|
+
this.webClient.views
|
|
967
|
+
.publish({
|
|
968
|
+
user_id: e.user,
|
|
969
|
+
view: this.buildHomeView(),
|
|
970
|
+
})
|
|
971
|
+
.catch((err) => {
|
|
972
|
+
log.logWarning(`Failed to publish App Home view`, String(err));
|
|
973
|
+
});
|
|
974
|
+
}
|
|
975
|
+
async handleBlockAction({ body, ack }) {
|
|
976
|
+
const action = body.actions?.[0];
|
|
977
|
+
if (!action) {
|
|
1022
978
|
ack();
|
|
1023
|
-
|
|
1024
|
-
|
|
979
|
+
return;
|
|
980
|
+
}
|
|
981
|
+
if (!action.action_id?.startsWith("force_stop_")) {
|
|
982
|
+
ack();
|
|
983
|
+
this.handleSlackInteraction(body, action);
|
|
984
|
+
return;
|
|
985
|
+
}
|
|
986
|
+
ack();
|
|
987
|
+
const sessionKey = action.action_id.replace("force_stop_", "").replace(/_/g, ":");
|
|
988
|
+
const userId = body.user?.id;
|
|
989
|
+
const channelId = body.container?.channel_id || sessionKey.split(":")[0];
|
|
990
|
+
log.logInfo(`[Force Stop] User ${userId} requested force stop for ${sessionKey}`);
|
|
991
|
+
// Use handler's forceStop method
|
|
992
|
+
this.handler.forceStop(sessionKey);
|
|
993
|
+
// Notify in channel
|
|
994
|
+
await this.postMessage(channelId, formatForceStopped("slack", userId ?? "unknown"));
|
|
995
|
+
// Refresh home tab
|
|
996
|
+
if (userId) {
|
|
1025
997
|
this.webClient.views
|
|
1026
998
|
.publish({
|
|
1027
|
-
user_id:
|
|
999
|
+
user_id: userId,
|
|
1028
1000
|
view: this.buildHomeView(),
|
|
1029
1001
|
})
|
|
1030
1002
|
.catch((err) => {
|
|
1031
|
-
log.logWarning(`Failed to
|
|
1003
|
+
log.logWarning(`Failed to refresh App Home view`, String(err));
|
|
1032
1004
|
});
|
|
1005
|
+
}
|
|
1006
|
+
}
|
|
1007
|
+
handleSlackInteraction(body, action) {
|
|
1008
|
+
const container = body.container ?? {};
|
|
1009
|
+
const channelId = container.channel_id;
|
|
1010
|
+
const userId = body.user?.id;
|
|
1011
|
+
if (!channelId || !userId)
|
|
1012
|
+
return;
|
|
1013
|
+
const selectedOption = action.selected_option;
|
|
1014
|
+
const selectedOptions = Array.isArray(action.selected_options)
|
|
1015
|
+
? action.selected_options
|
|
1016
|
+
: undefined;
|
|
1017
|
+
const selectedText = selectedOption?.text?.text ?? selectedOption?.value;
|
|
1018
|
+
const selectedTexts = selectedOptions?.map((option) => option.text?.text ?? option.value);
|
|
1019
|
+
const valueText = selectedTexts?.length
|
|
1020
|
+
? selectedTexts.join(", ")
|
|
1021
|
+
: (selectedText ?? action.value ?? action.action_id);
|
|
1022
|
+
const text = `[Slack action] ${action.action_id}: ${valueText}`;
|
|
1023
|
+
const ts = `action:${Date.now()}`;
|
|
1024
|
+
const threadTs = container.thread_ts;
|
|
1025
|
+
const sessionKey = resolveSlackSessionKey(channelId, threadTs);
|
|
1026
|
+
this.logToFile(channelId, {
|
|
1027
|
+
date: new Date().toISOString(),
|
|
1028
|
+
ts,
|
|
1029
|
+
...(threadTs ? { threadTs } : {}),
|
|
1030
|
+
user: userId,
|
|
1031
|
+
userName: body.user?.username ?? body.user?.name,
|
|
1032
|
+
text,
|
|
1033
|
+
attachments: [],
|
|
1034
|
+
isBot: false,
|
|
1035
|
+
platform: "slack",
|
|
1036
|
+
slackInteraction: {
|
|
1037
|
+
type: "block_actions",
|
|
1038
|
+
actionId: action.action_id,
|
|
1039
|
+
blockId: action.block_id,
|
|
1040
|
+
actionType: action.type,
|
|
1041
|
+
value: action.value,
|
|
1042
|
+
selectedOption: selectedOption
|
|
1043
|
+
? { text: selectedOption.text?.text, value: selectedOption.value }
|
|
1044
|
+
: undefined,
|
|
1045
|
+
selectedOptions: selectedOptions?.map((option) => ({
|
|
1046
|
+
text: option.text?.text,
|
|
1047
|
+
value: option.value,
|
|
1048
|
+
})),
|
|
1049
|
+
messageTs: container.message_ts,
|
|
1050
|
+
},
|
|
1033
1051
|
});
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
});
|
|
1060
|
-
}
|
|
1052
|
+
const event = {
|
|
1053
|
+
type: "slack_action",
|
|
1054
|
+
conversationId: channelId,
|
|
1055
|
+
conversationKind: channelId.startsWith("D") ? "direct" : "shared",
|
|
1056
|
+
ts,
|
|
1057
|
+
user: userId,
|
|
1058
|
+
text,
|
|
1059
|
+
attachments: [],
|
|
1060
|
+
...(threadTs ? { thread_ts: threadTs } : {}),
|
|
1061
|
+
sessionKey,
|
|
1062
|
+
};
|
|
1063
|
+
this.getQueue(this.resolveQueueKey(channelId, sessionKey)).enqueue(async () => {
|
|
1064
|
+
const slackEvent = {
|
|
1065
|
+
type: event.conversationKind === "direct" ? "dm" : "mention",
|
|
1066
|
+
conversationId: channelId,
|
|
1067
|
+
conversationKind: event.conversationKind,
|
|
1068
|
+
channel: channelId,
|
|
1069
|
+
ts,
|
|
1070
|
+
thread_ts: threadTs,
|
|
1071
|
+
user: userId,
|
|
1072
|
+
text,
|
|
1073
|
+
attachments: [],
|
|
1074
|
+
sessionKey,
|
|
1075
|
+
};
|
|
1076
|
+
return this.handler.handleEvent(event, this, createSlackAdapters(slackEvent, this));
|
|
1061
1077
|
});
|
|
1062
1078
|
}
|
|
1063
1079
|
/**
|