feat(groups): optional forge source label in message footers

- Group.forgeLabel (default off, editable per group in the console) shows the
  source forge on every message the group's routes dispatch
- Discord embed footer: forge name next to the repo + the site's favicon as
  icon_url (Gitea instance's own favicon from its origin)
- Telegram footer: hyperlinked site name (GitHub or Gitea hostname); custom
  webhooks render a plain 'Custom' label
- forgeInfo() derives branding from event.provider + repository.html_url;
  dispatch attaches it to the NeutralMessage like mentionRoleIds
- validateGroups accepts forgeLabel booleans; GroupEditor gains the toggle
- tests: forgeInfo unit, discord/telegram footer render, dispatch on/off
- docs: groups.md + message-format.md (en/zh), config.example.yaml, AGENTS.md
- fix: wrangler.jsonc compatibility_date was an incomplete '2026-'
This commit is contained in:
RhenCloud 2026-08-14 08:10:04 +08:00
parent a5324fb0ea
commit 3dce114cec
No known key found for this signature in database
GPG key ID: A574A617378C4E0B
19 changed files with 273 additions and 16 deletions

View file

@ -39,6 +39,10 @@ export function renderNeutralMessage(message: NeutralMessage): FormattedMessage
// Safety net: clamp every embed part to the Discord API limits so a single
// oversized formatter or custom payload can never hard-fail the request.
const footerText = cap(
[message.forge?.name, message.footer].filter(Boolean).join(" · "),
MAX_FOOTER,
);
return {
content,
embeds: [
@ -61,7 +65,9 @@ export function renderNeutralMessage(message: NeutralMessage): FormattedMessage
value: cap(f.value, MAX_FIELD_VALUE),
inline: f.inline,
})),
footer: message.footer ? { text: cap(message.footer, MAX_FOOTER) } : undefined,
footer: footerText
? { text: footerText, icon_url: message.forge?.iconUrl }
: undefined,
timestamp: message.timestamp,
},
],

View file

@ -89,6 +89,10 @@ export function renderNeutralMessage(message: NeutralMessage): string {
}
const meta: string[] = [];
if (message.forge) {
const name = mdToHtml(message.forge.name);
meta.push(message.forge.url ? `<a href="${esc(message.forge.url)}">${name}</a>` : name);
}
if (message.footer) meta.push(esc(message.footer));
const ts = formatTimestamp(message.timestamp);
if (ts) meta.push(ts);