Summary
Enhance the shared createAccountListHelpers() to support binding-aware default account resolution, account ID normalization, and scoped-binding filtering — eliminating per-channel reimplementations and fixing 5+ multi-account bugs.
Problem to Solve
The shared createAccountListHelpers() in src/channels/plugins/account-helpers.ts had three gaps:
-
No binding-aware default resolution — resolveDefaultAccountId() ignored agent bindings entirely. Only Telegram had custom code for this, so Discord, Slack, Signal, iMessage, and WhatsApp silently failed in multi-account + binding setups: bindings were configured but the default account was always "default" or the first alphabetical account.
-
No account ID normalization — listConfiguredAccountIds() didn't normalize keys, so mixed-case config entries (e.g., "Work" vs "work") could cause duplicate accounts or lookup mismatches.
-
Scoped bindings leaked into global default — resolveDefaultAgentBoundAccountId() returned the first matching binding regardless of scope constraints (guildId, teamId, peer, roles). A guild-specific Discord binding could become the global default account for CLI, onboarding, and status paths.
Additionally, Telegram's custom approach blindly merged listBoundAccountIds() into the account list — creating phantom accounts for bindings that referenced non-existent accounts.
Proposed Solution
- Enhanced shared helper with lowercase-normalized IDs, binding-aware
resolveDefaultAccountId() (validated against configured accounts), and validateBoundAccountIds() diagnostic helper
resolveDefaultAgentBoundAccountId() now skips scoped bindings (peer/guildId/teamId/roles)
- Migrated Telegram to use the shared helper with channel-specific
hasBaseLevelTelegramToken() for implicit default account detection (including tokenFile)
- Added binding-aware default resolution to LINE's
resolveDefaultLineAccountId()
- 25 unit tests covering all behaviors
Alternatives Considered
- Adding binding support individually per channel — perpetuates the duplication that caused this drift
- Blindly merging bound IDs into account list (Telegram's old approach) — creates phantom accounts per user feedback
Impact
- Affected: Discord, Slack, Signal, iMessage, WhatsApp, Telegram, LINE account resolution +
resolveDefaultAgentBoundAccountId() in routing/bindings
- Severity: Bug (silent multi-account failures)
- Frequency: Every multi-account setup with bindings
- Consequence: Ack reactions fail, cron announcements fail, wrong account picked for delivery
Related Issues
Summary
Enhance the shared
createAccountListHelpers()to support binding-aware default account resolution, account ID normalization, and scoped-binding filtering — eliminating per-channel reimplementations and fixing 5+ multi-account bugs.Problem to Solve
The shared
createAccountListHelpers()insrc/channels/plugins/account-helpers.tshad three gaps:No binding-aware default resolution —
resolveDefaultAccountId()ignored agent bindings entirely. Only Telegram had custom code for this, so Discord, Slack, Signal, iMessage, and WhatsApp silently failed in multi-account + binding setups: bindings were configured but the default account was always"default"or the first alphabetical account.No account ID normalization —
listConfiguredAccountIds()didn't normalize keys, so mixed-case config entries (e.g.,"Work"vs"work") could cause duplicate accounts or lookup mismatches.Scoped bindings leaked into global default —
resolveDefaultAgentBoundAccountId()returned the first matching binding regardless of scope constraints (guildId,teamId,peer,roles). A guild-specific Discord binding could become the global default account for CLI, onboarding, and status paths.Additionally, Telegram's custom approach blindly merged
listBoundAccountIds()into the account list — creating phantom accounts for bindings that referenced non-existent accounts.Proposed Solution
resolveDefaultAccountId()(validated against configured accounts), andvalidateBoundAccountIds()diagnostic helperresolveDefaultAgentBoundAccountId()now skips scoped bindings (peer/guildId/teamId/roles)hasBaseLevelTelegramToken()for implicit default account detection (including tokenFile)resolveDefaultLineAccountId()Alternatives Considered
Impact
resolveDefaultAgentBoundAccountId()in routing/bindingsRelated Issues