Skip to content

feat: add multi-provider issue tracking - #6315

Open
Bil0000 wants to merge 293 commits into
pingdotgg:mainfrom
Bil0000:feat/issues-page
Open

Bil0000 wants to merge 293 commits into
pingdotgg:mainfrom
Bil0000:feat/issues-page

Conversation

@Bil0000

@Bil0000 Bil0000 commented Aug 12, 2026

Copy link
Copy Markdown
Contributor

Adds an Issues workspace for GitHub, GitLab, Bitbucket, Azure DevOps, and Linear. Provider adapters expose one issue model for browsing, search, filters, details, comments, supported writes, and agent handoffs. Issue and pull-request views link related work.

Tracker connections use provider-neutral issueTrackers.* RPCs and issueTracking.connections, with credentials stored on the server. Linear account and project-team selection live in Settings → Integrations → Issue Tracking. Sort support, reference style, and closing-via-PR behavior come from provider capabilities. Migration code for unshipped branch states has been removed.

Known limits and follow-ups:

  • The Issues page uses the primary connected environment. Multi-environment browsing is a follow-up; the selected-item contracts retain environment identity.
  • Forgejo issues and the mobile Issues workspace are not supported in this pass. Linear issue creation and field/state edits stay in Linear.
  • The three shared write-boundary fixes remain in this PR at the contributor request. They are covered by focused atomic-write, secret-store, and settings-save tests; no prerequisite PRs are required.
  • Tracker connect currently supports API keys. OAuth is a follow-up: add start/complete authorization operations and refresh-token storage while preserving existing token callers. No OAuth flow or refresh token is stored by this implementation.

Validation from the prior revision: focused contract, provider, settings, prompt, and client tests; 195 server integration tests in an isolated network; scoped server and web typechecks; 149 focused PR-panel tests after integrating current main; 51 shared-write tests. CI covers the full suite. No fresh browser or live-tracker write pass was run for these audit fixes.

Prior UI evidence was captured locally. Its upload was blocked because the required official GitHub attachment-preview artifact had expired.

September 19 review fixes

  • Removed AI decoration from task creation and match actions. Task creation now opens a complete source-linked prompt without a preliminary model call or a sendable loading placeholder.
  • Solve and selected-item tasks use a new worktree draft. Task-shape controls appear only for multiple selections.
  • Aligned issue-row hover and selection behavior with pull requests; removed duplicate menu actions and redundant compact-header status. The compact header keeps Solve visible and shows assignees.
  • Gave completed and not-planned close actions distinct icons and colors. Title and description edit separately; descriptions use the existing rich composer without Write/Preview tabs.
  • Added durable, thread-scoped issue links with link_issue, unlink_issue, and list_thread_issues. Threads show linked issues with open/unlink actions; issues show linked threads.
  • Merged current main and resolved its conflicts while retaining the newer permission reads and transactional secret writes.

Validation: 148 focused web tests, 220 focused issue-link/backend tests, all 15 MCP HTTP integration tests, and 391 merge-related tests passed. Scoped web/server typechecks, lint, formatting, and per-commit Ponytail reviews passed. Full CI is green on 6c92b1a370. GitHub reports CLEAN and MERGEABLE; all 144 review threads are resolved. CodeRabbit could not recover its incremental-review checkpoint, and Macroscope skipped correctness review because of the workspace cost cap. No fresh bot approval is claimed.

Browser limitation: the isolated server responds, but the built-in Browser panel cannot reach its loopback/environment-port target (ERR_CONNECTION_REFUSED). No fresh browser or live-tracker write verification is claimed, and no after-image/video was captured.

Direct PR–issue links

  • Added durable PR ↔ issue links with link, open, unlink, and refresh controls on both pages. Links are saved in the connected T3 environment; host PR text and issue state stay unchanged.
  • Added thread-project-scoped MCP tools: link_issue_to_pull_request, unlink_issue_from_pull_request, and list_issue_pull_request_links.
  • Links are idempotent, preserve host identity, survive Linear title changes, and check the expected PR account before saving. Older servers do not receive unsupported RPCs.

Validation: 48 focused tests passed across the web controls, saved-link store, MCP handlers and HTTP server, WebSocket route, environment capability, and authorization. Scoped contracts/server/web typechecks, lint, formatting, and per-commit Ponytail reviews passed. Full CI is green on 475b025972. GitHub reports CLEAN and MERGEABLE; all 144 review threads are resolved. Fresh bot review remains limited: CodeRabbit is paused after its checkpoint failure, and Macroscope skipped correctness review under its workspace cost cap.

Browser limitation remains: the built-in panel fails to reach the isolated frontend while local HTTP returns 200. No fresh visual or live-host write verification is claimed. Saved-link lists show at most 100 links and explicitly report truncation; cross-client changes use the refresh control.

Model: GPT-6 Astra, with Sol and Luna for bounded tasks. Harness: Codex.

Note

Add pluggable issue adapters and workspace issue browsing UI

  • Introduces issue, issue-tracking, and work-item contracts plus WebSocket RPC methods covering listing, detail, activity, comments, mutations, label/assignee management, templates, Linear connection, and AI task generation/match finding across all providers
  • Adds server-side IssueService with per-provider adapters for GitHub, GitLab, Bitbucket, Azure DevOps, and Linear, each implementing IssueAdapter with provider-specific capabilities, viewer permissions, caching, and error normalization
  • Adds a full Issues web UI: a /issues route with list/filter/search/snapshot, IssueDetailPanel with summary and timeline tabs, LinearConnectionDialog, IssueCreateDialog, label/assignee pickers, reactions, and work-item multi-selection with AI task generation via WorkItemSelectionBar"n- Extracts shared source-control components (ListRow, ListEmptyState, ConversationGroup, TimelineComment, HostMarkdown, CommentComposer, EntityPicker, ListFilterMenu, SourceControlReactionBar) from pull-request-specific implementations and refactors PR panels to use them
  • Risk: ServerSettings now includes an issueTracking section and PullRequestDetail carries linkedIssues; out-of-tree consumers expecting the prior shapes will need updating. RIGHT_PANEL_STORAGE_VERSION bumps to 13 with migration that drops legacy :issues-panel state. ServerSecretStore.make removes an extra chmod(0600) call. writeFileStringAtomically no longer requires a Scope.
📊 Macroscope summarized b075ac0. 135 files reviewed, 56 issues evaluated, 39 issues filtered, 15 comments posted

🗂️ Filtered Issues

apps/server/src/issue/BitbucketIssueApi.ts — 1 comment posted, 2 evaluated, 1 filtered
  • line 306: commentsPage discards the size returned by decodeIssueCommentsJson and exposes only the retained comments. The provider consequently uses page.comments.length as commentCount; deleted or blank comments are filtered out and the walk stops after ten pages, so an issue's displayed comment count is silently too low (and cannot indicate its actual total). [ Out of scope (post-validation triage) ]
apps/server/src/issue/BitbucketIssueProvider.ts — 0 comments posted, 3 evaluated, 3 filtered
  • line 124: listIssues drops input.involvement when it calls api.listIssues, so Bitbucket receives identical requests for the all, assigned, and created filters. Selecting an involvement filter therefore still returns every matching Bitbucket issue instead of only issues assigned to or created by the viewer. [ Out of scope (triage) ]
  • line 124: listIssues also omits input.sort and input.order, leaving BitbucketIssueApi to always request -updated_on. The UI exposes created/updated ascending and other sort modes; for a repository larger than the page, it receives only the most recently updated slice, then the service cannot issue a continuation for a non-updated desc sort. Thus, for example, "created: oldest" omits the actual oldest issues rather than merely displaying them in the wrong order. [ Out of scope (triage) ]
  • line 169: getIssueActivity reports page.comments.length as commentCount even when page.truncated is true. BitbucketIssueApi stops after ten 50-comment pages, so an issue with more than 500 comments is displayed as having only the fetched subset (at most 500), despite the activity contract requiring the host's count when a bounded read falls short. [ Out of scope (post-validation triage) ]
apps/server/src/issue/GitHubIssueCli.ts — 0 comments posted, 1 evaluated, 1 filtered
  • line 169: GitHubIssueCommentScopeError is also returned by setReaction when a supplied comment belongs to another issue, but its message always identifies the operation as updateComment. That failed reaction is therefore reported to users as a comment-edit failure, giving the wrong operation and remediation context. [ Out of scope (post-validation triage) ]
apps/server/src/issue/GitLabIssueCli.ts — 1 comment posted, 4 evaluated, 3 filtered
  • line 303: cursorParams carries only updatedBefore and no offset for rows already returned at that inclusive timestamp. If more than one page of GitLab issues has the same updated_at, each continuation fetches the same first limit + 1 rows; IssueService filters them as seenAt and produces the same cursor again, so older issues never become reachable and pagination can repeatedly return an empty page. [ Already posted ]
  • line 593: linkedMergeRequests stops after LINKED_PAGES full responses but returns only an array, with no truncation indicator. An issue with more than 500 links from either endpoint silently omits all later merge requests, so the linked-PR panel presents incomplete data as complete. [ Out of scope (post-validation triage) ]
  • line 990: listIssueTemplates slices the project’s template entries to TEMPLATE_LIMIT before fetching them and the returned IssueTemplateList contains no truncation signal. Projects with more than 25 issue templates silently make every later template unavailable in the creation UI. [ Out of scope (post-validation triage) ]
apps/server/src/issue/gitHubIssueJson.ts — 1 comment posted, 2 evaluated, 1 filtered
  • line 885: toStateReason drops GitHub's valid DUPLICATE state reason into null. GitHub documents DUPLICATE as an IssueStateReason, so closed issues marked as duplicates are presented as having no close reason rather than being distinguished from completed or not-planned issues. [ Out of scope (post-validation triage) ]
apps/server/src/pullRequest/GitHubPullRequestProvider.ts — 0 comments posted, 3 evaluated, 3 filtered
  • line 254: The citation limit is applied inside parseIssueReferences before unlinkedIssueReferences removes links GitHub already supplied. Thus, if the first ten references are host-reported closing/cross-reference links and a new valid citation appears later in the PR text, that later citation is never looked up or shown. The intended request budget should be applied after existing host links are removed. [ Cross-file consolidated ]
  • line 267: listCitedIssues performs all parsed references in one GraphQL document, and its implementation fails the whole batch when any cited number does not exist. Because this call converts that failure to [], a PR that mentions both a valid issue and an invalid/stale # reference loses the valid related issue as well, rather than showing the independently resolved valid link. [ Out of scope (triage) ]
  • line 447: When listLinkedIssues fails (for example, a GitHub GraphQL permission or transient error), this fallback marks truncated as false. The returned detail then says the linked-issues list is complete and the UI suppresses its “More linked issues exist on the host”/incomplete indicator, even though no host links were read; the GitLab provider correctly uses truncated: true for the equivalent failure path. [ Out of scope (post-validation triage) ]
apps/server/src/pullRequest/issueReferences.ts — 0 comments posted, 6 evaluated, 6 filtered
  • line 52: withoutCode recognizes fences only at the physical line start, so a fenced block inside a Markdown block quote (for example > ````, > Add native context menu to delete threads #12, > ````) is retained and #12 is incorrectly added as a cited issue. Fenced code blocks are valid inside block quotes; strip container prefixes before detecting their fences. [ Out of scope (post-validation triage) ]
  • line 54: A line beginning with the active fence closes it even when it has trailing text. In ````` [ Out of scope (post-validation triage) ]
  • line 59: withoutCode does not remove indented Markdown code blocks. A body containing a four-space-indented sample such as #12 leaves the number in the prose and creates a cited issue, even though indented blocks render as literal code just like the fenced blocks this function excludes. [ Out of scope (post-validation triage) ]
  • line 61: withoutCode removes an apparent inline span by allowing the opening (``+) capture to backtrack to a shorter delimiter. For valid Markdown such as see #12 ` example the two-backtick span contains a single backtick, but this regex removes only the opening pair and leaves #12 to be treated as a citation. Inline code spans must close with an equal-length delimiter run, so parse the delimiter length without backtracking. [ Out of scope (post-validation triage) ]
  • line 112: parseIssueReferences scans and adds every URL before it scans any textual reference in the same title/body. Consequently, text such as See #7 and https://github.com/acme/web/issues/9 returns #9 before #7, contradicting the documented written-order contract and changing the order in which cited issues are displayed. [ Out of scope (post-validation triage) ]
  • line 117: parseIssueReferences applies the ten-reference limit before unlinkedIssueReferences removes issues already returned by the host. A body with ten host-linked closing references followed by a distinct cited issue returns only the first ten, which are then all filtered out, so the distinct issue is never looked up or shown despite requiring just one lookup. Limit the unlinked references instead. [ Already posted ]
apps/web/src/components/issue/IssueAssigneePicker.tsx — 0 comments posted, 1 evaluated, 1 filtered
  • line 77: After a successful assignment, all still contains the pre-write isAssigned flags until the candidates refresh completes. If the user immediately toggles another person, next is rebuilt from that stale list and the second replacement write omits the first person (for example, assign Ada, then immediately assign Grace sends only Grace), silently undoing the first assignment. [ Already posted ]
apps/web/src/components/issue/IssueCreateDialog.tsx — 1 comment posted, 2 evaluated, 1 filtered
  • line 397: hasChoice ignores offer.blankIssuesEnabled, so a repository whose template config disables blank issues but has no templates or contact links is treated as having “nothing to choose” and is forced into the blank composer. The create service only checks the provider capability, not this repository setting, so this path files an issue even though the repository explicitly disallowed blank submissions. [ Already posted ]
apps/web/src/components/issue/IssueLabelPicker.tsx — 0 comments posted, 1 evaluated, 1 filtered
  • line 111: written.base remains the original appliedKey after every successful toggle. If a user adds B, then adds C before the detail refresh from the B write returns, that first refresh supplies [A, B]; it no longer matches the original base [A], so current reverts to [A, B] even though C was just successfully written. A subsequent toggle then sends a replacement set built without C, silently removing C from the issue. [ Already posted ]
apps/web/src/components/issue/IssuesPanel.tsx — 0 comments posted, 2 evaluated, 2 filtered
  • line 442: A failed continuation hides all rows already loaded. After scrolling triggers a second-page request, ordered still contains the first page, but a failed query has data === null; this condition therefore replaces those retained entries with IssuesUnavailableState. The user loses access to successfully loaded issues and the only retry repeats the failed continuation, despite the component's pagination logic explicitly retaining the prior rows. [ Already posted ]
  • line 444: When the sole project returns a per-project listing failure (for example its issue tracker is disabled), IssueService returns a successful IssueListResult with an empty entries array and a populated errors array. This component ignores answered.errors, so line 444 renders “This repository has no issues to open” instead of an unavailable/error state, falsely presenting an unreadable tracker as an empty repository. [ Exceeded comment limit ]
apps/web/src/components/issue/issueList.logic.ts — 0 comments posted, 1 evaluated, 1 filtered
  • line 83: filterIssueQueryResults decides that a row was searched from entry.host alone. The contracts explicitly allow two adapters on one host, but callers build searchingHosts from a provider's host; if one adapter searches remotely and the other does not, every row for that host is retained as a presumed host match. A query can therefore show nonmatching issues from the non-searching provider instead of applying the required local filter. [ Exceeded comment limit ]
apps/web/src/components/pullRequest/PullRequestDetailPanel.tsx — 0 comments posted, 1 evaluated, 1 filtered
  • line 2722: Enabling onLinkIssues here makes the new “Link with agent” action hand off cross-repository GitHub issue matches to buildLinkIssuesHandoff, which instructs the agent to use the issue's full URL when repositories differ. GitHub closing keywords require OWNER/REPOSITORY#NUMBER for a different repository, not a URL, so a selected cross-repository match is merely linked rather than closed when the pull request merges. [ Out of scope (triage) ]
apps/web/src/components/sourceControl/ListFilterMenu.tsx — 0 comments posted, 1 evaluated, 1 filtered
  • line 43: ALL_PROJECTS_VALUE is a valid ProjectId: the shared contract only requires a non-empty trimmed string. If a persisted/imported project has ID "all", both its radio item and the "All projects" row use that value, and onValueChange always converts it to undefined; that project can never be selected to filter the list. [ Out of scope (post-validation triage) ]
apps/web/src/lib/openIssueLink.ts — 0 comments posted, 2 evaluated, 2 filtered
  • line 156: findProjectForIssue compares the raw checkout host and repository path to a browser URL. Azure SSH checkouts use identities such as ssh.dev.azure.com/v3/org/project/repository, while linked Azure items use https://dev.azure.com/org/project/_git/repository/...; both the host check at line 156 and the later path comparison fail. Consequently linked Azure issues/PRs from SSH-cloned projects always fall back to the browser instead of opening in the workspace panel. [ Exceeded comment limit ]
  • line 189: findProjectForLink extracts new URL(link.url).hostname, which drops the port, but sourceControlHostOf deliberately returns remote.host (including the port) for Forgejo identities. Thus a project cloned from https://forge.example:3000/... cannot match a linked item at that same URL: forge.example is compared with forge.example:3000, and the item is unnecessarily opened externally. [ Out of scope (post-validation triage) ]
apps/web/src/rightPanelStore.ts — 0 comments posted, 1 evaluated, 1 filtered
  • line 96: The new per-issue environmentId is never used when rendering the tab: ChatView passes activeThread.environmentId to IssueDetailPanel even for an issue surface carrying a different server. Opening an issue from a multi-server Issues/PR list therefore fetches the same project/reference from the thread's server rather than the server that supplied the selected issue, producing the wrong issue or a not-found panel. [ Already posted ]
apps/web/src/routes/_chat.issues.tsx — 0 comments posted, 6 evaluated, 5 filtered
  • line 424: updateSearch never serializes next.label into its returned IssuesSearch. Selecting a label via updateListScope (or performing any later URL update while a label is active) therefore removes label from the route state, so the list immediately becomes unfiltered instead of retaining/applying the chosen label. [ Already posted ]
  • line 1073: When the route initially loads (or reloads) with a host search parameter, hosts starts empty and this effect merges only the filtered response, which contains just that host. activeHosts consequently has length one and showProvider hides the provider control, leaving no UI action to clear the host filter and return to all providers. [ Exceeded comment limit ]
  • line 1126: creating is initialized to false and no code in this route ever calls setCreating(true). Consequently IssueCreateDialog is permanently closed, so users have no reachable UI path to create an issue from the new Issues workspace. [ Previously rejected ]
  • line 1187: The empty-state filtered flag omits search.label. For a URL containing a label filter that has no matches, the UI reports the unfiltered “No issues” state instead of explaining that the active filter excluded all issues. [ Out of scope (post-validation triage) ]
  • line 1320: The label-menu handler passes { label } to updateListScope, but that reaches updateSearch, whose reconstructed IssuesSearch omits label. Selecting a label therefore immediately removes it from the URL/state, leaving the label filter unable to apply. [ Already posted ]
apps/web/src/routes/_chat.pull-requests.tsx — 0 comments posted, 3 evaluated, 3 filtered
  • line 2055: onOpenLinkedPullRequest passes link.repository directly into the panel target. findProjectForLink deliberately accepts Azure DevOps links whose org/project path is only a prefix of the configured org/project/repository, but the target must use the project's repositoryIdentity.displayName (as repositoryForProjectLink does in the Issues route). Consequently, opening such a linked PR creates a reference the server refuses to read instead of showing the linked PR. [ Exceeded comment limit ]
  • line 2059: After opening the linked PR without a host, this updateSearch call leaves the prior tab's selectedHost in the URL. The linkedSelection effect then reopens the same PR with that stale host; because pullRequestSurfaceId includes host, this produces a second tab (and can attach the wrong host for a cross-host link). Set the linked project's host or clear selectedHost when updating the selection. [ Exceeded comment limit ]
  • line 2123: onOpenLinkedIssue stores the URL link's repository path instead of the resolved project's repositoryIdentity.displayName. In particular, findProjectForLink accepts Azure DevOps issue URLs with an org/project prefix while the configured project identity includes the repository; this target pairs that shortened path with the project id and the detail request is rejected rather than displaying the linked issue. [ Already posted ]
docs/user/source-control.md — 0 comments posted, 2 evaluated, 2 filtered
  • line 148: Track Issues Beside the Work is introduced with a level-3 heading immediately after ## Troubleshooting, so Markdown nests the primary issue-tracking feature under troubleshooting. It will appear as a troubleshooting subtopic in the document hierarchy/TOC rather than a top-level feature section. [ Exceeded comment limit ]
  • line 155: The supported-provider list omits Linear even though the shipped LinearIssueProvider exposes issues with provider: "linear". Users following this new issue-tracking documentation will be told only the four source-control hosts are supported and may not configure or look for Linear issue tracking. [ Exceeded comment limit ]

Summary by CodeRabbit

  • New Features
    • Added issue tracking for GitHub, GitLab, Bitbucket, Azure DevOps, and Linear.
    • Browse, search, filter, view, comment on, edit, label, assign, react to, create, close, and reopen supported issues.
    • Added Linear account and project connection management.
    • Added issue tabs, an Issues workspace, composer search, and pull-request issue links.
    • Added AI-assisted task generation and related/duplicate matching.
  • Bug Fixes
    • Improved cleanup, secret handling, pagination, error reporting, and stale-result protection.
  • Documentation
    • Added issue-tracking guidance.

@coderabbitai

coderabbitai Bot commented Aug 12, 2026

Copy link
Copy Markdown

Review Change StackReview Change Stack

Important

Review skipped

We couldn't safely recover the incremental review. No full review was started, and the last reviewed checkpoint was preserved. Retry later, or explicitly request a full review by commenting @coderabbitai full review.

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

This pull request adds a cross-provider issue tracking system for GitHub, GitLab, Bitbucket, Azure DevOps, and Linear. It adds an issue service with caching, work item matching and task generation across text generation providers, pull request to issue linking, and the related web UI, state management, routing, and contract changes. It also includes small unrelated fixes.

Changes

Issue Tracking Feature

Layer / File(s) Summary
Shared contracts and schemas
packages/contracts/src/issue*.ts, packages/contracts/src/workItem.ts, packages/contracts/src/sourceControl.ts, packages/contracts/src/settings.ts, packages/contracts/src/rpc.ts, packages/contracts/src/vcs.ts
Defines issue, issue tracking, work item, source control, settings, and RPC schemas shared by server and web code.
Azure DevOps issue provider
apps/server/src/issue/AzureDevOpsIssueCli.ts, AzureDevOpsIssueProvider.ts, azureDevOpsIssueJson.ts, tests, VcsProcess.ts, GitLabCli.ts
Implements the Azure DevOps issue CLI, JSON decoding, provider adapter, and a new state-rule failure classification.
Bitbucket issue provider
apps/server/src/issue/BitbucketIssueApi.ts, BitbucketIssueProvider.ts, bitbucketIssueJson.ts, tests
Implements the Bitbucket issue API, JSON decoding, and provider adapter.
GitHub issue provider
apps/server/src/issue/GitHubIssueCli.ts, GitHubIssueProvider.ts, gitHubIssueJson.ts, tests
Implements the GitHub CLI-backed issue service, JSON decoding, and provider adapter.
GitLab issue provider
apps/server/src/issue/GitLabIssueCli.ts, GitLabIssueProvider.ts, gitLabIssueJson.ts, tests
Implements the GitLab issue CLI, JSON decoding, and provider adapter.
Linear API and connection management
apps/server/src/issue/LinearApi.ts, LinearConnection.ts, LinearIssueProvider.ts, tests
Implements the Linear GraphQL client, account/binding coordination, and provider adapter.
Issue provider registry and issue service
apps/server/src/issue/IssueProvider.ts, IssueProviderRegistry.ts, IssueService.ts, server.ts, RpcAuthorization.ts, tests
Adds the provider contract, registry, cached read/write service, and server wiring.
Work item matching and prompts
apps/server/src/workItems/WorkItemMatching.ts, apps/server/src/textGeneration/*.ts, apps/server/src/ws.ts
Adds work item task/match generation across text generation providers and WebSocket RPCs.
Reaction JSON and GraphQL budget
apps/server/src/sourceControl/gitHubReactionJson.ts, gitLabReactionJson.ts, githubGraphQlBudget.ts
Adds shared reaction decoding and fixes rate-limit field insertion.
Pull request to issue linking
apps/server/src/pullRequest/*.ts, issueReferences.ts
Adds linked/cited issue resolution across all four hosted pull request providers.
Server settings and secret store fixes
apps/server/src/serverSettings.ts, ServerSecretStore.ts, atomicWrite.ts
Fixes secret permission handling, atomic write cleanup, and settings redaction ordering.
Web: chat view integration
apps/web/src/components/ChatView.tsx, RightPanelTabs.tsx, chat/ChatComposer.tsx, ComposerCommandMenu.tsx, Icons.tsx
Wires issue surfaces, mentions, and links into the chat UI.
Web: issue browsing and editing components
apps/web/src/components/issue/*.tsx
Adds the issue detail panel, summary/timeline tabs, list, filters, create dialog, and pickers.
Web: pull request panel refactor
apps/web/src/components/pullRequest/*.tsx, apps/web/src/components/sourceControl/*.tsx
Refactors pull request UI onto shared source-control components and adds linked-issue actions.
Web: work item selection and AI matching UI
apps/web/src/components/workItems/*.tsx, apps/web/src/state/workItems.ts, workItemSelection.ts
Adds cross-list work item selection and AI task/match UI.
Web: routing, right panel store, and settings
apps/web/src/rightPanelStore.ts, apps/web/src/routeTree.gen.ts, apps/web/src/routes/*.tsx, apps/web/src/lib/openIssueLink.ts, apps/web/src/components/sidebar/SidebarChrome.tsx, apps/web/src/components/settings/*.tsx
Adds issue link resolution, right panel issue surfaces, the /issues route, sidebar navigation, and the Linear settings entry point.
Documentation
docs/user/source-control.md
Documents the new issue browsing and agent handoff features.

Priority: ➖ Normal

Estimated code review effort: 5 (Critical) | ~180 minutes

Sequence Diagram(s)

sequenceDiagram
  participant User
  participant ChatView
  participant IssuesPanel
  participant IssueService
  participant IssueProviderRegistry
  participant IssueAdapter as "Provider Adapter (GitHub/GitLab/Bitbucket/AzureDevOps/Linear)"

  User->>ChatView: Open issues surface
  ChatView->>IssuesPanel: Render list request
  IssuesPanel->>IssueService: list(projectId, filters)
  IssueService->>IssueProviderRegistry: resolveProjects(projects)
  IssueProviderRegistry-->>IssueService: supported project sources
  IssueService->>IssueAdapter: listIssues(input)
  IssueAdapter-->>IssueService: ProviderIssuePage
  IssueService-->>IssuesPanel: IssueListResult
  IssuesPanel-->>User: Render issue rows
Loading
sequenceDiagram
  participant User
  participant WorkItemSelectionBar
  participant WS as "ws.ts RPC"
  participant TextGeneration
  participant WorkItemMatching

  User->>WorkItemSelectionBar: Select work items and click Create task
  WorkItemSelectionBar->>WS: workItemsGenerateTask(items, mode)
  WS->>TextGeneration: generateWorkItemTask(prompt input)
  TextGeneration-->>WS: WorkItemTaskGenerationResult
  WS-->>WorkItemSelectionBar: prompt draft
  WorkItemSelectionBar->>WS: workItemsFindMatches(source, relationship)
  WS->>WorkItemMatching: shortlistWorkItemCandidates(candidates)
  WS->>TextGeneration: findWorkItemMatches(source, shortlist)
  TextGeneration-->>WS: WorkItemMatchGenerationResult
  WS->>WorkItemMatching: resolveWorkItemMatches(generated)
  WS-->>WorkItemSelectionBar: resolved matches
Loading

Merge Risk: 🟠 High · up to b075a

Valid requests can fail, provider content may induce repository reads during generation, and several issue and pull-request actions remain unreliable. These material problems should be fixed before merge.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 43.48% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 322 functions across 134 files. (21 skipp… Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Title check ✅ Passed The title clearly summarizes the primary change: adding multi-provider issue tracking.
Description check ✅ Passed The description thoroughly covers the changes, rationale, UI impact, validation, known limitations, and review status. It does not use the template headings or checklist format exactly, but it provide…
Full details: Docstring Coverage

Explanation

Docstring coverage is 43.48% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 322 functions across 134 files. (21 skipped: 2 unsupported, 19 over the file limit.)

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create a new PR

Comment @coderabbitai help to get the list of available commands.

@github-actions github-actions Bot added vouch:unvouched PR author is not yet trusted in the VOUCHED list. size:XXL 1,000+ changed lines (additions + deletions). labels Aug 12, 2026
Comment thread apps/server/src/issue/AzureDevOpsIssueCli.ts
Comment thread apps/web/src/components/ChatView.tsx Outdated
Comment thread apps/web/src/components/issue/IssueAssigneePicker.tsx Outdated
Comment thread apps/server/src/issue/GitLabIssueCli.ts
Comment thread apps/web/src/lib/openIssueLink.ts Outdated
Comment thread apps/server/src/issue/AzureDevOpsIssueCli.ts Outdated
Comment thread apps/web/src/components/issue/IssueCreateDialog.tsx Outdated
Comment thread apps/server/src/pullRequest/gitHubPullRequestJson.ts
Comment thread apps/web/src/components/issue/issueList.logic.ts Outdated
Comment thread apps/web/src/components/issue/IssueDetailPanel.tsx Outdated

@macroscopeapp macroscopeapp Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed the new Effect service modules under apps/server/src/issue/ (CLI/API wrappers, providers, registry, IssueService), the touched pull-request services, and the contracts/client-runtime additions against the Effect service conventions.

Service shape, layer composition, dependency acquisition (yield* Foo.Foo), namespace imports, Foo["Service"] references, and the runtime boundaries in server.ts/ws.ts all follow the conventions. Two error-modelling findings in the new Azure DevOps issue modules are noted inline.

Posted via Macroscope — Effect Service Conventions

Comment thread apps/server/src/issue/AzureDevOpsIssueCli.ts Outdated
Comment thread apps/server/src/issue/AzureDevOpsIssueProvider.ts Outdated
Bil0000 added a commit to Bil0000/t3code that referenced this pull request Aug 12, 2026
A host reports a link only where somebody used a closing keyword or
cross-referenced the issue, so a pull request whose body says "part of
#12" showed no linked issue at all — which is what our own pingdotgg#6315 does.

The title and body are now read for references too, outside code spans
and fences, and each one is resolved against the host before it is
shown: a number in a body is not proof an issue exists. What resolves
is listed as cited, never as closing — only the host can say what
merging will close — and the host's own links always win.

Bounded at ten, and a failed resolve leaves the host's own links
standing rather than failing the read.
Comment thread apps/web/src/components/issue/IssueCreateDialog.tsx
Comment thread apps/server/src/issue/GitLabIssueCli.ts
Comment thread apps/server/src/issue/GitLabIssueCli.ts
Comment thread apps/web/src/routes/_chat.issues.tsx
Comment thread apps/web/src/routes/_chat.issues.tsx
Comment thread apps/server/src/issue/GitHubIssueCli.ts
Comment thread packages/contracts/src/issue.ts
Comment thread apps/server/src/issue/gitHubIssueJson.ts
Comment thread apps/web/src/components/issue/IssueCreateDialog.tsx
Comment thread apps/web/src/components/issue/IssueCreateDialog.tsx Outdated
Comment thread apps/web/src/components/issue/IssueDetailPanel.tsx Outdated
Comment thread apps/web/src/components/issue/IssuesPanel.tsx Outdated
Comment thread apps/web/src/components/issue/IssuesPanel.tsx
Comment thread apps/web/src/components/RightPanelTabs.tsx
Comment thread apps/web/src/components/issue/IssuesPanel.tsx
Comment thread apps/web/src/components/issue/IssueDetailPanel.tsx Outdated
Comment thread apps/web/src/components/issue/IssueDetailPanel.tsx
Comment thread apps/web/src/components/issue/IssuesPanel.tsx
Comment thread apps/web/src/components/issue/IssueAssigneePicker.tsx
Comment thread apps/web/src/components/issue/IssuesPanel.tsx
Comment thread apps/web/src/routes/_chat.pull-requests.tsx
Bil0000 added 18 commits August 12, 2026 17:10
Reading and writing the last list for an environment was copied whole: the same key,
the same guarded storage, the same page of rows kept and the same refusal to cache a
failure or a cursor. What a row is arrives as the caller's schema and what the key is
called as its prefix; the priority groups are sliced by whatever the surface files
them under, so Assigned and Reviewing need no name here.
Closing the dialog put the chooser back but kept the title, body, labels, assignees
and the project that had been picked, so the next "New issue" could open straight
onto a discarded draft — on a repository with no chooser, one keypress from filing it.
The guard was `filing`, which is only true a render later: a double click or a held
⌘ Enter got through it twice and filed the same issue twice.
⌘ Enter on the starting points filed an issue from whatever was still in the boxes:
the Create button is absent there, but the shortcut is not, and `canFile` never asked
whether a starting point had been taken.
Two fixes that landed in one commit while several agents worked this
branch at the same time.

Azure DevOps: the provider's `detail` copied `cause.message`, and its
own message is derived from that detail, so a failure said the same
sentence twice. It reads the error's own `detail` now, like every other
provider here.

GitLab: a continuation offset into the listing by a row count, so an
issue touched between two reads shifted every row past the boundary.
It carries on from `updated_before` instead, inclusively, which is what
the other two hosts already do; the service drops the rows it has
already sent.
@Bil0000

Bil0000 commented Sep 17, 2026

Copy link
Copy Markdown
Contributor Author

Addressed the audit blockers in this revision:

  1. Removed branch-only migrations (c50138553f): legacy team maps, credential migration, and old viewer cache keys are gone. Tracker status is now read-only.
  2. Added provider-neutral issueTrackers.status/connect/disconnect/bind RPCs, generic account/project contracts, issueTracking.connections, and provider-scoped secret names (89c1a51864). Connections are keyed by provider so partial settings updates preserve other trackers. The adapter owns connection behavior; WebSocket routing has no Linear-specific dispatch.
  3. Added supported sorts, reference style, and closing-via-PR capabilities (7d2301b4dc). The client and prompt paths use those values, and repository links come from adapter metadata. Tests cover a non-built-in tracker. The Azure URL parser still recognizes Azure URL grammar before a provider is resolved; that is URL parsing rather than a behavior gate. Reaction sort IDs remain stable, but only adapters advertising each sort enable it.
  4. Documented primary-environment-only Issues browsing as a follow-up in the description and user docs. The docs now include Linear setup and explicitly state that Forgejo issues are unsupported (271f244a48).
  5. Extracted the three shared write fixes into separate, tested branches: atomic writes, secret permissions, and settings saves. Their PRs are prepared but publishing them is pending explicit approval. The feature retains these dependencies until they merge.

All 16 Macroscope threads were verified and addressed or explained. Current-main conflict resolution retains the PR-panel action fix. Focused tests, 195 server integration tests, and scoped server/web typechecks pass. Final head e1714fd63a passes Check (lint, unused code, typechecks, desktop build), Test, all three server test shards, Rust, and Release Smoke. All 144 review threads are resolved. Shared/contracts typechecks and 33 shared settings tests pass too.

A fresh Macroscope correctness pass is currently blocked by the workspace cost limit (estimated $52.91 against $15 per review). Approvability also requires human review of the feature. No review budget or protection settings were changed. CodeRabbit was skipped as requested by the contributor.

@juliusmarminge

Copy link
Copy Markdown
Member

Re-audit of e1714fd

Verdict: the architectural blockers from the first audit are resolved. What's left is a merge conflict, the three carve-out PRs, and one contract question worth deciding before the tracker shape freezes. CI is green on this head (Check, Test, all three server shards, Rust, Release Smoke). Macroscope skipped its correctness pass on cost grounds, so no bot has reviewed this head.

The five "fix first" items

  1. Branch-only migration machinery: gone. projectTeams, syncLegacyBindings, migratedCredentialId, linear.api-token, and the updateSettings intercept in ws.ts no longer exist. Settings collapsed to issueTracking.connections[provider].projectBindings.
  2. Provider-named RPCs: fixed properly. linear.* is replaced by issueTrackers.{status,connect,disconnect,bind} with provider in the payload (issueTracking.ts). The seam is right: IssueAdapter.tracker?: IssueTracker, and ws.ts does issues.tracker(provider, op) and calls through, so a Jira adapter plugs in with zero wire or routing changes. The word "linear" appears in server code only inside LinearIssueProvider.ts.
  3. Capabilities: fixed. IssueCapabilities gained sorts, referenceStyle, closesViaPullRequest. Kind branches in the issue UI are down from ~10 to two: the azure-devops URL-grammar check in openIssueLink.ts (URL parsing, not a behavior gate) and stabilizeLinearProviderSummary, which synthesizes a Linear provider row from settings before the server reports one. That one hardcodes host: "linear.app" and sorts: ["updated"], a small leak but UI convenience rather than architecture.
  4. Single-environment issues page: unchanged, now documented as a follow-up in the description and user docs, with Forgejo explicitly called out as unsupported. Acceptable; the data model already carries environmentId, so the retrofit is contained to the route.
  5. Unrelated write fixes: still in the diff (atomicWrite.ts, ServerSecretStore chmod, serverSettings.ts secret materialization), with the author holding them on three separate branches pending approval to open PRs. The feature depends on them, so the sequence is: land those three, then rebase this to a pure feature diff.

New since the last audit

  • The branch is now conflicting with main in apps/web/src/components/ChatView.tsx. Needs another merge or rebase; CI ran on the pre-conflict head.
  • The tracker contract bakes in "connect = paste a token": IssueTrackerConnectInput = { provider, token } and IssueTracker.connect(token). Linear supports OAuth 2.0 with PKCE (no client secret needed on the user's server), which would be strictly better hygiene than a long-lived API key: 24h tokens, scoped consent, server-side revoke on disconnect. If we want that path later for Linear or Jira, connect needs a two-step shape (start → authorization URL, complete → code/state) with token-paste as one mode, and the stored secret needs room for a refresh token. Not a blocker, but it's the one remaining piece of wire surface that gets awkward to change after shipping, so worth a maintainer decision now even if the OAuth implementation itself is a follow-up.

Still open, non-blocking

Unchanged from the first pass: the copy-pasted SWR/epoch cache and unknown-kind refinement between IssueService and PullRequestService, the three copies of list orchestration on the web (_chat.pull-requests.tsx, _chat.issues.tsx, IssuesPanel.tsx), the half-adopted sourceControl/* extraction on the PR side, and the ~400 lines of workItems.* orchestration in ws.ts rather than a WorkItemService. All sensible follow-ups.

Verification limits

Read-only. I verified the migration removal, RPC/settings shape, capability additions, kind-branch count, docs text, and conflict state directly against e1714fd. I did not re-read the adapter bodies, the test delta, or the three carve-out branches. No browser run.

@Bil0000

Bil0000 commented Sep 18, 2026

Copy link
Copy Markdown
Contributor Author

Follow-up to the re-audit:

  • Resolved the ChatView conflict against current main while preserving both the issue-panel controls and the new composer/scroll measurements. The Issues page now supplies the new web/desktop shortcut context too.
  • At the contributor request, all three shared write fixes remain in this PR. No carve-out PRs were opened. Their existing focused tests remain in the feature branch, and the description no longer lists prerequisite PRs.
  • For this release, tracker connect is explicitly an API-key operation. OAuth remains a follow-up, as allowed by the re-audit. That path can add authorization start/complete RPCs and provider-scoped refresh-token records while preserving the current token input for API-key callers. No unused OAuth machinery was added. This scope choice is recorded in the description for maintainer review.

Validation: 480 focused tests pass, including shared writes, chat/PR-panel logic, and keyboard shortcuts. The scoped web typecheck passes. CI passes on b27ef8ec0b: Check, Test, all three server shards, Rust, and Release Smoke. GitHub reports MERGEABLE/CLEAN. No browser session or live tracker writes were used.

Resolves the PullRequestTimelineTab import conflict by keeping the shared
sourceControl timeline pieces and adopting PullRequestEditButton from main,
and renames Config.string to Config.String for the Effect rc.115 bump.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@Defmon3

Defmon3 commented Sep 18, 2026

Copy link
Copy Markdown

@Bil0000 Following up on your invitation to stack the Repository proposal on this PR: I refreshed against your current 3033fdac0 head and split the replacement into four open review units:

  1. Server API
  2. History client
  3. Repository pane
  4. Issues integration

Each shows only its own layer. The first targets your Issues branch; the remaining three target the preceding branch in my fork. I tested every cumulative layer on a dev server, including paging, file diffs, tab state, and shared issue filters. The unrelated general fixes remain separate.

Short interaction demo. Current screenshots and verification limits are in the descriptions. The old combined proposal is superseded, with its original images and discussion preserved.

Does History and the combined Repository pane fit the direction you want as a follow-up to #6315? The server and History layers are still substantial; this split is intended to make their dependencies and review scope clear.

@Bil0000

Bil0000 commented Sep 19, 2026

Copy link
Copy Markdown
Contributor Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Sep 19, 2026

Copy link
Copy Markdown
⚠️ Action not completed

Incremental review skipped.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@Bil0000

Bil0000 commented Sep 21, 2026

Copy link
Copy Markdown
Contributor Author

Fixed the two follow-up UI issues in e3f160f and e7f9a9c:

  • Open issue rows now highlight only on hover. Checked bulk selections and keyboard access are preserved.
  • The issue/PR link form uses the existing flex-column dialog layout, keeping its footer inside the popup, including at phone widths.

Merged current main separately in d6cc1d1 to resolve the PR conflicts while preserving issue links and current PR actions.

Verified: 276 focused tests, web typecheck, scoped lint, and real-app checks for hover, bulk selection, keyboard selection, form validation/cancel, and both link directions at desktop and phone sizes. CI is green on e7f9a9c. CodeRabbit skipped due to an incremental-review checkpoint error; Macroscope skipped due to the PR cost limit.

Defmon3 added a commit to Defmon3/t3code that referenced this pull request Sep 21, 2026
Defmon3 added a commit to Defmon3/t3code that referenced this pull request Sep 21, 2026

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:XXL 1,000+ changed lines (additions + deletions). vouch:trusted PR author is trusted by repo permissions or the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants