aios-core
Version:
Synkra AIOS: AI-Orchestrated System for Full Stack Development - Core Framework
100 lines (86 loc) • 3.03 kB
JavaScript
// SYN-14: Boot time captured before ANY require — measures hook cold start
const _BOOT_TIME = process.hrtime.bigint();
;
/**
* SYNAPSE Hook Entry Point — UserPromptSubmit
*
* Thin wrapper that reads JSON from stdin, delegates to SynapseEngine,
* and writes <synapse-rules> context to stdout.
*
* - Silent exit on missing .synapse/ directory
* - Silent exit on any error (never blocks the user prompt)
* - All errors logged to stderr with [synapse-hook] prefix
* - 5s safety timeout as defense-in-depth
*
* @module synapse-engine-hook
*/
const path = require('path');
const { resolveHookRuntime, buildHookOutput } = require(
path.join(__dirname, '..', '..', '.aios-core', 'core', 'synapse', 'runtime', 'hook-runtime.js'),
);
/** Safety timeout (ms) — defense-in-depth; Claude Code also manages hook timeout. */
const HOOK_TIMEOUT_MS = 5000;
/**
* Read all data from stdin as a JSON object.
* @returns {Promise<object>} Parsed JSON input
*/
function readStdin() {
return new Promise((resolve, reject) => {
let data = '';
process.stdin.setEncoding('utf8');
process.stdin.on('error', (e) => reject(e));
process.stdin.on('data', (chunk) => { data += chunk; });
process.stdin.on('end', () => {
try { resolve(JSON.parse(data)); }
catch (e) { reject(e); }
});
});
}
/** Main hook execution pipeline. */
async function main() {
const input = await readStdin();
const runtime = resolveHookRuntime(input);
if (!runtime) return;
const result = await runtime.engine.process(input.prompt, runtime.session);
// QW-1: Wire updateSession() — persist bracket transitions after each prompt
if (runtime.sessionId && runtime.sessionsDir) {
try {
const { updateSession } = require(
path.join(runtime.cwd, '.aios-core', 'core', 'synapse', 'session', 'session-manager.js'),
);
updateSession(runtime.sessionId, runtime.sessionsDir, {
context: { last_bracket: result.bracket || 'FRESH' },
});
} catch (_err) {
// Fire-and-forget — never block the prompt
}
}
const output = JSON.stringify(buildHookOutput(result.xml));
// Write and flush stdout (callback may not exist in mocked environments)
const flushed = process.stdout.write(output);
if (!flushed) {
await new Promise((resolve) => process.stdout.once('drain', resolve));
}
}
/**
* Safely exit the process — no-op inside Jest workers to prevent worker crashes.
* @param {number} code - Exit code
*/
function safeExit(code) {
if (process.env.JEST_WORKER_ID) return;
process.exit(code);
}
/** Entry point runner — sets safety timeout and executes main(). */
function run() {
const timer = setTimeout(() => safeExit(0), HOOK_TIMEOUT_MS);
timer.unref();
main()
.then(() => safeExit(0))
.catch((err) => {
console.error(`[synapse-hook] ${err.message}`);
safeExit(0);
});
}
if (require.main === module) run();
module.exports = { readStdin, main, run, HOOK_TIMEOUT_MS };