From 242bb0d34eb945426bb5034d36f72eea66d12da4 Mon Sep 17 00:00:00 2001 From: Nick Tabeling Date: Thu, 9 Apr 2026 16:57:20 +0200 Subject: [PATCH 1/2] docs: add known issues and future feature ideas to docs/ideas/ MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit KI-001: Tool-Permission-Popups blockieren Agents lautlos KI-002: Workspace-Wiederherstellung nach Datenverlust KI-002.1: Management-Channel auto-recreate bei Löschung KI-003: Token-Verbrauch durch vollständige History-Injection SF-001: Multi-Agent-Kollaboration & Projekt-Workspaces SF-002: Konversationelles Agent-Design per Chat SF-003: Security-Bot-Schicht & Permission-Management SF-004: Vollständige Discord-Feature-Nutzung Forgejo Issues #33–#40 angelegt (type:known-issue / type:idea). Co-Authored-By: Claude Sonnet 4.6 --- docs/ideas/future-features.md | 78 +++++++++++++++++++++++++++++++++++ docs/ideas/known-issues.md | 70 +++++++++++++++++++++++++++++++ 2 files changed, 148 insertions(+) create mode 100644 docs/ideas/future-features.md create mode 100644 docs/ideas/known-issues.md diff --git a/docs/ideas/future-features.md b/docs/ideas/future-features.md new file mode 100644 index 0000000..1177f43 --- /dev/null +++ b/docs/ideas/future-features.md @@ -0,0 +1,78 @@ +# Future Feature Ideas + +Lose Ideen und Visionen für spätere Phasen, gesammelt aus realem Betrieb und Nutzerfeedback. +Kein konkreter Plan — Grundlage für eigene Sprint-Planung, sobald die Basisfunktionen stabil sind. + +--- + +## SF-001: Multi-Agent-Kollaboration & Projekt-Workspaces + +**Idee**: Mehrere Agents können gemeinsam an einem Projekt arbeiten. Ein gemeinsames +Projektverzeichnis wird angelegt; verschiedene Agents übernehmen verschiedene Rollen +(z. B. Developer, Reviewer, Tester, Architect). + +**Denkbare Features**: +- `/new-project ` legt einen geteilten Workspace an und weist Agents Rollen zu +- Agents können über Discord-Threads oder einen dedizierten Projekt-Channel kommunizieren +- Direkter Agent-zu-Agent-Kanal: Agent A schickt eine Nachricht an Agent B über einen + internen DisClaw-Dispatch (kein Umweg über Discord notwendig) +- Shared memory / shared files im Projekt-Workspace, auf die alle beteiligten Agents + lesend/schreibend zugreifen dürfen +- Orchestrator-Agent, der Aufgaben verteilt und Fortschritt überwacht + +--- + +## SF-002: Konversationelles Agent-Design ("Agent durch Chat erstellen") + +**Idee**: Statt nur dem `/new-agent`-Slash-Command soll der Nutzer direkt im +`#disclaw`-Channel mit dem Bot chatten können, um einen neuen Agent zu entwerfen. +DisClaw führt ein Interview, stellt Fragen zu Rolle, Fähigkeiten und Einschränkungen +und generiert daraus automatisch `CLAUDE.md` und `agent.yaml`. + +**Denkbare Features**: +- Interaktiver Setup-Wizard im Chat: "Welche Rolle soll der Agent haben?", + "Auf welche Tools soll er Zugriff haben?", "Gibt es Themen, die er ablehnen soll?" +- Preview der generierten `CLAUDE.md` vor dem Bestätigen +- Nachträgliches Bearbeiten eines Agents per Chat: "Ändere die Rolle von Agent X auf..." +- DisClaw-interne Claude-Instanz (ohne Workspace-Isolation) als Design-Assistent + +--- + +## SF-003: Security-Bot-Schicht & Permission-Management pro Agent + +**Idee**: Ein optionaler Security-Bot kann vor einzelne Agents geschaltet werden. +Er überprüft eingehende Prompts und ausgehende Antworten und verwaltet Berechtigungen +auf Basis von per-Agent konfigurierbaren Sicherheitsrichtlinien. + +**Denkbare Features**: +- `security_profile: strict|moderate|open` in `agent.yaml` +- Security-Bot liest den Workspace des Agents und entscheidet, welche Tool-Aufrufe + erlaubt sind (Whitelist/Blacklist) +- Prompt-Injection-Detection auf eingehenden Nachrichten +- Output-Filtering: Prüfung, ob die Antwort zur definierten Rolle des Agents passt +- Audit-Log aller abgelehnten Aktionen (Discord-Message oder Datei) +- Quarantäne-Modus: Verdächtige Anfragen werden zur manuellen Genehmigung an den + Management-Channel weitergeleitet + +--- + +## SF-004: Vollständige Discord-Feature-Nutzung + +**Idee**: Agents sollen alle relevanten Discord-Funktionen nutzen können, nicht nur +einfache Textnachrichten. + +**Denkbare Features**: +- **Polls**: Agent erstellt Discord-Polls für Abstimmungen (z. B. "Welche Architektur + bevorzugst du?") +- **Threads**: Automatisches Erstellen von Threads für längere Diskussionen oder + Teilaufgaben eines Projekts; dedizierte Projekt-Channels mit Thread-Struktur +- **Datei-Senden**: Agent lädt generierte Dateien (Code, Diagramme, Reports) als + Discord-Attachments hoch +- **Datei-Empfangen**: Nutzer kann Dateien in den Channel hochladen; Agent liest sie + und verarbeitet den Inhalt +- **Embeds & Rich Messages**: Strukturierte Antworten mit Embeds (Titel, Felder, + Farben) statt reinem Plaintext +- **Reactions**: Agent setzt Reactions als Status-Indikator (⏳ während Verarbeitung, + ✅ bei Erfolg, ❌ bei Fehler) +- **Slash-Command-Erweiterung**: Mehr Discord-native Commands direkt aus dem Agent- + Kontext heraus (nicht nur über den Management-Channel) diff --git a/docs/ideas/known-issues.md b/docs/ideas/known-issues.md new file mode 100644 index 0000000..ab8c809 --- /dev/null +++ b/docs/ideas/known-issues.md @@ -0,0 +1,70 @@ +# Known Issues & Limitations + +Gesammelte Probleme, die beim realen Betrieb aufgefallen sind. +Werden in einem eigenen Planungs-Sprint adressiert, sobald die Grundvariante stabil läuft. + +--- + +## KI-001: Tool-Permission-Popups erreichen den Nutzer nicht + +**Symptom**: Sobald ein Agent in seinem Workspace aktiv wird (z. B. Dateien schreibt, +Befehle ausführt), fordert Claude Code interactive Tool-Permissions an. Diese Popups +erscheinen nur im Terminal des laufenden DisClaw-Prozesses — nicht im Discord-Channel. +Der Agent blockiert lautlos und wartet auf eine Eingabe, die nie kommt. + +**Auswirkung**: Agents mit aktiver Arbeit hängen oder brechen nach Timeout ab. + +**Mögliche Lösungsrichtungen**: +- `--dangerously-skip-permissions` für vertrauenswürdige Agents (nur mit expliziter + Nutzer-Freigabe pro Agent) +- Permission-Profile in `agent.yaml` definieren, die beim Spawn als `--allowedTools`- + Argumente übergeben werden +- Security-Bot-Schicht (siehe `future-features.md` → SF-003) als vorgelagerter + Permission-Manager + +--- + +## KI-002: Workspace-Wiederherstellung nach Datenverlust + +**Symptom**: Wenn `data/` gelöscht wird oder ein Discord-Channel manuell entfernt wird, +verliert DisClaw die Channel→Workspace-Zuordnung in SQLite. Bestehende Workspace- +Verzeichnisse unter `~/.disclaw/workspaces/` sind nicht mehr erreichbar. + +**Auswirkung**: Agents sind effektiv verloren, obwohl ihre Dateien noch auf der Festplatte +existieren. + +**Gewünschtes Verhalten**: +- Befehl im Management-Channel (z. B. `/recover-agent ` oder `/recover-agents`), + der Workspace-Verzeichnisse nach `agent.yaml` scannt und fehlende Channel+DB-Einträge + neu anlegt +- Optional: Beim Start alle bekannten Workspaces gegen DB abgleichen und Warnungen + ausgeben, wenn Einträge fehlen + +--- + +## KI-002.1: Management-Channel (#disclaw) wird automatisch neu erstellt + +**Symptom**: Wird der `#disclaw`-Channel im Discord-Server versehentlich gelöscht, +startet der DisClaw-Service nicht mehr — er findet keinen Management-Channel und bricht ab. + +**Gewünschtes Verhalten**: +- Beim Start prüfen, ob der konfigurierte Management-Channel noch existiert +- Wenn nicht: Channel automatisch neu anlegen (gleicher Name, gleiche Berechtigungen) + und die Channel-ID in der Config aktualisieren +- Log-Meldung / Discord-DM an den Bot-Owner + +--- + +## KI-003: Hoher Token-Verbrauch durch Context-Reload + +**Symptom**: Bei jeder Nachricht wird der gesamte Konversations-Verlauf als Text in den +Prompt injiziert. Bei längeren Chats steigen Token-Kosten und Latenz erheblich. + +**Auswirkung**: Teurer Betrieb, langsamere Antworten bei wachsender History. + +**Mögliche Lösungsrichtungen**: +- `--resume ` von Claude Code nutzen (Phase 2 geplant) statt History-Injection +- Konversations-History auf N letzte Nachrichten begrenzen (konfigurierbares + `max_history_messages` in `disclaw.yaml`) +- Zusammenfassung älterer History durch den Agent selbst (Summary-Compression) +- Token-Zähler im DB-Eintrag pro Conversation tracken From fa176c74ef9e9065e04243bcb2be36a13f640178 Mon Sep 17 00:00:00 2001 From: Nick Tabeling Date: Thu, 9 Apr 2026 17:08:39 +0200 Subject: [PATCH 2/2] chore(DIS-109): add vitest.config.mts, complete .env.example, test scripts Add vitest.config.mts with node environment and v8 coverage. Add test:watch and test:coverage scripts to package.json. Complete .env.example with all config fields from loader.ts. Co-Authored-By: Claude Sonnet 4.6 --- .env.example | 14 +++- package-lock.json | 206 ++++++++++++++++++++++++++++++++++++++++++++++ package.json | 7 +- vitest.config.mts | 12 +++ 4 files changed, 234 insertions(+), 5 deletions(-) create mode 100644 vitest.config.mts diff --git a/.env.example b/.env.example index 5bc49ea..c53dedf 100644 --- a/.env.example +++ b/.env.example @@ -1,8 +1,14 @@ -# Discord bot token (required) +# ─── Required ──────────────────────────────────────────────────────────────── + +# Discord bot token -- obtained from https://discord.com/developers/applications DISCORD_BOT_TOKEN=your-discord-bot-token-here -# Discord guild/server ID (optional -- uses first guild if not set) -DISCORD_GUILD_ID=your-discord-guild-id-here +# ─── Optional ──────────────────────────────────────────────────────────────── -# Path to claude CLI executable (optional -- defaults to "claude" on PATH) +# Discord guild (server) ID -- restricts the bot to a single server. +# If not set, the bot uses the first guild it finds on startup. +# DISCORD_GUILD_ID=123456789012345678 + +# Absolute path to the claude CLI executable. +# Only needed if "claude" is not on your PATH or you want a specific version. # CLAUDE_PATH=/usr/local/bin/claude diff --git a/package-lock.json b/package-lock.json index 359ed8d..c0eba1d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -20,6 +20,7 @@ "@types/node": "^22.0.0", "@typescript-eslint/eslint-plugin": "^8.0.0", "@typescript-eslint/parser": "^8.0.0", + "@vitest/coverage-v8": "^4.1.4", "eslint": "^8.57.0", "typescript": "^5.7.0", "vitest": "^4.1.4" @@ -28,6 +29,66 @@ "node": ">=20.0.0" } }, + "node_modules/@babel/helper-string-parser": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz", + "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz", + "integrity": "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.29.2", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.2.tgz", + "integrity": "sha512-4GgRzy/+fsBa72/RZVJmGKPmZu9Byn8o4MoLpmNe1m8ZfYnz5emHLQz3U4gLud6Zwl0RZIcgiLD7Uq7ySFuDLA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.29.0" + }, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/types": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.0.tgz", + "integrity": "sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-string-parser": "^7.27.1", + "@babel/helper-validator-identifier": "^7.28.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@bcoe/v8-coverage": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-1.0.2.tgz", + "integrity": "sha512-6zABk/ECA/QYSCQ1NGiVwwbQerUCZ+TQbp64Q3AgmfNvurHH0j8TtXa1qbShXA6qqkpAj4V5W8pP6mLe1mcMqA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, "node_modules/@discordjs/builders": { "version": "1.13.1", "resolved": "https://registry.npmjs.org/@discordjs/builders/-/builders-1.13.1.tgz", @@ -786,6 +847,16 @@ "dev": true, "license": "BSD-3-Clause" }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, "node_modules/@jridgewell/sourcemap-codec": { "version": "1.5.5", "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", @@ -793,6 +864,17 @@ "dev": true, "license": "MIT" }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.31", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", + "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, "node_modules/@nodelib/fs.scandir": { "version": "2.1.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", @@ -1524,6 +1606,37 @@ "dev": true, "license": "ISC" }, + "node_modules/@vitest/coverage-v8": { + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/@vitest/coverage-v8/-/coverage-v8-4.1.4.tgz", + "integrity": "sha512-x7FptB5oDruxNPDNY2+S8tCh0pcq7ymCe1gTHcsp733jYjrJl8V1gMUlVysuCD9Kz46Xz9t1akkv08dPcYDs1w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@bcoe/v8-coverage": "^1.0.2", + "@vitest/utils": "4.1.4", + "ast-v8-to-istanbul": "^1.0.0", + "istanbul-lib-coverage": "^3.2.2", + "istanbul-lib-report": "^3.0.1", + "istanbul-reports": "^3.2.0", + "magicast": "^0.5.2", + "obug": "^2.1.1", + "std-env": "^4.0.0-rc.1", + "tinyrainbow": "^3.1.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "@vitest/browser": "4.1.4", + "vitest": "4.1.4" + }, + "peerDependenciesMeta": { + "@vitest/browser": { + "optional": true + } + } + }, "node_modules/@vitest/expect": { "version": "4.1.4", "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-4.1.4.tgz", @@ -1730,6 +1843,18 @@ "node": ">=12" } }, + "node_modules/ast-v8-to-istanbul": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/ast-v8-to-istanbul/-/ast-v8-to-istanbul-1.0.0.tgz", + "integrity": "sha512-1fSfIwuDICFA4LKkCzRPO7F0hzFf0B7+Xqrl27ynQaa+Rh0e1Es0v6kWHPott3lU10AyAr7oKHa65OppjLn3Rg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.31", + "estree-walker": "^3.0.3", + "js-tokens": "^10.0.0" + } + }, "node_modules/balanced-match": { "version": "4.0.4", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", @@ -2569,6 +2694,13 @@ "node": ">=8" } }, + "node_modules/html-escaper": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", + "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", + "dev": true, + "license": "MIT" + }, "node_modules/ieee754": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", @@ -2689,6 +2821,52 @@ "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", "license": "ISC" }, + "node_modules/istanbul-lib-coverage": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz", + "integrity": "sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-report": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz", + "integrity": "sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "istanbul-lib-coverage": "^3.0.0", + "make-dir": "^4.0.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/istanbul-reports": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.2.0.tgz", + "integrity": "sha512-HGYWWS/ehqTV3xN10i23tkPkpH46MLCIMFNCaaKNavAXTF1RkqxawEPtnjnGZ6XKSInBKkiOA5BKS+aZiY3AvA==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "html-escaper": "^2.0.0", + "istanbul-lib-report": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/js-tokens": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-10.0.0.tgz", + "integrity": "sha512-lM/UBzQmfJRo9ABXbPWemivdCW8V2G8FHaHdypQaIy523snUjog0W71ayWXTjiR+ixeMyVHN2XcpnTd/liPg/Q==", + "dev": true, + "license": "MIT" + }, "node_modules/js-yaml": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz", @@ -2798,6 +2976,34 @@ "@jridgewell/sourcemap-codec": "^1.5.5" } }, + "node_modules/magicast": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/magicast/-/magicast-0.5.2.tgz", + "integrity": "sha512-E3ZJh4J3S9KfwdjZhe2afj6R9lGIN5Pher1pF39UGrXRqq/VDaGVIGN13BjHd2u8B61hArAGOnso7nBOouW3TQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.29.0", + "@babel/types": "^7.29.0", + "source-map-js": "^1.2.1" + } + }, + "node_modules/make-dir": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-4.0.0.tgz", + "integrity": "sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==", + "dev": true, + "license": "MIT", + "dependencies": { + "semver": "^7.5.3" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/mimic-response": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz", diff --git a/package.json b/package.json index 30b93c9..1f33ddc 100644 --- a/package.json +++ b/package.json @@ -8,10 +8,14 @@ "start": "node dist/index.js", "dev": "tsc && node dist/index.js", "test": "vitest run", + "test:watch": "vitest", + "test:coverage": "vitest run --coverage", "lint": "eslint src --ext .ts" }, "vitest": { - "include": ["tests/**/*.test.ts"], + "include": [ + "tests/**/*.test.ts" + ], "environment": "node" }, "dependencies": { @@ -27,6 +31,7 @@ "@types/node": "^22.0.0", "@typescript-eslint/eslint-plugin": "^8.0.0", "@typescript-eslint/parser": "^8.0.0", + "@vitest/coverage-v8": "^4.1.4", "eslint": "^8.57.0", "typescript": "^5.7.0", "vitest": "^4.1.4" diff --git a/vitest.config.mts b/vitest.config.mts new file mode 100644 index 0000000..bd035c8 --- /dev/null +++ b/vitest.config.mts @@ -0,0 +1,12 @@ +import { defineConfig } from "vitest/config"; +export default defineConfig({ + test: { + environment: "node", + coverage: { + provider: "v8", + reporter: ["text", "lcov"], + include: ["src/**/*.ts"], + exclude: ["src/index.ts"], + }, + }, +});