Repository navigation
feat(issues): add issue tracking core with GitHub issues - #19259
juliusmarminge wants to merge 7 commits into
Conversation
Thread transfer impact✅ Thread transfer remains within every enforced ceiling.
Baseline: 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. |
Issue tracking gets its own extension point beside source control so non-git trackers slot in without posing as source-control hosts. This layer adds the `@t3tools/issue-tracker-core` port and driver shape, the `issues.*` contracts and RPCs, an `IssueService` that resolves a project's tracker from its git remote and treats issues outside the project's own scope as read-only, and a GitHub tracker over the existing `GitHubApi`. Web UI, MCP tools, thread links, and the other trackers follow in later layers. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
With Effect 4.0.4 and the ten issue RPCs, typing `toLayer` over the whole WebSocket RPC group hits TypeScript's instantiation depth limit (TS2589, only reported when a single checker sees ws.ts after the orchestration runtime). The checker then gives up and types the handler layer's requirements as `any`, which spreads through the route and server layers into binCli.ts and the CLI tests. The issue RPCs now form `WsIssuesRpcGroup`, implemented by their own `toLayer`, and `WsRpcGroup` merges it with the rest. The wire surface, authorization, and instrumentation are unchanged. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
d929c7f to
cf13507
Compare
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
| ...(input.state === "all" ? [] : [`is:${input.state}`]), | ||
| ...(qualifier === null ? [] : [`${qualifier}:${input.viewer}`]), | ||
| "sort:updated-desc", | ||
| ...(text.length === 0 ? [] : [searchPhrase(text)]), |
There was a problem hiding this comment.
Small one on search: quoting the whole input keeps is:closed from being read as a qualifier, but it also turns the search into a phrase match. On this repo, is:issue "pull request panel" finds 32 issues, while "panel" "pull" "request" finds 68. Quoting each word on its own is just as safe against qualifiers and still finds issues where the words aren't next to each other. Ignore this if the phrase match is intended.
There was a problem hiding this comment.
Good catch, the phrase match wasn't intended. Each word is now quoted on its own in c306735, so is:closed still can't act as a qualifier but the words match apart.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
| repository(owner: $owner, name: $name) { | ||
| viewerPermission | ||
| issue(number: $number) { | ||
| ${ISSUE_ROW_FIELDS} |
There was a problem hiding this comment.
Opening any GitHub issue in the detail panel fails. GitHub rejects the detail query:
Field 'comments' has an argument conflict: {} or {last:"100"}?
ISSUE_DETAIL_GRAPHQL_QUERY interpolates ISSUE_ROW_FIELDS here, which already selects comments { totalCount }. Line 173 then selects comments(last: 100) { … } again. GraphQL won't merge the same field selected twice with different arguments, so the whole request errors. The issue list still works because the search query only uses the row fields.
The detail's comments(last: …) block already asks for totalCount, and RawDetailSchema overrides comments with that page. So the detail query can drop the row's count-only selection:
const ISSUE_ROW_BASE_FIELDS = `number title url state stateReason createdAt updatedAt closedAt
author { login avatarUrl ... on User { name } }
assignees(first: 20) { nodes { login name avatarUrl } }
labels(first: 20) { nodes { name color } }`;
const ISSUE_ROW_FIELDS = `${ISSUE_ROW_BASE_FIELDS}
comments { totalCount }`;Then use ${ISSUE_ROW_BASE_FIELDS} in ISSUE_DETAIL_GRAPHQL_QUERY.
The tests didn't catch this because the tracker test stubs graphql with canned responses and never validates the query text.
Found by running the whole stack (#19259–#19274) merged onto main at 614b432a79 in a dev desktop build. All 17 issues.detail calls failed with this error, while issues.list worked.
There was a problem hiding this comment.
Thanks for running the whole stack. That was a real blocker. Fixed in b72ded8 the way you suggested: the detail query uses ISSUE_ROW_BASE_FIELDS, so comments is selected once. I ran the detail, permission and search queries against a live issue here and GitHub accepts all three. The tracker test now also checks that the detail query names comments once, since its stubbed responses couldn't catch this.
There was a problem hiding this comment.
Confirmed in a dev build of the full stack: opened an issue, commented and closed it without errors.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Question on forks: issue scope follows the canonical repository identity, which prefers the |
Problem
T3 Code can track pull requests but not issues, and non-git trackers such as Linear and Jira have nowhere to plug in.
Change
Adds issue tracking as its own extension point beside source control.
@t3tools/issue-tracker-corepackage: theIssueTrackerApiport,IssueTrackerError, anddefineIssueTrackerDriver. Each tracker declares capabilities (create, edit, comment, labels, assignees, reactions, templates, linked PRs, states, close reasons); clients only offer what a tracker declares.{ tracker, host?, scope, key }(owner/repo+123, or a team key +ENG-123later), and state is{ category: open | closed, name }so tracker-specific states keep their own names. Tenissues.*RPCs; writes require the source-control write scope.IssueTrackerRegistryandIssueService. Project trackers resolve from the project's remote; issues on a repository no project owns are read-only.source-control-github, over the existingGitHubApi.WsIssuesRpcGroup, merged intoWsRpcGroup, with a separate handler layer inws.ts. With Effect 4.0.4, adding them to the single core group pushedServerWsRpcGroup.toLayerpast TypeScript's instantiation depth (a hiddenTS2589that surfaced as a missing-any-service error inbinCli.ts). Wire format, client, and authorization are unchanged. New domains should follow the same pattern.Bitbucket retired its issue tracker and registers none.
Stack
Verification
Targeted typechecks and the new service, GitHub tracker, and RPC authorization tests pass.
Rebuilt from #6315 by @Bil0000, which this stack uses as its reference for host APIs and UX.
Implemented with Claude Opus 5.5 and Claude Fable 5.1 in T3 Code, using the Claude Code harness.
🤖 Generated with Claude Code