Each slash command and context-menu entry is now its own named function;
handleCommand looks the name up in COMMAND_HANDLERS and delegates. Finding
where a command lives is now "grep handle<Name>" instead of scrolling 600
lines of sequential ifs.
Other cleanups in the same pass:
- Restore ActionRowBuilder, ModalBuilder, TextInputBuilder, TextInputStyle
to the top-level discord.js destructure. ActionRowBuilder was used at
runtime by /response delete and /panel but had been dropped from the
imports based on a stale "unused" diagnostic — those paths would have
thrown ReferenceError. Hoisting the previously-inline /signature
imports as well.
- Hoist `logTicketEvent` to the top imports (was inline-required at three
callsites).
- Extract findTicketForChannel(), runDeferred(), and fetchLoggingChannel()
helpers — replaces the lookup-then-defer-then-try-catch boilerplate
repeated in nearly every branch.
- Pull the force-close timer body into finalizeForceClose() and
postTranscript() so the timer registration is one line.
- Pull the panel button-row construction into buildPanelButtonRow().
- Split /response into its own RESPONSE_SUBCOMMANDS dispatch + per-sub
handlers.
- Consolidate the duplicated transcript date formatter into one local fmt().
No behavior change. All 23 modules still load clean; handleCommand,
handleContextMenu, handleAutocomplete, runEscalation, and runDeescalation
exports are preserved (handlers/buttons.js imports the last two).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>