Files
boc/EOS/project-memory.mjs
T
Bernt 05ed037fe8 pilot.landvex.com: HTTPS + Full Stack Verified
- 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!
2026-07-02 17:34:19 +00:00

224 lines
6.7 KiB
JavaScript

#!/usr/bin/env node
// ═══════════════════════════════════════════════════════════════════════════
// EOS Project Memory — Varför beslut fattades, vad som testades, etc.
// Erik-krav: "Inte chat history. Inte Markdown. Utan ett projektminne."
// ═══════════════════════════════════════════════════════════════════════════
import { readFileSync, writeFileSync, existsSync, appendFileSync } from 'fs';
const MEMORY_DIR = '/home/bernt/.openclaw/workspace/EOS/memory';
const DECISIONS_LOG = `${MEMORY_DIR}/decisions.jsonl`;
const EXPERIMENTS_LOG = `${MEMORY_DIR}/experiments.jsonl`;
const BUGS_LOG = `${MEMORY_DIR}/bugs.jsonl`;
const ARCHITECTURE_LOG = `${MEMORY_DIR}/architecture.jsonl`;
class ProjectMemory {
constructor() {
if (!existsSync(MEMORY_DIR)) {
// Skapa med mkdirSync
const { mkdirSync } = require('fs');
mkdirSync(MEMORY_DIR, { recursive: true });
}
}
/**
* Logga ett beslut
*/
logDecision(decision) {
const entry = {
timestamp: new Date().toISOString(),
type: 'decision',
id: decision.id || `dec-${Date.now()}`,
question: decision.question,
answer: decision.answer,
// Varför
reasoning: decision.reasoning,
alternatives: decision.alternatives || [],
rejected: decision.rejected || [],
// Vem
decidedBy: decision.decidedBy,
// Konsekvenser
consequences: decision.consequences,
// Status
status: decision.status || 'active',
// Om beslutet senare ändrades
supersededBy: decision.supersededBy || null
};
appendFileSync(DECISIONS_LOG, JSON.stringify(entry) + '\n', 'utf8');
return entry;
}
/**
* Logga ett experiment
*/
logExperiment(experiment) {
const entry = {
timestamp: new Date().toISOString(),
type: 'experiment',
id: experiment.id || `exp-${Date.now()}`,
hypothesis: experiment.hypothesis,
method: experiment.method,
result: experiment.result,
conclusion: experiment.conclusion,
// Lärande
lesson: experiment.lesson,
// Om experimentet misslyckades
failure: experiment.failure || null
};
appendFileSync(EXPERIMENTS_LOG, JSON.stringify(entry) + '\n', 'utf8');
return entry;
}
/**
* Logga en bugg
*/
logBug(bug) {
const entry = {
timestamp: new Date().toISOString(),
type: 'bug',
id: bug.id || `bug-${Date.now()}`,
description: bug.description,
component: bug.component,
rootCause: bug.rootCause,
fix: bug.fix,
// Lärande
lesson: bug.lesson,
// Om buggar kunde ha förhindrats
preventable: bug.preventable || false,
prevention: bug.prevention || null
};
appendFileSync(BUGS_LOG, JSON.stringify(entry) + '\n', 'utf8');
return entry;
}
/**
* Logga arkitekturförändring
*/
logArchitecture(change) {
const entry = {
timestamp: new Date().toISOString(),
type: 'architecture',
id: change.id || `arch-${Date.now()}`,
change: change.change,
reason: change.reason,
// Före/efter
before: change.before,
after: change.after,
// Konsekvenser
impact: change.impact,
// Om ändringen ångrades
reverted: change.reverted || false,
revertReason: change.revertReason || null
};
appendFileSync(ARCHITECTURE_LOG, JSON.stringify(entry) + '\n', 'utf8');
return entry;
}
/**
* Sök i projektminnet
*/
query(query) {
const results = [];
// Sök i alla loggar
for (const log of [DECISIONS_LOG, EXPERIMENTS_LOG, BUGS_LOG, ARCHITECTURE_LOG]) {
if (!existsSync(log)) continue;
const entries = readFileSync(log, 'utf8')
.split('\n')
.filter(line => line.trim())
.map(line => {
try { return JSON.parse(line); } catch { return null; }
})
.filter(Boolean);
for (const entry of entries) {
const text = JSON.stringify(entry).toLowerCase();
if (text.includes(query.toLowerCase())) {
results.push(entry);
}
}
}
return results;
}
/**
* Besvara en fråga om projektets historia
*/
answerQuestion(question) {
const results = this.query(question);
console.log(`🔍 "${question}"\n`);
if (results.length === 0) {
console.log(' Ingen information hittad.\n');
return null;
}
for (const result of results.slice(0, 5)) {
console.log(` [${result.type.toUpperCase()}] ${result.id}`);
console.log(` ${result.question || result.hypothesis || result.description || result.change}`);
console.log(` ${result.answer || result.conclusion || result.fix || result.reason}`);
console.log();
}
return results;
}
/**
* Visa projektminnets struktur
*/
showStructure() {
console.log('📚 PROJECT MEMORY\n');
const logs = [
{ name: 'Beslut', path: DECISIONS_LOG },
{ name: 'Experiment', path: EXPERIMENTS_LOG },
{ name: 'Buggar', path: BUGS_LOG },
{ name: 'Arkitektur', path: ARCHITECTURE_LOG }
];
for (const log of logs) {
const count = existsSync(log.path)
? readFileSync(log.path, 'utf8').split('\n').filter(l => l.trim()).length
: 0;
console.log(` ${log.name}: ${count} entries`);
}
console.log();
}
}
// ── Main ──────────────────────────────────────────────────────────────────
const memory = new ProjectMemory();
const command = process.argv[2] || '--structure';
if (command === '--structure') {
memory.showStructure();
} else if (command === '--query') {
const query = process.argv[3];
if (!query) {
console.log('Användning: node project-memory.mjs --query <fråga>');
process.exit(1);
}
memory.answerQuestion(query);
} else if (command === '--log-decision') {
memory.logDecision({
question: process.argv[3] || 'Varför valde vi X?',
answer: process.argv[4] || 'För att...',
reasoning: process.argv[5] || 'Eftersom...',
decidedBy: 'agent'
});
console.log('✅ Beslut loggat');
} else {
console.log('Användning:');
console.log(' node project-memory.mjs --structure # Visa struktur');
console.log(' node project-memory.mjs --query <fråga> # Sök i minnet');
console.log(' node project-memory.mjs --log-decision <q> <a> <r> # Logga beslut');
}