UNPKG

aios-core

Version:

Synkra AIOS: AI-Orchestrated System for Full Stack Development - Core Framework

308 lines (224 loc) 5.87 kB
# Unified Hooks System **Module:** `.aios-core/hooks/unified` **Purpose:** Cross-CLI hook abstraction layer **Supported CLIs:** Claude Code, Gemini Code --- ## Overview The Unified Hooks System provides a consistent interface for lifecycle hooks across different AI coding assistants (Claude Code, Gemini Code, future CLIs). ### Architecture ``` CLI-Specific Hooks (.claude/hooks/, .gemini/hooks/) Hook Interface (hook-interface.js) Hook Runners (runners/*.js) Application Logic (aios-core, aios-pro) ``` --- ## Components ### 1. Hook Interface (`hook-interface.js`) **Purpose:** Normalize hook events across CLIs **Event Mapping:** | Unified Event | Claude Code | Gemini Code | |---------------|-------------|-------------| | `sessionStart` | N/A | `SessionStart` | | `beforeAgent` | `PreToolUse` | `BeforeAgent` | | `beforeTool` | `PreToolUse` | `BeforeTool` | | `afterTool` | `PostToolUse` | `AfterTool` | | `sessionEnd` | `Stop` | `SessionEnd` | **Usage:** ```javascript const { UnifiedHook, EVENT_MAPPING } = require('./hook-interface'); class MyHook extends UnifiedHook { constructor() { super({ name: 'my-hook', event: 'beforeTool', matcher: 'write_file', timeout: 5000, }); } async execute(context) { // Your logic here return { status: 'allow' }; } } ``` ### 2. Hook Runners (`runners/`) **Purpose:** Implement specific hook logic **Current Runners:** - **`precompact-runner.js`** (Story MIS-3) - Captures session digest before context compact - Open Core architecture (delegates to aios-pro) - Fire-and-forget async execution **Runner Pattern:** ```javascript async function onHookEvent(context) { try { // 1. Check preconditions // 2. Execute async (setImmediate for non-blocking) // 3. Return immediately } catch (err) { // Silent failure - never block user } } function getHookConfig() { return { name: 'hook-name', event: 'UnifiedEvent', handler: onHookEvent, timeout: 5000, }; } ``` ### 3. Hook Registry (`hook-registry.js`) **Purpose:** Register and discover hooks **API:** ```javascript const registry = require('./hook-registry'); // Register hook registry.register(myHook); // Get hooks for event const hooks = registry.getHooksForEvent('beforeTool'); // Execute hooks await registry.executeHooks('beforeTool', context); ``` --- ## PreCompact Hook (Story MIS-3) ### Purpose Capture session knowledge before context compact to preserve institutional learnings. ### Architecture ``` Claude Code PreCompact Event .claude/hooks/precompact-session-digest.cjs runners/precompact-runner.js (pro-detector check) pro/memory/session-digest/extractor.js .aios/session-digests/{session-id}-{timestamp}.yaml ``` ### Performance - **Hook return:** < 50ms (fire-and-forget) - **Digest completion:** < 5s - **Never blocks compact** ### Graceful Degradation - If aios-pro not available: no-op (log and return) - If extraction fails: silent failure (log error) - If write fails: error propagated to logger --- ## Creating New Hooks ### Step 1: Create Runner ```javascript // .aios-core/hooks/unified/runners/my-runner.js async function onMyEvent(context) { try { // Implement your logic console.log('[MyHook] Event fired'); // Fire-and-forget if needed setImmediate(async () => { await doAsyncWork(context); }); return; // Return immediately } catch (err) { console.error('[MyHook] Error:', err.message); } } function getHookConfig() { return { name: 'my-hook', event: 'beforeTool', handler: onMyEvent, timeout: 5000, }; } module.exports = { onMyEvent, getHookConfig }; ``` ### Step 2: Register Hook ```javascript // .claude/hooks/my-hook.js const { onMyEvent } = require('../../.aios-core/hooks/unified/runners/my-runner'); module.exports = async (context) => { return await onMyEvent(context); }; ``` ### Step 3: Test Hook ```javascript // tests/hooks/unified/runners/my-runner.test.js describe('My Hook', () => { it('should execute without blocking', async () => { const startTime = Date.now(); await onMyEvent(context); const duration = Date.now() - startTime; expect(duration).toBeLessThan(50); // Fire-and-forget }); }); ``` --- ## Testing ### Unit Tests ```bash npm test -- tests/hooks/unified/ ``` ### Integration Tests ```bash npm test -- tests/integration/hooks/ ``` --- ## Best Practices ### 1. Fire-and-Forget Pattern ```javascript // Good: Non-blocking setImmediate(async () => { await slowOperation(); }); return; // Return immediately // Bad: Blocking await slowOperation(); return; ``` ### 2. Silent Failures ```javascript // Good: Silent failure catch (err) { console.error('[Hook] Failed:', err.message); // Don't throw - graceful degradation } // Bad: Propagates error catch (err) { throw err; // Blocks user! } ``` ### 3. Timeout Limits ```javascript // Good: < 5s timeout { timeout: 5000 } // Bad: Long timeout { timeout: 30000 // May delay user } ``` ### 4. Pro Detection (Open Core) ```javascript // Good: Graceful degradation const { isProAvailable } = require('../../../bin/utils/pro-detector'); if (!isProAvailable()) { console.log('[Hook] aios-pro not available, skipping'); return; } // Bad: Hard dependency const proModule = require('../../pro/...'); // Fails if pro absent ``` --- ## Related Stories - **Story GEMINI-INT.8:** Unified Hook Interface (completed) - **Story MIS-2:** Dead Code Cleanup (restored hooks foundation) - **Story MIS-3:** Session Digest (PreCompact Hook) **CURRENT** - **Story PRO-5:** aios-pro Repository Bootstrap (pro-detector pattern) --- *Unified Hooks System - AIOS Core* *Updated: 2026-02-09 - Story MIS-3*