feat(guilds): /guild, the module's own chat command

The first command through `api.registerSlashCommands` (MODULE_API 1.6.0,
TEAMS.md §7.1). The definition and the handler both live here; the bot pulls the
definition and runs no line of this module.

`/guild` and not `/team`, deliberately. Core does not own the word for a Team —
that is what deleted its Team pages in phase 3 — so it does not publish the noun
in a channel either. Core ships the dispatcher and zero commands.

The audience rungs are re-resolved in the handler rather than assumed: a shard
that gates guilds to staff does not become public because the question arrived
over Discord. The provider's own staleness guard is honoured too, so a stale
board answers "not connected" instead of reporting what it still holds, and
`resolveUserId` is exported rather than copied so "linked" means here what it
means on the roster.

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
2026-08-18 18:53:45 -05:00
parent 990a50b491
commit 2d1d91e372
5 changed files with 350 additions and 1 deletions

View File

@@ -331,4 +331,9 @@ async function projectRoster(externalId, members, viewer) {
// data and not a callback.
const pageUrlTemplate = '/uo/guilds/{externalId}'
module.exports = { getTeams, getTeamMembers, getTeamLeaders, projectRoster, boardIsCurrent, pageUrlTemplate }
// `resolveUserId` is exported for the `/guild` chat command, which counts linked
// members and must decide "linked" by the same rule the roster does — a second
// copy of that two-source check is a copy that drifts.
module.exports = {
getTeams, getTeamMembers, getTeamLeaders, projectRoster, boardIsCurrent, pageUrlTemplate, resolveUserId,
}