import type { GeneratedFile } from "./templates/scaffold-config.js"; import { type ScaffoldState } from "./templates/state.js"; export type UpdateFileStatus = "create" | "skip-modified" | "up-to-date" | "update"; export interface UpdatePlanEntry { /** * Where the previous contents were kept, relative to the target directory and * set only on entries that were actually backed up. Usually `.orig`, but * a taken name pushes it to `.orig.1` and so on, so callers must report * this rather than assuming the suffix. */ backupPath?: string; executable: boolean; newContent: string; path: string; status: UpdateFileStatus; } /** * How a path the state file records but the templates no longer render relates * to what is on disk. * * Deliberately not part of `UpdateFileStatus`: an orphan has no rendered * content, so it cannot honour `UpdatePlanEntry.newContent`, and widening that * union would enrol orphans in every `status !== "up-to-date"` filter -- all of * which mean "pending work to write". */ export type OrphanStatus = "orphan-external" | "orphan-gone" | "orphan-modified" | "orphan-unmodified"; export interface OrphanedFile { path: string; status: OrphanStatus; } export interface UpdatePlan { entries: UpdatePlanEntry[]; /** Paths recorded in the state file that the current config no longer renders. */ orphans: OrphanedFile[]; state: ScaffoldState; stateFile: GeneratedFile; } export declare const readScaffoldState: (targetDirectory: string) => Promise; /** * Re-render templates for a previously scaffolded project and classify every * generated file against what is on disk: * * - `up-to-date`: disk already matches the newly rendered content * - `update`: disk matches the hash recorded at scaffold time, so the file is * unmodified by the user and safe to overwrite with new content * - `create`: the file does not exist on disk * - `skip-modified`: the user changed the file since scaffolding; it is only * overwritten with `--force` * * Paths the state file records but the render no longer produces come back * separately as `orphans`. */ export declare const planUpdate: (targetDirectory: string, state: ScaffoldState) => Promise; export interface OrphanRemovalResult { /** * `removed` — deleted. * `skipped-changed` — the contents changed between the plan and the delete. * `skipped-external` — the recorded path escapes the target directory. * `skipped-missing` — already gone; the goal state held either way. */ outcome: "removed" | "skipped-changed" | "skipped-external" | "skipped-missing"; path: string; } export interface ApplyUpdateOptions { /** Write a `.orig` copy before overwriting a user-modified file. */ backup?: boolean; force?: boolean; /** * Called once per orphan this run tried to remove. A callback rather than a * second return value: `applyUpdatePlan` is public API, and the TOCTOU check * means "requested" and "removed" differ by construction, so the caller * cannot infer this from what it asked for. */ onOrphan?: (result: OrphanRemovalResult) => void; /** Restrict writes *and* removals to these paths; omit for every eligible one. */ only?: readonly string[]; /** Delete unmodified orphans. Ignored unless `force` is also true. */ removeOrphans?: boolean; } /** Suffix for the copy kept when `--force` overwrites a file you changed. */ export declare const backupFileSuffix = ".orig"; export declare const applyUpdatePlan: (targetDirectory: string, plan: UpdatePlan, options?: ApplyUpdateOptions) => Promise; //# sourceMappingURL=update.d.ts.map