// SC-13: hooks.json wires Stop event to otel-export.mjs // HIGH-risk-mitigering — verify deterministic config-pinning (mønster fra // tests/lib/doc-consistency.test.mjs). import { test } from 'node:test'; import { strict as assert } from 'node:assert'; import { readFileSync } from 'node:fs'; import { fileURLToPath } from 'node:url'; import { dirname, resolve } from 'node:path'; const __dirname = dirname(fileURLToPath(import.meta.url)); const HOOKS_JSON_PATH = resolve(__dirname, '../../hooks/hooks.json'); function loadHooksJson() { const raw = readFileSync(HOOKS_JSON_PATH, 'utf8'); return JSON.parse(raw); } test('hooks.json — Stop key exists with at least one entry', () => { const cfg = loadHooksJson(); assert.ok(cfg.hooks, 'hooks.json mangler top-level "hooks" object'); assert.ok(Array.isArray(cfg.hooks.Stop), 'hooks.json mangler "Stop" array'); assert.ok(cfg.hooks.Stop.length >= 1, 'Stop array er tom — forventet ≥1 entry'); }); test('hooks.json — Stop entry refererer otel-export.mjs', () => { const cfg = loadHooksJson(); const stopEntries = cfg.hooks.Stop; const allCommands = stopEntries.flatMap((entry) => (entry.hooks || []).map((h) => h.command || ''), ); const hasOtelExport = allCommands.some((cmd) => cmd.includes('otel-export.mjs')); assert.ok( hasOtelExport, `ingen Stop-hook refererer otel-export.mjs. Funnet: ${JSON.stringify(allCommands)}`, ); }); test('hooks.json — Stop entry bruker ${CLAUDE_PLUGIN_ROOT}-substitusjon', () => { const cfg = loadHooksJson(); const stopEntries = cfg.hooks.Stop; const otelEntry = stopEntries .flatMap((entry) => entry.hooks || []) .find((h) => (h.command || '').includes('otel-export.mjs')); assert.ok(otelEntry, 'fant ikke otel-export-entry i Stop'); assert.match( otelEntry.command, /\$\{CLAUDE_PLUGIN_ROOT\}/, 'otel-export-command bruker ikke ${CLAUDE_PLUGIN_ROOT}-prefix — relative paths feiler i headless', ); assert.match( otelEntry.command, /^node\s+/, 'otel-export-command starter ikke med "node " — invocation-form ikke korrekt', ); }); test('hooks.json — Stop entry har "type": "command"', () => { const cfg = loadHooksJson(); const stopEntries = cfg.hooks.Stop; const otelHook = stopEntries .flatMap((entry) => entry.hooks || []) .find((h) => (h.command || '').includes('otel-export.mjs')); assert.equal(otelHook.type, 'command', 'otel-export-hook mangler "type": "command"'); });