#!/usr/bin/env node // ═══════════════════════════════════════════════════════════════════════════ // Agent Runtime v2 — Med Runtime Trace och Acceptance Tests // ═══════════════════════════════════════════════════════════════════════════ import { RuntimeTrace } from './runtime-trace.mjs'; const AGENT_ROLES = { PLANNER: { id: 'planner', name: 'Planner', description: 'Bryter ned arbete och planerar', tools: ['plan', 'estimate', 'prioritize'], permissions: ['read', 'plan'], eosChecks: ['goal-alignment', 'dependency-check'] }, DEVELOPER: { id: 'developer', name: 'Developer', description: 'Skriver kod', tools: ['read', 'write', 'edit', 'exec'], permissions: ['read', 'write', 'edit'], eosChecks: ['no-hardcoded-secrets', 'test-required', 'no-direct-prod'] }, REVIEWER: { id: 'reviewer', name: 'Reviewer', description: 'Granskar kod och kör EOS/SIL', tools: ['read', 'analyze', 'verify'], permissions: ['read', 'analyze'], eosChecks: ['all-eos-rules', 'security-scan', 'dependency-audit'] }, OPERATOR: { id: 'operator', name: 'Operator', description: 'Deployment, drift och rollback', tools: ['deploy', 'monitor', 'rollback'], permissions: ['read', 'deploy'], eosChecks: ['readiness-gate', 'release-gate', 'backup-verified'] } }; class AgentRuntimeV2 { constructor(task) { this.task = task; this.trace = new RuntimeTrace(task.id); this.currentRole = null; this.context = {}; } /** * Kör en agent genom hela flödet med trace */ async execute() { console.log(`=== Agent Runtime: ${this.task.id} ===`); try { // Steg 1: Planner await this.runPlanner(); // Steg 2: Context Builder await this.buildContext(); // Steg 3: Project Memory await this.queryProjectMemory(); // Steg 4: Knowledge Graph await this.queryKnowledgeGraph(); // Steg 5: EOS Policy Check const eosResult = await this.runEOSCheck(); if (!eosResult.passed) { return this.block('EOS Policy Check failed', eosResult); } // Steg 6: Developer const devResult = await this.runDeveloper(); // Steg 7: Reviewer const reviewResult = await this.runReviewer(); if (!reviewResult.passed) { return this.block('Review failed', reviewResult); } // Steg 8: Operator const opResult = await this.runOperator(); // Steg 9: Commit return this.commit(); } catch (error) { return this.block(`Exception: ${error.message}`, { error: error.stack }); } } async runPlanner() { this.currentRole = AGENT_ROLES.PLANNER; const node = this.trace.addNode('PLANNER', { task: this.task.description }); // TODO: Implementera planering this.context.plan = { steps: [], estimatedTime: null, dependencies: [] }; this.trace.completeNode(node.id, { plan: this.context.plan }); return this.context.plan; } async buildContext() { const node = this.trace.addNode('CONTEXT', { task: this.task.description }); // TODO: Samla kontext från Git, filer, etc. this.context.git = { branch: null, uncommitted: null, remote: null }; this.context.confidence = 0.8; // TODO: Beräkna riktig confidence this.trace.completeNode(node.id, { confidence: this.context.confidence, git: this.context.git }); } async queryProjectMemory() { const node = this.trace.addNode('MEMORY', { queries: [] }); // TODO: Sök i MEMORY.md, dagliga filer, ADR this.context.memory = { relevantDecisions: [], similarTasks: [], lessonsLearned: [] }; this.trace.completeNode(node.id, { results: this.context.memory }); } async queryKnowledgeGraph() { const node = this.trace.addNode('KNOWLEDGE', { queries: [] }); // TODO: Sök i kunskapsgrafen this.context.knowledge = { relatedCapabilities: [], dependencies: [], impact: [] }; this.trace.completeNode(node.id, { results: this.context.knowledge }); } async runEOSCheck() { const node = this.trace.addNode('EOS', { rules: [] }); // TODO: Kör alla EOS-policyer const checks = [ 'no-hardcoded-secrets', 'no-direct-prod', 'test-required', 'git-required' ]; const results = checks.map(check => ({ check, passed: true, // TODO: Verklig kontroll evidence: null })); const allPassed = results.every(r => r.passed); if (!allPassed) { const failed = results.filter(r => !r.passed); this.trace.blockNode(node.id, `Failed: ${failed.map(f => f.check).join(', ')}`); return { passed: false, results }; } this.trace.completeNode(node.id, { passed: results.length, failed: 0 }); return { passed: true, results }; } async runDeveloper() { this.currentRole = AGENT_ROLES.DEVELOPER; const node = this.trace.addNode('DEVELOPER', { files: [] }); // TODO: Implementera kod this.context.implementation = { filesChanged: [], testsAdded: [], documentation: [] }; this.trace.completeNode(node.id, { implementation: this.context.implementation }); } async runReviewer() { this.currentRole = AGENT_ROLES.REVIEWER; const node = this.trace.addNode('REVIEWER', { checks: [] }); // TODO: Granska kod const checks = [ 'code-quality', 'security-scan', 'eos-compliance', 'test-coverage' ]; const results = checks.map(check => ({ check, passed: true, // TODO: Verklig kontroll evidence: null })); const allPassed = results.every(r => r.passed); if (!allPassed) { const failed = results.filter(r => !r.passed); this.trace.blockNode(node.id, `Failed: ${failed.map(f => f.check).join(', ')}`); return { passed: false, results }; } this.trace.completeNode(node.id, { passed: results.length, failed: 0 }); return { passed: true, results }; } async runOperator() { this.currentRole = AGENT_ROLES.OPERATOR; const node = this.trace.addNode('OPERATOR', { environment: null }); // TODO: Förbered deployment this.context.deployment = { environment: null, rollbackPlan: null, healthChecks: [] }; this.trace.completeNode(node.id, { deployment: this.context.deployment }); } async commit() { const node = this.trace.addNode('COMMIT'); // TODO: Git commit const result = { status: 'success', commitHash: null }; this.trace.completeNode(node.id, result); return { status: 'success', commitHash: null, trace: this.trace.toJSON() }; } block(reason, details) { // Hitta senaste nod och markera som blockerad const lastNode = this.trace.nodes[this.trace.nodes.length - 1]; if (lastNode) { this.trace.blockNode(lastNode.id, reason); } return { status: 'blocked', reason, details, trace: this.trace.toJSON() }; } /** * Hämta trace för analys */ getTrace() { return this.trace; } } // CLI if (process.argv[1] === new URL(import.meta.url).pathname) { const runtime = new AgentRuntimeV2({ id: 'test-task', description: 'Testa Agent Runtime v2' }); runtime.execute().then(result => { console.log('\n=== Resultat ==='); console.log(JSON.stringify(result, null, 2)); console.log('\n=== Trace ==='); console.log(runtime.getTrace().toText()); }); } export { AgentRuntimeV2, AGENT_ROLES };