/** * Filesystem-backed playbook resolver with 3-tier precedence. * * Lookup order (highest wins): * 1. `project` — `/.cleo/playbooks/.cantbook` * 2. `global` — `~/.local/share/cleo/playbooks/.cantbook` * (resolved via `@cleocode/paths` `getCleoHome()`) * 3. `packaged` — `@cleocode/playbooks/starter/.cantbook` * (resolved relative to this file's compiled location) * * This resolver is symmetric to `resolveAgent()` in `agent-resolver.ts`. * It is a pure filesystem resolver — no database involved. Same inputs * always produce the same outputs (pure function — no global state). * * Empty project or global tier directories are silently skipped; the resolver * falls through to the next tier. `PlaybookNotFoundError` is thrown only when * all three tiers miss, enumerating every tried path for operator clarity. * * @module playbook-resolver * @task T1937 * @see packages/core/src/store/agent-resolver.ts — symmetric agent resolver * @see ADR-068 Decision 4 — symmetric playbook tier resolver */ /** * The three tiers at which a `.cantbook` playbook may be discovered. * Mirrors the language used in `agent-resolver.ts` (AgentTier) for * consistent cross-resolver semantics. */ export type PlaybookTier = 'project' | 'global' | 'packaged'; /** * Resolved playbook envelope returned by {@link resolvePlaybook} and * {@link listPlaybooks}. Carries the tier of origin so callers can surface * provenance to the user (`cleo playbook list` table: Name | Tier | Path). * * @example * ```typescript * const resolved = resolvePlaybook('rcasd', { projectRoot: '/path/to/proj' }); * // → { name: 'rcasd', tier: 'packaged', path: '...rcasd.cantbook', source: '...' } * ``` */ export interface ResolvedPlaybook { /** Bare playbook name (no extension). */ name: string; /** Tier at which the playbook was found. */ tier: PlaybookTier; /** Absolute path to the `.cantbook` file. */ path: string; /** Raw UTF-8 source content of the `.cantbook` file. */ source: string; } /** * Options for {@link resolvePlaybook} and {@link listPlaybooks}. * * Mirrors the `ResolveAgentOptions` naming convention from `agent-resolver.ts` * so future callers can apply consistent patterns across both resolvers. */ export interface ResolvePlaybookOptions { /** * Absolute path to the project root. Required to locate the project-tier * playbook directory at `/.cleo/playbooks/`. * * When omitted, the project tier is silently skipped (no error). */ projectRoot?: string; /** * Preferred tier to try first. When supplied, that tier is moved to the * head of the lookup order; the remaining tiers follow in the default * sequence `project → global → packaged`. * * This is an extension point — Phase 1 callers do not use it but it * mirrors `ResolveAgentOptions.preferTier` for API symmetry. */ preferTier?: PlaybookTier; /** * Override the packaged-tier starter directory. Defaults to the * `@cleocode/playbooks/starter/` directory resolved relative to * this file's compiled location. Tests should set this to a fixture * directory containing `.cantbook` files to keep coverage hermetic. */ packagedStarterDir?: string; /** * Override the global-tier playbooks directory. Defaults to * `getCleoHome() + '/playbooks'`. Tests set this to a temp directory. */ globalPlaybooksDir?: string; } /** * Thrown when every tier in {@link resolvePlaybook} fails to locate the named * playbook. The `triedPaths` array enumerates the full absolute path that was * checked at each tier so operators can diagnose the miss without guessing. * * Mirrors `AgentNotFoundError` from `agent-resolver.ts`: * - Named typed error class with `code` and `exitCode` fields. * - `triedPaths` instead of `triedTiers` because the filesystem check is the * meaningful diagnostic (unlike agent resolution which queries a DB per tier). * * @task T1937 */ export declare class PlaybookNotFoundError extends Error { /** Bare playbook name that was searched for. */ readonly playbookName: string; /** Absolute paths tried at each tier, in lookup order. */ readonly triedPaths: string[]; /** Canonical CLEO error code for playbook-resolution misses. */ readonly code = "E_PLAYBOOK_NOT_FOUND"; /** CLI exit code reserved for playbook-resolution misses. */ readonly exitCode = 66; constructor( /** Bare playbook name that was searched for. */ playbookName: string, /** Absolute paths tried at each tier, in lookup order. */ triedPaths: string[]); } /** * Resolve a single `.cantbook` playbook by bare name using 3-tier precedence. * * Tiers walked in order: `project` → `global` → `packaged`. Project tier * MUST shadow global; global MUST shadow packaged. * * Empty higher tiers silently fall through — no error is emitted when the * project or global directory is absent or contains no `.cantbook` files. * * @param name - Bare playbook name without extension (e.g., `'rcasd'`). * @param options - Optional lookup overrides (see {@link ResolvePlaybookOptions}). * @returns The highest-precedence {@link ResolvedPlaybook} envelope. * @throws {PlaybookNotFoundError} When every tier misses. The error message * enumerates all tried absolute paths. * @example * ```typescript * import { resolvePlaybook } from '@cleocode/core'; * * const pb = resolvePlaybook('rcasd', { projectRoot: process.cwd() }); * console.log(pb.tier); // 'packaged' (if no project/global override exists) * console.log(pb.path); // '/path/to/.../playbooks/starter/rcasd.cantbook' * ``` * @task T1937 */ export declare function resolvePlaybook(name: string, options?: ResolvePlaybookOptions): ResolvedPlaybook; /** * List all `.cantbook` playbooks discoverable across all tiers, deduped by * name (project tier shadows global; global shadows packaged). * * Playbooks are returned with their tier provenance so callers can render a * `Name | Tier | Path` table for `cleo playbook list --tier all`. * * When the same name exists in multiple tiers, only the highest-precedence * entry is returned (project wins over global, global wins over packaged). * The returned order is: project tier entries first, then global, then * packaged (with shadowed entries omitted). * * @param options - Lookup options (see {@link ResolvePlaybookOptions}). * @returns Deduplicated list of {@link ResolvedPlaybook} entries, sorted by * tier precedence (project → global → packaged), then by name within * each tier. * @task T1937 */ export declare function listPlaybooks(options?: ResolvePlaybookOptions): ResolvedPlaybook[]; //# sourceMappingURL=playbook-resolver.d.ts.map