Skip to content

feat(frontend): provider switcher for tracker intake (GitHub, Linear, Jira)#2289

Draft
anirudh5harma wants to merge 10 commits into
AgentWrapper:mainfrom
anirudh5harma:codex/dashboard-intake-ui
Draft

feat(frontend): provider switcher for tracker intake (GitHub, Linear, Jira)#2289
anirudh5harma wants to merge 10 commits into
AgentWrapper:mainfrom
anirudh5harma:codex/dashboard-intake-ui

Conversation

@anirudh5harma

@anirudh5harma anirudh5harma commented Jun 29, 2026

Copy link
Copy Markdown

Summary

The desktop dashboard now exposes a provider switcher in project settings so a project can target GitHub, Linear, or Jira intake from the UI. Selecting a provider swaps the visible scope fields, scrubs any stale fields from the prior provider before save, and enforces per-provider validation. Sessions spawned by intake still surface a canonical <provider>:<native> badge on the board and inspector.

Closes #2283.

Depends on #2288. This branch is intentionally stacked on the backend branch; after #2288 merges it will be rebased onto main so the final diff contains only the frontend changes.

This ports aoagents/ReverbCode#425 and extends it to consume the multi-provider TrackerIntakeConfig shape introduced in #2288.

What this PR adds

  • Provider <Select> (GitHub / Linear / Jira) inside the Tracker intake card. The provider field is required when intake is enabled.
  • Provider-specific scope fields, shown conditionally:
    • GitHub → Repository (owner/repo, blank = git origin auto-derived)
    • Linear → Team key
    • Jira → Site URL + Project key
  • Save scrubbingrepo, team, baseURL, projectKey are explicitly cleared from the payload before the new provider's scope fields are set, so a switch never leaks a stale field into the daemon.
  • Per-provider validation — Linear without a team key and Jira without site URL + project key both block save with explicit messages. The existing label-or-assignee guard still applies across all three providers.
  • Inline credential hint — a small caption under the form names the env vars the selected provider reads (AO_GITHUB_TOKEN / AO_LINEAR_TOKEN / AO_JIRA_EMAIL + AO_JIRA_TOKEN) so users know where to put credentials without leaving Settings. Restart-the-daemon caveat included.
  • Provider-aware placeholders for labels / assignee (github login or * vs Linear display name vs Jira accountId or email).

Scope notes

  • Credentials are env vars, daemon-side. The UI does not collect, edit, or display tokens.
  • Live preflight / "credentials missing" status is intentionally inline-only (env-var hint). A live status endpoint can land later if needed.
  • Dry-run previews, last-poll status, activity history, and dedicated pause/resume APIs remain future work.
  • No polling, matching, or tracker writes run in Electron.

Validation

  • Focused frontend suite for ProjectSettingsForm: 10 tests, all pass — covers GitHub save round-trip, Linear save, Jira save, Linear validation, Jira validation, broad-intake guard, hidden-config preservation, daemon error surfacing.
  • Full frontend suite: 40 files, 379 tests, all green.
  • npm run frontend:typecheck
  • Manual visual pass deferred while canonical main has the pre-existing duplicate migration 20 panic; component-level coverage above is comprehensive.

Post-deploy monitoring

After #2288 lands, enable intake for one disposable project per provider and confirm:

  • Settings reload exactly what was saved, no field bleed across provider switches.
  • An eligible Linear / Jira issue produces a worker session with linear:ENG-N / jira:PROJ-N badges on the board.
  • Switching provider in the UI clears the previous scope fields visually and on the next save payload.
  • Inline env-var hint renders the correct vars per selection.

Rollback trigger: a switch silently leaving stale repo / team / projectKey in the saved payload, or settings save failing schema validation post-regen. Immediate mitigation: disable trackerIntake.enabled on the affected project.

@anirudh5harma anirudh5harma force-pushed the codex/dashboard-intake-ui branch from 313fe1e to 0fa0a68 Compare June 30, 2026 09:37
@anirudh5harma anirudh5harma changed the title feat(frontend): surface tracker intake controls feat(frontend): provider switcher for tracker intake (GitHub, Linear, Jira) Jun 30, 2026
anirudh5harma and others added 9 commits June 30, 2026 15:42
Add TrackerProviderLinear and TrackerProviderJira and extend
TrackerIntakeConfig with the provider-specific scope fields the new
adapters need:

- github keeps Repo (owner/repo or derived from origin)
- linear adds Team (team key)
- jira adds BaseURL + ProjectKey (Cloud site + project key)

TrackerRepo gains an optional BaseURL so Jira's tenant site can travel
with cross-issue queries without forcing a separate parameter.

Validate now branches per provider and rejects cross-provider field
bleed (e.g. a Linear Team left set after switching back to GitHub) so a
stale field can't silently survive a provider switch.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Implements ports.Tracker against Linear's GraphQL API. Scope is the
team key — List queries issues filtered by team + state.type + labels +
assignee displayName, paginated via the first: argument.

Workflow-state mapping:
- backlog/unstarted/triage -> open
- started -> in_progress
- completed -> done
- cancelled -> cancelled

Credentials come from AO_LINEAR_TOKEN (with LINEAR_API_KEY as a
fallback). Personal API keys and Bearer-prefixed OAuth tokens both pass
through the Authorization header opaquely.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Implements ports.Tracker against Jira Cloud REST. Scope is the project
key plus the tenant site base URL (carried per-call via
TrackerRepo.BaseURL so one adapter instance can serve multiple Jira
tenants under one account).

List builds a JQL query (project + statusCategory + labels + assignee
ORDER BY created DESC) and calls /rest/api/3/search. Quoted scalars are
escaped so a `"` in a label can't break out of the JQL string.

Status-category mapping:
- new / unknown -> open
- indeterminate -> in_progress
- done -> done, or cancelled when the status name is "Cancelled" /
  "Won't Do"

Description bodies use Jira's Atlassian Document Format; the adapter
flattens text leaves into plaintext so the intake prompt stays readable
without a heavyweight ADF dependency.

Credentials come from AO_JIRA_EMAIL + AO_JIRA_TOKEN as Basic auth.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Replace the observer's single ports.Tracker with a TrackerResolver
interface so each project's poll is dispatched to the adapter that
matches its configured provider. SingleTrackerResolver lets tests and
single-provider deployments keep using one adapter without constructing
a map.

trackerRepo() now computes the per-provider scope:
- github: configured Repo, falling back to the parsed origin URL
- linear: configured Team key
- jira: configured ProjectKey + BaseURL (passed via TrackerRepo.BaseURL)

The daemon wires a multiTrackerResolver that owns three lazy adapters,
constructed only on first use so projects that don't configure a given
provider pay no auth or network cost. GitHub keeps the existing
AO_GITHUB_TOKEN + `gh auth token` precedence; Linear reads
AO_LINEAR_TOKEN; Jira reads AO_JIRA_EMAIL + AO_JIRA_TOKEN.

The `seen` map no longer indexes by bare native ID. With three
providers in play, native IDs collide (Linear "ENG-1" vs Jira "ENG-1"),
so dedupe runs only on the canonical "<provider>:<native>" form.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Picks up TrackerIntakeConfig's new team / baseURL / projectKey fields
and the github / linear / jira provider enum from the domain change.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Add a Provider <Select> (github | linear | jira) to the Tracker intake
card and swap the field set on every change:

- github -> Repository
- linear -> Team key
- jira   -> Site URL + Project key

Save now scrubs the prior provider's scope fields before sending so a
stale repo / team / baseURL / projectKey can't leak in after a switch.
Per-provider validation messages flag a missing Linear team or Jira
site + project key; the existing label-or-assignee guard still applies
across all three. A small hint line in the card names the env vars the
selected provider reads so users know where to put credentials without
leaving Settings.

Tests cover the new Linear / Jira save paths and both provider-specific
validation paths in addition to the existing GitHub coverage.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@anirudh5harma anirudh5harma force-pushed the codex/dashboard-intake-ui branch from 0fa0a68 to e123a96 Compare June 30, 2026 10:13
canonicalTrackerIssueId was authored for the GitHub-only intake slice
and explicitly filtered to "github:"-prefixed ids. With multi-provider
intake the daemon now stamps sessions with "linear:<KEY>" and
"jira:<KEY>" too, so non-GitHub intake sessions were getting their
canonical badge dropped on the board and the Issue row hidden in the
inspector.

Accept any of the three documented provider prefixes. Manually created
tasks (no provider prefix) still get undefined so they don't grow a
phantom Issue badge.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Dashboard controls and visibility for tracker issue intake

1 participant