05ed037fe8
- DNS: pilot.landvex.com -> 16.170.83.169 - TLS: Let's Encrypt certificate (expires 2026-09-30) - Nginx: reverse proxy with SSL termination - API: https://pilot.landvex.com/api/v1/missions - UI: https://pilot.landvex.com/ - Upload: POST /api/v1/missions/import (multipart/form-data) Verified: ✅ https://pilot.landvex.com/health ✅ https://pilot.landvex.com/version ✅ https://pilot.landvex.com/api/v1/missions (list) ✅ https://pilot.landvex.com/api/v1/missions/:id (get) ✅ POST /api/v1/missions/import (video upload) ✅ UI loads with title 'LandveX Intelligence Lab' Next: Pilot 001 — Break the system!
288 lines
6.7 KiB
JavaScript
288 lines
6.7 KiB
JavaScript
#!/usr/bin/env node
|
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
// Agent Runtime — Den enda vägen genom systemet
|
|
// "Ingen agent ska kunna hoppa över Planner, Project Memory eller EOS"
|
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
|
|
/**
|
|
* Agent Runtime styr hur en agent arbetar.
|
|
*
|
|
* Flöde:
|
|
* Task
|
|
* ↓
|
|
* Planner — bryter ned arbete och planerar
|
|
* ↓
|
|
* Context Builder — samlar kontext
|
|
* ↓
|
|
* Project Memory — hämtar kunskap
|
|
* ↓
|
|
* Knowledge Graph — förstår relationer
|
|
* ↓
|
|
* EOS Policy Check — verifierar mot regler
|
|
* ↓
|
|
* Developer — skriver kod
|
|
* ↓
|
|
* Reviewer — granskar kod och kör EOS/SIL
|
|
* ↓
|
|
* Operator — deployment, drift, rollback
|
|
* ↓
|
|
* Commit
|
|
*
|
|
* Varje steg är obligatoriskt och loggat.
|
|
*/
|
|
|
|
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 AgentRuntime {
|
|
constructor(task) {
|
|
this.task = task;
|
|
this.log = [];
|
|
this.currentRole = null;
|
|
this.context = {};
|
|
}
|
|
|
|
/**
|
|
* Kör en agent genom hela flödet
|
|
*/
|
|
async execute() {
|
|
console.log(`=== Agent Runtime: ${this.task.id} ===`);
|
|
|
|
// 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();
|
|
}
|
|
|
|
async runPlanner() {
|
|
this.currentRole = AGENT_ROLES.PLANNER;
|
|
this.logStep('PLANNER', 'Breaking down task');
|
|
|
|
// TODO: Implementera planering
|
|
this.context.plan = {
|
|
steps: [],
|
|
estimatedTime: null,
|
|
dependencies: []
|
|
};
|
|
|
|
return this.context.plan;
|
|
}
|
|
|
|
async buildContext() {
|
|
this.logStep('CONTEXT', 'Building context');
|
|
|
|
// TODO: Samla kontext från Git, filer, etc.
|
|
this.context.git = {
|
|
branch: null,
|
|
uncommitted: null,
|
|
remote: null
|
|
};
|
|
}
|
|
|
|
async queryProjectMemory() {
|
|
this.logStep('MEMORY', 'Querying project memory');
|
|
|
|
// TODO: Sök i MEMORY.md, dagliga filer, ADR
|
|
this.context.memory = {
|
|
relevantDecisions: [],
|
|
similarTasks: [],
|
|
lessonsLearned: []
|
|
};
|
|
}
|
|
|
|
async queryKnowledgeGraph() {
|
|
this.logStep('KNOWLEDGE', 'Querying knowledge graph');
|
|
|
|
// TODO: Sök i kunskapsgrafen
|
|
this.context.knowledge = {
|
|
relatedCapabilities: [],
|
|
dependencies: [],
|
|
impact: []
|
|
};
|
|
}
|
|
|
|
async runEOSCheck() {
|
|
this.logStep('EOS', 'Running policy checks');
|
|
|
|
// 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);
|
|
|
|
return {
|
|
passed: allPassed,
|
|
results
|
|
};
|
|
}
|
|
|
|
async runDeveloper() {
|
|
this.currentRole = AGENT_ROLES.DEVELOPER;
|
|
this.logStep('DEVELOPER', 'Implementing');
|
|
|
|
// TODO: Implementera kod
|
|
this.context.implementation = {
|
|
filesChanged: [],
|
|
testsAdded: [],
|
|
documentation: []
|
|
};
|
|
}
|
|
|
|
async runReviewer() {
|
|
this.currentRole = AGENT_ROLES.REVIEWER;
|
|
this.logStep('REVIEWER', 'Reviewing');
|
|
|
|
// 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);
|
|
|
|
return {
|
|
passed: allPassed,
|
|
results
|
|
};
|
|
}
|
|
|
|
async runOperator() {
|
|
this.currentRole = AGENT_ROLES.OPERATOR;
|
|
this.logStep('OPERATOR', 'Preparing deployment');
|
|
|
|
// TODO: Förbered deployment
|
|
this.context.deployment = {
|
|
environment: null,
|
|
rollbackPlan: null,
|
|
healthChecks: []
|
|
};
|
|
}
|
|
|
|
async commit() {
|
|
this.logStep('COMMIT', 'Committing changes');
|
|
|
|
// TODO: Git commit
|
|
return {
|
|
status: 'success',
|
|
commitHash: null,
|
|
log: this.log
|
|
};
|
|
}
|
|
|
|
block(reason, details) {
|
|
this.logStep('BLOCKED', reason);
|
|
|
|
return {
|
|
status: 'blocked',
|
|
reason,
|
|
details,
|
|
log: this.log
|
|
};
|
|
}
|
|
|
|
logStep(phase, action) {
|
|
const entry = {
|
|
timestamp: new Date().toISOString(),
|
|
phase,
|
|
action,
|
|
role: this.currentRole?.id || 'system'
|
|
};
|
|
|
|
this.log.push(entry);
|
|
console.log(` [${phase}] ${action}`);
|
|
}
|
|
}
|
|
|
|
// CLI
|
|
if (process.argv[1] === new URL(import.meta.url).pathname) {
|
|
const runtime = new AgentRuntime({
|
|
id: 'test-task',
|
|
description: 'Testa Agent Runtime'
|
|
});
|
|
|
|
runtime.execute().then(result => {
|
|
console.log('\n=== Resultat ===');
|
|
console.log(JSON.stringify(result, null, 2));
|
|
});
|
|
}
|
|
|
|
export { AgentRuntime, AGENT_ROLES };
|