import type { EccEffectiveSelectionComponent, EccSelectionEvidence } from "./materialization-selection.js"; import type { EccMaterializationComponentInput } from "./materialization-types.js"; /** * F4: the target adapter for governed materialization, parameterized by target. * * The F2 resolver reports WHICH components are authorized to materialize; the * F1 engine writes bytes it is handed. Neither knows where a component's * content lands for a given target. This module is that join: it takes the * resolver's evidence-passed components, the source root holding the pinned * framework content, and the REQUESTED target set, and produces the `files` * each component needs — destination-relative path, exact bytes, operation kind. * * AIH-direct (ruling 5). The framework's own profile installer is never * invoked, required, or spawned here: the adapter reads bytes out of a pinned * checkout and hands them to AIH's engine, which is what makes per-component * control possible at all. * * Two pieces of knowledge already exist in this repository and are reused * rather than restated — `eccComponentSourcePaths` (which source paths a * component owns) and `eccContentDestinationMapping` (where one source path * lands for one target). A second copy of either would be free to drift from * the governed classifier that polices the same boundary. That mapping is * already target-aware, so ONE resolver serves every target; a per-target copy * of this file would be a second answer to the same question. * * Ownership kind: every file this adapter emits is `copy-file`. A framework * content destination — a skill directory, an agent definition, a rule file, * the plugin marketplace document — is a whole document authored end to end by * exactly one component, so whole-file ownership is what makes removal honest: * uninstall takes the file, and an existing operator file at the same path * refuses instead of being absorbed. Named-JSON-key ownership exists for * destinations SHARED with an operator or another writer, and every such * destination a framework target has is owned by other AIH lifecycles — client * settings belong to the hook registrar and usage-hook lifecycle, and MCP * configuration (`.mcp.json`, `mcp.json`, `opencode.json`, `config.toml`) * belongs to the managed MCP projection — so this adapter never merges into any * of them and refuses a component whose content would land there. * * Refusals are reported, never silently trimmed, and they are PER TARGET: a * component materializes for a target only when every file it declares has an * owned content destination for THAT target that can be read; otherwise that * target refuses it whole, by name, with the offending source path. Partial * materialization would install something other than what was selected while * the receipt claimed the component entire. */ /** * The six targets the governed materialization lifecycle is ruled for. * Everything else — zed, gemini, antigravity, copilot, windsurf — waits, * and says so by name rather than by silently doing nothing. */ export declare const GOVERNED_MATERIALIZATION_TARGETS: readonly ["claude", "codex", "kimi", "cursor", "opencode", "kiro"]; export type EccMaterializationTarget = (typeof GOVERNED_MATERIALIZATION_TARGETS)[number]; /** * The ruled targets actually DELIVERED. Rows land one at a time, so a ruled * target that has not landed yet refuses naming what is wired — the same * discipline the lifecycle's other refusals follow. Adding a target to this * list is what ships its row. * * All six are wired: this list now EQUALS the governed list, which is the * completion of F4. `tests/ecc/materialization-target.test.ts` pins that * equality, so a seventh governed target cannot be added without deciding what * the unwired branch below should say about it. */ export declare const WIRED_MATERIALIZATION_TARGETS: readonly EccMaterializationTarget[]; /** The name this lifecycle calls a target by, in reports and refusals. */ export declare function eccMaterializationTargetName(target: EccMaterializationTarget): string; /** * Narrow a requested CLI list to governed materialization targets, or refuse by * name. Two distinct refusals, because they mean different things to whoever * reads them: a CLI outside the ruled six is not a materialization target at * all, while a ruled one that has not landed yet is a row still to come. Both * name what IS wired and how to ask for it, so neither reads as "AIH does * nothing here" or as a dead end. */ export declare function assertGovernedMaterializationTargets(requested: readonly string[]): EccMaterializationTarget[]; export type EccTargetRefusalReason = "no-install-descriptor" | "unowned-destination" | "missing-source" | "unreadable-source" | "duplicate-destination" | "unsupported-component"; export interface EccTargetRefusal { id: string; reason: EccTargetRefusalReason; detail: string; } /** The same refusal, carrying WHICH target refused — the multi-target report needs it. */ export interface EccTargetedRefusal extends EccTargetRefusal { target: EccMaterializationTarget; } export interface EccTargetMaterializationRequest { /** Absolute path to the checkout holding the pinned framework content. */ sourceRoot: string; /** The requested governed targets, already narrowed by the assertion above. */ targets: readonly EccMaterializationTarget[]; /** The F2 resolver's evidence-passed components, carried through unchanged. */ components: readonly EccEffectiveSelectionComponent[]; /** Full current verification result, required only by the governed Kiro target. */ evidence?: EccSelectionEvidence; } export interface EccTargetMaterializationResult { /** Ready for `EccMaterializationRequest.components` — nothing else to attach. */ components: EccMaterializationComponentInput[]; refused: EccTargetedRefusal[]; } /** * The first pair of destinations in ONE target's list that resolve to the same * owned file, or `undefined`. Two spellings collide when `destinationIdentity` * folds them together — it folds Unicode normalization AND case, because both * resolve to one file on the platforms AIH targets. A pinned checkout carrying * `café.md` in NFC beside `café.md` in NFD (NTFS and ext4 both store those as * two entries), or `README.md` beside `readme.md` on a case-sensitive volume, * declares two sources for one destination. * * Exported because the folding, not the filesystem, is what has to be pinned: * neither pair can be CREATED on every platform, so the probe that proves this * rule holds must be able to hand it the pair directly. */ export declare function foldedDestinationCollision(paths: readonly string[]): { first: string; second: string; } | undefined; /** * Map evidence-passed components onto the requested targets: the `components` * half is a complete `EccMaterializationRequest.components`, and the `refused` * half names every component a target left unmaterialized, with its reason and * that target. * * A request for N targets emits, per component, the UNION of its per-target * destinations in ONE list — the receipt already holds N paths per component, * so there is no second receipt and no per-target root. Destinations two * targets share (`AGENTS.md`, `.agents/plugins/`, `.agents/skills/`) collapse on * `destinationIdentity`, the same folded identity every ownership guard uses; * without that collapse the engine would see one component claiming one * destination twice and refuse the whole request. * * That collapse is CROSS-target only, and it is safe for exactly one reason: a * destination two targets agree on comes from a mapping row with no target in * it, so both spellings are the identical string produced from the identical * source file. Two spellings that merely FOLD together never reach here — they * are a defect inside one target's own list, and `componentFiles` refuses the * component for that target before the union sees either of them. * * A target that refuses a component does not veto the others: the component * still materializes for the targets that own it, and the refusal is reported * against the target that made it. */ export declare function resolveEccTargetMaterialization(request: EccTargetMaterializationRequest): EccTargetMaterializationResult;