refactor(integrations): split issue-tracker clients under the max-lines budget (#14704)

The GitLab, GitHub, Jira and Linear integration modules, their two IPC
registrars, and the shared GitHub project types each carried a file-level
`eslint-disable max-lines` and ran 351-614 counted lines against a 300-line
budget. AGENTS.md calls for splitting rather than suppressing, and
config/max-lines-baseline.txt is a shrink-only ratchet, so this removes all
eight suppressions and prunes their entries (341 -> 333).

Pure move, no behavior change. Each client is cut along the seam it already
had: per-operation modules for the issue APIs (create / update / comment /
field options), and for Jira the request queue, site credential store,
authenticated request, and site identity. The two IPC registrars keep their own
handlers and delegate the rest to per-domain sub-registrars, so they remain
real entry points rather than re-export shims.

The IPC surface is proved intact rather than assumed: comparing (method,
channel) multisets between HEAD and the split gives 52 registrations across 52
distinct channels on both sides.

Provider-neutrality is preserved -- GitLab and GitHub keep separate, parallel
module layouts rather than being merged behind a shared abstraction.

Verified: oxlint clean, ratchet passes, typecheck clean, full unit suite green
(the one remaining failure is a pre-existing load flake in an untouched file,
green when re-run serially), no new runtime import cycles among 744 modules,
and no lint suppression added anywhere.
This commit is contained in:
Neil
2026-08-15 18:17:20 -07:00
committed by GitHub
parent 15e1ba3f84
commit 83117f2860
83 changed files with 4051 additions and 3697 deletions
+132
View File
@@ -0,0 +1,132 @@
// Why: the request half of the Project IPC contract, consumed mainly by main
// and preload; kept apart from the ProjectV2 data model in `./project-types`
// so renderer components importing domain shapes don't pull in arg payloads.
import type { GitHubProjectFieldMutationValue, GitHubProjectOwnerType } from './project-types'
import type { GitHubIssueUpdate } from '../issue-mutation-types'
// ─── IPC arg shapes (shared between main, preload, renderer) ──────────
export type GetProjectViewTableArgs = {
owner: string
ownerType: GitHubProjectOwnerType
projectNumber: number
/** GitHub host (e.g. GHES); absent means github.com. */
host?: string
/** View selection precedence: viewId > viewNumber > viewName > first
* TABLE_LAYOUT view. */
viewId?: string
viewNumber?: number
viewName?: string
/** Ephemeral GitHub-search-syntax query that replaces the view's filter for
* this fetch only. The view's stored filter on GitHub is not modified.
* `undefined` uses the view's saved filter; `''` explicitly clears it for
* this fetch and gets a distinct renderer cache key. */
queryOverride?: string
}
export type ProjectWorkItemDetailsBySlugArgs = {
owner: string
repo: string
host?: string
number: number
type: 'issue' | 'pr'
}
export type UpdateProjectItemFieldArgs = {
projectId: string
host?: string
itemId: string
fieldId: string
value: GitHubProjectFieldMutationValue
}
export type ClearProjectItemFieldArgs = {
projectId: string
host?: string
itemId: string
fieldId: string
}
export type UpdateIssueBySlugArgs = {
owner: string
repo: string
host?: string
number: number
updates: GitHubIssueUpdate & { body?: string }
}
export type UpdatePullRequestBySlugArgs = {
owner: string
repo: string
host?: string
number: number
updates: { title?: string; body?: string; state?: 'open' | 'closed' }
}
export type AddIssueCommentBySlugArgs = {
owner: string
repo: string
host?: string
number: number
body: string
}
export type UpdateIssueCommentBySlugArgs = {
owner: string
repo: string
host?: string
commentId: number
body: string
}
export type DeleteIssueCommentBySlugArgs = {
owner: string
repo: string
host?: string
commentId: number
}
export type ListLabelsBySlugArgs = {
owner: string
repo: string
host?: string
}
export type ListAssignableUsersBySlugArgs = {
owner: string
repo: string
host?: string
seedLogins?: string[]
}
export type ListIssueTypesBySlugArgs = {
owner: string
repo: string
host?: string
}
export type UpdateIssueTypeBySlugArgs = {
owner: string
repo: string
host?: string
number: number
/** null clears the issue type. */
issueTypeId: string | null
}
export type ResolveProjectRefArgs = {
input: string
host?: string
}
export type ListProjectViewsArgs = {
owner: string
ownerType: GitHubProjectOwnerType
projectNumber: number
host?: string
}
export type ListAccessibleProjectsArgs = {
/** GitHub host (e.g. GHES); absent means github.com. */
host?: string
}
+103
View File
@@ -0,0 +1,103 @@
// Why: the ok/error envelopes returned by Project IPC calls all share one
// classified error, and they pull in cross-module work-item/comment/user types
// that the ProjectV2 data model in `./project-types` never needs.
import type { PRComment } from './comment-types'
import type {
GitHubIssueType,
GitHubProjectOwnerType,
GitHubProjectSummary,
GitHubProjectTable,
GitHubProjectViewSummary
} from './project-types'
import type { GitHubAssignableUser } from './pull-request-types'
import type { GitHubWorkItemDetails } from './work-item-types'
// ─── Classified errors ─────────────────────────────────────────────────
export type GitHubProjectViewErrorType =
| 'auth_required'
| 'scope_missing'
| 'not_found'
| 'unsupported_layout'
| 'too_large'
| 'schema_drift'
| 'validation_error'
| 'network_error'
| 'rate_limited'
| 'unknown'
export type GitHubProjectViewError = {
type: GitHubProjectViewErrorType
message: string
/** Populated when the error is classifiable from a GraphQL response. Never
* includes tokens or full command stdout. */
details?: { path?: (string | number)[]; code?: string }
}
export type GetProjectViewTableResult =
| { ok: true; data: GitHubProjectTable }
| {
ok: false
error: GitHubProjectViewError
/** Populated for the `too_large` case and best-effort for
* `unsupported_layout` when a cheap count-only query succeeds. */
totalCount?: number
}
export type ListAccessibleProjectsResult =
| {
ok: true
projects: GitHubProjectSummary[]
/** Why: per-org discovery can partially fail (a single org 504s while
* the rest succeed). The picker renders a banner listing the affected
* org logins so the user knows their list is incomplete and can paste
* a URL to reach missing projects. Empty when discovery was clean. */
partialFailures?: { owner: string; message: string }[]
}
| { ok: false; error: GitHubProjectViewError }
export type ResolveProjectRefResult =
| {
ok: true
owner: string
ownerType: GitHubProjectOwnerType
number: number
title: string
host?: string
// Why: when the input is a /views/{n} URL, surface the parsed view
// number so the picker can skip the view-pick step and commit the
// selection directly. Absent for owner/number shorthand and project
// URLs without a /views/ segment.
viewNumber?: number
}
| { ok: false; error: GitHubProjectViewError }
export type ListProjectViewsResult =
| { ok: true; views: GitHubProjectViewSummary[] }
| { ok: false; error: GitHubProjectViewError }
export type ProjectWorkItemDetailsBySlugResult =
| { ok: true; details: GitHubWorkItemDetails }
| { ok: false; error: GitHubProjectViewError }
// ─── Mutations ─────────────────────────────────────────────────────────
export type GitHubProjectMutationResult =
| { ok: true }
| { ok: false; error: GitHubProjectViewError }
export type GitHubProjectCommentMutationResult =
| { ok: true; comment: PRComment }
| { ok: false; error: GitHubProjectViewError }
export type ListLabelsBySlugResult =
| { ok: true; labels: string[] }
| { ok: false; error: GitHubProjectViewError }
export type ListAssignableUsersBySlugResult =
| { ok: true; users: GitHubAssignableUser[] }
| { ok: false; error: GitHubProjectViewError }
export type ListIssueTypesBySlugResult =
| { ok: true; types: GitHubIssueType[] }
| { ok: false; error: GitHubProjectViewError }
-222
View File
@@ -1,13 +1,8 @@
/* eslint-disable max-lines -- Why: this module is the single source of truth for ProjectV2 shapes (settings, IPC payloads, view/field/value types) shared across main, preload, and renderer; splitting risks circular type imports. */
// Why: ProjectV2 shapes are distinct enough from the issue/PR work-item types
// that we keep them in a dedicated module. Preload and main-process callers
// import from here directly — do not re-export through `./types.ts` just to
// match the existing import block; routing through the issue types module
// would obscure ownership of the Project surface.
import type { PRComment } from './comment-types'
import type { GitHubAssignableUser } from './pull-request-types'
import type { GitHubWorkItemDetails } from './work-item-types'
import type { GitHubIssueUpdate } from '../issue-mutation-types'
export type GitHubProjectViewLayout = 'TABLE_LAYOUT' | 'BOARD_LAYOUT' | 'ROADMAP_LAYOUT'
export type GitHubProjectOwnerType = 'organization' | 'user'
@@ -234,84 +229,6 @@ export type GitHubProjectSettings = {
} | null
}
// ─── Classified errors ─────────────────────────────────────────────────
export type GitHubProjectViewErrorType =
| 'auth_required'
| 'scope_missing'
| 'not_found'
| 'unsupported_layout'
| 'too_large'
| 'schema_drift'
| 'validation_error'
| 'network_error'
| 'rate_limited'
| 'unknown'
export type GitHubProjectViewError = {
type: GitHubProjectViewErrorType
message: string
/** Populated when the error is classifiable from a GraphQL response. Never
* includes tokens or full command stdout. */
details?: { path?: (string | number)[]; code?: string }
}
export type GetProjectViewTableResult =
| { ok: true; data: GitHubProjectTable }
| {
ok: false
error: GitHubProjectViewError
/** Populated for the `too_large` case and best-effort for
* `unsupported_layout` when a cheap count-only query succeeds. */
totalCount?: number
}
export type ListAccessibleProjectsResult =
| {
ok: true
projects: GitHubProjectSummary[]
/** Why: per-org discovery can partially fail (a single org 504s while
* the rest succeed). The picker renders a banner listing the affected
* org logins so the user knows their list is incomplete and can paste
* a URL to reach missing projects. Empty when discovery was clean. */
partialFailures?: { owner: string; message: string }[]
}
| { ok: false; error: GitHubProjectViewError }
export type ResolveProjectRefResult =
| {
ok: true
owner: string
ownerType: GitHubProjectOwnerType
number: number
title: string
host?: string
// Why: when the input is a /views/{n} URL, surface the parsed view
// number so the picker can skip the view-pick step and commit the
// selection directly. Absent for owner/number shorthand and project
// URLs without a /views/ segment.
viewNumber?: number
}
| { ok: false; error: GitHubProjectViewError }
export type ListProjectViewsResult =
| { ok: true; views: GitHubProjectViewSummary[] }
| { ok: false; error: GitHubProjectViewError }
export type ProjectWorkItemDetailsBySlugResult =
| { ok: true; details: GitHubWorkItemDetails }
| { ok: false; error: GitHubProjectViewError }
// ─── Mutations ─────────────────────────────────────────────────────────
export type GitHubProjectMutationResult =
| { ok: true }
| { ok: false; error: GitHubProjectViewError }
export type GitHubProjectCommentMutationResult =
| { ok: true; comment: PRComment }
| { ok: false; error: GitHubProjectViewError }
export type GitHubProjectFieldMutationValue =
| { kind: 'single-select'; optionId: string }
| { kind: 'iteration'; iterationId: string }
@@ -319,142 +236,3 @@ export type GitHubProjectFieldMutationValue =
| { kind: 'number'; number: number }
/** YYYY-MM-DD. */
| { kind: 'date'; date: string }
export type ListLabelsBySlugResult =
| { ok: true; labels: string[] }
| { ok: false; error: GitHubProjectViewError }
export type ListAssignableUsersBySlugResult =
| { ok: true; users: GitHubAssignableUser[] }
| { ok: false; error: GitHubProjectViewError }
export type ListIssueTypesBySlugResult =
| { ok: true; types: GitHubIssueType[] }
| { ok: false; error: GitHubProjectViewError }
// ─── IPC arg shapes (shared between main, preload, renderer) ──────────
export type GetProjectViewTableArgs = {
owner: string
ownerType: GitHubProjectOwnerType
projectNumber: number
/** GitHub host (e.g. GHES); absent means github.com. */
host?: string
/** View selection precedence: viewId > viewNumber > viewName > first
* TABLE_LAYOUT view. */
viewId?: string
viewNumber?: number
viewName?: string
/** Ephemeral GitHub-search-syntax query that replaces the view's filter for
* this fetch only. The view's stored filter on GitHub is not modified.
* `undefined` uses the view's saved filter; `''` explicitly clears it for
* this fetch and gets a distinct renderer cache key. */
queryOverride?: string
}
export type ProjectWorkItemDetailsBySlugArgs = {
owner: string
repo: string
host?: string
number: number
type: 'issue' | 'pr'
}
export type UpdateProjectItemFieldArgs = {
projectId: string
host?: string
itemId: string
fieldId: string
value: GitHubProjectFieldMutationValue
}
export type ClearProjectItemFieldArgs = {
projectId: string
host?: string
itemId: string
fieldId: string
}
export type UpdateIssueBySlugArgs = {
owner: string
repo: string
host?: string
number: number
updates: GitHubIssueUpdate & { body?: string }
}
export type UpdatePullRequestBySlugArgs = {
owner: string
repo: string
host?: string
number: number
updates: { title?: string; body?: string; state?: 'open' | 'closed' }
}
export type AddIssueCommentBySlugArgs = {
owner: string
repo: string
host?: string
number: number
body: string
}
export type UpdateIssueCommentBySlugArgs = {
owner: string
repo: string
host?: string
commentId: number
body: string
}
export type DeleteIssueCommentBySlugArgs = {
owner: string
repo: string
host?: string
commentId: number
}
export type ListLabelsBySlugArgs = {
owner: string
repo: string
host?: string
}
export type ListAssignableUsersBySlugArgs = {
owner: string
repo: string
host?: string
seedLogins?: string[]
}
export type ListIssueTypesBySlugArgs = {
owner: string
repo: string
host?: string
}
export type UpdateIssueTypeBySlugArgs = {
owner: string
repo: string
host?: string
number: number
/** null clears the issue type. */
issueTypeId: string | null
}
export type ResolveProjectRefArgs = {
input: string
host?: string
}
export type ListProjectViewsArgs = {
owner: string
ownerType: GitHubProjectOwnerType
projectNumber: number
host?: string
}
export type ListAccessibleProjectsArgs = {
/** GitHub host (e.g. GHES); absent means github.com. */
host?: string
}