# `apply` _(no submodules)_ ## Purpose The plugin-side apply hook. The installer host owns the actual transactional materialisation (staged-tmp + atomic-rename + journal-based rollback); this hook's only job is to inspect the planned ops and return an `AgentSkillsHandle` summarising what was installed so `postInstall` can render a meaningful summary line. ## Features - Counts `write` ops to derive the `installed` count. - Echoes back the resolved `targetDir` so `postInstall` doesn't need to re-derive it from ops or answers. - Pure pass-through — no fs I/O, no side effects. ## Basic Example ```ts import { apply } from "@suaveplan/install-agent-skills"; const handle = await apply(ops, ctx, ".suaveplan/skills"); console.log(`installed: ${handle.installed}`); ``` ## Advanced Example ```ts import { apply } from "@suaveplan/install-agent-skills"; import type { FileOp, InstallerContext } from "@suaveplan/installer"; async function dryRunSummary( ops: ReadonlyArray, ctx: InstallerContext, targetDir: string ): Promise { const handle = await apply(ops, ctx, targetDir); return `dry-run plan: ${handle.installed} files would land in ${handle.targetDir}`; } ``` ## API Reference - `apply(ops, ctx, targetDir): Promise` — pure function returning `{ installed, targetDir }`. ## Implementation Notes Apply is intentionally trivial because the installer host enforces transactional semantics via its own `applyOps` — every `FileOp` returned from `plan` is materialised through staged-tmp + atomic-rename with a journal-based rollback, so plugin-side apply does not need to perform any I/O. Plugin authors who need to perform side effects beyond what `FileOp` can express should do so in `postInstall` (where the host has already committed the apply transaction) rather than reaching into apply directly — that keeps rollback-on-failure semantics intact. The `targetDir` argument is threaded through from `plugin.ts` which extracts it from the index patch op so we don't lose it across the plan/apply boundary.