(cmd: IncomingCommand)
| 514 | } |
| 515 | }, |
| 516 | async onCommand(cmd: IncomingCommand) { |
| 517 | // Dedup guard: drop duplicate deliveries of the same event within the TTL window. |
| 518 | if (cmd.eventId) { |
| 519 | const dupKey = `evt:${adapter.platform}:${cmd.eventId}`; |
| 520 | try { |
| 521 | if (await backend.dedup.seen(dupKey, cfg.dedupTtl ?? 300_000)) |
| 522 | return; |
| 523 | } catch (err) { |
| 524 | console.warn( |
| 525 | `[bot] dedup check failed for ${adapter.platform}; processing without dedup`, |
| 526 | err, |
| 527 | ); |
| 528 | } |
| 529 | } |
| 530 | |
| 531 | const command = commandHandlers.get(normalizeCommandName(cmd.command)); |
| 532 | if (!command) return; // unregistered command → skip |
| 533 | const thread = makeThread( |
| 534 | adapter, |
| 535 | cmd.replyTarget, |
| 536 | cmd.conversationKey, |
| 537 | ); |
| 538 | // Resolve typed options from any structured args the surface supplied |
| 539 | // (e.g. Discord); text-only surfaces (Slack) leave `options` empty and |
| 540 | // the handler reads `text`. |
| 541 | let options: Record<string, unknown> = {}; |
| 542 | if (command.options && cmd.rawOptions) { |
| 543 | const parsed = await parseToolArgs(command.options, cmd.rawOptions); |
| 544 | if (parsed.ok) options = parsed.value; |
| 545 | } |
| 546 | const ctx: CommandContext<Record<string, unknown>> = { |
| 547 | thread, |
| 548 | command: normalizeCommandName(cmd.command), |
| 549 | text: cmd.text, |
| 550 | options, |
| 551 | user: cmd.user, |
| 552 | platform: cmd.platform, |
| 553 | }; |
| 554 | const openModal = makeOpenModal( |
| 555 | adapter, |
| 556 | cmd.replyTarget, |
| 557 | cmd.triggerId, |
| 558 | ); |
| 559 | if (openModal) ctx.openModal = openModal; |
| 560 | await command.handler(ctx); |
| 561 | }, |
| 562 | async onThreadStarted(evt: IncomingThreadStart) { |
| 563 | // The adapter has already applied its static defaults (greeting / |
| 564 | // prompts) before emitting this, so handlers layer on top and never |
no test coverage detected
searching dependent graphs…