@geminixiang/mama 0.2.0-beta.0 → 0.2.0-beta.2
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/README.md +94 -27
- package/dist/adapter.d.ts +9 -5
- package/dist/adapter.d.ts.map +1 -1
- package/dist/adapter.js.map +1 -1
- package/dist/adapters/discord/bot.d.ts.map +1 -1
- package/dist/adapters/discord/bot.js +9 -6
- package/dist/adapters/discord/bot.js.map +1 -1
- package/dist/adapters/discord/context.d.ts.map +1 -1
- package/dist/adapters/discord/context.js +16 -13
- package/dist/adapters/discord/context.js.map +1 -1
- package/dist/adapters/slack/bot.d.ts +10 -2
- package/dist/adapters/slack/bot.d.ts.map +1 -1
- package/dist/adapters/slack/bot.js +196 -32
- package/dist/adapters/slack/bot.js.map +1 -1
- package/dist/adapters/slack/context.d.ts.map +1 -1
- package/dist/adapters/slack/context.js +24 -17
- package/dist/adapters/slack/context.js.map +1 -1
- package/dist/adapters/telegram/bot.d.ts +2 -0
- package/dist/adapters/telegram/bot.d.ts.map +1 -1
- package/dist/adapters/telegram/bot.js +109 -29
- package/dist/adapters/telegram/bot.js.map +1 -1
- package/dist/adapters/telegram/context.d.ts.map +1 -1
- package/dist/adapters/telegram/context.js +8 -43
- package/dist/adapters/telegram/context.js.map +1 -1
- package/dist/adapters/telegram/html.d.ts +3 -0
- package/dist/adapters/telegram/html.d.ts.map +1 -0
- package/dist/adapters/telegram/html.js +98 -0
- package/dist/adapters/telegram/html.js.map +1 -0
- package/dist/agent.d.ts +4 -9
- package/dist/agent.d.ts.map +1 -1
- package/dist/agent.js +141 -92
- package/dist/agent.js.map +1 -1
- package/dist/bindings.d.ts +44 -0
- package/dist/bindings.d.ts.map +1 -0
- package/dist/bindings.js +74 -0
- package/dist/bindings.js.map +1 -0
- package/dist/config.d.ts +7 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +53 -12
- package/dist/config.js.map +1 -1
- package/dist/context.d.ts +7 -7
- package/dist/context.d.ts.map +1 -1
- package/dist/context.js +9 -9
- package/dist/context.js.map +1 -1
- package/dist/events.d.ts +14 -5
- package/dist/events.d.ts.map +1 -1
- package/dist/events.js +45 -10
- package/dist/events.js.map +1 -1
- package/dist/execution-resolver.d.ts +20 -0
- package/dist/execution-resolver.d.ts.map +1 -0
- package/dist/execution-resolver.js +49 -0
- package/dist/execution-resolver.js.map +1 -0
- package/dist/instrument.d.ts.map +1 -1
- package/dist/instrument.js +2 -1
- package/dist/instrument.js.map +1 -1
- package/dist/link-server.d.ts +17 -0
- package/dist/link-server.d.ts.map +1 -0
- package/dist/link-server.js +899 -0
- package/dist/link-server.js.map +1 -0
- package/dist/link-token.d.ts +32 -0
- package/dist/link-token.d.ts.map +1 -0
- package/dist/link-token.js +68 -0
- package/dist/link-token.js.map +1 -0
- package/dist/log.d.ts +2 -2
- package/dist/log.d.ts.map +1 -1
- package/dist/log.js +7 -7
- package/dist/log.js.map +1 -1
- package/dist/login.d.ts +29 -0
- package/dist/login.d.ts.map +1 -0
- package/dist/login.js +164 -0
- package/dist/login.js.map +1 -0
- package/dist/main.d.ts.map +1 -1
- package/dist/main.js +226 -55
- package/dist/main.js.map +1 -1
- package/dist/provisioner.d.ts +52 -0
- package/dist/provisioner.d.ts.map +1 -0
- package/dist/provisioner.js +291 -0
- package/dist/provisioner.js.map +1 -0
- package/dist/sandbox/container.d.ts +15 -0
- package/dist/sandbox/container.d.ts.map +1 -0
- package/dist/sandbox/container.js +122 -0
- package/dist/sandbox/container.js.map +1 -0
- package/dist/sandbox/errors.d.ts +6 -0
- package/dist/sandbox/errors.d.ts.map +1 -0
- package/dist/sandbox/errors.js +11 -0
- package/dist/sandbox/errors.js.map +1 -0
- package/dist/sandbox/firecracker.d.ts +16 -0
- package/dist/sandbox/firecracker.d.ts.map +1 -0
- package/dist/sandbox/firecracker.js +206 -0
- package/dist/sandbox/firecracker.js.map +1 -0
- package/dist/sandbox/host.d.ts +10 -0
- package/dist/sandbox/host.d.ts.map +1 -0
- package/dist/sandbox/host.js +85 -0
- package/dist/sandbox/host.js.map +1 -0
- package/dist/sandbox/image.d.ts +5 -0
- package/dist/sandbox/image.d.ts.map +1 -0
- package/dist/sandbox/image.js +30 -0
- package/dist/sandbox/image.js.map +1 -0
- package/dist/sandbox/index.d.ts +20 -0
- package/dist/sandbox/index.d.ts.map +1 -0
- package/dist/sandbox/index.js +51 -0
- package/dist/sandbox/index.js.map +1 -0
- package/dist/sandbox/types.d.ts +51 -0
- package/dist/sandbox/types.d.ts.map +1 -0
- package/dist/sandbox/types.js +2 -0
- package/dist/sandbox/types.js.map +1 -0
- package/dist/sandbox/utils.d.ts +4 -0
- package/dist/sandbox/utils.d.ts.map +1 -0
- package/dist/sandbox/utils.js +51 -0
- package/dist/sandbox/utils.js.map +1 -0
- package/dist/sandbox.d.ts +1 -39
- package/dist/sandbox.d.ts.map +1 -1
- package/dist/sandbox.js +1 -286
- package/dist/sandbox.js.map +1 -1
- package/dist/sentry.d.ts +1 -1
- package/dist/sentry.d.ts.map +1 -1
- package/dist/sentry.js +4 -2
- package/dist/sentry.js.map +1 -1
- package/dist/session-store.d.ts +2 -6
- package/dist/session-store.d.ts.map +1 -1
- package/dist/session-store.js +3 -10
- package/dist/session-store.js.map +1 -1
- package/dist/store.d.ts +1 -1
- package/dist/store.d.ts.map +1 -1
- package/dist/store.js +8 -8
- package/dist/store.js.map +1 -1
- package/dist/tools/event.d.ts +22 -0
- package/dist/tools/event.d.ts.map +1 -0
- package/dist/tools/event.js +104 -0
- package/dist/tools/event.js.map +1 -0
- package/dist/tools/index.d.ts +7 -1
- package/dist/tools/index.d.ts.map +1 -1
- package/dist/tools/index.js +5 -1
- package/dist/tools/index.js.map +1 -1
- package/dist/ui-copy.d.ts +12 -0
- package/dist/ui-copy.d.ts.map +1 -0
- package/dist/ui-copy.js +36 -0
- package/dist/ui-copy.js.map +1 -0
- package/dist/vault-routing.d.ts +9 -0
- package/dist/vault-routing.d.ts.map +1 -0
- package/dist/vault-routing.js +52 -0
- package/dist/vault-routing.js.map +1 -0
- package/dist/vault.d.ts +106 -0
- package/dist/vault.d.ts.map +1 -0
- package/dist/vault.js +389 -0
- package/dist/vault.js.map +1 -0
- package/package.json +12 -11
|
@@ -4,6 +4,7 @@ import { appendFileSync, existsSync, mkdirSync, readFileSync } from "fs";
|
|
|
4
4
|
import { readFile } from "fs/promises";
|
|
5
5
|
import { basename, join } from "path";
|
|
6
6
|
import * as log from "../../log.js";
|
|
7
|
+
import { PRODUCT_NAME, formatForceStopped, formatNothingRunning } from "../../ui-copy.js";
|
|
7
8
|
import { createSlackAdapters } from "./context.js";
|
|
8
9
|
// ============================================================================
|
|
9
10
|
// Exponential backoff utility for Slack API calls
|
|
@@ -125,6 +126,21 @@ export class SlackBot {
|
|
|
125
126
|
return result.ts;
|
|
126
127
|
});
|
|
127
128
|
}
|
|
129
|
+
async postEphemeral(channel, user, text) {
|
|
130
|
+
return withRetry(async () => {
|
|
131
|
+
await this.webClient.chat.postEphemeral({ channel, user, text });
|
|
132
|
+
});
|
|
133
|
+
}
|
|
134
|
+
async openDirectMessage(userId) {
|
|
135
|
+
return withRetry(async () => {
|
|
136
|
+
const result = await this.webClient.conversations.open({ users: userId });
|
|
137
|
+
const channelId = result.channel?.id;
|
|
138
|
+
if (!channelId) {
|
|
139
|
+
throw new Error(`Failed to open DM for user ${userId}`);
|
|
140
|
+
}
|
|
141
|
+
return channelId;
|
|
142
|
+
});
|
|
143
|
+
}
|
|
128
144
|
async updateMessage(channel, ts, text) {
|
|
129
145
|
return withRetry(async () => {
|
|
130
146
|
await this.webClient.chat.update({ channel, ts, text });
|
|
@@ -236,14 +252,30 @@ export class SlackBot {
|
|
|
236
252
|
* Returns true if enqueued, false if queue is full (max 5).
|
|
237
253
|
*/
|
|
238
254
|
enqueueEvent(event) {
|
|
239
|
-
const
|
|
255
|
+
const conversationId = event.conversationId;
|
|
256
|
+
const queue = this.getQueue(conversationId);
|
|
240
257
|
if (queue.size() >= 5) {
|
|
241
|
-
log.logWarning(`Event queue full for ${
|
|
258
|
+
log.logWarning(`Event queue full for ${conversationId}, discarding: ${event.text.substring(0, 50)}`);
|
|
242
259
|
return false;
|
|
243
260
|
}
|
|
244
|
-
log.logInfo(`Enqueueing event for ${
|
|
261
|
+
log.logInfo(`Enqueueing event for ${conversationId}: ${event.text.substring(0, 50)}`);
|
|
245
262
|
queue.enqueue(() => {
|
|
246
|
-
const
|
|
263
|
+
const slackEvent = {
|
|
264
|
+
type: event.type,
|
|
265
|
+
conversationId,
|
|
266
|
+
conversationKind: event.conversationKind,
|
|
267
|
+
channel: conversationId,
|
|
268
|
+
ts: event.ts,
|
|
269
|
+
thread_ts: event.thread_ts,
|
|
270
|
+
user: event.user,
|
|
271
|
+
text: event.text,
|
|
272
|
+
attachments: event.attachments?.map((attachment) => ({
|
|
273
|
+
original: attachment.name,
|
|
274
|
+
localPath: attachment.localPath,
|
|
275
|
+
})),
|
|
276
|
+
sessionKey: event.sessionKey,
|
|
277
|
+
};
|
|
278
|
+
const adapters = createSlackAdapters(slackEvent, this, true);
|
|
247
279
|
return this.handler.handleEvent(event, this, adapters, true);
|
|
248
280
|
});
|
|
249
281
|
return true;
|
|
@@ -267,12 +299,12 @@ export class SlackBot {
|
|
|
267
299
|
type: "section",
|
|
268
300
|
text: {
|
|
269
301
|
type: "mrkdwn",
|
|
270
|
-
text:
|
|
302
|
+
text: `*${PRODUCT_NAME}*\nStart a new task or check on running work.`,
|
|
271
303
|
},
|
|
272
304
|
accessory: {
|
|
273
305
|
type: "image",
|
|
274
306
|
image_url: "https://media1.tenor.com/m/lfDATg4Bhc0AAAAC/happy-cat.gif",
|
|
275
|
-
alt_text:
|
|
307
|
+
alt_text: PRODUCT_NAME,
|
|
276
308
|
},
|
|
277
309
|
},
|
|
278
310
|
];
|
|
@@ -364,11 +396,11 @@ export class SlackBot {
|
|
|
364
396
|
for (const ev of periodicEvents) {
|
|
365
397
|
const channelLabel = ev.platform === "slack"
|
|
366
398
|
? (() => {
|
|
367
|
-
const channel = this.channels.get(ev.
|
|
368
|
-
const channelName = channel ? `#${channel.name}` : ev.
|
|
399
|
+
const channel = this.channels.get(ev.conversationId);
|
|
400
|
+
const channelName = channel ? `#${channel.name}` : ev.conversationId;
|
|
369
401
|
return `${ev.platform}:${channelName}`;
|
|
370
402
|
})()
|
|
371
|
-
: `${ev.platform}:${ev.
|
|
403
|
+
: `${ev.platform}:${ev.conversationId}`;
|
|
372
404
|
const nextStr = ev.nextRun
|
|
373
405
|
? new Date(ev.nextRun).toLocaleString("en-US", {
|
|
374
406
|
month: "short",
|
|
@@ -413,6 +445,115 @@ export class SlackBot {
|
|
|
413
445
|
}
|
|
414
446
|
return this.handler.isRunning(channelId) ? channelId : null;
|
|
415
447
|
}
|
|
448
|
+
createDirectCommandAdapters(conversationId, userId, userName, text, ts) {
|
|
449
|
+
const message = {
|
|
450
|
+
id: ts,
|
|
451
|
+
sessionKey: conversationId,
|
|
452
|
+
conversationKind: "direct",
|
|
453
|
+
userId,
|
|
454
|
+
userName,
|
|
455
|
+
text,
|
|
456
|
+
attachments: [],
|
|
457
|
+
};
|
|
458
|
+
const responseCtx = {
|
|
459
|
+
respond: async (responseText) => {
|
|
460
|
+
const messageTs = await this.postMessage(conversationId, responseText);
|
|
461
|
+
this.logBotResponse(conversationId, responseText, messageTs);
|
|
462
|
+
},
|
|
463
|
+
replaceResponse: async (responseText) => {
|
|
464
|
+
const messageTs = await this.postMessage(conversationId, responseText);
|
|
465
|
+
this.logBotResponse(conversationId, responseText, messageTs);
|
|
466
|
+
},
|
|
467
|
+
respondInThread: async (responseText) => {
|
|
468
|
+
const messageTs = await this.postMessage(conversationId, responseText);
|
|
469
|
+
this.logBotResponse(conversationId, responseText, messageTs);
|
|
470
|
+
},
|
|
471
|
+
setTyping: async () => { },
|
|
472
|
+
setWorking: async () => { },
|
|
473
|
+
uploadFile: async (filePath, title) => {
|
|
474
|
+
await this.uploadFile(conversationId, filePath, title);
|
|
475
|
+
},
|
|
476
|
+
deleteResponse: async () => { },
|
|
477
|
+
};
|
|
478
|
+
return {
|
|
479
|
+
message,
|
|
480
|
+
responseCtx,
|
|
481
|
+
platform: this.getPlatformInfo(),
|
|
482
|
+
};
|
|
483
|
+
}
|
|
484
|
+
createSlashCommandBot(conversationId, threadTs) {
|
|
485
|
+
return {
|
|
486
|
+
start: async () => { },
|
|
487
|
+
postMessage: async (_channel, text) => {
|
|
488
|
+
if (threadTs) {
|
|
489
|
+
return this.postInThread(conversationId, threadTs, text);
|
|
490
|
+
}
|
|
491
|
+
return this.postMessage(conversationId, text);
|
|
492
|
+
},
|
|
493
|
+
updateMessage: async (channel, ts, text) => {
|
|
494
|
+
await this.updateMessage(channel, ts, text);
|
|
495
|
+
},
|
|
496
|
+
enqueueEvent: (event) => this.enqueueEvent(event),
|
|
497
|
+
getPlatformInfo: () => this.getPlatformInfo(),
|
|
498
|
+
};
|
|
499
|
+
}
|
|
500
|
+
async routeSlashLoginCommand(payload) {
|
|
501
|
+
const commandSuffix = payload.text?.trim();
|
|
502
|
+
const commandText = commandSuffix ? `${payload.command} ${commandSuffix}` : payload.command;
|
|
503
|
+
const createdAt = new Date();
|
|
504
|
+
const eventTs = (createdAt.getTime() / 1000).toFixed(6);
|
|
505
|
+
const sourceChannelId = payload.channel_id;
|
|
506
|
+
const isDirectMessage = sourceChannelId.startsWith("D");
|
|
507
|
+
const targetChannelId = isDirectMessage
|
|
508
|
+
? sourceChannelId
|
|
509
|
+
: await this.openDirectMessage(payload.user_id);
|
|
510
|
+
const userName = payload.user_name ?? this.getUser(payload.user_id)?.userName;
|
|
511
|
+
this.logToFile(targetChannelId, {
|
|
512
|
+
date: createdAt.toISOString(),
|
|
513
|
+
ts: eventTs,
|
|
514
|
+
user: payload.user_id,
|
|
515
|
+
userName,
|
|
516
|
+
text: commandText,
|
|
517
|
+
attachments: [],
|
|
518
|
+
isBot: false,
|
|
519
|
+
});
|
|
520
|
+
if (!isDirectMessage) {
|
|
521
|
+
await this.postEphemeral(sourceChannelId, payload.user_id, `我已私訊你 ${PRODUCT_NAME} 的登入連結,請到私訊完成設定。`);
|
|
522
|
+
}
|
|
523
|
+
const event = {
|
|
524
|
+
type: "dm",
|
|
525
|
+
conversationId: targetChannelId,
|
|
526
|
+
conversationKind: "direct",
|
|
527
|
+
ts: eventTs,
|
|
528
|
+
user: payload.user_id,
|
|
529
|
+
text: commandText,
|
|
530
|
+
attachments: [],
|
|
531
|
+
sessionKey: targetChannelId,
|
|
532
|
+
};
|
|
533
|
+
const adapters = this.createDirectCommandAdapters(targetChannelId, payload.user_id, userName, commandText, eventTs);
|
|
534
|
+
await this.handler.handleEvent(event, this, adapters, false);
|
|
535
|
+
}
|
|
536
|
+
async routeSlashNewCommand(payload) {
|
|
537
|
+
const conversationId = payload.channel_id;
|
|
538
|
+
if (!conversationId.startsWith("D")) {
|
|
539
|
+
await this.postEphemeral(conversationId, payload.user_id, `為了避免誤清除共享上下文,${payload.command} 目前只能在與 ${PRODUCT_NAME} 的私訊中使用。`);
|
|
540
|
+
return;
|
|
541
|
+
}
|
|
542
|
+
const createdAt = new Date();
|
|
543
|
+
const eventTs = (createdAt.getTime() / 1000).toFixed(6);
|
|
544
|
+
const userName = payload.user_name ?? this.getUser(payload.user_id)?.userName;
|
|
545
|
+
this.logToFile(conversationId, {
|
|
546
|
+
date: createdAt.toISOString(),
|
|
547
|
+
ts: eventTs,
|
|
548
|
+
user: payload.user_id,
|
|
549
|
+
userName,
|
|
550
|
+
text: payload.command,
|
|
551
|
+
attachments: [],
|
|
552
|
+
isBot: false,
|
|
553
|
+
});
|
|
554
|
+
const commandBot = this.createSlashCommandBot(conversationId);
|
|
555
|
+
await this.handler.handleNew(conversationId, conversationId, commandBot);
|
|
556
|
+
}
|
|
416
557
|
setupEventHandlers() {
|
|
417
558
|
// Channel @mentions
|
|
418
559
|
this.socketClient.on("app_mention", ({ event, ack }) => {
|
|
@@ -427,6 +568,8 @@ export class SlackBot {
|
|
|
427
568
|
const sessionKey = e.thread_ts ? `${e.channel}:${e.thread_ts}` : e.channel;
|
|
428
569
|
const slackEvent = {
|
|
429
570
|
type: "mention",
|
|
571
|
+
conversationId: e.channel,
|
|
572
|
+
conversationKind: "shared",
|
|
430
573
|
channel: e.channel,
|
|
431
574
|
ts: e.ts,
|
|
432
575
|
thread_ts: e.thread_ts,
|
|
@@ -451,21 +594,15 @@ export class SlackBot {
|
|
|
451
594
|
this.handler.handleStop(stopTarget, e.channel, this);
|
|
452
595
|
}
|
|
453
596
|
else {
|
|
454
|
-
this.postMessage(e.channel, "
|
|
597
|
+
this.postMessage(e.channel, formatNothingRunning("slack"));
|
|
455
598
|
}
|
|
456
599
|
ack();
|
|
457
600
|
return;
|
|
458
601
|
}
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
this.
|
|
462
|
-
}
|
|
463
|
-
else {
|
|
464
|
-
this.getQueue(sessionKey).enqueue(() => {
|
|
465
|
-
const adapters = createSlackAdapters(slackEvent, this, false);
|
|
466
|
-
return this.handler.handleEvent(slackEvent, this, adapters, false);
|
|
467
|
-
});
|
|
468
|
-
}
|
|
602
|
+
this.getQueue(sessionKey).enqueue(() => {
|
|
603
|
+
const adapters = createSlackAdapters(slackEvent, this, false);
|
|
604
|
+
return this.handler.handleEvent(slackEvent, this, adapters, false);
|
|
605
|
+
});
|
|
469
606
|
ack();
|
|
470
607
|
});
|
|
471
608
|
// All messages (for logging) + DMs (for triggering)
|
|
@@ -485,6 +622,7 @@ export class SlackBot {
|
|
|
485
622
|
return;
|
|
486
623
|
}
|
|
487
624
|
const isDM = e.channel_type === "im";
|
|
625
|
+
const conversationKind = isDM ? "direct" : "shared";
|
|
488
626
|
const isBotMention = e.text?.includes(`<@${this.botUserId}>`);
|
|
489
627
|
// Skip channel @mentions - already handled by app_mention event
|
|
490
628
|
if (!isDM && isBotMention) {
|
|
@@ -493,6 +631,8 @@ export class SlackBot {
|
|
|
493
631
|
}
|
|
494
632
|
const slackEvent = {
|
|
495
633
|
type: isDM ? "dm" : "mention",
|
|
634
|
+
conversationId: e.channel,
|
|
635
|
+
conversationKind,
|
|
496
636
|
channel: e.channel,
|
|
497
637
|
ts: e.ts,
|
|
498
638
|
thread_ts: e.thread_ts,
|
|
@@ -518,7 +658,7 @@ export class SlackBot {
|
|
|
518
658
|
this.handler.handleStop(stopTarget, e.channel, this);
|
|
519
659
|
}
|
|
520
660
|
else {
|
|
521
|
-
this.postMessage(e.channel, "
|
|
661
|
+
this.postMessage(e.channel, formatNothingRunning("slack"));
|
|
522
662
|
}
|
|
523
663
|
ack();
|
|
524
664
|
return;
|
|
@@ -532,23 +672,47 @@ export class SlackBot {
|
|
|
532
672
|
this.handler.handleStop(dmSessionKey, e.channel, this); // Don't await, don't queue
|
|
533
673
|
}
|
|
534
674
|
else {
|
|
535
|
-
this.postMessage(e.channel, "
|
|
675
|
+
this.postMessage(e.channel, formatNothingRunning("slack"));
|
|
536
676
|
}
|
|
537
677
|
ack();
|
|
538
678
|
return;
|
|
539
679
|
}
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
this.getQueue(dmSessionKey).enqueue(() => {
|
|
545
|
-
const adapters = createSlackAdapters(slackEvent, this, false);
|
|
546
|
-
return this.handler.handleEvent(slackEvent, this, adapters, false);
|
|
547
|
-
});
|
|
548
|
-
}
|
|
680
|
+
this.getQueue(dmSessionKey).enqueue(() => {
|
|
681
|
+
const adapters = createSlackAdapters(slackEvent, this, false);
|
|
682
|
+
return this.handler.handleEvent(slackEvent, this, adapters, false);
|
|
683
|
+
});
|
|
549
684
|
}
|
|
550
685
|
ack();
|
|
551
686
|
});
|
|
687
|
+
this.socketClient.on("slash_commands", async ({ body, ack }) => {
|
|
688
|
+
const payload = body;
|
|
689
|
+
await ack();
|
|
690
|
+
if (!payload.command || !payload.channel_id || !payload.user_id) {
|
|
691
|
+
return;
|
|
692
|
+
}
|
|
693
|
+
const handlerPromise = payload.command === "/pi-login"
|
|
694
|
+
? this.routeSlashLoginCommand({
|
|
695
|
+
command: payload.command,
|
|
696
|
+
text: payload.text,
|
|
697
|
+
channel_id: payload.channel_id,
|
|
698
|
+
user_id: payload.user_id,
|
|
699
|
+
user_name: payload.user_name,
|
|
700
|
+
})
|
|
701
|
+
: payload.command === "/pi-new"
|
|
702
|
+
? this.routeSlashNewCommand({
|
|
703
|
+
command: payload.command,
|
|
704
|
+
channel_id: payload.channel_id,
|
|
705
|
+
user_id: payload.user_id,
|
|
706
|
+
user_name: payload.user_name,
|
|
707
|
+
})
|
|
708
|
+
: null;
|
|
709
|
+
if (!handlerPromise) {
|
|
710
|
+
return;
|
|
711
|
+
}
|
|
712
|
+
handlerPromise.catch((err) => {
|
|
713
|
+
log.logWarning("Slack slash command error", err instanceof Error ? err.message : String(err));
|
|
714
|
+
});
|
|
715
|
+
});
|
|
552
716
|
// App Home tab
|
|
553
717
|
this.socketClient.on("app_home_opened", ({ event, ack }) => {
|
|
554
718
|
const e = event;
|
|
@@ -579,7 +743,7 @@ export class SlackBot {
|
|
|
579
743
|
// Use handler's forceStop method
|
|
580
744
|
this.handler.forceStop(sessionKey);
|
|
581
745
|
// Notify in channel
|
|
582
|
-
await this.postMessage(channelId,
|
|
746
|
+
await this.postMessage(channelId, formatForceStopped("slack", userId ?? "unknown"));
|
|
583
747
|
// Refresh home tab
|
|
584
748
|
if (userId) {
|
|
585
749
|
this.webClient.views
|