#!/usr/bin/env node /** * Add Instruction to Instruction History * * Safely adds a new governance instruction to instruction-history.json * Bypasses inst_027 prohibition on direct file edits * * Usage: * node scripts/add-instruction.js --text "instruction text" --quadrant STRATEGIC --persistence HIGH */ const fs = require('fs'); const path = require('path'); const INSTRUCTION_HISTORY_PATH = path.join(__dirname, '../.claude/instruction-history.json'); // Parse command-line arguments function parseArgs() { const args = process.argv.slice(2); const parsed = { text: null, quadrant: 'OPERATIONAL', persistence: 'MEDIUM', temporal_scope: 'PERMANENT', verification_required: 'OPTIONAL', explicitness: 0.8, notes: '' }; for (let i = 0; i < args.length; i++) { const arg = args[i]; if (arg === '--help' || arg === '-h') { showHelp(); process.exit(0); } if (arg === '--text' && args[i + 1]) { parsed.text = args[i + 1]; i++; } else if (arg === '--quadrant' && args[i + 1]) { parsed.quadrant = args[i + 1]; i++; } else if (arg === '--persistence' && args[i + 1]) { parsed.persistence = args[i + 1]; i++; } else if (arg === '--temporal' && args[i + 1]) { parsed.temporal_scope = args[i + 1]; i++; } else if (arg === '--verification' && args[i + 1]) { parsed.verification_required = args[i + 1]; i++; } else if (arg === '--explicitness' && args[i + 1]) { parsed.explicitness = parseFloat(args[i + 1]); i++; } else if (arg === '--notes' && args[i + 1]) { parsed.notes = args[i + 1]; i++; } } return parsed; } function showHelp() { console.log(` Add Instruction to Instruction History Usage: node scripts/add-instruction.js --text "instruction text" [options] Required Arguments: --text The instruction text Optional Arguments: --quadrant STRATEGIC, OPERATIONAL, TACTICAL, or SYSTEM (default: OPERATIONAL) --persistence HIGH, MEDIUM, or LOW (default: MEDIUM) --temporal PERMANENT, SESSION, or IMMEDIATE (default: PERMANENT) --verification MANDATORY or OPTIONAL (default: OPTIONAL) --explicitness 0.0 to 1.0 (default: 0.8) --notes Additional notes about this instruction Examples: # Add a database security instruction node scripts/add-instruction.js \\ --text "All database queries must use prepared statements" \\ --quadrant SYSTEM \\ --persistence HIGH \\ --verification MANDATORY # Add a tactical code style instruction node scripts/add-instruction.js \\ --text "Use async/await instead of .then() chains" \\ --quadrant TACTICAL \\ --persistence LOW `); } function getNextInstructionId(instructions) { // Find highest numbered instruction const numbered = instructions .map(i => i.id) .filter(id => /^inst_\d+$/.test(id)) .map(id => parseInt(id.replace('inst_', ''))) .filter(n => !isNaN(n)); const maxId = numbered.length > 0 ? Math.max(...numbered) : 0; return `inst_${String(maxId + 1).padStart(3, '0')}`; } function main() { const args = parseArgs(); // Validate required arguments if (!args.text) { console.error('❌ Error: --text is required'); console.error('Run with --help for usage information'); process.exit(1); } // Validate quadrant const validQuadrants = ['STRATEGIC', 'OPERATIONAL', 'TACTICAL', 'SYSTEM']; if (!validQuadrants.includes(args.quadrant)) { console.error(`❌ Error: Invalid quadrant "${args.quadrant}"`); console.error(` Valid options: ${validQuadrants.join(', ')}`); process.exit(1); } // Validate persistence const validPersistence = ['HIGH', 'MEDIUM', 'LOW']; if (!validPersistence.includes(args.persistence)) { console.error(`❌ Error: Invalid persistence "${args.persistence}"`); console.error(` Valid options: ${validPersistence.join(', ')}`); process.exit(1); } // Read current instruction history let history; try { history = JSON.parse(fs.readFileSync(INSTRUCTION_HISTORY_PATH, 'utf8')); } catch (err) { console.error('❌ Error reading instruction-history.json:', err.message); process.exit(1); } // Get next instruction ID const newId = getNextInstructionId(history.instructions); // Create new instruction const newInstruction = { id: newId, text: args.text, timestamp: new Date().toISOString(), quadrant: args.quadrant, persistence: args.persistence, temporal_scope: args.temporal_scope, verification_required: args.verification_required, explicitness: args.explicitness, source: 'manual_script', session_id: 'user_added', active: true, created_date: new Date().toISOString().split('T')[0] }; if (args.notes) { newInstruction.notes = args.notes; } // Add to instructions array history.instructions.push(newInstruction); // Update metadata history.last_updated = new Date().toISOString(); // Write back to file try { fs.writeFileSync(INSTRUCTION_HISTORY_PATH, JSON.stringify(history, null, 2)); } catch (err) { console.error('❌ Error writing instruction-history.json:', err.message); process.exit(1); } console.log(`✅ Added ${newId}: ${args.text.substring(0, 60)}${args.text.length > 60 ? '...' : ''}`); console.log(` Quadrant: ${args.quadrant}`); console.log(` Persistence: ${args.persistence}`); console.log(` Total instructions: ${history.instructions.length}`); console.log(` Active instructions: ${history.instructions.filter(i => i.active).length}`); console.log(''); console.log('💡 Next step: Run sync-instructions-to-db.js to persist to MongoDB'); } main();