Phase 1a: Tool-Repo-Skelett + Vault-Pfad-Discovery
- package.json mit Scripts (build, dev, test, init-vault, index, ingest, sync) - TypeScript-Config (tsconfig.json) + Vitest-Config - CLI-Entry (bin/mindomat.mjs + src/cli/index.ts) - Vault-Pfad-Discovery (1.2) mit CLI-Arg + Env-Var Fallback - 10 Unit-Tests fuer Vault-Pfad-Discovery (alle gruen) - Stubs fuer init-vault, index, ingest, sync (Placeholder, volle Implementierung in 1.3/1.5/2.3/1.8) - webapp/-Stubs (Phase 1.6 Vorbereitung) - README mit Install-Anleitung aktualisiert Smoke-Tests: - mindomat --version => mindomat 0.1.0 - mindomat --help => vollstaendige Hilfe - mindomat index => Fehler 'Vault-Pfad fehlt' (Exit 2) - mindomat index --vault => Stub-Aufruf (Exit 0)
This commit is contained in:
1 parent
707e96c116
commit
f86c3bf8ce
17 files changed
+2135
-11
No files matched your search
@@ -1,20 +1,77 @@
|
||||
# Mind-o-Mat
|
||||
|
||||
Lokales Second-Brain-System für einen Obsidian-kompatiblen Markdown-Vault.
|
||||
Lokales Second-Brain-System für Obsidian-kompatible Markdown-Vaults. Besteht aus zwei Repos:
|
||||
|
||||
> **Status:** Brainstorming-Phase. Spezifikation v0.1 in `10 Wiki/SPEC.md` ist Entwurf, nicht freigegeben.
|
||||
- **Dieses Repo** (`Mind-o-Mat`) — die Code-Basis (Tool). Wird gebaut und über npm publiziert.
|
||||
- **Vault-Repo** (z. B. `Mind-o-Mat-Vault`) — die Notizen. Wird mit dem Tool initialisiert und via gitea synchronisiert.
|
||||
|
||||
## Was es mal können soll
|
||||
> **Status:** Phase 1a in Arbeit. CLI-Skelett + Vault-Pfad-Discovery implementiert, andere Befehle sind Stubs. Siehe `10 Wiki/Plan.md` für den vollständigen Plan.
|
||||
|
||||
- **Wissen wiederfinden** auch wenn das exakte Wort fehlt (Bedeutungssuche).
|
||||
- **Konflikte automatisch markieren** zwischen Notizen, die sich widersprechen.
|
||||
- **Graph-Ansicht** deines gesamten Vaults mit erkennbaren Themen-Clustern.
|
||||
## Installation (Vault-User)
|
||||
|
||||
## Aktueller Stand
|
||||
```bash
|
||||
# Tool global installieren (einmalig)
|
||||
npm install -g mindomat
|
||||
|
||||
- `10 Wiki/SPEC.md` — Entwurf der Spezifikation mit allen 5 Architektur-Bausteinen.
|
||||
- Alles weitere ist TODO und wird in Iterationen aufgebaut.
|
||||
# Vault initialisieren
|
||||
mindomat init-vault C:\Pfad\Zu\Mein-Vault
|
||||
cd C:\Pfad\Zu\Mein-Vault
|
||||
git remote add origin https://git.example.com/Dein-Name/Mein-Vault.git
|
||||
git push -u origin main
|
||||
|
||||
## Mitmachen
|
||||
# QMD installieren (einmalig, ~2 GB Modelle)
|
||||
npm install -g @tobilu/qmd
|
||||
cd C:\Pfad\Zu\Mein-Vault
|
||||
qmd collection add 00_Inbox --name inbox
|
||||
qmd collection add 01_Daily --name daily
|
||||
qmd collection add 10_Wiki --name wiki
|
||||
qmd collection add 20_Projekte --name projekte
|
||||
qmd embed
|
||||
|
||||
Im Moment ist das Repo vor allem ein Ort, um die Idee festzuhalten, bevor irgendwas implementiert wird. Siehe `10 Wiki/SPEC.md` für die offenen Fragen und den aktuellen Stand der Planung.
|
||||
# Vault indizieren (erzeugt landkarte.json)
|
||||
MINDOMAT_VAULT_PATH=C:\Pfad\Zu\Mein-Vault mindomat index
|
||||
```
|
||||
|
||||
## CLI-Referenz
|
||||
|
||||
```bash
|
||||
mindomat --version # Version anzeigen
|
||||
mindomat --help # Hilfe
|
||||
mindomat init-vault <pfad> # Vault-Struktur erstellen
|
||||
mindomat index --vault <pfad> # Vault indizieren
|
||||
mindomat ingest --vault <pfad> # Inbox-Notizen verarbeiten
|
||||
mindomat sync --vault <pfad> # gitea-Sync
|
||||
```
|
||||
|
||||
Der Vault-Pfad wird in dieser Reihenfolge aufgelöst:
|
||||
|
||||
1. CLI-Argument `--vault <pfad>` (oder `-v <pfad>`)
|
||||
2. Environment-Variable `MINDOMAT_VAULT_PATH`
|
||||
3. Fehler: klare Meldung
|
||||
|
||||
## Entwicklung (Tool-Contributor)
|
||||
|
||||
```bash
|
||||
git clone https://git.orfel.de/Jannik/Mind-o-Mat
|
||||
cd Mind-o-Mat
|
||||
npm install
|
||||
npm run build # TypeScript kompilieren
|
||||
npm test # Unit-Tests (Vitest)
|
||||
npm run test:watch # Tests im Watch-Mode
|
||||
```
|
||||
|
||||
## Architektur
|
||||
|
||||
Siehe `10 Wiki/SPEC.md` (Spezifikation) und `10 Wiki/Plan.md` (20 Aufgaben, 5 Phasen).
|
||||
|
||||
**5 Bausteine:**
|
||||
|
||||
1. **Vault** — Markdown-Dateien, Single Source of Truth (im Vault-Repo)
|
||||
2. **Indexer** — deterministisch, erzeugt `landkarte.json` (im Tool)
|
||||
3. **QMD** — lokale Hybridsuche, ~2 GB GGUF-Modelle (im Vault installiert)
|
||||
4. **Wiki** — Ingest pflegt Markdown-Seiten via Minimax-API
|
||||
5. **Webapp/PWA** — React + Cytoscape, Graph-Ansicht, Mobile-Editor
|
||||
|
||||
## Lizenz
|
||||
|
||||
MIT
|
||||
@@ -0,0 +1,11 @@
|
||||
#!/usr/bin/env node
|
||||
// Mind-o-Mat CLI Entry
|
||||
// Phase 1.1: Grundgeruest. Liest Args, dispatcht an Befehle.
|
||||
// Importiert von dist/ (nach `npm run build`).
|
||||
|
||||
import { runCli } from '../dist/cli/index.js';
|
||||
|
||||
runCli(process.argv.slice(2)).catch((err) => {
|
||||
console.error('Fehler:', err.message);
|
||||
process.exit(1);
|
||||
});
|
||||
Generated
+1632
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,51 @@
|
||||
{
|
||||
"name": "mindomat",
|
||||
"version": "0.1.0",
|
||||
"description": "Lokales Second-Brain-System für Obsidian-kompatible Markdown-Vaults",
|
||||
"type": "module",
|
||||
"bin": {
|
||||
"mindomat": "./bin/mindomat.mjs"
|
||||
},
|
||||
"main": "./dist/index.js",
|
||||
"types": "./dist/index.d.ts",
|
||||
"exports": {
|
||||
".": {
|
||||
"types": "./dist/index.d.ts",
|
||||
"import": "./dist/index.js"
|
||||
}
|
||||
},
|
||||
"files": [
|
||||
"bin",
|
||||
"dist",
|
||||
"README.md"
|
||||
],
|
||||
"scripts": {
|
||||
"build": "tsc",
|
||||
"dev": "tsc --watch",
|
||||
"test": "vitest run",
|
||||
"test:watch": "vitest",
|
||||
"init-vault": "npm run build && node bin/mindomat.mjs init-vault",
|
||||
"index": "npm run build && node bin/mindomat.mjs index",
|
||||
"ingest": "npm run build && node bin/mindomat.mjs ingest",
|
||||
"sync": "npm run build && node bin/mindomat.mjs sync"
|
||||
},
|
||||
"keywords": [
|
||||
"second-brain",
|
||||
"obsidian",
|
||||
"markdown",
|
||||
"knowledge-management",
|
||||
"pkm"
|
||||
],
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=22.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"gray-matter": "^4.0.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^22.0.0",
|
||||
"typescript": "^5.6.0",
|
||||
"vitest": "^2.1.0"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
// 1.5 index: Indiziert den Vault
|
||||
// Phase 1.5: STUB
|
||||
|
||||
export async function indexCommand(vaultPath: string, _args: string[]): Promise<void> {
|
||||
console.log(`index: würde Vault indizieren unter ${vaultPath}`);
|
||||
console.log(' (Stub — vollständige Implementierung kommt in Phase 1.5)');
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
// CLI Entry: Argument-Parsing, Help, Version, Dispatch zu den Befehlen
|
||||
// Phase 1.1
|
||||
|
||||
import { resolveVaultPath, assertVaultExists, VaultPathError } from '../vault-path.js';
|
||||
import { initVaultCommand } from './init-vault.js';
|
||||
import { indexCommand } from './index-cmd.js';
|
||||
import { ingestCommand } from './ingest.js';
|
||||
import { syncCommand } from './sync.js';
|
||||
|
||||
const VERSION = '0.1.0';
|
||||
|
||||
export async function runCli(args: string[]): Promise<void> {
|
||||
// Global flags vor erstem Subkommando
|
||||
if (args.includes('--version') || args.includes('-v')) {
|
||||
console.log(`mindomat ${VERSION}`);
|
||||
return;
|
||||
}
|
||||
|
||||
if (args.includes('--help') || args.includes('-h') || args.length === 0) {
|
||||
printHelp();
|
||||
return;
|
||||
}
|
||||
|
||||
// Subkommando + Rest
|
||||
const [command, ...rest] = args;
|
||||
|
||||
// Befehle, die KEIN Vault brauchen
|
||||
if (command === 'init-vault') {
|
||||
await initVaultCommand(rest);
|
||||
return;
|
||||
}
|
||||
|
||||
// Befehle, die Vault brauchen
|
||||
let resolved;
|
||||
try {
|
||||
resolved = resolveVaultPath({ args: rest, env: process.env, cwd: process.cwd() });
|
||||
} catch (err) {
|
||||
if (err instanceof VaultPathError) {
|
||||
console.error(err.message);
|
||||
process.exit(2);
|
||||
}
|
||||
throw err;
|
||||
}
|
||||
|
||||
assertVaultExists(resolved.path);
|
||||
|
||||
switch (command) {
|
||||
case 'index':
|
||||
await indexCommand(resolved.path, rest);
|
||||
break;
|
||||
case 'ingest':
|
||||
await ingestCommand(resolved.path, rest);
|
||||
break;
|
||||
case 'sync':
|
||||
await syncCommand(resolved.path, rest);
|
||||
break;
|
||||
default:
|
||||
console.error(`Unbekanntes Kommando: ${command}`);
|
||||
printHelp();
|
||||
process.exit(2);
|
||||
}
|
||||
}
|
||||
|
||||
function printHelp(): void {
|
||||
console.log(`mindomat ${VERSION} — lokales Second-Brain-System
|
||||
|
||||
Verwendung:
|
||||
mindomat <kommando> [optionen]
|
||||
|
||||
Kommandos:
|
||||
init-vault <pfad> Erstellt einen neuen Vault (Phase 1.3)
|
||||
index Indiziert den Vault (Phase 1.5)
|
||||
ingest Verarbeitet Inbox-Notizen (Phase 2.3)
|
||||
sync Sync zu gitea (Phase 1.8)
|
||||
|
||||
Globale Optionen:
|
||||
--vault <pfad>, -v Pfad zum Vault (sonst MINDOMAT_VAULT_PATH)
|
||||
--version Version anzeigen
|
||||
--help, -h Diese Hilfe
|
||||
|
||||
Beispiele:
|
||||
mindomat init-vault C:\\GitHub\\Mein-Vault
|
||||
mindomat index --vault C:\\GitHub\\Mein-Vault
|
||||
MINDOMAT_VAULT_PATH=C:\\GitHub\\Mein-Vault mindomat index
|
||||
`);
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
// 2.3 ingest: Verarbeitet Inbox-Notizen
|
||||
// Phase 2.3: STUB
|
||||
|
||||
export async function ingestCommand(vaultPath: string, _args: string[]): Promise<void> {
|
||||
console.log(`ingest: würde Notizen verarbeiten in ${vaultPath}`);
|
||||
console.log(' (Stub — vollständige Implementierung kommt in Phase 2.3)');
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
// 1.3 init-vault: Erstellt einen neuen Vault
|
||||
// Phase 1.3: STUB — wird in 1.3 implementiert
|
||||
|
||||
export async function initVaultCommand(args: string[]): Promise<void> {
|
||||
const target = args[0];
|
||||
if (!target) {
|
||||
console.error('Verwendung: mindomat init-vault <pfad>');
|
||||
process.exit(2);
|
||||
}
|
||||
console.log(`init-vault: würde Vault erstellen unter ${target}`);
|
||||
console.log(' (Stub — vollständige Implementierung kommt in Phase 1.3)');
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
// 1.8 sync: Sync zu gitea
|
||||
// Phase 1.8: STUB
|
||||
|
||||
export async function syncCommand(vaultPath: string, _args: string[]): Promise<void> {
|
||||
console.log(`sync: würde syncen für Vault ${vaultPath}`);
|
||||
console.log(' (Stub — vollständige Implementierung kommt in Phase 1.8)');
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
// Mind-o-Mat Library Entry
|
||||
// Phase 1.1: Re-Exports fuer npm-Nutzer
|
||||
|
||||
export { resolveVaultPath } from './vault-path.js';
|
||||
export type { VaultPathOptions } from './vault-path.js';
|
||||
@@ -0,0 +1,94 @@
|
||||
// 1.2 Vault-Pfad-Discovery
|
||||
// Phase 1.2: Tool findet Vault ueber CLI-Arg oder Env-Var
|
||||
|
||||
import { existsSync, statSync } from 'node:fs';
|
||||
import { resolve } from 'node:path';
|
||||
|
||||
export interface VaultPathOptions {
|
||||
/** CLI-Argumente (z. B. process.argv) */
|
||||
args: string[];
|
||||
/** Environment-Variablen (z. B. process.env) */
|
||||
env: NodeJS.ProcessEnv;
|
||||
/** CWD fuer Pfad-Aufloesung */
|
||||
cwd: string;
|
||||
}
|
||||
|
||||
export interface ResolvedVault {
|
||||
path: string;
|
||||
source: 'cli' | 'env';
|
||||
}
|
||||
|
||||
export class VaultPathError extends Error {
|
||||
constructor(message: string, public readonly code: 'MISSING' | 'NOT_FOUND' | 'NOT_DIRECTORY') {
|
||||
super(message);
|
||||
this.name = 'VaultPathError';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Findet den Vault-Pfad in dieser Reihenfolge:
|
||||
* 1. CLI-Argument --vault <pfad> (oder -v)
|
||||
* 2. Environment-Variable MINDOMAT_VAULT_PATH
|
||||
*
|
||||
* Wirft VaultPathError mit klarem Code, wenn nichts gefunden oder Pfad ungueltig.
|
||||
*/
|
||||
export function resolveVaultPath(opts: VaultPathOptions): ResolvedVault {
|
||||
const { args, env, cwd } = opts;
|
||||
|
||||
// 1. CLI-Arg
|
||||
const cliPath = extractCliVaultArg(args);
|
||||
if (cliPath) {
|
||||
const abs = resolve(cwd, cliPath);
|
||||
return { path: abs, source: 'cli' };
|
||||
}
|
||||
|
||||
// 2. Env-Var
|
||||
const envPath = env.MINDOMAT_VAULT_PATH;
|
||||
if (envPath && envPath.trim().length > 0) {
|
||||
const abs = resolve(cwd, envPath);
|
||||
return { path: abs, source: 'env' };
|
||||
}
|
||||
|
||||
// 3. Nichts gefunden
|
||||
throw new VaultPathError(
|
||||
'Vault-Pfad fehlt. Setze MINDOMAT_VAULT_PATH oder nutze --vault <pfad>.',
|
||||
'MISSING'
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Extrahiert --vault <pfad> oder -v <pfad> aus den Args.
|
||||
* Unterstuetzt auch --vault=<pfad>.
|
||||
*/
|
||||
function extractCliVaultArg(args: string[]): string | null {
|
||||
for (let i = 0; i < args.length; i++) {
|
||||
const a = args[i];
|
||||
if (a === '--vault' || a === '-v') {
|
||||
return args[i + 1] ?? null;
|
||||
}
|
||||
if (a.startsWith('--vault=')) {
|
||||
return a.slice('--vault='.length);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prueft, ob der Pfad ein existierendes Verzeichnis ist.
|
||||
* Wirft VaultPathError wenn nicht.
|
||||
*/
|
||||
export function assertVaultExists(path: string): void {
|
||||
if (!existsSync(path)) {
|
||||
throw new VaultPathError(
|
||||
`Vault-Pfad existiert nicht: ${path}`,
|
||||
'NOT_FOUND'
|
||||
);
|
||||
}
|
||||
const stat = statSync(path);
|
||||
if (!stat.isDirectory()) {
|
||||
throw new VaultPathError(
|
||||
`Vault-Pfad ist kein Verzeichnis: ${path}`,
|
||||
'NOT_DIRECTORY'
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,115 @@
|
||||
// Unit-Tests für 1.2 Vault-Pfad-Discovery
|
||||
// Phase 1.2 Test
|
||||
|
||||
import { describe, it, expect } from 'vitest';
|
||||
import { resolveVaultPath, assertVaultExists, VaultPathError } from '../src/vault-path.js';
|
||||
import { mkdtempSync, rmSync } from 'node:fs';
|
||||
import { tmpdir } from 'node:os';
|
||||
import { join } from 'node:path';
|
||||
|
||||
describe('resolveVaultPath', () => {
|
||||
const cwd = process.cwd();
|
||||
const env: NodeJS.ProcessEnv = {};
|
||||
|
||||
it('liest --vault <pfad> aus CLI-Args', () => {
|
||||
const result = resolveVaultPath({
|
||||
args: ['--vault', 'C:\\foo'],
|
||||
env: {},
|
||||
cwd,
|
||||
});
|
||||
expect(result.path).toBe('C:\\foo');
|
||||
expect(result.source).toBe('cli');
|
||||
});
|
||||
|
||||
it('liest -v <pfad> Kurzform', () => {
|
||||
const result = resolveVaultPath({
|
||||
args: ['-v', 'C:\\bar'],
|
||||
env: {},
|
||||
cwd,
|
||||
});
|
||||
expect(result.path).toBe('C:\\bar');
|
||||
expect(result.source).toBe('cli');
|
||||
});
|
||||
|
||||
it('liest --vault=<pfad> Gleichheits-Form', () => {
|
||||
const result = resolveVaultPath({
|
||||
args: ['--vault=C:\\baz'],
|
||||
env: {},
|
||||
cwd,
|
||||
});
|
||||
expect(result.path).toBe('C:\\baz');
|
||||
expect(result.source).toBe('cli');
|
||||
});
|
||||
|
||||
it('faellt zurück auf MINDOMAT_VAULT_PATH, wenn keine CLI-Arg', () => {
|
||||
const result = resolveVaultPath({
|
||||
args: [],
|
||||
env: { MINDOMAT_VAULT_PATH: 'C:\\env-vault' },
|
||||
cwd,
|
||||
});
|
||||
expect(result.path).toBe('C:\\env-vault');
|
||||
expect(result.source).toBe('env');
|
||||
});
|
||||
|
||||
it('CLI-Arg ueberschreibt Env-Var', () => {
|
||||
const result = resolveVaultPath({
|
||||
args: ['--vault', 'C:\\cli-wins'],
|
||||
env: { MINDOMAT_VAULT_PATH: 'C:\\env-loses' },
|
||||
cwd,
|
||||
});
|
||||
expect(result.path).toBe('C:\\cli-wins');
|
||||
expect(result.source).toBe('cli');
|
||||
});
|
||||
|
||||
it('wirft VaultPathError MISSING, wenn weder CLI noch Env', () => {
|
||||
expect(() => resolveVaultPath({
|
||||
args: [],
|
||||
env: {},
|
||||
cwd,
|
||||
})).toThrow(VaultPathError);
|
||||
try {
|
||||
resolveVaultPath({ args: [], env: {}, cwd });
|
||||
} catch (err) {
|
||||
expect(err).toBeInstanceOf(VaultPathError);
|
||||
expect((err as VaultPathError).code).toBe('MISSING');
|
||||
}
|
||||
});
|
||||
|
||||
it('wirft VaultPathError MISSING, wenn Env-Var leer', () => {
|
||||
expect(() => resolveVaultPath({
|
||||
args: [],
|
||||
env: { MINDOMAT_VAULT_PATH: ' ' },
|
||||
cwd,
|
||||
})).toThrow(VaultPathError);
|
||||
});
|
||||
|
||||
it('loest relative Pfade gegen cwd auf', () => {
|
||||
const result = resolveVaultPath({
|
||||
args: ['--vault', 'relativ'],
|
||||
env: {},
|
||||
cwd: 'C:\\base',
|
||||
});
|
||||
// Windows-spezifisch: join mit Backslashes
|
||||
expect(result.path).toMatch(/relativ/);
|
||||
expect(result.path).toMatch(/C:\\base/);
|
||||
});
|
||||
});
|
||||
|
||||
describe('assertVaultExists', () => {
|
||||
let tmpDir: string;
|
||||
|
||||
it('laesst existierende Verzeichnisse durch', () => {
|
||||
tmpDir = mkdtempSync(join(tmpdir(), 'mindomat-test-'));
|
||||
expect(() => assertVaultExists(tmpDir)).not.toThrow();
|
||||
rmSync(tmpDir, { recursive: true, force: true });
|
||||
});
|
||||
|
||||
it('wirft NOT_FOUND fuer nicht existierende Pfade', () => {
|
||||
try {
|
||||
assertVaultExists('C:\\gibt-es-nicht\\garantiert\\nicht');
|
||||
} catch (err) {
|
||||
expect(err).toBeInstanceOf(VaultPathError);
|
||||
expect((err as VaultPathError).code).toBe('NOT_FOUND');
|
||||
}
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,25 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "ES2022",
|
||||
"module": "ESNext",
|
||||
"moduleResolution": "Bundler",
|
||||
"lib": ["ES2022"],
|
||||
"outDir": "./dist",
|
||||
"rootDir": "./src",
|
||||
"strict": true,
|
||||
"esModuleInterop": true,
|
||||
"skipLibCheck": true,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"declaration": true,
|
||||
"declarationMap": true,
|
||||
"sourceMap": true,
|
||||
"resolveJsonModule": true,
|
||||
"isolatedModules": true,
|
||||
"verbatimModuleSyntax": true,
|
||||
"noUnusedLocals": true,
|
||||
"noUnusedParameters": true,
|
||||
"noImplicitReturns": true
|
||||
},
|
||||
"include": ["src/**/*"],
|
||||
"exclude": ["node_modules", "dist", "tests", "webapp"]
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
// Vitest Config
|
||||
// Phase 1.1
|
||||
|
||||
import { defineConfig } from 'vitest/config';
|
||||
|
||||
export default defineConfig({
|
||||
test: {
|
||||
include: ['tests/**/*.test.ts'],
|
||||
environment: 'node',
|
||||
globals: false,
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1 @@
|
||||
# Phase 1.6: Vite + React + TS Skelett kommt hier hin
|
||||
@@ -0,0 +1 @@
|
||||
# Mind-o-Mat Webapp
|
||||
@@ -0,0 +1 @@
|
||||
<!doctype html><html><head><meta charset='utf-8'><title>Mind-o-Mat</title></head><body><div id='root'></div><script type='module' src='/src/main.tsx'></script></body></html>
|
||||
Reference in new issue
Block a user