Summary
Add a @slack connector so a Slack message / thread / channel can be @-mentioned in the editor, resolved to a chip, and expanded into live context at copy time — the same pattern as the existing @github, @linear, @notion, and @sentry connectors.
Background
Connectors are the scalable unit behind an app chip. The editor and search panel only know how to ask a connector for search results and rendered context; each connector owns its own API details. They're registered in one place and resolved concurrently at copy time by SelfContainedRenderer.
Reference connector: GitHubAppConnector / LinearAppConnector in Sources/ComposerApp/Support/AppConnectors.swift.
Implementation steps
- Auth — Slack needs a token, so declare
auth as ConnectorAuth.apiToken(label: "Bot/User Token", hint: "xoxb-… / xoxp-…", createURL: "https://api.slack.com/apps") on the connector. The token is entered in Settings and read at runtime from ConnectorSecretStore (~/.local/share/Composer/connector-secrets.json, 0600).
- Connector struct — add
private struct SlackAppConnector: ComposerAppConnector to AppConnectors.swift: let id = "@slack", the auth above, search(_:context:), and render(selection:).
search() → query Slack (e.g. search.messages, plus conversations.list for channels) and return AppSearchResults.
render(selection:) → fetch the message/thread text (e.g. resolve a permalink → conversations.history/conversations.replies) and format it as a self-contained context section.
- Register — add
SlackAppConnector() to AppConnectorRegistry.all.
- Selection type — add a
case slack(SlackReference) to AppSelection in AppReference.swift and handle it in AppToken.string(appID:selection:) / AppToken.parse(_:) so the chip round-trips through the note's plain text.
- Mention catalog — add a
MentionItem (id @slack, label, subtitle, SF Symbol) to MentionCatalog.all and map "@slack": .service in MentionCatalog.appCategory in MentionToken.swift.
- Service (optional but cleaner) — put the Slack Web API calls in a
SlackService.swift under Sources/ComposerApp/Services/, reading the token from ConnectorSecretStore.
- Settings token field — confirm the ENGINES/connectors section of
SettingsView renders the token field for any connector whose auth is .apiToken (the existing token-backed connectors already do this — match their wiring).
Acceptance criteria
References
- Existing token-backed connectors (
@linear, @notion, @sentry) in AppConnectors.swift are the closest templates.
Summary
Add a
@slackconnector so a Slack message / thread / channel can be@-mentioned in the editor, resolved to a chip, and expanded into live context at copy time — the same pattern as the existing@github,@linear,@notion, and@sentryconnectors.Background
Connectors are the scalable unit behind an app chip. The editor and search panel only know how to ask a connector for search results and rendered context; each connector owns its own API details. They're registered in one place and resolved concurrently at copy time by
SelfContainedRenderer.Reference connector:
GitHubAppConnector/LinearAppConnectorinSources/ComposerApp/Support/AppConnectors.swift.Implementation steps
authasConnectorAuth.apiToken(label: "Bot/User Token", hint: "xoxb-… / xoxp-…", createURL: "https://api.slack.com/apps")on the connector. The token is entered in Settings and read at runtime fromConnectorSecretStore(~/.local/share/Composer/connector-secrets.json,0600).private struct SlackAppConnector: ComposerAppConnectortoAppConnectors.swift:let id = "@slack", theauthabove,search(_:context:), andrender(selection:).search()→ query Slack (e.g.search.messages, plusconversations.listfor channels) and returnAppSearchResults.render(selection:)→ fetch the message/thread text (e.g. resolve a permalink →conversations.history/conversations.replies) and format it as a self-contained context section.SlackAppConnector()toAppConnectorRegistry.all.case slack(SlackReference)toAppSelectioninAppReference.swiftand handle it inAppToken.string(appID:selection:)/AppToken.parse(_:)so the chip round-trips through the note's plain text.MentionItem(id@slack, label, subtitle, SF Symbol) toMentionCatalog.alland map"@slack": .serviceinMentionCatalog.appCategoryinMentionToken.swift.SlackService.swiftunderSources/ComposerApp/Services/, reading the token fromConnectorSecretStore.SettingsViewrenders the token field for any connector whoseauthis.apiToken(the existing token-backed connectors already do this — match their wiring).Acceptance criteria
@slackappears in the mention picker under the service category.SelfContainedRenderer../script/build_and_run.sh --verifypasses.References
@linear,@notion,@sentry) inAppConnectors.swiftare the closest templates.