#!/usr/bin/env node // ═══════════════════════════════════════════════════════════════════════════ // EOS Capability Registry — Resonera i verksamhetsförmågor, inte tekniska komponenter // Erik-krav: "Då börjar ni resonera i verksamhetsförmågor snarare än tekniska komponenter" // ═══════════════════════════════════════════════════════════════════════════ import { readFileSync, writeFileSync, existsSync } from 'fs'; const REGISTRY_PATH = '/home/bernt/.openclaw/workspace/EOS/capability-registry.json'; /** * Capabilities för quiXzoom/LandveX */ const DEFAULT_CAPABILITIES = [ { id: 'cap-mission-mgmt', name: 'Mission Management', description: 'Hantera uppdrag (missions) för Zoomers', owner: 'Mission Team', services: ['Mission Service'], apis: ['/mission/create', '/mission/assign', '/mission/complete'], database: 'missions', tests: ['mission.integration.ts'], dashboards: ['Mission KPI', 'Completion Rate'], dependencies: ['cap-user-mgmt', 'cap-payment'], budget: { maxDirectDeps: 8, maxExternalApis: 2, maxDatabases: 1 } }, { id: 'cap-user-mgmt', name: 'User Management', description: 'Hantera Zoomers, kunder och identiteter', owner: 'Identity Team', services: ['Identity Service', 'Wallet Service'], apis: ['/user/register', '/user/login', '/user/verify'], database: 'users', tests: ['user.integration.ts', 'identity.unit.ts'], dashboards: ['User Growth', 'Verification Rate'], dependencies: ['cap-payment'], budget: { maxDirectDeps: 6, maxExternalApis: 2, maxDatabases: 1 } }, { id: 'cap-payment', name: 'Payment Processing', description: 'Hantera betalningar via Stripe Connect', owner: 'Finance Team', services: ['Payment Service', 'Stripe Adapter'], apis: ['/payment/create', '/payment/webhook', '/payout/schedule'], database: 'transactions', tests: ['payment.integration.ts'], dashboards: ['Revenue', 'Payout Status'], dependencies: [], budget: { maxDirectDeps: 4, maxExternalApis: 1, maxDatabases: 1 } }, { id: 'cap-content', name: 'Content Management', description: 'Hantera bilder, video och dokument', owner: 'Content Team', services: ['Media Service', 'Storage Adapter'], apis: ['/media/upload', '/media/retrieve', '/media/delete'], database: 'media_metadata', tests: ['media.integration.ts'], dashboards: ['Storage Usage', 'Upload Success Rate'], dependencies: [], budget: { maxDirectDeps: 5, maxExternalApis: 1, maxDatabases: 1 } }, { id: 'cap-analytics', name: 'Analytics & Reporting', description: 'Samla och analysera data', owner: 'Data Team', services: ['Analytics Service', 'Report Engine'], apis: ['/analytics/event', '/report/generate'], database: 'analytics', tests: ['analytics.unit.ts'], dashboards: ['System Health', 'Business Metrics'], dependencies: ['cap-mission-mgmt', 'cap-user-mgmt'], budget: { maxDirectDeps: 6, maxExternalApis: 2, maxDatabases: 1 } } ]; class CapabilityRegistry { constructor() { this.capabilities = this.loadCapabilities(); } loadCapabilities() { if (existsSync(REGISTRY_PATH)) { return JSON.parse(readFileSync(REGISTRY_PATH, 'utf8')); } return DEFAULT_CAPABILITIES; } saveCapabilities() { writeFileSync(REGISTRY_PATH, JSON.stringify(this.capabilities, null, 2)); } /** * Hitta capability från vilken som helst referens */ resolve(reference) { // Sök på ID let cap = this.capabilities.find(c => c.id === reference); if (cap) return cap; // Sök på service cap = this.capabilities.find(c => c.services.includes(reference)); if (cap) return cap; // Sök på API cap = this.capabilities.find(c => c.apis.includes(reference)); if (cap) return cap; // Sök på databas cap = this.capabilities.find(c => c.database === reference); if (cap) return cap; return null; } /** * Kontrollera om en ändring bryter mot capability-struktur */ validateChange(change) { const cap = this.resolve(change.capability); if (!cap) { return { valid: false, reason: `Ingen capability hittad för: ${change.capability}` }; } const issues = []; // Kontrollera beroenden if (change.newDependencies) { const currentDeps = cap.dependencies.length; const newDeps = change.newDependencies.length; if (currentDeps + newDeps > cap.budget.maxDirectDeps) { issues.push(`För många beroenden: ${currentDeps + newDeps}/${cap.budget.maxDirectDeps}`); } } // Kontrollera externa API:er if (change.newExternalApis) { const currentApis = cap.apis.filter(a => a.includes('stripe') || a.includes('external')).length; const newApis = change.newExternalApis.length; if (currentApis + newApis > cap.budget.maxExternalApis) { issues.push(`För många externa API:er: ${currentApis + newApis}/${cap.budget.maxExternalApis}`); } } // Kontrollera databaser if (change.newDatabase) { if (cap.database && change.newDatabase !== cap.database) { issues.push(`Flera databaser: ${cap.database}, ${change.newDatabase} (max: ${cap.budget.maxDatabases})`); } } return { valid: issues.length === 0, capability: cap, issues, budget: cap.budget }; } /** * Visa capability-karta */ showMap() { console.log('🗺️ CAPABILITY MAP\n'); for (const cap of this.capabilities) { console.log(`📦 ${cap.name} (${cap.id})`); console.log(` ${cap.description}`); console.log(` Ägare: ${cap.owner}`); console.log(); console.log(' 🔗 Services:'); for (const service of cap.services) { console.log(` • ${service}`); } console.log(' 📡 APIs:'); for (const api of cap.apis) { console.log(` • ${api}`); } console.log(` 🗄️ Database: ${cap.database}`); console.log(' 🧪 Tests:'); for (const test of cap.tests) { console.log(` • ${test}`); } console.log(' 📊 Dashboards:'); for (const dash of cap.dashboards) { console.log(` • ${dash}`); } if (cap.dependencies.length > 0) { console.log(' ⬇️ Dependencies:'); for (const dep of cap.dependencies) { const depCap = this.resolve(dep); console.log(` • ${depCap?.name || dep}`); } } console.log(' 💰 Budget:'); console.log(` Max direkta beroenden: ${cap.budget.maxDirectDeps}`); console.log(` Max externa API:er: ${cap.budget.maxExternalApis}`); console.log(` Max databaser: ${cap.budget.maxDatabases}`); console.log(); } } /** * Visa beroendegraf */ showDependencyGraph() { console.log('📊 DEPENDENCY GRAPH\n'); for (const cap of this.capabilities) { const deps = cap.dependencies.map(d => { const depCap = this.resolve(d); return depCap?.name || d; }); const depCount = deps.length; const budgetStatus = depCount > cap.budget.maxDirectDeps ? '🔴' : depCount > cap.budget.maxDirectDeps * 0.8 ? '⚠️' : '✅'; console.log(`${depCount}/${cap.budget.maxDirectDeps} ${budgetStatus} ${cap.name}`); if (deps.length > 0) { for (const dep of deps) { console.log(` → ${dep}`); } } console.log(); } } } // ── Main ────────────────────────────────────────────────────────────────── const registry = new CapabilityRegistry(); const command = process.argv[2] || '--map'; if (command === '--map') { registry.showMap(); } else if (command === '--deps') { registry.showDependencyGraph(); } else if (command === '--validate') { const change = { capability: process.argv[3] || 'cap-mission-mgmt', newDependencies: process.argv[4]?.split(',') || [], newExternalApis: process.argv[5]?.split(',') || [], newDatabase: process.argv[6] || null }; const result = registry.validateChange(change); console.log(`🔍 Validerar ändring för: ${change.capability}\n`); if (result.valid) { console.log('✅ Ändringen bryter inte mot capability-strukturen\n'); } else { console.log('❌ Ändringen bryter mot capability-strukturen\n'); for (const issue of result.issues) { console.log(` • ${issue}`); } console.log(); console.log('💰 Budget:'); console.log(` Max direkta beroenden: ${result.budget.maxDirectDeps}`); console.log(` Max externa API:er: ${result.budget.maxExternalApis}`); console.log(` Max databaser: ${result.budget.maxDatabases}`); } } else { console.log('Användning:'); console.log(' node capability-registry.mjs --map # Visa capability-karta'); console.log(' node capability-registry.mjs --deps # Visa beroendegraf'); console.log(' node capability-registry.mjs --validate [deps] [apis] [db] # Validera ändring'); }