#!/usr/bin/env node /** * Tractatus Session Initialization * Hook test: 2025-10-24 * * Automatically runs all mandatory framework checks at session start. * Should be called at the beginning of every Claude Code session. * * Copyright 2025 Tractatus Project * Licensed under Apache License 2.0 */ const fs = require('fs'); const path = require('path'); const { execSync } = require('child_process'); const SESSION_STATE_PATH = path.join(__dirname, '../.claude/session-state.json'); const INSTRUCTION_HISTORY_PATH = path.join(__dirname, '../.claude/instruction-history.json'); const TOKEN_CHECKPOINTS_PATH = path.join(__dirname, '../.claude/token-checkpoints.json'); /** * Color output helpers */ const colors = { reset: '\x1b[0m', bright: '\x1b[1m', green: '\x1b[32m', yellow: '\x1b[33m', blue: '\x1b[34m', red: '\x1b[31m', cyan: '\x1b[36m' }; function log(message, color = 'reset') { console.log(`${colors[color]}${message}${colors.reset}`); } function header(message) { console.log(''); log('═'.repeat(70), 'cyan'); log(` ${message}`, 'bright'); log('═'.repeat(70), 'cyan'); console.log(''); } function section(message) { console.log(''); log(`▶ ${message}`, 'blue'); } function success(message) { log(` ✓ ${message}`, 'green'); } function warning(message) { log(` ⚠ ${message}`, 'yellow'); } function error(message) { log(` ✗ ${message}`, 'red'); } /** * Check if this is a new session or restart */ function isNewSession() { try { const sessionState = JSON.parse(fs.readFileSync(SESSION_STATE_PATH, 'utf8')); // Check if session_id is today's date const today = new Date().toISOString().split('T')[0]; const sessionDate = sessionState.session_id.split('-').slice(0, 3).join('-'); // Check if message count is 0 (new session) const isNew = sessionState.message_count === 0; // Check if session started today const isToday = sessionDate === today; return { isNew, isToday, sessionState }; } catch (err) { // If file doesn't exist or can't be read, treat as new session return { isNew: true, isToday: true, sessionState: null }; } } /** * Initialize session state */ function initializeSessionState() { const sessionId = new Date().toISOString().split('T')[0] + '-001'; const timestamp = new Date().toISOString(); const sessionState = { version: '1.0.0', session_id: sessionId, started: timestamp, message_count: 1, token_estimate: 0, last_framework_activity: { ContextPressureMonitor: { message: 1, tokens: 0, timestamp: timestamp, last_level: 'NORMAL', last_score: 0 }, InstructionPersistenceClassifier: { message: 0, tokens: 0, timestamp: null, last_classification: null }, CrossReferenceValidator: { message: 0, tokens: 0, timestamp: null, last_validation: null }, BoundaryEnforcer: { message: 0, tokens: 0, timestamp: null, last_check: null }, MetacognitiveVerifier: { message: 0, tokens: 0, timestamp: null, last_verification: null }, PluralisticDeliberationOrchestrator: { message: 0, tokens: 0, timestamp: null, last_deliberation: null } }, staleness_thresholds: { messages: 20, tokens: 30000 }, alerts: [], last_updated: timestamp, initialized: true }; fs.writeFileSync(SESSION_STATE_PATH, JSON.stringify(sessionState, null, 2)); return sessionState; } /** * Reset token checkpoints for new session */ function resetTokenCheckpoints() { const checkpoints = { version: '1.0.0', budget: 200000, checkpoints: [ { percentage: 25, tokens: 50000, completed: false, timestamp: null }, { percentage: 50, tokens: 100000, completed: false, timestamp: null }, { percentage: 75, tokens: 150000, completed: false, timestamp: null } ], next_checkpoint: 50000, overdue: false, last_check: new Date().toISOString() }; fs.writeFileSync(TOKEN_CHECKPOINTS_PATH, JSON.stringify(checkpoints, null, 2)); return checkpoints; } /** * Load and summarize instruction history */ function loadInstructionHistory() { try { if (!fs.existsSync(INSTRUCTION_HISTORY_PATH)) { return { total: 0, high: 0, medium: 0, low: 0 }; } const history = JSON.parse(fs.readFileSync(INSTRUCTION_HISTORY_PATH, 'utf8')); const active = history.instructions?.filter(i => i.active) || []; const summary = { total: active.length, high: active.filter(i => i.persistence === 'HIGH').length, medium: active.filter(i => i.persistence === 'MEDIUM').length, low: active.filter(i => i.persistence === 'LOW').length, strategic: active.filter(i => i.quadrant === 'STRATEGIC').length, system: active.filter(i => i.quadrant === 'SYSTEM').length }; return summary; } catch (err) { warning(`Could not load instruction history: ${err.message}`); return { total: 0, high: 0, medium: 0, low: 0 }; } } /** * Run initial pressure check */ function runPressureCheck() { try { const output = execSync( 'node scripts/check-session-pressure.js --tokens 0/200000 --messages 1 --tasks 0', { encoding: 'utf8', stdio: 'pipe' } ); // Extract pressure level from output const levelMatch = output.match(/Pressure Level:\s+\[.*?m(.*?)\[/); const scoreMatch = output.match(/Overall Score:\s+([\d.]+)%/); return { level: levelMatch ? levelMatch[1] : 'NORMAL', score: scoreMatch ? parseFloat(scoreMatch[1]) : 0, output: output }; } catch (err) { error(`Pressure check failed: ${err.message}`); return { level: 'UNKNOWN', score: 0, output: '' }; } } /** * Check if local development server is running on port 9000 * ENFORCEMENT: Blocks session if not running during development work */ function checkLocalServer() { try { const output = execSync('lsof -i :9000 -t', { encoding: 'utf8', stdio: 'pipe' }); return output.trim().length > 0; } catch (err) { // lsof returns non-zero exit code if no process found return false; } } /** * Start local development server */ function startLocalServer() { try { log(' Attempting to start local server...', 'cyan'); execSync('npm start &', { encoding: 'utf8', stdio: 'inherit', detached: true }); // Wait for server to start let attempts = 0; while (attempts < 10) { if (checkLocalServer()) { return true; } execSync('sleep 1'); attempts++; } return false; } catch (err) { return false; } } /** * Main initialization */ async function main() { header('Tractatus Framework - Session Initialization'); // Check session status section('1. Checking Session Status'); const { isNew, isToday, sessionState } = isNewSession(); if (!isNew && sessionState) { log(` Session: ${sessionState.session_id}`, 'cyan'); log(` Messages: ${sessionState.message_count}`, 'cyan'); log(` Status: Continuing existing session`, 'yellow'); console.log(''); warning('This is a CONTINUED session - framework should already be active'); warning('If this is actually a NEW session, delete .claude/session-state.json'); } else { success('New session detected - initializing framework'); const newState = initializeSessionState(); log(` Session ID: ${newState.session_id}`, 'cyan'); } // Check for post-compaction restart marker const markerPath = path.join(__dirname, '../.claude/session-complete.marker'); let explicitRecoveryDoc = null; // Store recovery_doc before deleting marker (inst_083) if (fs.existsSync(markerPath)) { try { const marker = JSON.parse(fs.readFileSync(markerPath, 'utf8')); // Store recovery_doc BEFORE deleting marker (inst_083: Ensure correct handoff) if (marker.recovery_doc) { explicitRecoveryDoc = marker.recovery_doc; } console.log(''); log('═'.repeat(70), 'yellow'); warning('⚠️ PREVIOUS SESSION ENDED WITH CLOSEDOWN'); log('═'.repeat(70), 'yellow'); console.log(''); log(`📄 Recovery document: ${marker.recovery_doc}`, 'cyan'); log(' This appears to be a POST-COMPACTION restart.', 'yellow'); log(' Read recovery document for full session context.', 'yellow'); console.log(''); log(' Closedown timestamp: ' + new Date(marker.closedown_timestamp).toLocaleString(), 'cyan'); if (marker.framework_health_score !== undefined) { log(` Framework health: ${marker.framework_health_score}/100`, 'cyan'); } if (marker.tasks_pending && marker.tasks_pending.length > 0) { console.log(''); warning(` Pending tasks from previous session (${marker.tasks_pending.length}):`); marker.tasks_pending.slice(0, 3).forEach(task => { log(` • ${task}`, 'yellow'); }); if (marker.tasks_pending.length > 3) { log(` ... and ${marker.tasks_pending.length - 3} more (see recovery doc)`, 'yellow'); } } console.log(''); log('═'.repeat(70), 'yellow'); console.log(''); // Delete marker (consumed) fs.unlinkSync(markerPath); success('Compaction marker consumed - proceeding with initialization'); } catch (markerErr) { warning(`Could not parse compaction marker: ${markerErr.message}`); // Delete malformed marker fs.unlinkSync(markerPath); } } // Check for handoff documents (inst_083: Auto-inject handoff context) section('1a. Previous Session Handoff Detection'); try { // Prefer explicit recovery_doc from marker, fall back to alphabetical sort let latestHandoff = null; let handoffPath = null; if (explicitRecoveryDoc) { // Use explicit recovery doc from compaction marker (inst_083: Reliable handoff) const explicitPath = path.join(__dirname, '..', explicitRecoveryDoc); if (fs.existsSync(explicitPath)) { latestHandoff = explicitRecoveryDoc; handoffPath = explicitPath; log(` Using explicit recovery doc from marker: ${explicitRecoveryDoc}`, 'cyan'); } else { warning(` Marker specified ${explicitRecoveryDoc} but file not found`); warning(` Falling back to alphabetical sort`); } } // Fall back to modification time sort if no explicit recovery doc if (!latestHandoff) { const baseDir = path.join(__dirname, '..'); const handoffFiles = fs.readdirSync(baseDir) .filter(f => f.startsWith('SESSION_CLOSEDOWN_') && f.endsWith('.md')) .map(f => ({ name: f, path: path.join(baseDir, f), mtime: fs.statSync(path.join(baseDir, f)).mtime })) .sort((a, b) => b.mtime - a.mtime); // Most recent first if (handoffFiles.length > 0) { latestHandoff = handoffFiles[0].name; handoffPath = handoffFiles[0].path; const mtimeStr = handoffFiles[0].mtime.toISOString(); log(` Using most recent handoff (${mtimeStr}): ${latestHandoff}`, 'cyan'); } } if (latestHandoff && handoffPath) { const handoffContent = fs.readFileSync(handoffPath, 'utf8'); console.log(''); log('═'.repeat(70), 'yellow'); warning(`📄 PREVIOUS SESSION HANDOFF: ${latestHandoff}`); log('═'.repeat(70), 'yellow'); console.log(''); // Extract and display Priorities section const prioritiesMatch = handoffContent.match(/\*\*Priorities\*\*:([\s\S]*?)(?=\n##|\n---|\n\*\*|$)/); if (prioritiesMatch) { log(' 📋 PRIORITIES FROM PREVIOUS SESSION:', 'bright'); const priorities = prioritiesMatch[1].trim().split('\n').filter(line => line.trim()); priorities.forEach(priority => { log(` ${priority.trim()}`, 'yellow'); }); console.log(''); } // Extract and display Recent Commits (recent work) const commitsMatch = handoffContent.match(/\*\*Recent Commits\*\*:\s*```([\s\S]*?)```/); if (commitsMatch) { log(' 📝 RECENT WORK (Last Commits):', 'bright'); const commits = commitsMatch[1].trim().split('\n').filter(line => line.trim()).slice(0, 3); commits.forEach(commit => { log(` ${commit.trim()}`, 'cyan'); }); console.log(''); } // Extract and display Known Issues/Blockers const issuesMatch = handoffContent.match(/\*\*Known Issues\*\*:([\s\S]*?)(?=\n##|\n---|\n\*\*|$)/); if (issuesMatch) { log(' ⚠️ KNOWN ISSUES:', 'bright'); const issues = issuesMatch[1].trim().split('\n').filter(line => line.trim()); issues.forEach(issue => { log(` ${issue.trim()}`, 'red'); }); console.log(''); } // Extract cleanup summary const cleanupMatch = handoffContent.match(/Background processes killed:\s+(\d+)/); if (cleanupMatch) { log(` 🧹 Previous session cleanup: ${cleanupMatch[1]} background processes killed`, 'cyan'); console.log(''); } log('═'.repeat(70), 'yellow'); log(' HANDOFF CONTEXT LOADED - Continue with priorities above', 'green'); log('═'.repeat(70), 'yellow'); console.log(''); } else { log(' No recent handoff documents found - fresh start', 'cyan'); } } catch (handoffErr) { warning(`Could not load handoff document: ${handoffErr.message}`); } // Reset checkpoints for new day section('2. Resetting Token Checkpoints'); const checkpoints = resetTokenCheckpoints(); success(`Token budget: ${checkpoints.budget.toLocaleString()}`); success(`Next checkpoint: ${checkpoints.next_checkpoint.toLocaleString()} tokens (25%)`); // Check for orphaned background processes (inst_023) section('2a. Checking Background Processes (inst_023)'); try { const bgCheckOutput = execSync('node scripts/track-background-process.js list', { encoding: 'utf8', stdio: 'pipe' }); if (bgCheckOutput.includes('No tracked processes')) { success('No background processes tracked'); } else { log(bgCheckOutput, 'cyan'); // Check for orphaned processes from previous sessions const state = JSON.parse(fs.readFileSync('.claude/session-state.json', 'utf8')); const currentSession = state.session_id; const procs = state.background_processes || []; const orphaned = procs.filter(p => { try { process.kill(p.pid, 0); // Check if running return p.session !== currentSession; } catch (e) { return false; // Not running } }); if (orphaned.length > 0) { warning(`Found ${orphaned.length} orphaned process(es) from previous sessions`); orphaned.forEach(p => { log(` • PID ${p.pid}: ${p.description} (from ${p.session})`, 'yellow'); }); console.log(''); log(' Run "node scripts/track-background-process.js cleanup" to clean up', 'cyan'); } } } catch (err) { log(` Could not check background processes: ${err.message}`, 'yellow'); } // Hook approval cache reset (inst_061) section('2b. Hook Approval Cache Reset (inst_061)'); try { const approvalCache = '.claude/approval-cache.json'; if (fs.existsSync(approvalCache)) { const cache = JSON.parse(fs.readFileSync(approvalCache, 'utf8')); const state = JSON.parse(fs.readFileSync('.claude/session-state.json', 'utf8')); if (cache.sessionId !== state.sessionId) { // Session changed - reset cache cache.sessionId = state.sessionId; cache.approvals = []; fs.writeFileSync(approvalCache, JSON.stringify(cache, null, 2)); success('Hook approval cache reset for new session'); } else { log(` ${cache.approvals.length} approval(s) cached from current session`, 'cyan'); } } else { success('No approval cache (will be created on first use)'); } } catch (err) { log(` Could not check approval cache: ${err.message}`, 'yellow'); } // Load instruction history section('3. Loading Instruction History'); const instructions = loadInstructionHistory(); if (instructions.total === 0) { log(' No active instructions stored', 'yellow'); } else { success(`Active instructions: ${instructions.total}`); if (instructions.high > 0) { log(` HIGH persistence: ${instructions.high}`, 'cyan'); } if (instructions.medium > 0) { log(` MEDIUM persistence: ${instructions.medium}`, 'cyan'); } if (instructions.low > 0) { log(` LOW persistence: ${instructions.low}`, 'cyan'); } console.log(''); if (instructions.strategic > 0 || instructions.system > 0) { warning(`Critical instructions active (STRATEGIC: ${instructions.strategic}, SYSTEM: ${instructions.system})`); warning('These must be validated before conflicting actions'); } } // Run initial pressure check section('4. Running Initial Pressure Check'); const pressure = runPressureCheck(); success(`Pressure Level: ${pressure.level}`); success(`Overall Score: ${pressure.score}%`); // Framework component status section('5. Framework Components'); success('ContextPressureMonitor: ACTIVE'); success('InstructionPersistenceClassifier: READY'); success('CrossReferenceValidator: READY'); success('BoundaryEnforcer: READY'); success('MetacognitiveVerifier: READY (selective mode)'); success('PluralisticDeliberationOrchestrator: READY'); // Framework operational statistics section('5a. Framework Operational Statistics'); try { // Import services to get stats const BoundaryEnforcer = require('../src/services/BoundaryEnforcer.service'); const ContextPressureMonitor = require('../src/services/ContextPressureMonitor.service'); const CrossReferenceValidator = require('../src/services/CrossReferenceValidator.service'); const InstructionPersistenceClassifier = require('../src/services/InstructionPersistenceClassifier.service'); const MetacognitiveVerifier = require('../src/services/MetacognitiveVerifier.service'); const PluralisticDeliberationOrchestrator = require('../src/services/PluralisticDeliberationOrchestrator.service'); const stats = { boundary: BoundaryEnforcer.getStats(), pressure: ContextPressureMonitor.getStats(), validator: CrossReferenceValidator.getStats(), classifier: InstructionPersistenceClassifier.getStats(), verifier: MetacognitiveVerifier.getStats(), deliberation: PluralisticDeliberationOrchestrator.getStats() }; const totalActivity = stats.boundary.total_enforcements + stats.pressure.total_analyses + stats.validator.total_validations + stats.classifier.total_classifications + stats.verifier.total_verifications + stats.deliberation.total_deliberations; if (totalActivity === 0) { log(' No framework activity yet (fresh start)', 'cyan'); log(' Services will begin logging during session operations', 'cyan'); } else { success(`Framework activity detected: ${totalActivity} total operations`); if (stats.boundary.total_enforcements > 0) { log(` • BoundaryEnforcer: ${stats.boundary.total_enforcements} enforcements`, 'cyan'); } if (stats.pressure.total_analyses > 0) { log(` • ContextPressureMonitor: ${stats.pressure.total_analyses} analyses`, 'cyan'); } if (stats.validator.total_validations > 0) { log(` • CrossReferenceValidator: ${stats.validator.total_validations} validations`, 'cyan'); } if (stats.classifier.total_classifications > 0) { log(` • InstructionPersistenceClassifier: ${stats.classifier.total_classifications} classifications`, 'cyan'); } if (stats.verifier.total_verifications > 0) { log(` • MetacognitiveVerifier: ${stats.verifier.total_verifications} verifications`, 'cyan'); } if (stats.deliberation.total_deliberations > 0) { log(` • PluralisticDeliberationOrchestrator: ${stats.deliberation.total_deliberations} deliberations`, 'cyan'); } } // Check audit log database try { const mongoose = require('mongoose'); if (mongoose.connection.readyState !== 1) { await mongoose.connect('mongodb://localhost:27017/tractatus_dev', { serverSelectionTimeoutMS: 2000 }); } const AuditLog = mongoose.model('AuditLog'); const auditCount = await AuditLog.countDocuments(); const serviceBreakdown = await AuditLog.aggregate([ { $group: { _id: '$service', count: { $sum: 1 } } }, { $sort: { count: -1 } } ]); if (auditCount > 0) { console.log(''); success(`Audit logs: ${auditCount} decisions recorded`); const distinctServices = serviceBreakdown.length; log(` Services logging: ${distinctServices}/6`, distinctServices === 6 ? 'green' : 'yellow'); serviceBreakdown.slice(0, 6).forEach(s => { log(` ${s._id}: ${s.count} log${s.count !== 1 ? 's' : ''}`, 'cyan'); }); console.log(''); log(' 📊 Dashboard: http://localhost:9000/admin/audit-analytics.html', 'cyan'); } } catch (dbErr) { // MongoDB not available - skip audit stats log(' Audit database not available - stats unavailable', 'yellow'); } } catch (statsErr) { warning(`Could not load framework statistics: ${statsErr.message}`); } // Framework fade detection (inst_064) section('5b. Framework Activity Verification (inst_064)'); try { const sessionState = JSON.parse(fs.readFileSync('.claude/session-state.json', 'utf8')); const currentMessage = sessionState.message_count || 0; const stalenessThreshold = sessionState.staleness_thresholds?.messages || 20; const componentActivity = sessionState.last_framework_activity || {}; const fadeAlerts = []; const activeComponents = []; // Check each component for staleness const requiredComponents = [ 'ContextPressureMonitor', 'InstructionPersistenceClassifier', 'CrossReferenceValidator', 'BoundaryEnforcer', 'MetacognitiveVerifier', 'PluralisticDeliberationOrchestrator' ]; requiredComponents.forEach(component => { const activity = componentActivity[component]; if (!activity || !activity.timestamp) { // Never used fadeAlerts.push(`${component}: Never used this session`); } else { const messagesSinceUse = currentMessage - (activity.message || 0); if (messagesSinceUse > stalenessThreshold) { fadeAlerts.push(`${component}: ${messagesSinceUse} messages since last use (threshold: ${stalenessThreshold})`); } else { activeComponents.push(component); } } }); if (fadeAlerts.length === 0) { success('All framework components active - no fade detected'); log(` Active components: ${activeComponents.length}/6`, 'cyan'); } else if (fadeAlerts.length === requiredComponents.length) { // Fresh session - all components unused log(' Fresh session - framework components not yet triggered', 'cyan'); log(' Components will activate during session operations', 'cyan'); } else { // Partial fade detected warning(`Framework fade detected: ${fadeAlerts.length}/6 components stale`); fadeAlerts.forEach(alert => { log(` ⚠ ${alert}`, 'yellow'); }); console.log(''); warning('CRITICAL: Framework fade = governance collapse (inst_064)'); log(' Ensure components are used per their triggers:', 'yellow'); log(' • ContextPressureMonitor: Session start, checkpoints, complex ops', 'cyan'); log(' • CrossReferenceValidator: Schema changes, config mods, architecture', 'cyan'); log(' • BoundaryEnforcer: Privacy, ethics, values-sensitive decisions', 'cyan'); log(' • MetacognitiveVerifier: 3+ file mods or 5+ sequential steps', 'cyan'); log(' • InstructionPersistenceClassifier: Explicit instructions given', 'cyan'); log(' • PluralisticDeliberationOrchestrator: Values conflicts flagged', 'cyan'); } } catch (err) { error(`Framework fade check failed: ${err.message}`); } // Run framework tests section('6. Running Framework Tests'); try { log(' Running unit tests for Tractatus services...', 'cyan'); const testOutput = execSync( 'npm test -- --testPathPattern="tests/unit/(ContextPressureMonitor|InstructionPersistenceClassifier|CrossReferenceValidator|BoundaryEnforcer|MetacognitiveVerifier|PluralisticDeliberationOrchestrator)" 2>&1', { encoding: 'utf8' } ); // Extract test results const passMatch = testOutput.match(/Tests:\s+(\d+) passed/); const failMatch = testOutput.match(/(\d+) failed/); const totalMatch = testOutput.match(/(\d+) total/); if (failMatch && parseInt(failMatch[1]) > 0) { console.log(''); error(`Framework tests FAILED: ${failMatch[1]} failures`); error('Framework components are not functioning correctly - cannot proceed'); log(' Run: npm test -- --testPathPattern="tests/unit" for details', 'yellow'); console.log(''); error('Session initialization ABORTED due to test failures'); console.log(''); process.exit(1); // Exit with failure code } else if (passMatch) { success(`All framework tests passed (${passMatch[1]}/${totalMatch ? totalMatch[1] : passMatch[1]} tests)`); } else { warning('Could not parse test results - tests may have run successfully'); } } catch (err) { // Test failures throw non-zero exit code - this is a FAILURE condition const output = err.stdout || err.stderr || err.message; const passMatch = output.match(/Tests:\s+(\d+) passed/); const failMatch = output.match(/(\d+) failed/); // Check if tests actually passed despite stderr output if (passMatch && (!failMatch || parseInt(failMatch[1]) === 0)) { const totalMatch = output.match(/(\d+) total/); success(`All framework tests passed (${passMatch[1]}/${totalMatch ? totalMatch[1] : passMatch[1]} tests)`); // Tests passed, continue with remaining initialization steps } else { console.log(''); if (failMatch && parseInt(failMatch[1]) > 0) { error(`Framework tests FAILED: ${failMatch[1]} failures`); error('Framework components are not functioning correctly - cannot proceed'); log(' Run: npm test -- --testPathPattern="tests/unit" to see failures', 'yellow'); } else { error('Framework tests encountered an error'); error(err.message); } console.log(''); error('Session initialization ABORTED due to test failures'); console.log(''); process.exit(1); // Exit with failure code } } // Prohibited Terms Scan (Framework Phase 1) section('7. Scanning for Prohibited Terms'); try { const ProhibitedTermsScanner = require('./framework-components/ProhibitedTermsScanner'); const scanner = new ProhibitedTermsScanner({ silent: false }); const violations = await scanner.scan(); if (violations.length === 0) { success('No prohibited terms found (inst_016/017/018 compliant)'); } else { console.log(''); warning(`Found ${violations.length} violation(s) in user-facing content:`); // Group by rule const byRule = violations.reduce((acc, v) => { if (!acc[v.rule]) acc[v.rule] = []; acc[v.rule].push(v); return acc; }, {}); Object.entries(byRule).forEach(([rule, items]) => { log(` ${rule}: ${items.length} violation(s)`, 'yellow'); }); console.log(''); log(' Run: node scripts/framework-components/ProhibitedTermsScanner.js --details', 'cyan'); log(' Or: node scripts/framework-components/ProhibitedTermsScanner.js --fix', 'cyan'); console.log(''); } } catch (err) { warning(`Could not run prohibited terms scanner: ${err.message}`); } // CSP Compliance Scan section('8. CSP Compliance Scan (inst_008)'); try { const { scanForViolations, displayViolations } = require('./check-csp-violations'); const violations = scanForViolations(); if (violations.length === 0) { success('No CSP violations found in public files'); } else { error(`Found ${violations.length} CSP violation(s) in codebase`); console.log(''); // Group by file for summary const fileGroups = {}; violations.forEach(v => { fileGroups[v.file] = (fileGroups[v.file] || 0) + 1; }); Object.entries(fileGroups).forEach(([file, count]) => { log(` • ${file}: ${count} violation(s)`, 'yellow'); }); console.log(''); warning('Run: node scripts/check-csp-violations.js for details'); warning('Run: node scripts/fix-csp-violations.js to remediate'); console.log(''); } } catch (err) { warning(`Could not run CSP scan: ${err.message}`); } // Defense-in-Depth Health Check (inst_072) section('8a. Defense-in-Depth Health Check (inst_072)'); try { const auditResult = execSync('node scripts/audit-defense-in-depth.js 2>&1', { encoding: 'utf8', stdio: 'pipe' }); if (auditResult.includes('All 5 layers')) { success('All 5 credential protection layers verified'); } else { const incompleteCount = (auditResult.match(/❌/g) || []).length; warning(`${incompleteCount} defense layer(s) incomplete`); log(' Run: node scripts/audit-defense-in-depth.js for details', 'cyan'); } } catch (err) { // Non-blocking - just warn warning('Defense-in-depth audit incomplete (see details above)'); } // Dependency License Check (inst_080) section('8b. Dependency License Check (inst_080)'); try { execSync('node scripts/check-dependency-licenses.js', { encoding: 'utf8', stdio: 'pipe' }); success('All dependencies are Apache 2.0 compatible'); } catch (err) { // Check if it's a critical failure or just warnings const output = err.stdout || ''; if (output.includes('CRITICAL')) { error('Prohibited dependency licenses detected'); log(' Run: node scripts/check-dependency-licenses.js for details', 'red'); } else if (output.includes('HIGH')) { warning('Restrictive licenses detected (may require review)'); log(' Run: node scripts/check-dependency-licenses.js for details', 'yellow'); } else { success('Dependency licenses checked (some flagged for review)'); } } // ENFORCEMENT: Local development server check section('9. Development Environment Enforcement'); const localServerRunning = checkLocalServer(); if (!localServerRunning) { error('LOCAL DEVELOPMENT SERVER NOT RUNNING ON PORT 9000'); console.log(''); log(' ⚠️ MANDATORY REQUIREMENT:', 'bright'); log(' All development work MUST be tested locally before production deployment.', 'yellow'); log(' The local server on port 9000 is required for:', 'yellow'); log(' • Testing changes before deployment', 'cyan'); log(' • Verifying integrations work correctly', 'cyan'); log(' • Preventing production-first development', 'cyan'); log(' • Framework fade prevention', 'cyan'); console.log(''); log(' To fix:', 'bright'); log(' 1. Open a new terminal', 'cyan'); log(' 2. cd /home/theflow/projects/tractatus', 'cyan'); log(' 3. npm start', 'cyan'); log(' 4. Re-run: node scripts/session-init.js', 'cyan'); console.log(''); log(' Once the server is running, session-init will pass.', 'green'); console.log(''); error('SESSION BLOCKED: Start local server before proceeding'); console.log(''); process.exit(1); } success('Local development server running on port 9000'); success('Development environment ready'); // Hook Architecture Status section('10. Continuous Enforcement Architecture'); const hookValidatorsExist = fs.existsSync(path.join(__dirname, 'hook-validators')); if (hookValidatorsExist) { success('Hook validators installed (architectural enforcement)'); log(' • validate-file-edit.js: Enforces pre-action checks, CSP, conflicts', 'cyan'); log(' • validate-file-write.js: Prevents overwrites, enforces boundaries', 'cyan'); log(' • check-token-checkpoint.js: Prevents checkpoint fade', 'cyan'); console.log(''); log(' 📋 Pre-approved commands documented in PRE_APPROVED_COMMANDS.md', 'cyan'); log(' 🔍 Hook architecture prevents voluntary compliance failures', 'cyan'); } else { warning('Hook validators not yet installed'); log(' Hooks provide architectural enforcement beyond documentation', 'yellow'); } // Database Sync section('10. Syncing Instructions to Database'); try { log(' Synchronizing .claude/instruction-history.json to MongoDB...', 'cyan'); const { syncInstructions } = require('./sync-instructions-to-db.js'); // Run sync in silent mode (no verbose output) const syncResult = await syncInstructions(); if (syncResult && syncResult.success) { success(`Database synchronized: ${syncResult.finalCount} active rules`); if (syncResult.added > 0) { log(` Added: ${syncResult.added} new rules`, 'cyan'); } if (syncResult.updated > 0) { log(` Updated: ${syncResult.updated} existing rules`, 'cyan'); } if (syncResult.deactivated > 0) { log(` Deactivated: ${syncResult.deactivated} orphaned rules`, 'cyan'); } } else { warning('Database sync skipped or failed - admin UI may show stale data'); } } catch (err) { warning(`Database sync failed: ${err.message}`); log(' Admin UI may show outdated rule counts', 'yellow'); log(' Run: node scripts/sync-instructions-to-db.js --force to sync manually', 'yellow'); } // Credential Vault Server (Optional) section('11. Credential Vault Server'); const vaultPath = path.join(process.env.HOME, 'Documents/credentials/vault.kdbx'); const vaultServerPath = path.join(__dirname, '../.credential-vault'); if (fs.existsSync(vaultPath)) { // Vault exists, try to start server try { // Check if already running let vaultServerRunning = false; try { const lsofOutput = execSync('lsof -i :8888 -t', { encoding: 'utf8', stdio: 'pipe' }); vaultServerRunning = lsofOutput.trim().length > 0; } catch (err) { vaultServerRunning = false; } if (vaultServerRunning) { success('Credential vault server already running on port 8888'); log(' URL: http://127.0.0.1:8888', 'cyan'); } else { log(' Starting credential vault server...', 'cyan'); // Install dependencies if needed const nodeModulesExists = fs.existsSync(path.join(vaultServerPath, 'node_modules')); if (!nodeModulesExists) { log(' Installing vault server dependencies...', 'cyan'); execSync('npm install', { cwd: vaultServerPath, stdio: 'pipe' }); } // Start server in background const { spawn } = require('child_process'); const vaultServer = spawn('node', ['server.js'], { cwd: vaultServerPath, detached: true, stdio: 'ignore' }); vaultServer.unref(); // Wait briefly for server to start execSync('sleep 2'); // Verify it started try { const lsofOutput = execSync('lsof -i :8888 -t', { encoding: 'utf8', stdio: 'pipe' }); if (lsofOutput.trim().length > 0) { success('Credential vault server started on port 8888'); log(' URL: http://127.0.0.1:8888', 'cyan'); log(' Features: Interactive UI, WebSocket, auto-lock', 'cyan'); } else { warning('Vault server may not have started successfully'); } } catch (err) { warning('Could not verify vault server status'); } } } catch (err) { warning(`Could not start credential vault server: ${err.message}`); log(' Vault server is optional - manual start: cd .credential-vault && npm start', 'yellow'); } } else { log(' Vault not created yet - skipping server startup', 'cyan'); log(' Create vault: ~/Documents/credentials/scripts/create-vault.sh', 'yellow'); } // Calendar Reminders section('12. Scheduled Task Reminders'); try { // Check if MongoDB is running and calendar system is available let dueSoonTasks = []; let overdueTasks = []; // Try to connect to MongoDB and query tasks directly const mongoose = require('mongoose'); const ScheduledTask = require('../src/models/ScheduledTask.model.js'); // Only attempt if mongoose has an active connection or can connect if (mongoose.connection.readyState === 1) { // Already connected dueSoonTasks = await ScheduledTask.getDueSoon(7); overdueTasks = await ScheduledTask.getOverdue(); } else { // Try to connect to MongoDB try { await mongoose.connect('mongodb://localhost:27017/tractatus_dev', { serverSelectionTimeoutMS: 2000 }); dueSoonTasks = await ScheduledTask.getDueSoon(7); overdueTasks = await ScheduledTask.getOverdue(); } catch (dbErr) { log(' Calendar database not available - skipping reminders', 'cyan'); log(' Start MongoDB to see scheduled tasks', 'yellow'); throw dbErr; // Re-throw to skip to catch block } } if (overdueTasks.length === 0 && dueSoonTasks.length === 0) { success('No urgent tasks - all clear'); } else { if (overdueTasks.length > 0) { console.log(''); error(`⚠️ ${overdueTasks.length} OVERDUE TASK(S):`); overdueTasks.slice(0, 5).forEach(task => { const dueDate = new Date(task.dueDate).toLocaleDateString(); log(` • [${task.priority}] ${task.title}`, 'red'); log(` Due: ${dueDate} | Category: ${task.category}`, 'yellow'); if (task.documentRef) { log(` Doc: ${task.documentRef}`, 'cyan'); } }); if (overdueTasks.length > 5) { log(` ... and ${overdueTasks.length - 5} more`, 'yellow'); } } if (dueSoonTasks.length > 0) { console.log(''); warning(`📅 ${dueSoonTasks.length} task(s) due within 7 days:`); dueSoonTasks.slice(0, 5).forEach(task => { const dueDate = new Date(task.dueDate).toLocaleDateString(); const daysUntil = Math.ceil((new Date(task.dueDate) - new Date()) / (1000 * 60 * 60 * 24)); log(` • [${task.priority}] ${task.title}`, 'yellow'); log(` Due in ${daysUntil} day(s) (${dueDate}) | ${task.category}`, 'cyan'); if (task.documentRef) { log(` Doc: ${task.documentRef}`, 'cyan'); } }); if (dueSoonTasks.length > 5) { log(` ... and ${dueSoonTasks.length - 5} more`, 'yellow'); } } console.log(''); log(' 📋 View all tasks: http://localhost:9000/admin/calendar.html', 'cyan'); } } catch (err) { warning(`Could not load calendar reminders: ${err.message}`); log(' Calendar system may not be initialized yet', 'yellow'); } // Summary header('Framework Initialization Complete'); console.log(''); log(' All 6 components are active and monitoring this session.', 'green'); console.log(''); log(' Next Actions:', 'bright'); log(' • Framework will monitor continuously', 'cyan'); log(' • Token checkpoint at 50,000 tokens (25%)', 'cyan'); log(' • Pressure checks at 25%, 50%, 75% milestones', 'cyan'); log(' • All instructions will be cross-referenced', 'cyan'); console.log(''); log(' ⚠️ MANDATORY REPORTING (Framework Discipline):', 'bright'); log(' • MUST report pressure to user at 50k, 100k, 150k tokens', 'yellow'); log(' • Format: "📊 Context Pressure: [LEVEL] ([SCORE]%) | Tokens: [X]/200000 | Next: [Y]"', 'yellow'); log(' • Failure to report = Framework fade (triggers recovery)', 'yellow'); console.log(''); log(' Claude: You may now proceed with session work.', 'green'); console.log(''); // Exit successfully process.exit(0); } // Run main().catch(err => { console.error(''); error(`Initialization failed: ${err.message}`); console.error(''); process.exit(1); });