Skip to content

PrPoller

Defined in: src/pr-poller.ts:106

Polls PR status for active sessions and caches it in memory. One gh process runs at a time (sequential awaits) to bound the synchronous execFileSync blocking in the forge runner and avoid GitHub rate spikes.

Two cadences. The full tick sweep (every intervalMs, default 120s) covers every active session and prunes the cache. A faster fastTick (every fastIntervalMs, default 15s) re-polls only sessions with an open PR — the in-flight ones whose CI/merge/review state can still move. Without it the list overview lagged the detail view (GitRail, which polls its open PR every 15s): checks: "pending" is short-lived and the 120s sweep routinely sampled none then success two sweeps later, never recording the running state, so the list jumped straight to green and never showed the pulsing “CI running” dot. The fast sweep is capped at fastBatch open PRs per tick (round-robin beyond it) so it never fans out one blocking gh per PR over an unbounded backlog.

new PrPoller(store, resolveForge, onChange, intervalMs?, pollDelayMs?, reconcileBranch?, fastIntervalMs?, fastBatch?, ownsPr?): PrPoller

Defined in: src/pr-poller.ts:136

Pick<SessionStore, "list" | "get">

(repoPath) => GitForge | null

(id, git) => void

number = 120_000

number = 1000

Coalescing window for pollSession — bursts of status flips near a turn’s end collapse into one gh call.

(s) => string | null

Called when the stored branch yields no PR: re-resolves the session’s live worktree branch (an agent may have renamed it), persists the adoption, and returns the new branch to retry against — or null when nothing changed.

number = 15_000

Fast cadence for re-polling open PRs (in-flight CI/merge state).

number = 8

Max open PRs polled per fast tick; the rest rotate in on later ticks.

(s, headSha) => boolean | null

Whether a name-matched terminal (merged/closed) PR’s head commit actually belongs to the session’s branch. Guards against gh pr list --head <name> returning a prior, already-merged PR that merely reused this branch name. false → discard the stale PR; true/null → trust it.

PrPoller

drop(id): void

Defined in: src/pr-poller.ts:299

string

void

PrCache.drop


fastTick(): Promise<void>

Defined in: src/pr-poller.ts:180

Accelerated re-poll of in-flight PRs (cached state === "open") so the list overview tracks CI running/transition as live as the detail view, without the 120s sweep’s lag. Capped at fastBatch per tick, rotating so every open PR is covered across a few ticks rather than fanning out one gh per PR each time.

Promise<void>


get(id): GitState | undefined

Defined in: src/pr-poller.ts:293

Read one session’s cached state without materializing the whole map — O(1) for per-request callers (e.g. GET /git) that only need a single key.

string

GitState | undefined

PrCache.get


pollSession(id): void

Defined in: src/pr-poller.ts:266

Targeted poll triggered by an external signal — chiefly an agent finishing a turn, which is when it has most likely just run gh pr create. Surfaces the PR badge within seconds instead of waiting up to intervalMs for the next full sweep. Debounced per session (so a burst of status flips makes at most one gh call); de-duped per session via inFlight, and serialized behind any in-flight sweep through withGh so it never runs gh concurrently with one (queued, not dropped).

string

void


set(id, git): void

Defined in: src/pr-poller.ts:296

string

GitState

void

PrCache.set


snapshot(): Record<string, GitState>

Defined in: src/pr-poller.ts:290

Record<string, GitState>

PrCache.snapshot


start(): void

Defined in: src/pr-poller.ts:303

void


stop(): void

Defined in: src/pr-poller.ts:307

void


tick(): Promise<void>

Defined in: src/pr-poller.ts:159

Promise<void>