/** * Linear adapter — GraphQL fetch helpers for board/issue data. * * There is no project or view configuration: the only server-side filter is * "assigned to the API key's viewer AND carries an `agent-*` label." This * module returns Linear's native status name plus workflow `state.type`; the * task-source factory applies status-name disambiguation and state-type * fallback when building canonical issues. */ import type { LinearClient } from "@linear/sdk"; import type { ResolvedConfig } from "../../config.ts"; import { type WorktreePreparation } from "../../taskSource.ts"; import { type AgentResolution } from "./parsing.ts"; export declare const ISSUES_PAGE_SIZE = 250; export interface Blocker { id: string; title: string; status: string | undefined; /** * Linear workflow `state.type` for the blocker (`unstarted` | `started` | * `completed` | `canceled` | `duplicate` | `backlog` | `triage`). Canonical * classification uses this as a fallback after configured status names. */ stateType: string | undefined; } export interface Issue { id: string; uuid: string; title: string; description: string; status: string; statusId: string; /** Linear workflow `state.type` — canonical classification fallback after status-name matching. */ stateType: string; assignee: string; updatedAt: string; /** * `undefined` unless the task is in Todo with a parseable `agent-*` label * and a known-repo reference in its description — i.e. the dispatcher would * actually pick it up. Non-Todo tasks do not resolve repositories because * that would invite tick-spam warnings on already-finished work. */ repository: string | undefined; /** Parsed from the `agent-*` label when present, including non-Todo tasks for slot logs. */ agent: string | undefined; teamId: string; blockers: Blocker[]; hasMoreBlockers: boolean; /** Linear `Issue.url` — direct web link to the task. */ url: string; /** Linear priority: 1=Urgent, 2=High, 3=Medium, 4=Low, 0=No priority. */ priority: number; worktreePreparation?: WorktreePreparation; } /** * `Issue` narrowed to "this task is for groundcrew". Consumers operate on * the canonical `GroundcrewIssue` from `taskSource.ts`; this internal * variant just shapes the adapter's local Linear type. */ export type GroundcrewIssue = Issue & { agent: string; repository: string; }; /** * Linear task that was silently dropped from `issues` because it has at * least one sub-issue and groundcrew works sub-issues rather than parents. */ export interface ParentSkip { id: string; title: string; childCount: number; } export interface BoardState { timestamp: string; issues: Issue[]; parentSkips: ParentSkip[]; } export interface BoardSource { verify: () => Promise; fetch: () => Promise; } interface BoardSourceDeps { config: ResolvedConfig; client: LinearClient; } export declare function createBoardSource(deps: BoardSourceDeps): BoardSource; export declare function isIssueInProgress(issue: Pick): boolean; export declare function isIssueTodo(issue: Pick): boolean; export declare function isTerminalStateType(stateType: string | undefined): boolean; export declare function isTerminalStatusForIssue(issue: Pick): boolean; /** * Terminal check for a blocker. Driven by Linear's workflow `state.type` so * renamed status columns ("Shipped" instead of "Done") are still classified * correctly. An undefined `stateType` falls through to non-terminal. */ export declare function isTerminalStatusForBlocker(blocker: Blocker): boolean; export interface IssueRelationNode { type: string; issue?: { identifier: string; title: string; state?: { name: string; type?: string; } | null; } | null; } export declare function agentForResolution(resolution: Exclude): string; interface ResolvedIssue { uuid: string; title: string; description: string; repository: string; agent: string; teamId: string; stateType: string; status: string; statusId: string; assignee: string; updatedAt: string; blockers: Blocker[]; hasMoreBlockers: boolean; url: string; priority: number; worktreePreparation?: WorktreePreparation; } export interface RawLinearIssue { uuid: string; title: string; description: string; teamId: string; labels: Array<{ name: string; }>; /** Linear workflow state name, e.g. "Todo", "In Review". May be "" if state was null. */ stateName: string; stateType: string; stateId: string; assignee: string; updatedAt: string; blockers: Blocker[]; hasMoreBlockers: boolean; /** * `true` when the task has at least one sub-issue (child). Parent * tasks are filtered out by `fetchBoard` and never dispatched — * doctor reads this to surface that decision instead of falsely * reporting "would dispatch." */ hasChildren: boolean; /** Linear `Issue.url` — direct web link to the task. */ url: string; /** Linear priority: 1=Urgent, 2=High, 3=Medium, 4=Low, 0=No priority. */ priority: number; } export declare function fetchBlockersForTask(arguments_: { client: LinearClient; task: string; uuid: string; }): Promise; export declare function fetchRawLinearIssue(arguments_: { client: LinearClient; task: string; }): Promise; export declare function fetchInProgressIssueCount(arguments_: { client: LinearClient; }): Promise; export declare function fetchResolvedIssue(arguments_: { client: LinearClient; config: ResolvedConfig; task: string; }): Promise; export declare function warnIfNotEnabledFallback(task: string, agentResolution: AgentResolution, config: ResolvedConfig): void; export declare function blockersFromRelations(relations: IssueRelationNode[]): Blocker[]; export {}; //# sourceMappingURL=fetch.d.ts.map