/** * The guidance-layer install primitive. * * Extracted from `guidance-install.ts` so compliance packs can reuse the copy, * the containment check and the index merge without reusing its entry point. * `installBundledGuidance` installs *every* layer registered in the content * package's guidance index and is called from `init`, `update`, and a `safe`-tier * doctor migration that auto-applies without prompting — so a pack layer * registered in that index would land in every upgrading project with no pack * requested. This primitive takes an explicit entry list and has no * install-everything mode. * * **The modified-detector is injected, not shared.** `installBundledGuidance` * decides "locally modified" by comparing the on-disk body against the * *currently bundled* body. That is right for framework layers, whose bundled * body is the only reference available, and wrong for packs: a pack whose content * is updated upstream would make every installed layer read as locally edited, so * `remove` would refuse to delete anything and corrected control text would never * land. Packs compare against the hash recorded at install instead. A primitive * that hard-coded either rule would be wrong for one caller. * * Requirements: compliance-packs/AC-63 (single containment definition), and the * behaviour `guidance-layers-never-resolve/AC-1, AC-3, AC-4, AC-5, AC-14` * established, which this file now carries. */ /** One entry in a guidance `index.yaml`. Extra keys are data and are preserved. */ export interface GuidanceIndexEntry { name: string; file: string; [key: string]: unknown; } /** Outcome of an installation pass. */ export interface LayerInstallReport { /** Layer names newly written to disk. */ installed: string[]; /** * Repo-relative paths newly written, including `index.yaml` when it changed. * Kept alongside `installed` so callers never have to reconstruct a filename * from a layer name — the two differ whenever a layer registers a filename * that is not `.md`. */ installedPaths: string[]; /** Layer names already present with identical content. */ alreadyCurrent: string[]; /** Layer names present but modified per the injected detector — left untouched. */ locallyModified: string[]; /** True when the target `index.yaml` gained entries. */ indexUpdated: boolean; warnings: string[]; } /** How a caller decides a layer on disk is not ours to overwrite. */ export type ModifiedDetector = (targetPath: string, bundledBody: string) => boolean; export interface InstallLayersOptions { /** Decides whether an existing target counts as locally modified. */ isModified: ModifiedDetector; /** Repo-relative prefix for `installedPaths`, e.g. `.aidlc/guidance`. */ relPrefix: string; /** Compute the report without writing anything. */ dryRun?: boolean; /** Label used in warnings, e.g. `guidance layer` or `pack 'soc2' layer`. */ label?: string; } /** * Read and validate a guidance `index.yaml`, returning its entries. * * @returns Entries, or null when the file is absent or unusable. */ export declare function readIndexEntries(indexPath: string): GuidanceIndexEntry[] | null; /** * True when `file` is a safe relative name that stays inside `dir`. * * `file` comes out of a YAML index, so it is data, not a constant: an absolute * path or a `..` segment would make `join` escape the guidance directory and, on * the target side, write outside it. Checked lexically **before** any disk access * — ordering this after an existence check is how a sibling defect in this repo * turned an error path into an out-of-bounds oracle. * * Exported so there is exactly one definition of the rule; a pack loader calls * this rather than writing a second one (compliance-packs/AC-63). */ export declare function isContainedRelative(dir: string, file: string): boolean; /** * Copy an explicit list of layers into `targetDir` and merge the target index. * * Non-destructive by construction: a layer the injected detector reports as * modified is left alone, and existing index entries are preserved wholesale * rather than rebuilt, so fields the target owns (notably the retrospective-fed * `lessons` layer's `last_consolidated`) survive. * * @param sourceDir - Directory holding the layer bodies to copy from. * @param targetDir - Directory to install into, e.g. `/.aidlc/guidance`. * @param entries - The layers to install. There is no "everything" mode. * @param opts - Injected detector, path prefix, dry-run flag, warning label. */ export declare function installLayers(sourceDir: string, targetDir: string, entries: GuidanceIndexEntry[], opts: InstallLayersOptions): LayerInstallReport; /** * The framework's modified-detector: the on-disk body differs from the bundled one. * * Correct for bundled framework layers, whose bundled body is the only reference * that exists. Deliberately **not** used for packs — see the module note. */ export declare const bundledBodyDiffers: ModifiedDetector; /** * Drop layer registrations from a target index by name. * * Removing the registration is what makes a layer *inert*, and it is separate from * deleting the file on purpose. When a pack is removed but one of its layers has * been locally edited, the bytes stay (they are the project's now) while the * registration goes — otherwise `loadGuidanceLayers` keeps handing an uninstalled * pack's constraints to every agent, which is the drift state `doctor` classifies * as a defect. * * Never touches the files themselves, and never touches a registration it was not * asked about. * * @returns The names actually removed, so a caller can report accurately rather * than assuming. */ export declare function unregisterLayers(targetDir: string, names: string[], opts?: { dryRun?: boolean; }): string[]; //# sourceMappingURL=layer-install.d.ts.map