# `error-codes` ## Purpose Defines the canonical error-code registry for `@suaveplan/installer` and the `InstallerError` class that carries those codes. Every failure path inside the host — manifest validation, plugin discovery, prompt validation, plan validation, conflict resolution, apply, and rollback — surfaces as an `InstallerError` with a literal-typed `code` drawn from this registry. That contract makes failures machine-classifiable: callers can write exhaustive `switch` statements on `code` and add new codes only by extending the registry, never by string-matching free-form messages. ## Features - Frozen registry built via `defineCodes("INSTALLER", [...])` from `@suaveplan/error`, so `Object.isFrozen(INSTALLER_CODES)` is `true` at module load time. - All codes are namespaced as `INSTALLER.` strings. - `InstallerError` extends `SuaveplanError` so `instanceof` plus `.code` narrowing remains exhaustive. - Public widened constructor — callers can `throw new InstallerError(code, key, options)` directly without going through a factory. - Stable code surface: nine reasons (`PLUGIN_NOT_FOUND`, `PLUGIN_LOAD_FAILED`, `PLUGIN_INVALID_MANIFEST`, `PROMPT_VALIDATION_FAILED`, `PLAN_FAILED`, `APPLY_CONFLICT`, `APPLY_FAILED`, `ROLLBACK_FAILED`, `ABORTED`). ## Basic Example ```ts import { INSTALLER_CODES, InstallerError } from "@suaveplan/installer"; throw new InstallerError( INSTALLER_CODES.PLUGIN_NOT_FOUND, "installer.plugin.not_found", { context: { id: "agent-skills" } } ); ``` ## Advanced Example ```ts import { InstallerError } from "@suaveplan/installer"; function classify(err: unknown): string { if (!(err instanceof InstallerError)) return "unknown"; switch (err.code) { case "INSTALLER.PLUGIN_NOT_FOUND": return "missing-plugin"; case "INSTALLER.APPLY_CONFLICT": return "conflict"; case "INSTALLER.ROLLBACK_FAILED": return "fatal-rollback"; default: return "other"; } } ``` ## API Reference - `INSTALLER_CODES` — frozen `{ [K]: "INSTALLER.K" }` map. Read-only at runtime and at the type level. - `type InstallerErrorCode` — union of every `INSTALLER.*` literal in the registry. - `class InstallerError extends SuaveplanError` — carries `code`, `message`, optional `cause`, `context`, `timestamp`, and `traceId` from the base class. ## Implementation Notes `defineCodes` freezes the returned object so consumers cannot mutate the registry — this matches the conformance assertion in `error-codes.spec-conformance.test.ts` (`INSTALLER-09`). The `InstallerError` constructor sets `this.name = "InstallerError"` because `SuaveplanError`'s default `new.target.name` is reset by some bundlers and the explicit assignment guarantees stable serialised names. Every throw inside this package should pick a code from this registry; throwing a bare `Error` from internal code is treated as a regression by the conformance suite.