80 lines
2.4 KiB
JavaScript
Executable file
80 lines
2.4 KiB
JavaScript
Executable file
#!/usr/bin/env node
|
|
/**
|
|
* UserPromptSubmit hook — detects resonance / tension / shift / red-line
|
|
* signals in the user message and suggests a mid-session soul-memory entry.
|
|
*
|
|
* Non-blocking: never rejects the prompt. Emits a short nudge when a
|
|
* trigger keyword matches. Max one nudge per session is enforced via a
|
|
* file marker under _byan/_memory/.
|
|
*/
|
|
|
|
const fs = require('fs');
|
|
const path = require('path');
|
|
|
|
const projectDir = process.env.CLAUDE_PROJECT_DIR || process.cwd();
|
|
const markerPath = path.join(projectDir, '_byan', '_memory', '.soul-memory-nudge-sent');
|
|
|
|
const TRIGGERS = {
|
|
resonance: ['resonne', 'ca me parle', 'exactement', 'c\'est ca', 'that resonates'],
|
|
tension: ['pas d\'accord', 'disagree', 'non mais', 'pourquoi tu', 'tu te trompes'],
|
|
shift: ['je change d\'avis', 'autrement', 'en fait', 'je realise', 'i realize'],
|
|
redLine: ['ligne rouge', 'jamais', 'je refuse', 'red line', 'never acceptable'],
|
|
};
|
|
|
|
function readStdin() {
|
|
return new Promise((resolve) => {
|
|
let data = '';
|
|
if (process.stdin.isTTY) return resolve('');
|
|
process.stdin.on('data', (chunk) => (data += chunk));
|
|
process.stdin.on('end', () => resolve(data));
|
|
});
|
|
}
|
|
|
|
function findTrigger(text) {
|
|
const lower = (text || '').toLowerCase();
|
|
for (const [category, patterns] of Object.entries(TRIGGERS)) {
|
|
for (const p of patterns) {
|
|
if (lower.includes(p)) return { category, pattern: p };
|
|
}
|
|
}
|
|
return null;
|
|
}
|
|
|
|
(async () => {
|
|
let additionalContext = '';
|
|
|
|
try {
|
|
const raw = await readStdin();
|
|
let prompt = '';
|
|
try {
|
|
const parsed = JSON.parse(raw);
|
|
prompt = parsed.prompt || parsed.userPrompt || parsed.message || '';
|
|
} catch {
|
|
prompt = raw;
|
|
}
|
|
|
|
if (!fs.existsSync(markerPath)) {
|
|
const hit = findTrigger(prompt);
|
|
if (hit) {
|
|
additionalContext = `BYAN soul-memory trigger detected (${hit.category}): "${hit.pattern}". Per soul-memory protocol, consider offering the user a mid-session introspection entry. Maximum 2 entries per session, always validated by user.`;
|
|
try {
|
|
fs.mkdirSync(path.dirname(markerPath), { recursive: true });
|
|
fs.writeFileSync(markerPath, new Date().toISOString());
|
|
} catch {
|
|
// keep going
|
|
}
|
|
}
|
|
}
|
|
} catch {
|
|
// never block
|
|
}
|
|
|
|
process.stdout.write(
|
|
JSON.stringify({
|
|
hookSpecificOutput: {
|
|
hookEventName: 'UserPromptSubmit',
|
|
additionalContext: additionalContext || '',
|
|
},
|
|
})
|
|
);
|
|
})();
|