/**
 * Hooks staleness — one executable file per hook. Project layer is EXCLUDED
 * by design: a cloned public repo with `.agents/hooks/foo` must not plant a
 * hook that fires next time the user runs an agent inside it (see
 * `src/lib/installations/versions.ts:1832-1836`). Only user + system + extras count.
 *
 * Auxiliary files (README.md, promptcuts.yaml) live in hooks/ but are not
 * hooks — the executable bit on the source distinguishes them. This matches
 * the filter in `getAvailableResources`.
 */
import * as fs from 'fs';
import * as path from 'path';
import { hookLayers, listAcrossLayers, resolveByName } from '../layers.js';
import { fingerprintFile, isFileStale } from '../fingerprint.js';
/** Extensions that are NEVER hooks — docs, configuration, plain data. */
const NON_SCRIPT_EXTENSIONS = new Set([
    '.md', '.markdown', '.rst', '.txt',
    '.yaml', '.yml', '.json', '.toml', '.ini', '.conf',
]);
/** Extensions that explicitly mark a file as a script regardless of exec bit. */
const SCRIPT_EXTENSIONS = new Set([
    '.sh', '.bash', '.zsh',
    '.py', '.js', '.ts', '.mjs', '.cjs',
    '.rb', '.pl', '.ps1',
]);
function isHookScript(full) {
    try {
        const stat = fs.statSync(full);
        if (!stat.isFile())
            return false;
        const ext = path.extname(full).toLowerCase();
        if (SCRIPT_EXTENSIONS.has(ext))
            return true;
        // Otherwise require exec bit AND a non-data extension. Older sync runs
        // chmod 0o755'd everything including `promptcuts.yaml` / `README.md`,
        // so exec bit alone can't be trusted.
        if ((stat.mode & 0o111) === 0)
            return false;
        return !NON_SCRIPT_EXTENSIONS.has(ext);
    }
    catch {
        return false;
    }
}
export const hooksChecker = {
    type: 'hooks',
    listNames(_cwd) {
        return listAcrossLayers(hookLayers(), 'hooks', (_, full) => isHookScript(full));
    },
    build(name, _cwd) {
        const resolved = resolveByName(hookLayers(), path.join('hooks', name), isHookScript);
        if (!resolved)
            return null;
        const fp = fingerprintFile(resolved.path);
        return fp ? { source: fp } : null;
    },
    isFresh(name, stored, _cwd) {
        const resolved = resolveByName(hookLayers(), path.join('hooks', name), isHookScript);
        if (!resolved)
            return false;
        return !isFileStale(stored.source, resolved.path);
    },
};
