Implements architectural enforcement of governance rules (inst_016/017/018/079) for all external communications. Publication blocked at API level if violations detected. New Features: - Framework content checker script with pattern matching for prohibited terms - Admin UI displays framework violations with severity indicators - Manual "Check Framework" button for pre-publication validation - API endpoint /api/blog/check-framework for real-time content analysis Governance Rules Added: - inst_078: "ff" trigger for manual framework invocation in conversations - inst_079: Dark patterns prohibition (sovereignty principle) - inst_080: Open source commitment enforcement (community principle) - inst_081: Pluralism principle with indigenous framework recognition Session Management: - Fix session-init.js infinite loop (removed early return after tests) - Add session-closedown.js for comprehensive session handoff - Refactor check-csp-violations.js to prevent parent process exit Framework Services: - Enhanced PluralisticDeliberationOrchestrator with audit logging - Updated all 6 services with consistent initialization patterns - Added framework invocation scripts for blog content validation Files: blog.controller.js:1211-1305, blog.routes.js:77-82, blog-curation.html:61-72, blog-curation.js:320-446 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
216 lines
6.3 KiB
JavaScript
Executable file
216 lines
6.3 KiB
JavaScript
Executable file
#!/usr/bin/env node
|
|
|
|
/**
|
|
* Framework Integration Hook
|
|
*
|
|
* Automatically invokes framework services during Claude Code tool execution.
|
|
* This hook runs on every tool use and routes to appropriate framework services.
|
|
*
|
|
* Integrated Services:
|
|
* - BoundaryEnforcer: Security, architectural, cross-project boundaries
|
|
* - ContextPressureMonitor: Token/message pressure tracking
|
|
* - CrossReferenceValidator: Instruction compliance validation
|
|
* - MetacognitiveVerifier: Decision reasoning verification
|
|
* - InstructionPersistenceClassifier: New instruction classification
|
|
* - PluralisticDeliberationOrchestrator: Value conflict deliberation
|
|
*/
|
|
|
|
const path = require('path');
|
|
const fs = require('fs');
|
|
|
|
// Parse command line arguments
|
|
const args = process.argv.slice(2);
|
|
const toolName = args[0]; // 'Edit', 'Write', 'Read', 'Bash', etc.
|
|
const toolArgsJson = args[1]; // JSON string of tool arguments
|
|
|
|
// Exit early if no args (allow execution)
|
|
if (!toolName || !toolArgsJson) {
|
|
process.exit(0);
|
|
}
|
|
|
|
let toolArgs;
|
|
try {
|
|
toolArgs = JSON.parse(toolArgsJson);
|
|
} catch (err) {
|
|
// Invalid JSON, allow execution
|
|
process.exit(0);
|
|
}
|
|
|
|
/**
|
|
* Main framework integration logic
|
|
*/
|
|
async function integrateFramework() {
|
|
const mongoose = require('mongoose');
|
|
|
|
// Connect to MongoDB
|
|
try {
|
|
await mongoose.connect('mongodb://localhost:27017/tractatus_dev', {
|
|
serverSelectionTimeoutMS: 2000
|
|
});
|
|
} catch (err) {
|
|
// MongoDB not available, skip framework (allow execution)
|
|
process.exit(0);
|
|
}
|
|
|
|
// Import framework services
|
|
const BoundaryEnforcer = require('../../src/services/BoundaryEnforcer.service');
|
|
const ContextPressureMonitor = require('../../src/services/ContextPressureMonitor.service');
|
|
const CrossReferenceValidator = require('../../src/services/CrossReferenceValidator.service');
|
|
const MetacognitiveVerifier = require('../../src/services/MetacognitiveVerifier.service');
|
|
|
|
const sessionId = 'claude-code-session-' + new Date().toISOString().split('T')[0];
|
|
|
|
try {
|
|
// Route to appropriate framework service based on tool
|
|
switch (toolName) {
|
|
case 'Edit':
|
|
case 'Write':
|
|
await handleFileModification(toolArgs, sessionId);
|
|
break;
|
|
|
|
case 'Bash':
|
|
await handleBashCommand(toolArgs, sessionId);
|
|
break;
|
|
|
|
case 'Read':
|
|
await handleFileRead(toolArgs, sessionId);
|
|
break;
|
|
|
|
default:
|
|
// Unknown tool, allow execution
|
|
break;
|
|
}
|
|
|
|
await mongoose.disconnect();
|
|
process.exit(0); // Allow execution
|
|
|
|
} catch (err) {
|
|
console.error('[Framework Hook] Error:', err.message);
|
|
await mongoose.disconnect();
|
|
|
|
// If framework service blocks, exit with code 1
|
|
if (err.blocked) {
|
|
process.exit(1); // Block execution
|
|
}
|
|
|
|
process.exit(0); // Allow execution on errors
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Handle file modifications (Edit, Write tools)
|
|
*/
|
|
async function handleFileModification(args, sessionId) {
|
|
const BoundaryEnforcer = require('../../src/services/BoundaryEnforcer.service');
|
|
const CrossReferenceValidator = require('../../src/services/CrossReferenceValidator.service');
|
|
const MetacognitiveVerifier = require('../../src/services/MetacognitiveVerifier.service');
|
|
|
|
const filePath = args.file_path || args.path || 'unknown';
|
|
const content = args.new_string || args.content || '';
|
|
|
|
// Check boundaries
|
|
const boundaryContext = {
|
|
sessionId,
|
|
action: 'file_modification',
|
|
target: filePath,
|
|
description: `Modify ${path.basename(filePath)}`,
|
|
metadata: {
|
|
tool: 'Edit/Write',
|
|
contentLength: content.length
|
|
}
|
|
};
|
|
|
|
try {
|
|
await BoundaryEnforcer.checkBoundaries(boundaryContext);
|
|
} catch (err) {
|
|
if (err.message.includes('boundary')) {
|
|
throw { blocked: true, reason: err.message };
|
|
}
|
|
}
|
|
|
|
// Validate against instructions (if modifying governance files)
|
|
const governanceFiles = ['CLAUDE.md', 'instruction-history.json', 'auth.middleware.js', 'auth.controller.js'];
|
|
const isGovernanceFile = governanceFiles.some(f => filePath.includes(f));
|
|
|
|
if (isGovernanceFile) {
|
|
await CrossReferenceValidator.validateAgainstInstructions({
|
|
sessionId,
|
|
action: 'modify_governance_file',
|
|
description: `Modifying ${path.basename(filePath)}`,
|
|
context: { file: filePath }
|
|
});
|
|
}
|
|
|
|
// Metacognitive verification for security-critical files
|
|
const securityFiles = ['auth', 'security', 'credential', 'jwt', 'password'];
|
|
const isSecurityFile = securityFiles.some(keyword => filePath.toLowerCase().includes(keyword));
|
|
|
|
if (isSecurityFile) {
|
|
await MetacognitiveVerifier.verifyDecision({
|
|
sessionId,
|
|
action: 'modify_security_file',
|
|
reasoning: `Modifying security-critical file: ${filePath}`,
|
|
context: {
|
|
file: filePath,
|
|
security_impact: true,
|
|
requires_approval: true
|
|
}
|
|
});
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Handle Bash command execution
|
|
*/
|
|
async function handleBashCommand(args, sessionId) {
|
|
const BoundaryEnforcer = require('../../src/services/BoundaryEnforcer.service');
|
|
|
|
const command = args.command || '';
|
|
|
|
// Check for cross-project commands
|
|
const crossProjectPatterns = ['/family-history/', '/sydigital/', 'cd ../'];
|
|
const isCrossProject = crossProjectPatterns.some(pattern => command.includes(pattern));
|
|
|
|
if (isCrossProject) {
|
|
await BoundaryEnforcer.checkBoundaries({
|
|
sessionId,
|
|
action: 'bash_command',
|
|
target: command,
|
|
description: 'Cross-project bash command',
|
|
metadata: {
|
|
command: command.substring(0, 100)
|
|
}
|
|
});
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Handle file reads
|
|
*/
|
|
async function handleFileRead(args, sessionId) {
|
|
// File reads are generally allowed, just track context pressure
|
|
const ContextPressureMonitor = require('../../src/services/ContextPressureMonitor.service');
|
|
|
|
// Update pressure tracking (passive monitoring)
|
|
// This doesn't block, just logs
|
|
try {
|
|
const sessionState = JSON.parse(
|
|
fs.readFileSync(path.join(__dirname, '../../.claude/session-state.json'), 'utf8')
|
|
);
|
|
|
|
await ContextPressureMonitor.analyzeContext({
|
|
sessionId,
|
|
tokens: sessionState.token_estimate || 0,
|
|
budget: 200000,
|
|
messages: sessionState.message_count || 0
|
|
});
|
|
} catch (err) {
|
|
// Ignore pressure monitoring errors
|
|
}
|
|
}
|
|
|
|
// Run integration
|
|
integrateFramework().catch(err => {
|
|
console.error('[Framework Hook] Fatal error:', err.message);
|
|
process.exit(0); // Allow execution on fatal errors
|
|
});
|