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.
132 lines • 7.02 kB
TypeScript
import { type GitRunner } from './project.js';
/**
* The maintenance sweep (#298): a background job that walks the registered repos,
* finds the commits each repo has grown since its last maintenance review, and runs
* the maintainability loop on them. Per-repo review state is a small local file
* (`.the-framework/maintenance.json`, gitignored) recording the last-reviewed commit,
* so a sweep only ever acts on new work. The capacity gate is the existing budget cap
* (`--max-cost`). #298's "check the limit" half is reachable after all — the agent
* reports the account's quota per turn (#517) and on demand (#521) — but this sweep
* does not gate on it yet; that is #519's consumption limits.
*/
/** The per-repo review-state filename under `.the-framework/`. */
export declare const MAINTENANCE_FILE = "maintenance.json";
/** What a repo's last maintenance review recorded. */
export interface MaintenanceState {
/** The HEAD commit the maintenance loop last reviewed (a full SHA). */
reviewedSha?: string;
/** ISO timestamp of that review. */
reviewedAt?: string;
/**
* ISO timestamp of the last automatic codebase-wide sweep (#882). Deliberately separate
* from {@link MaintenanceState.reviewedAt}: that one tracks how far the commit-delta sweep
* (#298) has read, and this one paces a whole-codebase pass that ignores commits entirely.
* Sharing a key would make either feature silently reset the other's schedule.
*/
sweptAt?: string;
}
/**
* How long a repo is left alone between automatic codebase-wide sweeps (#882).
*
* A week, and deliberately not configurable: per #879 the answer to "should this have a
* setting?" is no unless a setting earns itself. The sweep only queues follow-up entries and
* only runs on an idle machine under its quota boundary, so the cost of it being a little too
* eager is a backlog entry, not a bill.
*/
export declare const DEFAULT_MAINTENANCE_INTERVAL_MS: number;
/**
* Whether a repo is due an automatic sweep: never swept, or swept longer ago than the interval.
*
* A never-swept repo is due immediately, which is the case #882 exists for. The commit-delta
* sweep (#298) treats a first-seen repo the opposite way, baselining it at HEAD so its whole
* pre-existing history is never reviewed, and that is precisely the gap this closes.
*
* An unparseable timestamp counts as due: a repo whose state file was hand-edited into nonsense
* should get swept, not fall silently out of the schedule forever.
*/
export declare function maintenanceDue(state: MaintenanceState, now: number, intervalMs?: number): boolean;
/** Minimal fs seam so the state IO is unit-testable without touching disk. */
export interface MaintenanceFs {
read(path: string): Promise<string>;
write(path: string, contents: string): Promise<void>;
mkdir(path: string): Promise<void>;
}
/** The review-state file path for a repo. */
export declare function maintenanceStatePath(cwd: string): string;
/** Read a repo's review state. Forgiving: a missing/unreadable/malformed file yields `{}`. */
export declare function readMaintenanceState(cwd: string, fs?: MaintenanceFs): Promise<MaintenanceState>;
/** Record a repo's review state, creating `.the-framework/` as needed. */
export declare function writeMaintenanceState(cwd: string, state: MaintenanceState, fs?: MaintenanceFs): Promise<void>;
/**
* Record part of a repo's state, leaving the keys not mentioned alone.
*
* Load-bearing since #882: {@link writeMaintenanceState} replaces the file wholesale, and two
* features now write it. The commit-delta sweep (#298) writes `reviewedSha`/`reviewedAt` and the
* automatic sweep writes `sweptAt`, so a wholesale write from either one would silently reset the
* other's schedule.
*/
export declare function mergeMaintenanceState(cwd: string, patch: MaintenanceState, fs?: MaintenanceFs): Promise<void>;
/** What the sweep decided for one repo. */
export type MaintenanceAction = 'baseline' | 'review' | 'skip' | 'error';
/** A repo's assessed maintenance status. */
export interface RepoReview {
/** Registry id, when assessed from the registry. */
id?: string;
/** Absolute repo path. */
path: string;
/** Current HEAD SHA, when resolvable. */
headSha?: string;
/** The last-reviewed SHA, when the repo has been reviewed before. */
reviewedSha?: string;
/** Commits in `reviewedSha..HEAD` (0 for a first-seen or up-to-date repo). */
newCommits: number;
/** What to do: baseline a first-seen repo, review new commits, skip an up-to-date one, or an error. */
action: MaintenanceAction;
/** Context for an `error` or an unusual `review` (e.g. rewritten history). */
note?: string;
}
/**
* Assess one repo: resolve HEAD, read its review state, and count the commits since
* the last review. A never-reviewed repo is `baseline` (we record HEAD without
* reviewing history retroactively); an unchanged repo is `skip`; new commits are
* `review`. A non-repo / missing git is `error` (skipped, never throws). A reviewed
* SHA git no longer knows (rebased away) falls back to `review`.
*/
export declare function assessRepo(path: string, git?: GitRunner, fs?: MaintenanceFs): Promise<RepoReview>;
/** Assess every registered repo, tagging each review with its registry id. */
export declare function planMaintenanceSweep(repos: readonly {
id?: string;
path: string;
}[], git?: GitRunner, fs?: MaintenanceFs): Promise<RepoReview[]>;
/** The tally a sweep returns. */
export interface SweepSummary {
reviewed: number;
baselined: number;
skipped: number;
failed: number;
/** Repos not reached because `maxRepos` was hit. */
pending: number;
}
/** Injected effects for {@link maintainSweep}, so the orchestration is testable off disk/process. */
export interface SweepDeps {
/** Run the maintenance loop on a repo; resolves true on success. */
agent(review: RepoReview): Promise<boolean>;
/** Persist a repo's review state (called after a baseline or a successful review). */
record(path: string, state: MaintenanceState): Promise<void>;
/** Progress line. */
log(message: string): void;
/** ISO timestamp for a recorded review (injected so runs are deterministic in tests). */
now(): string;
/** Stop after reviewing this many repos in one sweep (baselines/skips don't count). */
maxRepos?: number;
}
/**
* Orchestrate a sweep over pre-assessed reviews: baseline first-seen repos (record
* HEAD, no run), skip up-to-date ones, and run the maintenance loop on the rest —
* recording the reviewed SHA only when the agent succeeds, so a failure is retried next
* sweep. Honors `maxRepos`; the remainder is reported as `pending`.
*/
export declare function maintainSweep(reviews: readonly RepoReview[], deps: SweepDeps): Promise<SweepSummary>;
/** Short SHA for logs. */
export declare function short(sha: string | undefined): string;
//# sourceMappingURL=maintenance.d.ts.map