120 lines
4.6 KiB
JavaScript
120 lines
4.6 KiB
JavaScript
// Generated, do not edit. sha256:b0dd28dca0d6350eaa3cdbb0db8611b54c802d92405f31a10da8e494e94fbaf6
|
|
import { createInterface } from 'node:readline';
|
|
|
|
import { CONFIG } from '../../shared/config.js';
|
|
import { initDatabase, closeDatabase, dbFile, databaseStatus } from '../db.js';
|
|
import { prepareLayout, activeName } from '../portfolios.mjs';
|
|
import { openDatabase } from '../db/conn.mjs';
|
|
import { logAiToolCall } from '../data/ai-audit.js';
|
|
import { isAiActive, AI_INACTIVE_TEXT } from '../ai/gate.js';
|
|
import { flushChanges } from '../data/bus.js';
|
|
import { createMcpServer } from './protocol.mjs';
|
|
import { allTools } from './tools.mjs';
|
|
import '../edition.mjs';
|
|
|
|
const naarGebruiker = (regel) => process.stderr.write(`[assetapp-mcp] ${regel}\n`);
|
|
|
|
function stopAlsUit() {
|
|
if (isAiActive()) return false;
|
|
naarGebruiker('de AI-koppeling staat uit (schuif "Actief" onder Systeem → AI-activiteit). '
|
|
+ 'Deze server doet niets en stopt; zet de schuif aan en start uw AI-programma opnieuw.');
|
|
return true;
|
|
}
|
|
|
|
try {
|
|
naarGebruiker(prepareLayout().regel);
|
|
naarGebruiker(initDatabase());
|
|
const uit = stopAlsUit();
|
|
closeDatabase();
|
|
if (uit) process.exit(0);
|
|
} catch (e) {
|
|
naarGebruiker(`kan de database niet openen: ${e.message}`);
|
|
process.exit(1);
|
|
}
|
|
|
|
const tools = allTools();
|
|
const server = createMcpServer({
|
|
tools,
|
|
logCall: logAiToolCall,
|
|
onLogError: (e) => naarGebruiker(`LET OP: een tool-aanroep is NIET vastgelegd: ${e.message}`),
|
|
});
|
|
|
|
naarGebruiker(`gereed als '${CONFIG.AI.SERVER_NAME}', ${tools.length} tool(s), sessie ${server.session.id}`);
|
|
|
|
const lezer = createInterface({ input: process.stdin, crlfDelay: Infinity });
|
|
|
|
function kijkIn(regel) {
|
|
try {
|
|
const bericht = JSON.parse(regel);
|
|
return {
|
|
id: Object.hasOwn(bericht, 'id') ? bericht.id : undefined,
|
|
method: typeof bericht.method === 'string' ? bericht.method : null,
|
|
};
|
|
} catch { return { id: undefined, method: null }; }
|
|
}
|
|
|
|
const HEEFT_DATABASE_NODIG = 'tools/call';
|
|
|
|
const INTERNE_FOUT = -32603;
|
|
|
|
function stuurFout(regel, melding) {
|
|
const { id } = kijkIn(regel);
|
|
if (id === undefined) return;
|
|
process.stdout.write(`${JSON.stringify({ jsonrpc: '2.0', id, error: { code: INTERNE_FOUT, message: melding } })}\n`);
|
|
}
|
|
|
|
function uitlegBijStand(stand) {
|
|
const naam = activeName();
|
|
if (stand.reden === 'leeg') {
|
|
return `De portefeuille '${naam}' heeft nog geen ingerichte database. Dat gebeurt zodra de app hem `
|
|
+ 'een keer opent (Systeem → Portefeuilles → Openen). Tot dan is er hier niets te lezen.';
|
|
}
|
|
if (stand.reden === 'oud') {
|
|
return `De database van portefeuille '${naam}' staat op versie ${stand.versie} en deze app verwacht `
|
|
+ `${CONFIG.SCHEMA_VERSION}. De migraties draaien als de app die portefeuille opent; doe dat eerst.`;
|
|
}
|
|
return `De database van portefeuille '${naam}' staat op versie ${stand.versie}, en deze MCP-server kent `
|
|
+ `tot en met ${CONFIG.SCHEMA_VERSION}. Is de app net bijgewerkt, herstart dan de AI-koppeling in je `
|
|
+ 'AI-client: dit proces laadt nieuwe code pas bij een herstart. Anders is de app zelf ouder dan de '
|
|
+ 'database; werk hem dan bij.';
|
|
}
|
|
|
|
let wachtrij = Promise.resolve();
|
|
|
|
lezer.on('line', (regel) => {
|
|
const tekst = regel.trim();
|
|
if (!tekst) return;
|
|
wachtrij = wachtrij.then(async () => {
|
|
try { openDatabase(dbFile()); }
|
|
catch (e) {
|
|
naarGebruiker(`kan de database niet openen voor dit bericht: ${e.message}`);
|
|
stuurFout(tekst, `De database van de actieve portefeuille is nu niet te openen: ${e.message}`);
|
|
return;
|
|
}
|
|
const stand = databaseStatus();
|
|
if (stand.klaar && !isAiActive()) {
|
|
stuurFout(tekst, AI_INACTIVE_TEXT);
|
|
naarGebruiker('de AI-koppeling is uitgezet; deze server stopt.');
|
|
try { closeDatabase(); } catch { }
|
|
process.exit(0);
|
|
}
|
|
if (!stand.klaar && kijkIn(tekst).method === HEEFT_DATABASE_NODIG) {
|
|
naarGebruiker(`de database van deze portefeuille is niet bruikbaar (${stand.reden}); bericht geweigerd`);
|
|
stuurFout(tekst, uitlegBijStand(stand));
|
|
try { closeDatabase(); } catch { }
|
|
return;
|
|
}
|
|
try {
|
|
const antwoord = await server.handleRegel(tekst);
|
|
if (antwoord) process.stdout.write(`${JSON.stringify(antwoord)}\n`);
|
|
} catch (e) {
|
|
naarGebruiker(`onverwachte fout bij het afhandelen van een bericht: ${e.message}`);
|
|
} finally {
|
|
try { flushChanges(); } catch (e) { naarGebruiker(`signalen wegschrijven mislukte: ${e.message}`); }
|
|
try { closeDatabase(); } catch (e) { naarGebruiker(`database sluiten mislukte: ${e.message}`); }
|
|
}
|
|
});
|
|
});
|
|
|
|
lezer.on('close', () => { naarGebruiker('verbinding gesloten door de client'); process.exit(0); });
|