Repository navigation
fix(web): close Issues integration gaps (#25) - #38
Conversation
- Servers advertise an `issues` capability; the Issues list, the sidebar Issues icon, the palette's "Open issues" action and the PRs/Issues switch use only servers that have it, so upstream and older servers no longer answer `issues.list` with an unknown-tag error. - The side panel shows the Issue's linked threads (open one) and its closing and thread-linked pull requests (open on GitHub), read for the one Issue, so it works when opened from a thread's link too. The Issue detail read now carries closing pull requests. - The command palette finds threads by linked Issue: `#N`, `owner/repo#N` or an Issue URL asks `threadsForIssues` on servers with Issue links, debounced and bounded to 20 repositories per server. - Start thread prefers a project on a server that keeps Issue links. - User docs cover linking by hand, unlinking and the MCP tools. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Thread transfer impact✅ Thread transfer remains within every enforced ceiling.
Baseline: unavailable · PR result: Scenario and decoded snapshot size10 historical turns, 5 command tools per turn, 878.9 KiB retained MCP result per historical turn, and a 1.05 MiB retained result in the measured turn.
Updated in place by a trusted workflow. PR artifacts are strictly validated and never executed. |
Review fixes for PR #38: - The palette's Issue lookup sends the Issue's closing pull requests: from the loaded Issues list entry, else, for `owner/repo#N` or a URL, from one debounced Issue read on a server that lists Issues. A bare `#N` the list does not hold finds stored and branch links only; the user docs say so. - An `issue=` link without a usable `selectedEnvironmentId` resolves to a server that lists Issues, one keeping Issue links first, and never to a server without `issues.*`. - The detail read's mapping moves to `issueDetailOf`, with a CI test decoding a fixture with one closing pull request and one null node. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
|
Merging with the Fork Stack Model check failing for a known CI cause unrelated to this change: the workflow on this PR's base ( |
* fix(web): close Issues integration gaps (#25) - Servers advertise an `issues` capability; the Issues list, the sidebar Issues icon, the palette's "Open issues" action and the PRs/Issues switch use only servers that have it, so upstream and older servers no longer answer `issues.list` with an unknown-tag error. - The side panel shows the Issue's linked threads (open one) and its closing and thread-linked pull requests (open on GitHub), read for the one Issue, so it works when opened from a thread's link too. The Issue detail read now carries closing pull requests. - The command palette finds threads by linked Issue: `#N`, `owner/repo#N` or an Issue URL asks `threadsForIssues` on servers with Issue links, debounced and bounded to 20 repositories per server. - Start thread prefers a project on a server that keeps Issue links. - User docs cover linking by hand, unlinking and the MCP tools. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * fix(web): find closing-reference threads from the palette (#25) Review fixes for PR #38: - The palette's Issue lookup sends the Issue's closing pull requests: from the loaded Issues list entry, else, for `owner/repo#N` or a URL, from one debounced Issue read on a server that lists Issues. A bare `#N` the list does not hold finds stored and branch links only; the user docs say so. - An `issue=` link without a usable `selectedEnvironmentId` resolves to a server that lists Issues, one keeping Issue links first, and never to a server without `issues.*`. - The detail read's mapping moves to `issueDetailOf`, with a CI test decoding a fixture with one closing pull request and one null node. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…d status (#25) (#37) * feat(web): show parent threads as working while child threads work (#31) (#33) * feat(web): show parent threads as working while child threads work (#31) Child threads are hidden from the sidebar, so their work never reached the parent row. A shared pure helper derives descendant child-thread activity from thread shells; the sidebar row feeds it through the existing status resolvers (Working pill and timer with "· N agents", child approvals as the parent's approval), and the auto-settle sweep keeps such parents active like threads with live background work. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * docs(fork): record PR for sidebar-child-working (#31) Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * fix(web): surface child input, time from the earliest child (#31) Review fixes: a child waiting on user input now shows the parent's awaiting-input state, and children waiting on input or with any background work (monitoring included) keep the parent from auto-settling. An idle parent's Working timer starts at its earliest working child, and the "· N agents" count sits outside the aria-hidden timer. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * feat(web): browse GitHub Issues next to PRs (#27) (#32) * feat(web): browse GitHub Issues next to PRs (#27) The Pull Requests page gains a PRs/Issues toggle (`view=issues`) and the sidebar an Issues icon. Issues from every GitHub repository of the user's projects are read live through `gh` (one GraphQL search per host page, within the existing GraphQL budget and rate-limit handling), merged across connected environments, and shown as Open, Done or Not planned. Search, sort, repository/label/milestone/parent filters, a parent tree that marks sub-Issues outside the user's projects, and a side panel with body, comments, comment, close and reopen. The command palette searches the listed Issues while the page is open. No storage: upstream tables, migrations and events are unchanged. Upstream edits are allowlisted and mapped under the `issues-browse` feature. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * docs(fork): map the Issues browse PR (#27) Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * fix(web): surface Issues list failures and address review (#27) - Show a failed server or "Load more" page with Retry above the rows that stay, and stop offering "Load more" while it failed. - Toasts for comment and close/reopen carry GitHub's reason. - Locked Issues keep the comment box (GitHub has no viewerCanComment); a note explains and GitHub's refusal is shown. - Count non-GitHub repositories once by host and repository across worktrees, pages and servers. - Palette Issues group follows Actions and appears only once typed. - Remove unused scoreIssueMatch and knip-flagged exports; table tests for issueStateOf and issueSearchQuery; typecheck fix in the live suite. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * feat(server): link GitHub Issues to threads (#28) (#34) * feat(server): link GitHub Issues to threads (#28) Store only non-derivable Issue links in the fork-owned fork_thread_issue_links table (created by the fork, outside upstream migrations and the event log). Derive branch links from conventional <type>/<number>-<slug> branches and closing-reference links from the thread's linked pull requests (real gh) or, for Issues, from the closing pull requests the caller already read. Expose issueLinks.* RPCs (for thread, batched threads for Issues, link, unlink, change push) behind an issueLinks capability, link_issue/unlink_issue/list_thread_issues MCP tools, an Issues section in the "Linked PRs and Issues" panel, and a start-thread-from-Issue action that opens a draft in the matching project, prefills it and links it at once. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * fix(server): keep retried threads' Issue links and refresh on batched changes - Prune deleted threads' links only once deleted over a week ago: a failed first-send bootstrap deletes a thread and the retry re-creates its id. - Deliver change pushes to the client one batch at a time and match a batch if any change names the thread or Issue. - Render the Issues section only where the server advertises issueLinks. - Enable and rename the command palette entry for the linked surface. - Cover caller-supplied closing references in CI with real rows. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * feat(web): computed Issue status with grouping and filters (#29) (#36) * feat(web): computed Issue status with grouping and filters (#29) Each Issue gets one status from the #25 table, first match wins: GitHub state and close reason, open native blockers, closing pull requests (open, draft) with the trusted `review/independent` mark on their head, task-branch links, and whether a linked thread or any descendant child thread works now. The Issues page read gains blockers, closing pull requests with head SHA and the review mark in the same per-page GraphQL query (cost 2 -> 3 per 100 rows); marks count only when the query's viewer posted them. The view groups by status with Done and Not planned collapsed, adds Status and Linked filters, shows linked threads on rows, wires Start thread on rows and the side panel, and opens the side panel from a thread's linked Issue through the `issue` search parameter. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * fix(web): count thread-linked PRs, trust marks across servers, drafts pause (#29) Review fixes for PR #36: - A PR into a non-default branch makes no closing reference, so the Issue's PRs are now its closing PRs plus the open PRs linked to its linked threads, deduped by repository and number. Each host's first search page reads those thread-linked PRs as `resource(url:)` aliases in the same GraphQL request (cost stays 3 per 100 rows with 50 aliases; a missing PR answers null instead of failing the page), and `threadsForIssues` returns each thread's PR keys. - Threads are looked up on every server that keeps Issue links, and a review mark is trusted when any server that listed the Issue runs as its poster; the server now returns the mark's creator and its viewer. - An open draft PR with nobody working reads as Paused; merged PRs keep not counting while the Issue is open. - The status table moves to contracts so the live suite checks it too. - The Issues view subscribes to a working-thread key atom instead of all thread shells, and a row's Start thread waits and ignores repeat clicks. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * fix(server): read only PRs of Issue-linked threads, also without a search (#29) Re-review fixes for PR #36: - Thread-linked pull request candidates now come from threads that link to an Issue (a stored, non-dismissed link or a task branch), through a new `IssueLinks.pullRequestsOfIssueThreads`. Last-synced snapshot state no longer filters them: the same GraphQL read returns GitHub's state. The 50 cap stays as a bound and logs when it truncates. - A server whose repositories a filter excludes still reads its candidates and viewer in a small aliases-only request. - While one row starts a thread, every row's Start button is disabled. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * fix(web): close Issues integration gaps (#25) (#38) * fix(web): close Issues integration gaps (#25) - Servers advertise an `issues` capability; the Issues list, the sidebar Issues icon, the palette's "Open issues" action and the PRs/Issues switch use only servers that have it, so upstream and older servers no longer answer `issues.list` with an unknown-tag error. - The side panel shows the Issue's linked threads (open one) and its closing and thread-linked pull requests (open on GitHub), read for the one Issue, so it works when opened from a thread's link too. The Issue detail read now carries closing pull requests. - The command palette finds threads by linked Issue: `#N`, `owner/repo#N` or an Issue URL asks `threadsForIssues` on servers with Issue links, debounced and bounded to 20 repositories per server. - Start thread prefers a project on a server that keeps Issue links. - User docs cover linking by hand, unlinking and the MCP tools. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * fix(web): find closing-reference threads from the palette (#25) Review fixes for PR #38: - The palette's Issue lookup sends the Issue's closing pull requests: from the loaded Issues list entry, else, for `owner/repo#N` or a URL, from one debounced Issue read on a server that lists Issues. A bare `#N` the list does not hold finds stored and branch links only; the user docs say so. - An `issue=` link without a usable `selectedEnvironmentId` resolves to a server that lists Issues, one keeping Issue links first, and never to a server without `issues.*`. - The detail read's mapping moves to `issueDetailOf`, with a CI test decoding a fixture with one closing pull request and one null node. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…d status (#25) (#37) * feat(web): show parent threads as working while child threads work (#31) (#33) * feat(web): show parent threads as working while child threads work (#31) Child threads are hidden from the sidebar, so their work never reached the parent row. A shared pure helper derives descendant child-thread activity from thread shells; the sidebar row feeds it through the existing status resolvers (Working pill and timer with "· N agents", child approvals as the parent's approval), and the auto-settle sweep keeps such parents active like threads with live background work. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * docs(fork): record PR for sidebar-child-working (#31) Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * fix(web): surface child input, time from the earliest child (#31) Review fixes: a child waiting on user input now shows the parent's awaiting-input state, and children waiting on input or with any background work (monitoring included) keep the parent from auto-settling. An idle parent's Working timer starts at its earliest working child, and the "· N agents" count sits outside the aria-hidden timer. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * feat(web): browse GitHub Issues next to PRs (#27) (#32) * feat(web): browse GitHub Issues next to PRs (#27) The Pull Requests page gains a PRs/Issues toggle (`view=issues`) and the sidebar an Issues icon. Issues from every GitHub repository of the user's projects are read live through `gh` (one GraphQL search per host page, within the existing GraphQL budget and rate-limit handling), merged across connected environments, and shown as Open, Done or Not planned. Search, sort, repository/label/milestone/parent filters, a parent tree that marks sub-Issues outside the user's projects, and a side panel with body, comments, comment, close and reopen. The command palette searches the listed Issues while the page is open. No storage: upstream tables, migrations and events are unchanged. Upstream edits are allowlisted and mapped under the `issues-browse` feature. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * docs(fork): map the Issues browse PR (#27) Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * fix(web): surface Issues list failures and address review (#27) - Show a failed server or "Load more" page with Retry above the rows that stay, and stop offering "Load more" while it failed. - Toasts for comment and close/reopen carry GitHub's reason. - Locked Issues keep the comment box (GitHub has no viewerCanComment); a note explains and GitHub's refusal is shown. - Count non-GitHub repositories once by host and repository across worktrees, pages and servers. - Palette Issues group follows Actions and appears only once typed. - Remove unused scoreIssueMatch and knip-flagged exports; table tests for issueStateOf and issueSearchQuery; typecheck fix in the live suite. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * feat(server): link GitHub Issues to threads (#28) (#34) * feat(server): link GitHub Issues to threads (#28) Store only non-derivable Issue links in the fork-owned fork_thread_issue_links table (created by the fork, outside upstream migrations and the event log). Derive branch links from conventional <type>/<number>-<slug> branches and closing-reference links from the thread's linked pull requests (real gh) or, for Issues, from the closing pull requests the caller already read. Expose issueLinks.* RPCs (for thread, batched threads for Issues, link, unlink, change push) behind an issueLinks capability, link_issue/unlink_issue/list_thread_issues MCP tools, an Issues section in the "Linked PRs and Issues" panel, and a start-thread-from-Issue action that opens a draft in the matching project, prefills it and links it at once. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * fix(server): keep retried threads' Issue links and refresh on batched changes - Prune deleted threads' links only once deleted over a week ago: a failed first-send bootstrap deletes a thread and the retry re-creates its id. - Deliver change pushes to the client one batch at a time and match a batch if any change names the thread or Issue. - Render the Issues section only where the server advertises issueLinks. - Enable and rename the command palette entry for the linked surface. - Cover caller-supplied closing references in CI with real rows. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * feat(web): computed Issue status with grouping and filters (#29) (#36) * feat(web): computed Issue status with grouping and filters (#29) Each Issue gets one status from the #25 table, first match wins: GitHub state and close reason, open native blockers, closing pull requests (open, draft) with the trusted `review/independent` mark on their head, task-branch links, and whether a linked thread or any descendant child thread works now. The Issues page read gains blockers, closing pull requests with head SHA and the review mark in the same per-page GraphQL query (cost 2 -> 3 per 100 rows); marks count only when the query's viewer posted them. The view groups by status with Done and Not planned collapsed, adds Status and Linked filters, shows linked threads on rows, wires Start thread on rows and the side panel, and opens the side panel from a thread's linked Issue through the `issue` search parameter. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * fix(web): count thread-linked PRs, trust marks across servers, drafts pause (#29) Review fixes for PR #36: - A PR into a non-default branch makes no closing reference, so the Issue's PRs are now its closing PRs plus the open PRs linked to its linked threads, deduped by repository and number. Each host's first search page reads those thread-linked PRs as `resource(url:)` aliases in the same GraphQL request (cost stays 3 per 100 rows with 50 aliases; a missing PR answers null instead of failing the page), and `threadsForIssues` returns each thread's PR keys. - Threads are looked up on every server that keeps Issue links, and a review mark is trusted when any server that listed the Issue runs as its poster; the server now returns the mark's creator and its viewer. - An open draft PR with nobody working reads as Paused; merged PRs keep not counting while the Issue is open. - The status table moves to contracts so the live suite checks it too. - The Issues view subscribes to a working-thread key atom instead of all thread shells, and a row's Start thread waits and ignores repeat clicks. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * fix(server): read only PRs of Issue-linked threads, also without a search (#29) Re-review fixes for PR #36: - Thread-linked pull request candidates now come from threads that link to an Issue (a stored, non-dismissed link or a task branch), through a new `IssueLinks.pullRequestsOfIssueThreads`. Last-synced snapshot state no longer filters them: the same GraphQL read returns GitHub's state. The 50 cap stays as a bound and logs when it truncates. - A server whose repositories a filter excludes still reads its candidates and viewer in a small aliases-only request. - While one row starts a thread, every row's Start button is disabled. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * fix(web): close Issues integration gaps (#25) (#38) * fix(web): close Issues integration gaps (#25) - Servers advertise an `issues` capability; the Issues list, the sidebar Issues icon, the palette's "Open issues" action and the PRs/Issues switch use only servers that have it, so upstream and older servers no longer answer `issues.list` with an unknown-tag error. - The side panel shows the Issue's linked threads (open one) and its closing and thread-linked pull requests (open on GitHub), read for the one Issue, so it works when opened from a thread's link too. The Issue detail read now carries closing pull requests. - The command palette finds threads by linked Issue: `#N`, `owner/repo#N` or an Issue URL asks `threadsForIssues` on servers with Issue links, debounced and bounded to 20 repositories per server. - Start thread prefers a project on a server that keeps Issue links. - User docs cover linking by hand, unlinking and the MCP tools. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * fix(web): find closing-reference threads from the palette (#25) Review fixes for PR #38: - The palette's Issue lookup sends the Issue's closing pull requests: from the loaded Issues list entry, else, for `owner/repo#N` or a URL, from one debounced Issue read on a server that lists Issues. A bare `#N` the list does not hold finds stored and branch links only; the user docs say so. - An `issue=` link without a usable `selectedEnvironmentId` resolves to a server that lists Issues, one keeping Issue links first, and never to a server without `issues.*`. - The detail read's mapping moves to `issueDetailOf`, with a CI test decoding a fixture with one closing pull request and one null node. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Problem
The final integration review of #37 found gaps that no component PR owned:
pullRequests, so upstream and older servers answeredissues.listwithUnknown request tag: a permanent error banner and no Load more.Fix
ServerEnvironmentadvertisesissues: true(an optional contract key, likeissueLinks). The Issues list reads only those servers, and the sidebar Issues icon, the palette's "Open issues" action and the PRs/Issues switch show only when a connected server has it. One pure helper,environmentIdsWithCapability, backs the list and theissueLinkschecks.threadsForIssuescall to every server withissueLinks. So it also works when opened from a thread's link, with the row not loaded.issueDetailOf.#N,owner/repo#Nor an Issue URL, the palette asksthreadsForIssueson servers withissueLinks, debounced by 300 ms. A bare#Nis bounded to 20 GitHub repositories per server. Linked threads show first, including archived ones, each once. Plain words and bare numbers stay ordinary searches.owner/repo#Nor a URL, from one debouncedissues.detailread on a server that lists Issues.#Nthat the list has not loaded finds stored and branch links only; the user docs say so.link_issueandunlink_issueMCP tools, the panel's linked work and the palette lookup.resolveIssueProjecttakes a preference, and Start thread prefers a checkout on a server that keeps Issue links, falling back to the first checkout.issue=link resolves its server throughresolveIssuePanelEnvironment. That uses the namedselectedEnvironmentIdonly when that server lists Issues; otherwise it picks a server that lists Issues and checks the repository out, preferring one that keeps Issue links. So a shared link never reaches an upstream server.Proof
Everything below ran at the head of this PR.
ghand GitHub (apps/server:T3CODE_ISSUES_LIVE=1 T3_LIVE_GITHUB=1 vp test run src/issues/ src/issueLinks/): 58 passed, 1 skipped (Browse Issues: list, filters, parent tree and side panel #27's write test, which needs its fixture).merged, which no longer drives Computed Issue status, status grouping and filters #29's status.vp test run src/environment src/issues src/issueLinks src/auth/RpcAuthorization.test.ts src/mcp/McpHttpServer.test.ts: 113 passed, 12 skipped (the live suites). It includes a CI test that decodes a detail fixture with one closing PR node and one null node and maps it throughissueDetailOf.src/server.test.ts: 197/197.vp test run src/components/issues/ src/components/CommandPalette.logic.test.ts src/components/SidebarChildActivity.logic.test.ts: 102 passed. New tests cover:environmentIdsWithCapability;issuePanelPullRequests: order, dedupe, unread state;resolveIssueProjectpreferring anissueLinksserver;resolveIssuePanelEnvironment.issueStatus.test.tsandissueLinks.test.ts: 45 passed.tsc --noEmit -p tsconfig.jsonin apps/server, apps/web, packages/contracts, packages/shared and packages/client-runtime: 0 errors.vp lint: 0 findings in the changed fork files.CommandPalette.tsx,SidebarChrome.tsxandServerEnvironment.tshave 4 warnings both before and after this change.vp fmt --checkon changed files: clean.vp run knip:check: pass.scripts/fork-check.sh: OK.Notes
issues-status. ItssharedFilesaddServerEnvironment.ts,CommandPalette.tsx,SidebarChrome.tsxandcontracts/environment.ts, all already allowlisted.Model: Claude Opus 5.5 (medium) via T3 Code
🤖 Generated with Claude Code