1.3 init-vault: - Erstellt komplette Vault-Struktur (12 Ordner + .gitignore + Konfig.md + README + CLAUDE.md) - 2 Demo-Notizen mit heutigem Datum - git init mit main-Branch - Fragt interaktiv nach gitea-URL (oder --remote Parameter, --no-interactive) - Macht initialen Commit - Idempotent (Vault-existiert-Skip oder --force) - Argumente: --force, --no-commit, --no-interactive, --remote <url> 1.5 Indexer: - Deterministisch: 2 Laeufe ergeben byte-identische Outputs (Test bestaetigt) - Liest Vault, parst Frontmatter mit gray-matter - Extrahiert Wikilinks mit Regex - Schreibt landkarte.json + 99_System/Index.md + 10_Wiki/Index.md - Ueberspringt eigene Outputs (Index.md) und System-Ordner - Pfad-Normalisierung zu Forward-Slashes fuer Windows-Kompatibilitaet - Statisches generated-Feld (kein Timestamp) fuer Determinismus 1.6 Webapp: - Vite + React + TypeScript + Cytoscape.js - Liest landkarte.json, rendert Force-directed Graph - Knoten nach Typ eingefaerbt (inbox/daily/wiki/project) - Hover/Klick zeigt Node-Details - Build in 2.25s, 32 Module, 590 KB JS (Cytoscape last) Tests: - 12 Unit-Tests gruen (10 Vault-Path + 2 Determinismus) - Indexer-Smoke: 5 Notizen, 3 Kanten auf Test-Vault - Webapp-Build erfolgreich Phase 1 Erfolgskriterium: Webapp zeigt Notizen als verbundenen Graph (Build verifiziert)
96 lines
2.8 KiB
TypeScript
96 lines
2.8 KiB
TypeScript
// Deterministik-Test: zwei Indexer-Laeufe ergeben byte-identische Outputs
|
|
// Phase 1.5
|
|
|
|
import { describe, it, expect } from 'vitest';
|
|
import { execSync } from 'node:child_process';
|
|
import { readFileSync, mkdtempSync, writeFileSync, mkdirSync, rmSync, existsSync } from 'node:fs';
|
|
import { tmpdir } from 'node:os';
|
|
import { join } from 'node:path';
|
|
|
|
const TOOL_PATH = 'C:/GitHub/Mind-o-Mat';
|
|
const CLI = `node ${TOOL_PATH}/bin/mindomat.mjs`;
|
|
|
|
function createTestVault(): string {
|
|
const dir = mkdtempSync(join(tmpdir(), 'mindomat-determinism-'));
|
|
|
|
// 12 Ordner
|
|
const dirs = [
|
|
'00_Inbox', '00_Inbox/Verarbeitet', '00_Inbox/Problemfaelle',
|
|
'01_Daily', '10_Wiki', '10_Wiki/Seiten',
|
|
'20_Projekte', '90_Templates',
|
|
'99_System', '99_System/Skripte', '99_System/Logs', '99_System/Cache',
|
|
];
|
|
for (const d of dirs) {
|
|
mkdirSync(join(dir, d), { recursive: true });
|
|
}
|
|
|
|
// 3 Test-Notizen mit deterministischen Wikilinks
|
|
writeFileSync(join(dir, '00_Inbox', '2026-01-01_A.md'), `---
|
|
title: A
|
|
created: 2026-01-01
|
|
---
|
|
|
|
# A
|
|
|
|
Verweist auf [[B]] und [[C]].
|
|
`);
|
|
writeFileSync(join(dir, '00_Inbox', '2026-01-02_B.md'), `---
|
|
title: B
|
|
created: 2026-01-02
|
|
---
|
|
|
|
# B
|
|
|
|
Verweist auf [[A]].
|
|
`);
|
|
writeFileSync(join(dir, '00_Inbox', '2026-01-03_C.md'), `---
|
|
title: C
|
|
created: 2026-01-03
|
|
---
|
|
|
|
# C
|
|
|
|
Kein Link.
|
|
`);
|
|
|
|
return dir;
|
|
}
|
|
|
|
describe('Indexer Determinismus', () => {
|
|
it('zwei Laeufe ergeben byte-identische Outputs', () => {
|
|
const vault = createTestVault();
|
|
try {
|
|
// Erster Lauf
|
|
execSync(`${CLI} index --vault "${vault}" --no-interactive`, { stdio: 'pipe' });
|
|
const l1 = readFileSync(join(vault, 'landkarte.json'), 'utf-8');
|
|
const i1sys = readFileSync(join(vault, '99_System', 'Index.md'), 'utf-8');
|
|
const i1wiki = readFileSync(join(vault, '10_Wiki', 'Index.md'), 'utf-8');
|
|
|
|
// Zweiter Lauf
|
|
execSync(`${CLI} index --vault "${vault}" --no-interactive`, { stdio: 'pipe' });
|
|
const l2 = readFileSync(join(vault, 'landkarte.json'), 'utf-8');
|
|
const i2sys = readFileSync(join(vault, '99_System', 'Index.md'), 'utf-8');
|
|
const i2wiki = readFileSync(join(vault, '10_Wiki', 'Index.md'), 'utf-8');
|
|
|
|
expect(l2).toBe(l1);
|
|
expect(i2sys).toBe(i1sys);
|
|
expect(i2wiki).toBe(i1wiki);
|
|
} finally {
|
|
rmSync(vault, { recursive: true, force: true });
|
|
}
|
|
});
|
|
|
|
it('landkarte.json enthaelt alle Notizen + Edges', () => {
|
|
const vault = createTestVault();
|
|
try {
|
|
execSync(`${CLI} index --vault "${vault}" --no-interactive`, { stdio: 'pipe' });
|
|
const landkarte = JSON.parse(readFileSync(join(vault, 'landkarte.json'), 'utf-8'));
|
|
expect(landkarte.nodes.length).toBe(3);
|
|
// A->B, A->C, B->A = 3 Edges
|
|
expect(landkarte.edges.length).toBe(3);
|
|
} finally {
|
|
rmSync(vault, { recursive: true, force: true });
|
|
}
|
|
});
|
|
});
|