import type { VerificationPipelineRun } from "../verification/types.js"; import type { Plan, PlanContext, WriteAction } from "./plan.js"; import { VerificationReport } from "./verify.js"; export interface WriteSummary { path: string; describe: string; merged: boolean; /** * Effect relative to current disk state. `unchanged` writes are skipped (no * backup); `kept` is a write-once file that already exists (left untouched). */ effect: "create" | "overwrite" | "merge" | "unchanged" | "kept"; } export interface RemoveSummary { path: string; describe: string; /** `remove` = move to `.aih/legacy/`; `delete` = hard-delete (single-slot `.aih.bak` * backup); `absent` = nothing on disk. */ effect: "remove" | "delete" | "absent"; /** Repo-relative destination (`.aih/legacy/…` or `.aih.bak`), when present. */ to?: string; } export interface PlanResult { capability: string; applied: boolean; writes: WriteSummary[]; docs: { describe: string; text: string; path?: string; effect?: "create" | "overwrite" | "unchanged"; }[]; probes: { describe: string; }[]; execs: { describe: string; argv: string[]; ran: boolean; code?: number | null; ok?: boolean; /** Redacted, tail-bounded child stderr. Present only when the action failed. */ stderr?: string; /** Redacted, tail-bounded child stdout, for children that diagnose there. */ stdout?: string; }[]; /** Read-only computed reports surfaced verbatim (text) + machine-readable (`data`). */ digests: { describe: string; text: string; data?: unknown; }[]; backups: string[]; /** Files aih removed (moved to `.aih/legacy/`) or would remove (dry-run). */ removed: RemoveSummary[]; report?: VerificationReport; /** Structured verification sidecar; legacy `report` remains the CLI compatibility surface. */ verification?: VerificationPipelineRun; } /** * Write a single, explicitly-requested analysis artifact (e.g. a `--sarif` report) * to a repo-contained path, transactionally. Returns the backups created (0 or 1). * * DESIGN — why this is NOT gated on `--apply`: the harness invariant "no writes * without --apply" protects the user's MANAGED project surface (bootloaders, * configs, the context dir) from being mutated without consent. A `--sarif` file * is not part of that surface — it is a report OUTPUT the operator requested by * naming its path on the command line, exactly like `report --out` or a test * runner writing `junit.xml`. Naming the path IS the consent. Crucially, the * primary use case — `aih bootstrap-ai --verify --sarif results.sarif` feeding * GitHub code-scanning — runs the drift gate WITHOUT `--apply` (CI must not * regenerate the repo it is gating); apply-gating the artifact would make the flag * a no-op in exactly the scenario it exists for, or force `--apply` to also rewrite * every bootloader. So the artifact is decoupled from the plan's apply gate — but * NOT from its safety machinery: the path is still contained to `root` * ({@link assertContained}) and an overwrite is still backed up to `*.aih.bak` via * {@link FsTransaction}. Re-writing identical bytes is a no-op (no rewrite, no * backup churn), matching {@link executePlan}'s idempotency contract. */ export declare function writeArtifact(ctx: PlanContext, relPath: string, contents: string): string[]; /** Compute final file contents for a write action, applying JSON merge if requested. */ export declare function resolveContents(action: WriteAction, absPath: string): string; /** * Execute a plan. In dry-run (`ctx.apply === false`) nothing is written — the * result still reports exactly what would change. With `ctx.apply` writes are * committed transactionally; with `ctx.verify` probe actions run and populate a * {@link VerificationReport}. */ export declare function executePlan(plan: Plan, ctx: PlanContext, opts?: { skipWorktreeGate?: boolean; }): Promise; /** Human-readable summary of a plan result (used when --json is off). */ export declare function summarizeResult(result: PlanResult): string;