site-mariage/.claude/hooks/strict-context-inject.js
Corentin Joguet bff653acd6 first commit
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-15 10:30:37 +02:00

86 lines
2.9 KiB
JavaScript

#!/usr/bin/env node
/**
* UserPromptSubmit hook — BYAN Strict Mode context injector.
*
* Two behaviors :
* - When a strict session is engaged, inject the strict banner plus a live
* status line (passes done / required, locked scope hash) so the agent
* stays anchored to the contract on every turn.
* - When no session is engaged but the user's prompt contains an activation
* keyword (prod, production, client, contrat, ...), inject a suggestion to
* lock strict mode before building. It suggests, it does not auto-lock.
*
* Emits empty context on any error.
*/
const {
loadConfig,
loadState,
isEngaged,
passCount,
lastVerdict,
readStdin,
parseJson,
} = require('./lib/strict-runtime');
function findKeyword(prompt, keywords) {
if (!prompt || !Array.isArray(keywords)) return null;
const lower = prompt.toLowerCase();
for (const k of keywords) {
const kw = String(k).toLowerCase();
if (/^[a-z]+$/.test(kw)) {
if (new RegExp(`\\b${kw}\\b`).test(lower)) return k;
} else if (lower.includes(kw)) {
return k;
}
}
return null;
}
// Pure : returns the additionalContext string (possibly empty).
function buildContext({ state, config, prompt }) {
if (isEngaged(state)) {
const minPasses = (config && config.min_passes) || 3;
const banner = (config && config.banners && config.banners.context) || '[STRICT MODE ACTIVE]';
const done = passCount(state);
const hash = state.scope_lock ? state.scope_lock.scope_hash : 'unknown';
return (
`${banner}\n` +
`Locked scope: ${hash} | self-verify ${done}/${minPasses} | last verdict ${lastVerdict(state) || 'none'}.\n` +
`Stay inside the locked scope. Do not declare done before byan_strict_complete returns an audit token.`
);
}
const keyword = findKeyword(prompt, config && config.auto_keywords);
if (keyword) {
return (
`[STRICT MODE SUGGESTED]\n` +
`The request mentions "${keyword}", which signals a production-grade deliverable. ` +
`Before building, consider locking strict mode with byan_strict_lock_scope ` +
`(verbatim scope + testable acceptance criteria). Strict mode enforces ` +
`>= ${(config && config.min_passes) || 3} self-verify passes and a 95% confidence floor on hard claims. ` +
`Confirm with the user, then lock.`
);
}
return '';
}
if (require.main === module) {
(async () => {
const state = loadState();
const config = loadConfig();
const payload = parseJson(await readStdin());
const prompt = payload.prompt || payload.user_prompt || payload.userPrompt || '';
const additionalContext = buildContext({ state, config, prompt });
process.stdout.write(
JSON.stringify({
hookSpecificOutput: { hookEventName: 'UserPromptSubmit', additionalContext },
})
);
process.exit(0);
})();
}
module.exports = { buildContext, findKeyword };