/** * claude-code hook installer: SessionEnd (capture) + SessionStart (stash). * * Edits .claude/settings.json parse-preservingly: only the two hook arrays * are touched; every other key is carried through untouched (FR3.4). * Identity rule: our hook commands end with the `#aidlc-cost-hook` marker — * install/remove/status match on the marker alone, so command bodies can * change between versions without orphaning old hooks (design §5). * * Hook merge semantics are additive across settings files by platform * design, so user hooks are safe by construction. */ import { type ShimProblem } from './shim.js'; export declare const HOOK_MARKER = "#aidlc-cost-hook"; /** * The hook commands. * * These used to embed absolute paths to both the node binary and the CLI, * resolved once at install time (FR3.10). That made silent breakage inevitable: * any username, machine, or `nvm` change invalidated them and nothing reported * it (cost-capture-goes-dark/AC-1). They now invoke the generated shim, which * resolves both at run time and logs when it cannot — see `./shim.ts` for the * candidate order and the AC-15 security constraints. * * `nodePath`/`cliPath` are still taken, but only to seed the shim's *hints*; * they no longer appear in the command text. */ export declare function hookCommands(_nodePath?: string, _cliPath?: string): { sessionEnd: string; sessionStart: string; }; /** * Install (idempotently) the cost hooks into project settings. * * `nodePath`/`cliPath` seed the shim's hints; they are validated at run time and * never appear in the command text, so the installed hook survives an * environment move (cost-capture-goes-dark/AC-1, AC-2). */ export declare function installClaudeCodeHooks(projectRoot: string, nodePath: string, cliPath: string): void; /** Remove our hooks; leaves everything else untouched. */ export declare function removeClaudeCodeHooks(projectRoot: string): void; export interface HookStatus { installed: boolean; /** * The hook still uses the pre-shim form, with node and CLI paths frozen at * install time, and should be re-installed (cost-capture-goes-dark/AC-18). * * This replaces the old `commandResolvable` flag. Asking "does the recorded * absolute path still exist?" was the right question only while the command * contained an absolute path; now that it invokes the shim there is no path to * go stale, so the question that remains is whether a hook predates the shim. */ legacy: boolean; /** * The hook is armed but the shim it invokes cannot run — null when it can, and * always null when nothing is installed (an absent hook is a different * condition, not a broken one). * * `legacy` above answers "does this hook predate the shim?". It does not, and * cannot, answer "is the shim there?" — which is the state that cost this * project 41 hours of capture while status read `installed`. See * `shim.ts:shimProblem`. */ shim: ShimProblem | null; /** * The installed command text is not what the current installer would write, so * the hook is armed with an older contract. * * Generic on purpose. `legacy` answers one historical question (does this * predate the shim?) and needed a migration written for it; this asks the * question that recurs — *is the command current?* — so the next command-shape * change is repaired by the machinery already here rather than by another * bespoke detector. `stash-unstash-on-end` is the first such change: a * SessionEnd hook without `--session-end` still works via the payload signal, * but it should not stay behind. * * A legacy hook is outdated too. Order in the migration registry settles that: * `legacy-cost-hooks` re-installs first, and this then reads clean. */ outdated: boolean; } export declare function claudeCodeHookStatus(projectRoot: string): HookStatus; /** * A hook command predates the shim when it does not invoke it. Matching on the * shim rather than on "looks like an absolute path" keeps this correct for any * future command shape: the only thing that matters is whether capture goes * through the run-time resolver. */ export declare function isLegacyCommand(command: string | undefined): boolean; //# sourceMappingURL=claude-code.d.ts.map