UNPKG

framework

Version:

The (AI) Framework: turnkey, zero-config AI orchestration that wraps a coding-agent CLI (Claude Code) as a black box and takes you from an idea to a running app. Vite for AI.

75 lines 4.69 kB
import { type GitRunner } from './project.js'; import type { SpikeAssignment } from './auto-pm.js'; /** The first line of a placeholder sibling: the claim, naming the agent that holds it. */ export declare const SPIKE_LOCK_PREFIX = "PENDING:"; /** * How old a PENDING lock must be before it is presumed dead and released. Generous against the * slowest live path — spiking and planning can take hours, on top of a cloud queue — because a * lock released under a live agent re-opens the double-work window the lock exists to close, * while a dead agent's ticket only waits one interval longer. This is a bug-recovery mechanism * that ideally never fires (#1364 review), so erring long costs nearly nothing. */ export declare const SPIKE_LOCK_STALE_MS: number; /** Whether a sibling's content is a PENDING placeholder rather than a real spike or plan. */ export declare function isSpikeLock(md: string): boolean; /** What a lock file holds: the claim line and nothing else, so the check above stays trivial. */ export declare function spikeLockContent(agentId: string): string; /** The commit a batch of locks lands as. Names the count so the history reads as what happened. */ export declare function lockMessage(count: number): string; /** The commit a release lands as. */ export declare function releaseMessage(count: number): string; /** Injectable seams so both operations are unit-testable off disk, git, and GitHub. */ export interface SpikeLockDeps { git?: GitRunner; /** Write one lock file (default `fs.writeFile`). */ write?: (path: string, content: string) => Promise<void>; /** Read one sibling (default `fs.readFile`); a rejection reads as "not a lock". */ read?: (path: string) => Promise<string>; /** Delete one lock file (default `fs.rm`). */ remove?: (path: string) => Promise<void>; /** List `tickets/` (default `fs.readdir`); a rejection reads as an empty directory. */ list?: (dir: string) => Promise<string[]>; /** * Whether any open PR touches `file` (#1313's read, reused): a finished agent's PR carries the * real sibling, so an open one keeps the lock however old it is. `undefined` means the answer * could not be read, which also keeps the lock — releasing on a `gh` hiccup would re-open the * double-work window over a network blip. */ prTouches?: (cwd: string, file: string) => Promise<boolean | undefined>; /** Clock, injectable for tests. */ now?: () => number; /** Override {@link SPIKE_LOCK_STALE_MS}. */ staleMs?: number; /** Progress line. */ log?: (message: string) => void; } /** * Claim `assignments`' tickets for their agents: write both placeholder siblings per ticket, * commit the whole batch in one pathspec-scoped commit, and push it to origin's default branch * ({@link pushLockCommit}). Resolves the subset actually locked — a ticket whose sibling appeared since the candidates * were enumerated is skipped, not overwritten: an existing file is someone's claim or someone's * work, and either outranks this batch. * * A batch whose commit failed is rolled back (the written files removed) and resolves `[]`: * uncommitted placeholders in the user's checkout would be noise git blames on nobody. A batch * whose *push* failed is kept and resolved as locked — the commit still guards every run forked * from this checkout, which is the common case, and the sweep should not stand a healthy local * fan-out down over a network blip. The push is what closes the cross-machine window (#1320), so * its failure is logged rather than swallowed. * * Never throws: this runs on a background tick with nothing to catch it. */ export declare function acquireSpikeLocks(cwd: string, assignments: readonly SpikeAssignment[], deps?: SpikeLockDeps): Promise<SpikeAssignment[]>; /** * Release the PENDING locks whose agents are presumed dead, so a crashed spike does not brick its * ticket forever. A lock is stale exactly when all three hold (#1327's rule): its content is still * the placeholder, no open PR touches it (a finished agent's PR carries the real sibling — the * #1313 claim takes over from here), and its last commit is older than {@link SPIKE_LOCK_STALE_MS}. * An *uncommitted* placeholder is left alone: it is a batch being acquired right now, or a commit * failure {@link acquireSpikeLocks} already rolled back. * * Deletions land as one pathspec-scoped commit, pushed best-effort like the acquisition. * Resolves the released tickets' filenames. Never throws. */ export declare function releaseStaleSpikeLocks(cwd: string, deps?: SpikeLockDeps): Promise<string[]>; //# sourceMappingURL=spike-locks.d.ts.map