import type { BoardRegistry } from '../../boards/index.js'; import type { IntakeStorage } from '../../storage/domains/intake/base.js'; import type { IntegrationStorageHandle } from '../../storage/domains/integrations/base.js'; import type { FactoryProjectsStorage } from '../../storage/domains/projects/base.js'; import type { SourceControlStorageHandle } from '../../storage/domains/source-control/base.js'; import type { WorkItemRow, WorkItemsStorage } from '../../storage/domains/work-items/base.js'; import type { IntegrationContext } from '../base.js'; import type { GithubAppIdentity } from './app-identity.js'; import type { GithubEventRules } from './default-rules.js'; import type { GithubRepositoryPermission } from './integration.js'; import type { ParsedGithubWebhook } from './webhook.js'; export declare function trustedCollaborator(github: GithubRulesIntegration, input: { installationId: number; repository: string; login: string; }): Promise; export declare function sweepTrustLookup(github: GithubRulesIntegration, repository: ReconcileRepository): (login: string) => Promise; export interface GithubRulesIntegration { readonly rules: GithubEventRules; readonly slug?: string; /** * Factory's own GitHub login, used to ignore its own writes. Optional because * not every integration can name itself; when absent, self-recognition falls * back to the configured slug and, failing that, to content Factory stamps * itself (see `FACTORY_TRIAGE_COMMENT_MARKER`). */ readonly identity?: GithubAppIdentity; getRepositoryCollaboratorPermission(installationId: number, repoFullName: string, username: string): Promise; } export interface GithubRulesOptions { github: GithubRulesIntegration; sourceControl: SourceControlStorageHandle; /** Integration-scoped storage; provenance rows are validated at read. */ integrationStorage: IntegrationStorageHandle; projects: FactoryProjectsStorage; storage: WorkItemsStorage; configVersion: string; boards: BoardRegistry; /** Label routes decide which installed board a labelled issue lands on. Absent means Work. */ intake?: Pick; } export declare class GithubRules { #private; private readonly options; constructor(options: GithubRulesOptions); ingest(parsed: ParsedGithubWebhook): Promise<{ status: 'ignored' | 'committed' | 'replayed' | 'missing'; }>; } export interface ReconcilePullRequestState { title: string; url: string; state: 'open' | 'closed'; draft: boolean; merged: boolean; assignees?: string[]; requestedReviewers?: string[]; labels?: string[]; headBranch: string; baseBranch: string; author?: string; createdAt?: string; mergedBy?: string; } export type GithubPullRequestFetcher = (input: { installationId: number; repository: string; number: number; }) => Promise; export interface ReconcileIssueState { title: string; url: string; state: 'open' | 'closed'; /** GitHub close reason: `completed`, `not_planned`, or `duplicate`. */ stateReason?: string; assignees?: string[]; labels?: string[]; author?: string; createdAt?: string; updatedAt?: string; } export type GithubIssueFetcher = (input: { installationId: number; repository: string; number: number; }) => Promise; export interface ReconcileRepository { id: number; fullName: string; installationId: number; } export interface ReconcileSweepSummary { /** Factory-configured repositories included in the sweep. */ repositories: number; /** PRs whose live state was fetched from GitHub. */ checked: number; /** Missed merges replayed through the rules ingress. */ merged: number; /** Missed closes-without-merge replayed through the rules ingress. */ closed: number; /** PRs/issues (or whole repositories) skipped because of an error. */ failed: number; /** Error samples with context, capped at {@link RECONCILE_ERROR_SAMPLE_LIMIT}. */ errors: Array<{ repository: string; pullRequestNumber?: number; issueNumber?: number; error: string; }>; } export type GithubPullRequestReconciler = (repositories: ReconcileRepository[]) => Promise; export declare const RECONCILE_ERROR_SAMPLE_LIMIT = 5; export declare function sameStrings(left: unknown, right: string[] | undefined): boolean; /** * Extracts the issue number a work item tracks, but only when the item * belongs to the given repository. Stricter than * {@link reconcilablePullRequestNumber}: a canonical key with no URL is only * trusted when the intake-stamped `githubRepositoryId` confirms the * repository, because the sweep initiates closes on its own. */ export declare function reconcilableIssueNumber(item: WorkItemRow, repository: ReconcileRepository): number | undefined; export declare function reconciledIssueClosedEvent(repository: ReconcileRepository, issueNumber: number, state: ReconcileIssueState): ParsedGithubWebhook; export declare function reconciledClosedEvent(repository: ReconcileRepository, pullRequestNumber: number, state: ReconcilePullRequestState): ParsedGithubWebhook; /** * State-based safety net for merge signals: webhooks and event-log tailing * can miss a merge (cursor gaps, downtime, terminally failed decisions), so * this sweep compares still-open PR cards against actual GitHub state and * replays the merge through the normal rules ingress when they disagree. */ export declare function createGithubPullRequestReconciler(options: GithubRulesOptions, fetchPullRequest: GithubPullRequestFetcher): GithubPullRequestReconciler; export declare function githubRulesOptions(github: GithubRulesIntegration, context: IntegrationContext): GithubRulesOptions | undefined; export declare function attachGithubRules(github: GithubRulesIntegration, context: IntegrationContext): ((event: ParsedGithubWebhook) => Promise) | undefined; export declare function attachGithubReconciler(github: GithubRulesIntegration, context: IntegrationContext, fetchPullRequest: GithubPullRequestFetcher): GithubPullRequestReconciler | undefined; //# sourceMappingURL=rules.d.ts.map