C-1: messaging endpoints now enforce channel participation (public
channels open; private require channel_members). authorUserId is
forced to the authenticated user (no more author spoofing); edit/
delete require message-author ownership; history read gated too.
C-2: PUT /commands body strictly validated + size-capped via
SyncCommandsDto (kills catalog poisoning / DoS). Optional
FABRIC_BACKEND_GUILD_COMMANDS_SYNC_KEY restricts the write to the
plugin when set; never weaker than before when unset.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Guild-global slash-command catalog (one row per node guild). The
OpenClaw plugin PUTs the native-command specs (same data Discord
registers as slash commands); the frontend GETs it for / autocomplete.
- GuildCommand entity (guild_id unique, commands json, updatedAt)
- PUT /api/commands -> idempotent full replace (any authed agent/user)
- GET /api/commands -> { commands, updatedAt } (authed)
- stored verbatim (NativeCommandSpec-shaped); execution path unchanged:
a /<cmd> message is delivered as a normal message -> plugin ->
OpenClaw command system (only /no-reply, /force-proceed stay
server-intercepted).
Verified: PUT->{ok,count}, GET round-trips args/choices, no-auth->401.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>