/** * GitHub PR-native checkpoint mechanism. * * On request(): opens a draft PR per `bober run` (idempotent — reuses * existing run-tracking PR) and appends a checkpoint comment. Polls the PR * for resolution via: (a) merge → auto-approve all pending, (b) 'approve * ' comment or 'bober/approved-' label, (c) 'reject * ' comment, (d) 'edit \n```...```' * comment. Falls back to disk mechanism with a warning when gh is unavailable. * * Sprint 10 — colocated in mechanisms/ per Sprint 7+8+9 precedent. */ import type { CheckpointArtifact, CheckpointId, CheckpointMechanism, CheckpointOutcome } from "../types.js"; /** Single mockable seam for all `gh` CLI calls. */ export interface GhClient { version(): Promise<{ ok: boolean; stdout: string; }>; authStatus(): Promise<{ ok: boolean; stderr: string; }>; repoView(): Promise<{ url: string; owner: string; name: string; } | null>; prList(headRef: string): Promise>; prCreate(opts: { title: string; body: string; draft: boolean; }): Promise<{ number: number; url: string; }>; prEdit(prNumber: number, body: string): Promise; prReady(prNumber: number): Promise; prComment(prNumber: number, body: string): Promise; prView(prNumber: number): Promise<{ state: string; merged: boolean; labels: Array<{ name: string; }>; comments: Array<{ id: number; body: string; createdAt: string; }>; }>; } /** Default GhClient implementation — wraps execa. */ export declare function createGhClient(cwd: string): GhClient; export interface PrMechanismOptions { /** Default 30_000ms; floor 10_000ms (GitHub rate limits). Configurable via pipeline.prPollMs. */ pollMs?: number; /** Default 7d; matches disk cap. */ timeoutMs?: number; /** Required — one PR per run, reused across checkpoints. */ runId?: string; /** Used in the PR title — e.g., "bober(run-XXX): ". */ featureName?: string; /** * Override the current branch head ref (normally auto-detected via git). * Inject this in tests to avoid calling the real git binary. */ headRef?: string; } /** Parsed resolution signal from PR state + comments + labels. */ type PrSignal = { type: "approve"; } | { type: "reject"; feedback: string; } | { type: "edit"; editDelta: { before: string; after: string; }; } | { type: "merge"; } | null; export declare class PrCheckpointMechanism implements CheckpointMechanism { private readonly gh; private readonly fallback; private readonly options; private readonly now; private readonly cwd; /** Cached PR number for this run — set on first request(), reused thereafter. */ private runPrNumber; /** Per-checkpoint states — updated as checkpoints are added and resolved. */ private checkpointStates; /** Number of in-flight request() calls. Used to defer prReady until all requests finish. */ private inFlightCount; /** Pending prReady timer handle — cancelled if a new request() starts before it fires. */ private prReadyTimer; /** * @param gh - Mockable GhClient. Tests pass a fake; prod uses createGhClient(cwd). * @param fallback - Mechanism used when gh is unavailable. Defaults to DiskCheckpointMechanism * rooted at /.bober/approvals. MUST be disk (not cli/noop) per evaluator note. * @param options - poll/timeout/runId/featureName. * @param now - Clock injection for deterministic timeout tests (matches disk.ts:69). * @param cwd - Working directory, defaults to process.cwd(). */ constructor(gh: GhClient, fallback?: CheckpointMechanism, options?: PrMechanismOptions, now?: () => number, cwd?: string); request(checkpoint: CheckpointId, artifact: CheckpointArtifact): Promise; /** Check if gh is available and the repo has a GitHub remote. */ private checkAvailability; /** Find existing run PR or create a new one. Caches the PR number for the run. */ private ensureRunPr; /** Render the PR body with a per-checkpoint checkbox list. */ private renderPrBody; /** Render a checkpoint comment to post on the PR. */ private renderCheckpointComment; /** Poll the PR until it resolves (merge / approve / reject / edit) or times out. */ private pollPrUntilResolved; } /** * Parse PR state + comments + labels to determine the resolution signal. * Strict parsing — rejects typos like 'approveeee' or 'aproove'. */ export declare function parseSignals(view: { state: string; merged: boolean; labels: Array<{ name: string; }>; comments: Array<{ id: number; body: string; createdAt: string; }>; }, checkpoint: CheckpointId, artifact: CheckpointArtifact): PrSignal; export {}; //# sourceMappingURL=pr.d.ts.map