KeeperHub / KeeperHub/keeperhub
Notification polish: Slack channel templating, Discord username/avatar/embeds, Telegram HTML + disablePreview
- Dominant language
- TypeScript
- Stars
- 24
- Forks
- 93
- Avg merge
- 1d 8h
- Merged PRs (30d)
- 266
Description
## Reason
Every KeeperHub workflow ends with an alert, and all three notifiers have small paper cuts that break real alerting:
1. **Slack channel ignores `{{variables}}`.** `plugins/slack/index.ts` declares `slackChannel` as `type: "text"`, but its own placeholder advertises `{{NodeName.channel}}`. Per `plugins/registry.ts`, only `template-input` / `template-textarea` resolve `{{...}}` — a `text` field sends the literal braces. A workflow that routes alerts to a channel computed upstream (e.g. severity router) silently posts to the wrong place or fails with `channel_not_found`.
2. **Discord can only send flat text.** `plugins/discord/index.ts` exposes a single `discordMessage` field. The Discord webhook API supports `username`, `avatar_url`, and rich `embeds` with `title`/`color`, but none are reachable — every alert looks identical, so on-call cannot tell critical from info at a glance.
3. **Telegram forces MarkdownV2 or nothing.** `parseMode` options are only `none` / `MarkdownV2`. MarkdownV2 requires escaping `(., -, _, *, [, ], (, ), ~, `, >, #, +, =, |, {, }, !)` with a backslash (the step's own placeholder warns about this). Balances, addresses, and tx hashes are full of those characters, so templated alerts randomly fail with `can't parse entities`. Telegram's `HTML` mode (``, ``, ...) has no such escaping trap and is what most bots use. There is also no `disable_web_page_preview` toggle, so long explorer links render noisy previews.
What told me to expect it: the Slack placeholder itself (`#general or {{NodeName.channel}}`), the Discord webhook docs (`username`/`avatar_url`/`embeds`), and the Telegram Bot API (`parse_mode: HTML`, `disable_web_page_preview`).
### Repro (no credentials needed)
- Slack: create a Send Slack Message node, set Channel to `{{Router.channel}}` — the field type is `text`, so the braces are never resolved.
- Discord: try to set a red critical embed or custom bot name — no such field exists.
- Telegram: set Parse Mode to MarkdownV2 with message `Balance: 1.2345 ETH at 0x1234_abcd` — Telegram rejects it unless every `.`/`_` is escaped; there is no HTML alternative.
## Scope
Covers, all additive and optional (existing workflows unchanged):
- `plugins/slack/index.ts`: `slackChannel` `text` -> `template-input` (1 line, no step change — templating resolves upstream).
- `plugins/discord/index.ts` + `steps/send-message.ts`: optional `username`, `avatarUrl`, `embedTitle`, `embedColor` (none/red/green/yellow/blue/gray). When title or a non-none color is set, the step also sends `embeds: [{title, description, color}]`; otherwise the payload is exactly `{content}` as before. Values truncated to Discord limits (username 80, title 256, description 4096).
- `plugins/telegram/index.ts` + `steps/send-message.ts`: `parseMode` gains `HTML`; new optional `disablePreview` select (true/false, default false) mapped to `disable_web_page_preview`.
- Tests: new `tests/unit/notifications-polish.test.ts` (6 cases) + all 7 existing `discord-send-message` tests still pass.
Explicitly not covered: Slack Block Kit / attachments, Discord thread IDs / message editing, Telegram Markdown (legacy) / inline keyboards / media. Each of those is a separate issue if wanted.
Checked on `staging` at `28233554f`. No schema/migration, no auth change, no new dependency, fixed-host egress only.
## Plan
PR to `staging` with the above + tests, verifying:
- `tsx scripts/discover-plugins.ts` regenerates cleanly
- `tsgo --noEmit` clean except the pre-existing `tests/unit/workflow-directive-detection.test.ts` `@workflow/builders` error (untouched file, also present on clean staging)
- `vitest run tests/unit/notifications-polish.test.ts tests/unit/discord-send-message.test.ts` — 13/13 green
- `safeFetch` with `plugin` tag unchanged; raw `fetch` untouched (no new egress surface)
Contributor guide
Research direction
Start with plugins/slack/index.ts, plugins/discord/index.ts, plugins/telegram/index.ts, and steps/send-message.ts, then inspect the existing discord-send-message tests and plugin field types. Run the two named Vitest suites and review tests/unit/notifications-polish.test.ts. Done means the optional notification fields and Telegram HTML/preview behavior work without changing existing workflows, discovery regenerates cleanly, and the stated checks pass.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- typescript
- Domain
- api, backend, testing
- Issue type
- Feature
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Active
- Clarity
- Clearly specified
- Newbie friendliness
- 68/100