feat(voyage): wire Stop event to otel-export.mjs in hooks.json
Step 13 of v4.1 — adds Stop hook entry pointing to
hooks/scripts/otel-export.mjs (added in Step 12 / commit c5fb745).
Mounts the orchestrator on Claude Code's Stop event so OTel/Prometheus
export runs at session-end when VOYAGE_EXPORT_MODE is set.
HIGH-risk-mitigering: tests/hooks/hooks-json-stop-wired.test.mjs
asserter at Stop-key finnes, refererer otel-export.mjs, bruker
\${CLAUDE_PLUGIN_ROOT}-substitusjon, og har type:command.
Tests: 464 → 468 (4 new). All green.
This commit is contained in:
parent
c5fb7456d5
commit
a39f7ec2e2
2 changed files with 75 additions and 0 deletions
|
|
@ -60,6 +60,16 @@
|
|||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"Stop": [
|
||||
{
|
||||
"hooks": [
|
||||
{
|
||||
"type": "command",
|
||||
"command": "node ${CLAUDE_PLUGIN_ROOT}/hooks/scripts/otel-export.mjs"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
|
|
|||
65
plugins/voyage/tests/hooks/hooks-json-stop-wired.test.mjs
Normal file
65
plugins/voyage/tests/hooks/hooks-json-stop-wired.test.mjs
Normal file
|
|
@ -0,0 +1,65 @@
|
|||
// 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"');
|
||||
});
|
||||
Loading…
Add table
Add a link
Reference in a new issue