Summary
Add a @jira connector so a Jira issue (or JQL search result) 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, and they're resolved concurrently at copy time by SelfContainedRenderer. @linear is the closest existing analogue (issue tracker, token auth, reference-typed selection).
Reference connector: LinearAppConnector in Sources/ComposerApp/Support/AppConnectors.swift.
Implementation steps
-
Auth — Jira Cloud uses Basic auth with an Atlassian API token + account email + site URL (https://<site>.atlassian.net). The current ConnectorAuth.apiToken(label:hint:createURL:) captures a single secret, so decide one of:
- encode
email:token (and capture the site separately), or
- extend
ConnectorAuth with a case that carries the extra fields.
Pick the lighter option that keeps Settings simple and document it in the PR. createURL should deep-link to https://id.atlassian.com/manage-profile/security/api-tokens. The secret is stored in ConnectorSecretStore.
-
Connector struct — add private struct JiraAppConnector: ComposerAppConnector to AppConnectors.swift: let id = "@jira", the auth above, search(_:context:), and render(selection:).
search() → query the Jira REST API v3 (e.g. /rest/api/3/search with JQL, or issue-key lookup) and return AppSearchResults.
render(selection:) → fetch the issue summary, description, status, assignee, and key comments, and format them as a self-contained context section.
-
Register — add JiraAppConnector() to AppConnectorRegistry.all.
-
Selection type — add a case jira(JiraReference) 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 @jira, label, subtitle, SF Symbol) to MentionCatalog.all and map "@jira": .service in MentionCatalog.appCategory in MentionToken.swift.
-
Service (optional but cleaner) — put the Jira REST calls in a JiraService.swift under Sources/ComposerApp/Services/, reading the secret from ConnectorSecretStore.
-
Settings token field — confirm the connectors section of SettingsView renders the auth field(s); match the wiring of the existing token-backed connectors.
Acceptance criteria
References
LinearAppConnector in AppConnectors.swift is the closest template (issue tracker, token auth, reference-typed selection).
Summary
Add a
@jiraconnector so a Jira issue (or JQL search result) 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, and they're resolved concurrently at copy time by
SelfContainedRenderer.@linearis the closest existing analogue (issue tracker, token auth, reference-typed selection).Reference connector:
LinearAppConnectorinSources/ComposerApp/Support/AppConnectors.swift.Implementation steps
Auth — Jira Cloud uses Basic auth with an Atlassian API token + account email + site URL (
https://<site>.atlassian.net). The currentConnectorAuth.apiToken(label:hint:createURL:)captures a single secret, so decide one of:email:token(and capture the site separately), orConnectorAuthwith a case that carries the extra fields.Pick the lighter option that keeps Settings simple and document it in the PR.
createURLshould deep-link tohttps://id.atlassian.com/manage-profile/security/api-tokens. The secret is stored inConnectorSecretStore.Connector struct — add
private struct JiraAppConnector: ComposerAppConnectortoAppConnectors.swift:let id = "@jira", theauthabove,search(_:context:), andrender(selection:).search()→ query the Jira REST API v3 (e.g./rest/api/3/searchwith JQL, or issue-key lookup) and returnAppSearchResults.render(selection:)→ fetch the issue summary, description, status, assignee, and key comments, and format them as a self-contained context section.Register — add
JiraAppConnector()toAppConnectorRegistry.all.Selection type — add a
case jira(JiraReference)toAppSelectioninAppReference.swiftand handle it inAppToken.string(appID:selection:)/AppToken.parse(_:)so the chip round-trips through the note's plain text.Mention catalog — add a
MentionItem(id@jira, label, subtitle, SF Symbol) toMentionCatalog.alland map"@jira": .serviceinMentionCatalog.appCategoryinMentionToken.swift.Service (optional but cleaner) — put the Jira REST calls in a
JiraService.swiftunderSources/ComposerApp/Services/, reading the secret fromConnectorSecretStore.Settings token field — confirm the connectors section of
SettingsViewrenders the auth field(s); match the wiring of the existing token-backed connectors.Acceptance criteria
@jiraappears in the mention picker under the service category.SelfContainedRenderer../script/build_and_run.sh --verifypasses.References
LinearAppConnectorinAppConnectors.swiftis the closest template (issue tracker, token auth, reference-typed selection).