diff --git a/.gitignore b/.gitignore
index 328228c..0af7db9 100644
--- a/.gitignore
+++ b/.gitignore
@@ -34,3 +34,6 @@ docker-compose.override.yml
app/.next/
dist/
*.local
+
+# TS incremental build
+*.tsbuildinfo
diff --git a/ai-act-kompass/README.md b/ai-act-kompass/README.md
new file mode 100644
index 0000000..0ca801e
--- /dev/null
+++ b/ai-act-kompass/README.md
@@ -0,0 +1,38 @@
+# đ§ AI-Act-Kompass
+
+**Standalone EU-AI-Act-Compliance-Toolkit fĂŒr KMU.** Local-first: keine Cloud, keine Telemetrie, keine DatenĂŒbertragung â alle Daten bleiben im Browser des Nutzers (localStorage, mit JSON-Export/-Import).
+
+> â ïž Strukturierte Arbeitshilfe auf Basis der Verordnung (EU) 2024/1689 â **keine Rechtsberatung**.
+
+## Was es kann
+
+- **Bewertungs-Wizard**: erfasst ein KI-System und klassifiziert es automatisch nach der Systematik des AI Act â KI-Definition (Art. 3 Nr. 1) â verbotene Praktiken (Art. 5) â Hochrisiko (Art. 6, Annex I/III, inkl. Ausnahme Art. 6 Abs. 3 und Profiling-Sperre) â Transparenzpflichten (Art. 50) â minimales Risiko. GPAI-Pflichten (Art. 53 ff.) werden separat geflaggt.
+- **KI-Inventar**: alle Systeme des Unternehmens mit Risikoklasse, Rolle und Verantwortlichen â exportierbar als Markdown (AI Asset Register).
+- **Pflichten-Checklisten**: rollenspezifisch (Anbieter/Betreiber/EinfĂŒhrer/HĂ€ndler) abgeleitete Pflichten mit Rechtsgrundlage, Geltungsfrist und Umsetzungsstatus.
+- **Dokumenten-Generator**: Risikoklassifizierungs-Bericht, MaĂnahmenplan und Annex-IV-GrundgerĂŒst (technische Dokumentation) als Markdown.
+- **Fristen-Ăbersicht**: alle Geltungsfristen des AI Act inkl. der Digital-Omnibus-Verschiebung (Annex III â 02.12.2027).
+
+## Architektur
+
+| Schicht | Inhalt |
+|---|---|
+| `src/engine/` | Reine, getestete Regel-Engine: `classify`, `deriveObligations`, Dokumenten-Generatoren. Kein DOM, keine Seiteneffekte. |
+| `src/content/` | Versionierter regulatorischer **Content-Pack** (Verbote, Annex-III-Bereiche, Pflichten, Fristen) als Daten â vorbereitet fĂŒr einen spĂ€teren signierten Update-Feed. |
+| `src/store/` | localStorage-Persistenz + Export/Import (JSON). |
+| `src/ui/` | React-UI (Dashboard, Wizard, Detailansicht, Einstellungen), Deutsch. |
+
+Kein Backend, kein Build-Server nötig â `dist/` ist eine statische Site und lĂ€uft von Datei-Share, Intranet oder localhost.
+
+## Entwicklung
+
+```bash
+npm install
+npm run dev # Dev-Server
+npm test # Engine-Tests (Vitest)
+npm run typecheck # TS strict
+npm run build # Statischer Build nach dist/
+```
+
+## GeschÀftsmodell (geplant)
+
+Standalone-App + Abo fĂŒr den **Regulatory-Content-Feed**: Die App gehört dem Kunden und lĂ€uft lokal; das Abo liefert aktualisierte Regelinhalte (delegierte Rechtsakte, harmonisierte Normen, FristenĂ€nderungen), Templates und Norm-Mappings. Synergie mit `@shieldx/core`: Art.-15-Pflicht (Robustheit/Cybersicherheit gegen Prompt Injection & Co.) verweist direkt auf ShieldX als technische Umsetzung.
diff --git a/ai-act-kompass/index.html b/ai-act-kompass/index.html
new file mode 100644
index 0000000..8d9c556
--- /dev/null
+++ b/ai-act-kompass/index.html
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+ AI-Act-Kompass
+
+
+
+
+
+
diff --git a/ai-act-kompass/package-lock.json b/ai-act-kompass/package-lock.json
new file mode 100644
index 0000000..e365235
--- /dev/null
+++ b/ai-act-kompass/package-lock.json
@@ -0,0 +1,2135 @@
+{
+ "name": "@shieldx/ai-act-kompass",
+ "version": "0.1.0",
+ "lockfileVersion": 3,
+ "requires": true,
+ "packages": {
+ "": {
+ "name": "@shieldx/ai-act-kompass",
+ "version": "0.1.0",
+ "dependencies": {
+ "react": "^18.3.1",
+ "react-dom": "^18.3.1"
+ },
+ "devDependencies": {
+ "@types/react": "^18.3.12",
+ "@types/react-dom": "^18.3.1",
+ "@vitejs/plugin-react": "^4.3.4",
+ "typescript": "^5.6.3",
+ "vite": "^5.4.11",
+ "vitest": "^2.1.8"
+ }
+ },
+ "node_modules/@babel/code-frame": {
+ "version": "7.29.7",
+ "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.7.tgz",
+ "integrity": "sha512-Aup7aUOfpbAUg2ROOJN6Iw5f9DMBlzu0mIkm/malLQFN/YQgO48wCj0Kxa3sEHJvPVFg7siR+qRInwXd2qhQKw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-validator-identifier": "^7.29.7",
+ "js-tokens": "^4.0.0",
+ "picocolors": "^1.1.1"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/compat-data": {
+ "version": "7.29.7",
+ "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.29.7.tgz",
+ "integrity": "sha512-locTkQyKvwIEgBzVrn8693ebc97F2U8ZHjbXwDXJ5Fn2TCpNwTlKcaKLkdHop5c/icOFE7qt7Q9JC5hnKNa6Gg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/core": {
+ "version": "7.29.7",
+ "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.29.7.tgz",
+ "integrity": "sha512-RgHBCvtjbOK2gXSNBNIkNoEc9qoVEtau3hj8gEqKQuL3HZAibKarWFEI3Lfm6EYKkLalOh8eSrj9b+ch9H/VBA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/code-frame": "^7.29.7",
+ "@babel/generator": "^7.29.7",
+ "@babel/helper-compilation-targets": "^7.29.7",
+ "@babel/helper-module-transforms": "^7.29.7",
+ "@babel/helpers": "^7.29.7",
+ "@babel/parser": "^7.29.7",
+ "@babel/template": "^7.29.7",
+ "@babel/traverse": "^7.29.7",
+ "@babel/types": "^7.29.7",
+ "@jridgewell/remapping": "^2.3.5",
+ "convert-source-map": "^2.0.0",
+ "debug": "^4.1.0",
+ "gensync": "^1.0.0-beta.2",
+ "json5": "^2.2.3",
+ "semver": "^6.3.1"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/babel"
+ }
+ },
+ "node_modules/@babel/generator": {
+ "version": "7.29.7",
+ "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.7.tgz",
+ "integrity": "sha512-DkXD5OJQaAQIdZ1bt3UZdEnHAn9Imd3IVBdX03UFe+ony9Ojw5pzr9YVKGDY1jt+Gcn/FnGkNf8r+Vj5NOJWtQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/parser": "^7.29.7",
+ "@babel/types": "^7.29.7",
+ "@jridgewell/gen-mapping": "^0.3.12",
+ "@jridgewell/trace-mapping": "^0.3.28",
+ "jsesc": "^3.0.2"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helper-compilation-targets": {
+ "version": "7.29.7",
+ "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.29.7.tgz",
+ "integrity": "sha512-wem6WaBj4NaVYVdNhLPPVacES6ZJ+KBBfSkTMD3YZxbP3rm3Di85tJU5ljaUNhaOynt+Aj0xruhYuzQBt8n71g==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/compat-data": "^7.29.7",
+ "@babel/helper-validator-option": "^7.29.7",
+ "browserslist": "^4.24.0",
+ "lru-cache": "^5.1.1",
+ "semver": "^6.3.1"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helper-globals": {
+ "version": "7.29.7",
+ "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.29.7.tgz",
+ "integrity": "sha512-3nQVUAtvkKH9zahfWgw96Jc/uFOmjACE1kQz82E2lqWmHBgjzbNlsC22nuQTfahmWeQtTq5nQ/4Nnd2A1wj4zA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helper-module-imports": {
+ "version": "7.29.7",
+ "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.29.7.tgz",
+ "integrity": "sha512-ejHwrQQYcm9xnTivShn2IDOlIzInN34AXskvq9QicvCtEzq1Vzclu/tKF8Jq1Cg8JG2GL6/EmjgsCT7lXepE3g==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/traverse": "^7.29.7",
+ "@babel/types": "^7.29.7"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helper-module-transforms": {
+ "version": "7.29.7",
+ "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.29.7.tgz",
+ "integrity": "sha512-UPUVSyXbOh627KiCIGQSgwWzGeBKLkaJ9PJEdrngIwMSzxLR4jS4+f1f1jb7VzBbg8nFLaYotvVPFCTqdrmTAg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-module-imports": "^7.29.7",
+ "@babel/helper-validator-identifier": "^7.29.7",
+ "@babel/traverse": "^7.29.7"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0"
+ }
+ },
+ "node_modules/@babel/helper-plugin-utils": {
+ "version": "7.29.7",
+ "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.29.7.tgz",
+ "integrity": "sha512-G7sHYigPY17oO5SYWnfD/0MTBwVR781S/JI643e/JhUYgVgWE/61SoW3NH9KWUKyKq5LVh3npif99Wkt6j86Jw==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helper-string-parser": {
+ "version": "7.29.7",
+ "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.29.7.tgz",
+ "integrity": "sha512-Pb5ijPrZ89GDH8223L4UP8i6QApWxs04RbPQJTeWDV0/keR2E36MeKnyr6LYmUUvqRRI+Iv87SuF1W6ErINzYw==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helper-validator-identifier": {
+ "version": "7.29.7",
+ "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.29.7.tgz",
+ "integrity": "sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helper-validator-option": {
+ "version": "7.29.7",
+ "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.29.7.tgz",
+ "integrity": "sha512-N9ZErrD+yW5geCDtBqnOoxmR8+tNKiGuxKlDpuJxfsqpa2dFcexaziGAE/qoHLiDDreVNMupxGmSoNlyvsA3gw==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helpers": {
+ "version": "7.29.7",
+ "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.29.7.tgz",
+ "integrity": "sha512-1k2lAGRMfHTcwuNYcCNUmaUffmQv8KWMfh2iJUUeRlwlwH4FdNG7mfPI10NPfLHJFThE4Tyr4mv7kTNZOiPuBg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/template": "^7.29.7",
+ "@babel/types": "^7.29.7"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/parser": {
+ "version": "7.29.7",
+ "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.7.tgz",
+ "integrity": "sha512-hnORnjP/1P/zFEndoeX+n+t1RwWRJiJpM/jO7FW32Kn9r5+sJB2JWOdYo4L6k78j15eCwY3Gm/7364B1EMwtNg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/types": "^7.29.7"
+ },
+ "bin": {
+ "parser": "bin/babel-parser.js"
+ },
+ "engines": {
+ "node": ">=6.0.0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-react-jsx-self": {
+ "version": "7.29.7",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.29.7.tgz",
+ "integrity": "sha512-TL0hMc9xzy86VD31nUiwzd5otRAcyEPcsegCxolO0PvcXuH1v0kECe/UIznYFihpkvU5wg/jk4v0TTEFfm53fw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.29.7"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-react-jsx-source": {
+ "version": "7.29.7",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.29.7.tgz",
+ "integrity": "sha512-06IyK09H3wi4cGbhDBwp5gUGo0IKtnYa8tyTiephirPCK6fbobVGiXMMI5zLQ4aKEYP3wZ3ArU44o+8KMrSG/Q==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.29.7"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/template": {
+ "version": "7.29.7",
+ "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.29.7.tgz",
+ "integrity": "sha512-puq+Gf35oI24FeN11LkoUQFqv9uwNeWpxXZi/Ji3rRIoKAzKnxRaZ+Gkj0vKS9ZCiTESfng1N9LyOyXvo+m+Gg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/code-frame": "^7.29.7",
+ "@babel/parser": "^7.29.7",
+ "@babel/types": "^7.29.7"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/traverse": {
+ "version": "7.29.7",
+ "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.29.7.tgz",
+ "integrity": "sha512-EhlfNQtZ+NK22w5BM61ciuiq1m58ed33Wr1Xan//ZRTy6hgjnwyCffRYwzsGXdASJSUJ1guZILsErh1eQcl+zw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/code-frame": "^7.29.7",
+ "@babel/generator": "^7.29.7",
+ "@babel/helper-globals": "^7.29.7",
+ "@babel/parser": "^7.29.7",
+ "@babel/template": "^7.29.7",
+ "@babel/types": "^7.29.7",
+ "debug": "^4.3.1"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/types": {
+ "version": "7.29.7",
+ "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.7.tgz",
+ "integrity": "sha512-4zBIxpPzowiZpusoFkyGVwakdRJUyuH5PxQ/PrqghfdFWWasvnCdPfQXHrenDai+gyLARulZjZowCOj6fjT4pA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-string-parser": "^7.29.7",
+ "@babel/helper-validator-identifier": "^7.29.7"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@esbuild/aix-ppc64": {
+ "version": "0.21.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz",
+ "integrity": "sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==",
+ "cpu": [
+ "ppc64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "aix"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/android-arm": {
+ "version": "0.21.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.21.5.tgz",
+ "integrity": "sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==",
+ "cpu": [
+ "arm"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "android"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/android-arm64": {
+ "version": "0.21.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.21.5.tgz",
+ "integrity": "sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "android"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/android-x64": {
+ "version": "0.21.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.21.5.tgz",
+ "integrity": "sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "android"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/darwin-arm64": {
+ "version": "0.21.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.21.5.tgz",
+ "integrity": "sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/darwin-x64": {
+ "version": "0.21.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.21.5.tgz",
+ "integrity": "sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/freebsd-arm64": {
+ "version": "0.21.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.21.5.tgz",
+ "integrity": "sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "freebsd"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/freebsd-x64": {
+ "version": "0.21.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.21.5.tgz",
+ "integrity": "sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "freebsd"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/linux-arm": {
+ "version": "0.21.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.21.5.tgz",
+ "integrity": "sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==",
+ "cpu": [
+ "arm"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/linux-arm64": {
+ "version": "0.21.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.21.5.tgz",
+ "integrity": "sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/linux-ia32": {
+ "version": "0.21.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.21.5.tgz",
+ "integrity": "sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==",
+ "cpu": [
+ "ia32"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/linux-loong64": {
+ "version": "0.21.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.21.5.tgz",
+ "integrity": "sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==",
+ "cpu": [
+ "loong64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/linux-mips64el": {
+ "version": "0.21.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.21.5.tgz",
+ "integrity": "sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==",
+ "cpu": [
+ "mips64el"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/linux-ppc64": {
+ "version": "0.21.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.21.5.tgz",
+ "integrity": "sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==",
+ "cpu": [
+ "ppc64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/linux-riscv64": {
+ "version": "0.21.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.21.5.tgz",
+ "integrity": "sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==",
+ "cpu": [
+ "riscv64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/linux-s390x": {
+ "version": "0.21.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.21.5.tgz",
+ "integrity": "sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==",
+ "cpu": [
+ "s390x"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/linux-x64": {
+ "version": "0.21.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.21.5.tgz",
+ "integrity": "sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/netbsd-x64": {
+ "version": "0.21.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.21.5.tgz",
+ "integrity": "sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "netbsd"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/openbsd-x64": {
+ "version": "0.21.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.21.5.tgz",
+ "integrity": "sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "openbsd"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/sunos-x64": {
+ "version": "0.21.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.21.5.tgz",
+ "integrity": "sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "sunos"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/win32-arm64": {
+ "version": "0.21.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.21.5.tgz",
+ "integrity": "sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/win32-ia32": {
+ "version": "0.21.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.21.5.tgz",
+ "integrity": "sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==",
+ "cpu": [
+ "ia32"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/win32-x64": {
+ "version": "0.21.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.21.5.tgz",
+ "integrity": "sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@jridgewell/gen-mapping": {
+ "version": "0.3.13",
+ "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz",
+ "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@jridgewell/sourcemap-codec": "^1.5.0",
+ "@jridgewell/trace-mapping": "^0.3.24"
+ }
+ },
+ "node_modules/@jridgewell/remapping": {
+ "version": "2.3.5",
+ "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz",
+ "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@jridgewell/gen-mapping": "^0.3.5",
+ "@jridgewell/trace-mapping": "^0.3.24"
+ }
+ },
+ "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",
+ "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==",
+ "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/@rolldown/pluginutils": {
+ "version": "1.0.0-beta.27",
+ "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-beta.27.tgz",
+ "integrity": "sha512-+d0F4MKMCbeVUJwG96uQ4SgAznZNSq93I3V+9NHA4OpvqG8mRCpGdKmK8l/dl02h2CCDHwW2FqilnTyDcAnqjA==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/@rollup/rollup-android-arm-eabi": {
+ "version": "4.62.2",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.62.2.tgz",
+ "integrity": "sha512-6o7ZLZK+BeenkZCFNDXqpbjw9bD6nuWonvS/lwQJp7NoVVxm6p3qE7qQ5jGuBjiFsgvqjD8mZAU5oWxTmbOeOg==",
+ "cpu": [
+ "arm"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "android"
+ ]
+ },
+ "node_modules/@rollup/rollup-android-arm64": {
+ "version": "4.62.2",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.62.2.tgz",
+ "integrity": "sha512-BaH7BllCACHoH1LguOU56UItGfUWjujlO65kS9LAodViaN4bwIKd7oeW/ZHJ/4ljr/7MIiENnNy3HJ0zXv8Zkw==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "android"
+ ]
+ },
+ "node_modules/@rollup/rollup-darwin-arm64": {
+ "version": "4.62.2",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.62.2.tgz",
+ "integrity": "sha512-v39RCCvj4He82I9sFmk+M1VZ0PLM9sfsLVikjfx2hYBNALhrrOR2D3JjQA6AhlaSOgcR+RzrKY7e1+bT6SUO/A==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ]
+ },
+ "node_modules/@rollup/rollup-darwin-x64": {
+ "version": "4.62.2",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.62.2.tgz",
+ "integrity": "sha512-yl0y2vq3S3lHeuXhEdss6TWfKW8vkujImO12tn4ZkG/4oghr09LvdYm2RElVjokTQiUvDUGXLGsYeLqUMCKpGA==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ]
+ },
+ "node_modules/@rollup/rollup-freebsd-arm64": {
+ "version": "4.62.2",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.62.2.tgz",
+ "integrity": "sha512-tT4pvt4qXD+vEoezupCWi+a1F0vvDiksiHc+PxRlYTOH1I6/X4id9jPxTP+Fg+545euaFT1jJVs4CEdHZAU1vw==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "freebsd"
+ ]
+ },
+ "node_modules/@rollup/rollup-freebsd-x64": {
+ "version": "4.62.2",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.62.2.tgz",
+ "integrity": "sha512-6nU5F2wCW+qvCBhTn1pdIU3bzsIoF7EUwsCDRxilWGprQR6yd508YnH9+OKFCwpfS8pjZqDUmnCAr7exax0XCg==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "freebsd"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-arm-gnueabihf": {
+ "version": "4.62.2",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.62.2.tgz",
+ "integrity": "sha512-n1GJHPOvpIfhi3TmrCeh6S6URt9BFCt0KQE3qvexyGCTAKpR4Lg+eWvNZEqu7epxwus/8ElT3hacYEucm49SZg==",
+ "cpu": [
+ "arm"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-arm-musleabihf": {
+ "version": "4.62.2",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.62.2.tgz",
+ "integrity": "sha512-JqgflS8wEB+UXV/vS1RpRbifGBeN4D5lz8D8oOFbFZw4vedvdOgCFAjfBmIMdW3yL10XpQQ0Ambepw6MXrhOnA==",
+ "cpu": [
+ "arm"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-arm64-gnu": {
+ "version": "4.62.2",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.62.2.tgz",
+ "integrity": "sha512-wnFJkogWvN4jm/hQRF2UBaeUmk20j5+DmHvoyWii2b8HJDyvz1MF2OU/6ynXt2KR63rbZLWkFpoytpdc/yBuSA==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-arm64-musl": {
+ "version": "4.62.2",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.62.2.tgz",
+ "integrity": "sha512-HVu2bp0zhvJ8xHEV9+UUs7S90VadmBSY3LcIMvozbPo4AuMGDWlz3ymHLHZPX4hR67TKTt8Qp5PJ5RBg/i+RMQ==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-loong64-gnu": {
+ "version": "4.62.2",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.62.2.tgz",
+ "integrity": "sha512-mQqqAV8QaoSgr9I2fKDLY2BAVvmKjWoGiu/cSYQonsLvtqwEn1E4QYfnCOcp5zoEqNhsDYin1s6jx/VJmrxlZg==",
+ "cpu": [
+ "loong64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-loong64-musl": {
+ "version": "4.62.2",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.62.2.tgz",
+ "integrity": "sha512-IxKLoxCQ2IWi6bT2akyDUBGsOImDKB+sPp4EsTmwFQ/fMwpCKm8uLSSgP/Kx/QYUgKis6SEZ5/Nlhup0DIA0PQ==",
+ "cpu": [
+ "loong64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-ppc64-gnu": {
+ "version": "4.62.2",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.62.2.tgz",
+ "integrity": "sha512-Mk5ha2RQSgyFfmYYLkBpPnUk8D8FriBxesO1u9O75X0mHgXL1UQcH5Itl2lurWL2tj0RxV9b9tJgipac0hRY9A==",
+ "cpu": [
+ "ppc64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-ppc64-musl": {
+ "version": "4.62.2",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.62.2.tgz",
+ "integrity": "sha512-CjvEnqJL/0/TQ3TXX3OPIJ/kmBellrWd4heXUmHeJlTnmwjKpSJzoehLaL6Xk0ZnMHBu9dZuFADNOrtjF4v+2w==",
+ "cpu": [
+ "ppc64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-riscv64-gnu": {
+ "version": "4.62.2",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.62.2.tgz",
+ "integrity": "sha512-1SiZbzwdkaDURsew/tSOrooKiYy7EQGT6m8ufavAi9NEyQb/6VuIxFXAL1fqa4iZe3g4NbNk4P7J32z2tw5Mgg==",
+ "cpu": [
+ "riscv64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-riscv64-musl": {
+ "version": "4.62.2",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.62.2.tgz",
+ "integrity": "sha512-nQts12zJ3NQRoE6uYljOH89v7szzLDvG2JD/vsX+vGXU8w/At1GowTZ5/7qeFQ8m7L55rpR8Okugnuo5bgjy2Q==",
+ "cpu": [
+ "riscv64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-s390x-gnu": {
+ "version": "4.62.2",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.62.2.tgz",
+ "integrity": "sha512-E9/ll019jhPIJgpzfZoIkBGhcz+kKNgVWYRY0zr9srBdPPFVpvOKW8VaJKUbeK+eZXyQF9ltME+Kk6affeaPgg==",
+ "cpu": [
+ "s390x"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-x64-gnu": {
+ "version": "4.62.2",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.62.2.tgz",
+ "integrity": "sha512-5BqxR/pshjey51iliyzTD5Xi3EN0aLmQ2lZ3lvefVV9c82BvrLo2/6OT55iifpWBufs6kdwWbuOKS841DrmK9A==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-x64-musl": {
+ "version": "4.62.2",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.62.2.tgz",
+ "integrity": "sha512-uNN83XxQrRAh/w0/pmAfibcwyb6YWt4gP+dpnQKPVJshAloQ785ii8CT8ZCIxkGg9opVsvAlGhFitSm6D1Jjpg==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-openbsd-x64": {
+ "version": "4.62.2",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.62.2.tgz",
+ "integrity": "sha512-srjEIxSH3LRnJN6THczDHWQplqEMFiAJrTab0msUryh9kwNpkICf3Ea6q6MN/2cZwRFUNx5w+h6Hpi4QuHS6Zg==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "openbsd"
+ ]
+ },
+ "node_modules/@rollup/rollup-openharmony-arm64": {
+ "version": "4.62.2",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.62.2.tgz",
+ "integrity": "sha512-8hOJnxgbyObnCm5AlRA3A931xX19xq80RjVTKgJOvEKWqJruP/Uf12IbAOaDjjEXYRewwHLfmF0YRIdK3OwKWA==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "openharmony"
+ ]
+ },
+ "node_modules/@rollup/rollup-win32-arm64-msvc": {
+ "version": "4.62.2",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.62.2.tgz",
+ "integrity": "sha512-mmF4AY1i0hG/bLWUctUq59gtmgaSIRa3cu/A3JFRp/sCNEme2bgDEiDS22P9FbnJB8NJNF4jPJiSP5RHQpUTDg==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ]
+ },
+ "node_modules/@rollup/rollup-win32-ia32-msvc": {
+ "version": "4.62.2",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.62.2.tgz",
+ "integrity": "sha512-DZgkknc6jhHrk46V25vbAM0zZkyP0nSDkJB8/dRkLTxv470dOmWDqGoEJl/9A0dFfS7yE3REOwNDxpHwSLSt0Q==",
+ "cpu": [
+ "ia32"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ]
+ },
+ "node_modules/@rollup/rollup-win32-x64-gnu": {
+ "version": "4.62.2",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.62.2.tgz",
+ "integrity": "sha512-T6xr6ucWSFto+VGajA8YH26LdpHRuP4YLHEKAtCWvJDOlnmWcDZVCI2Jmjr+IFHDlt2zRaTAKE4tfjTaWLgJBg==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ]
+ },
+ "node_modules/@rollup/rollup-win32-x64-msvc": {
+ "version": "4.62.2",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.62.2.tgz",
+ "integrity": "sha512-BfzEnDJOt9T8M989/lA37EcJgat01wLRnoi5dQf3QzOH7jzpqTAzdDbVfRljVr5r+jzKqpbHeyOfAaXxAd0PAA==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ]
+ },
+ "node_modules/@types/babel__core": {
+ "version": "7.20.5",
+ "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz",
+ "integrity": "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/parser": "^7.20.7",
+ "@babel/types": "^7.20.7",
+ "@types/babel__generator": "*",
+ "@types/babel__template": "*",
+ "@types/babel__traverse": "*"
+ }
+ },
+ "node_modules/@types/babel__generator": {
+ "version": "7.27.0",
+ "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.27.0.tgz",
+ "integrity": "sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/types": "^7.0.0"
+ }
+ },
+ "node_modules/@types/babel__template": {
+ "version": "7.4.4",
+ "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.4.tgz",
+ "integrity": "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/parser": "^7.1.0",
+ "@babel/types": "^7.0.0"
+ }
+ },
+ "node_modules/@types/babel__traverse": {
+ "version": "7.28.0",
+ "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.28.0.tgz",
+ "integrity": "sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/types": "^7.28.2"
+ }
+ },
+ "node_modules/@types/estree": {
+ "version": "1.0.9",
+ "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.9.tgz",
+ "integrity": "sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/@types/prop-types": {
+ "version": "15.7.15",
+ "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.15.tgz",
+ "integrity": "sha512-F6bEyamV9jKGAFBEmlQnesRPGOQqS2+Uwi0Em15xenOxHaf2hv6L8YCVn3rPdPJOiJfPiCnLIRyvwVaqMY3MIw==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/@types/react": {
+ "version": "18.3.31",
+ "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.31.tgz",
+ "integrity": "sha512-vfEqpXTvwT91yhmwdfouStN2hSKwTvyRs8qpLfADyrq/kxDw0hZM7Wk9Ug1FELj8hIby+S/+kQCSRFF32nv2Qw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@types/prop-types": "*",
+ "csstype": "^3.2.2"
+ }
+ },
+ "node_modules/@types/react-dom": {
+ "version": "18.3.7",
+ "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.3.7.tgz",
+ "integrity": "sha512-MEe3UeoENYVFXzoXEWsvcpg6ZvlrFNlOQ7EOsvhI3CfAXwzPfO8Qwuxd40nepsYKqyyVQnTdEfv68q91yLcKrQ==",
+ "dev": true,
+ "license": "MIT",
+ "peerDependencies": {
+ "@types/react": "^18.0.0"
+ }
+ },
+ "node_modules/@vitejs/plugin-react": {
+ "version": "4.7.0",
+ "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-4.7.0.tgz",
+ "integrity": "sha512-gUu9hwfWvvEDBBmgtAowQCojwZmJ5mcLn3aufeCsitijs3+f2NsrPtlAWIR6OPiqljl96GVCUbLe0HyqIpVaoA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/core": "^7.28.0",
+ "@babel/plugin-transform-react-jsx-self": "^7.27.1",
+ "@babel/plugin-transform-react-jsx-source": "^7.27.1",
+ "@rolldown/pluginutils": "1.0.0-beta.27",
+ "@types/babel__core": "^7.20.5",
+ "react-refresh": "^0.17.0"
+ },
+ "engines": {
+ "node": "^14.18.0 || >=16.0.0"
+ },
+ "peerDependencies": {
+ "vite": "^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0"
+ }
+ },
+ "node_modules/@vitest/expect": {
+ "version": "2.1.9",
+ "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-2.1.9.tgz",
+ "integrity": "sha512-UJCIkTBenHeKT1TTlKMJWy1laZewsRIzYighyYiJKZreqtdxSos/S1t+ktRMQWu2CKqaarrkeszJx1cgC5tGZw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@vitest/spy": "2.1.9",
+ "@vitest/utils": "2.1.9",
+ "chai": "^5.1.2",
+ "tinyrainbow": "^1.2.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/vitest"
+ }
+ },
+ "node_modules/@vitest/mocker": {
+ "version": "2.1.9",
+ "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-2.1.9.tgz",
+ "integrity": "sha512-tVL6uJgoUdi6icpxmdrn5YNo3g3Dxv+IHJBr0GXHaEdTcw3F+cPKnsXFhli6nO+f/6SDKPHEK1UN+k+TQv0Ehg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@vitest/spy": "2.1.9",
+ "estree-walker": "^3.0.3",
+ "magic-string": "^0.30.12"
+ },
+ "funding": {
+ "url": "https://opencollective.com/vitest"
+ },
+ "peerDependencies": {
+ "msw": "^2.4.9",
+ "vite": "^5.0.0"
+ },
+ "peerDependenciesMeta": {
+ "msw": {
+ "optional": true
+ },
+ "vite": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@vitest/pretty-format": {
+ "version": "2.1.9",
+ "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-2.1.9.tgz",
+ "integrity": "sha512-KhRIdGV2U9HOUzxfiHmY8IFHTdqtOhIzCpd8WRdJiE7D/HUcZVD0EgQCVjm+Q9gkUXWgBvMmTtZgIG48wq7sOQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "tinyrainbow": "^1.2.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/vitest"
+ }
+ },
+ "node_modules/@vitest/runner": {
+ "version": "2.1.9",
+ "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-2.1.9.tgz",
+ "integrity": "sha512-ZXSSqTFIrzduD63btIfEyOmNcBmQvgOVsPNPe0jYtESiXkhd8u2erDLnMxmGrDCwHCCHE7hxwRDCT3pt0esT4g==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@vitest/utils": "2.1.9",
+ "pathe": "^1.1.2"
+ },
+ "funding": {
+ "url": "https://opencollective.com/vitest"
+ }
+ },
+ "node_modules/@vitest/snapshot": {
+ "version": "2.1.9",
+ "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-2.1.9.tgz",
+ "integrity": "sha512-oBO82rEjsxLNJincVhLhaxxZdEtV0EFHMK5Kmx5sJ6H9L183dHECjiefOAdnqpIgT5eZwT04PoggUnW88vOBNQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@vitest/pretty-format": "2.1.9",
+ "magic-string": "^0.30.12",
+ "pathe": "^1.1.2"
+ },
+ "funding": {
+ "url": "https://opencollective.com/vitest"
+ }
+ },
+ "node_modules/@vitest/spy": {
+ "version": "2.1.9",
+ "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-2.1.9.tgz",
+ "integrity": "sha512-E1B35FwzXXTs9FHNK6bDszs7mtydNi5MIfUWpceJ8Xbfb1gBMscAnwLbEu+B44ed6W3XjL9/ehLPHR1fkf1KLQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "tinyspy": "^3.0.2"
+ },
+ "funding": {
+ "url": "https://opencollective.com/vitest"
+ }
+ },
+ "node_modules/@vitest/utils": {
+ "version": "2.1.9",
+ "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-2.1.9.tgz",
+ "integrity": "sha512-v0psaMSkNJ3A2NMrUEHFRzJtDPFn+/VWZ5WxImB21T9fjucJRmS7xCS3ppEnARb9y11OAzaD+P2Ps+b+BGX5iQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@vitest/pretty-format": "2.1.9",
+ "loupe": "^3.1.2",
+ "tinyrainbow": "^1.2.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/vitest"
+ }
+ },
+ "node_modules/assertion-error": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-2.0.1.tgz",
+ "integrity": "sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/baseline-browser-mapping": {
+ "version": "2.10.41",
+ "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.10.41.tgz",
+ "integrity": "sha512-WwS7MHhqGHHlaVsqRZnhvCEMS0owDX+SxRlve7JkuH7My1Ara3ZriTmCQupPfYjxMZ8I/tgxtJYr2t7taHaH4A==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "bin": {
+ "baseline-browser-mapping": "dist/cli.cjs"
+ },
+ "engines": {
+ "node": ">=6.0.0"
+ }
+ },
+ "node_modules/browserslist": {
+ "version": "4.28.4",
+ "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.4.tgz",
+ "integrity": "sha512-MTc8i/x9jBQd1iMw2CFGS+rwMa07eYjLR0CCTLDACl9xhxy+nIs3KeML/biicXtk9JrZ6dnnTatmc7ErPXIxqw==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "opencollective",
+ "url": "https://opencollective.com/browserslist"
+ },
+ {
+ "type": "tidelift",
+ "url": "https://tidelift.com/funding/github/npm/browserslist"
+ },
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/ai"
+ }
+ ],
+ "license": "MIT",
+ "dependencies": {
+ "baseline-browser-mapping": "^2.10.38",
+ "caniuse-lite": "^1.0.30001799",
+ "electron-to-chromium": "^1.5.376",
+ "node-releases": "^2.0.48",
+ "update-browserslist-db": "^1.2.3"
+ },
+ "bin": {
+ "browserslist": "cli.js"
+ },
+ "engines": {
+ "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7"
+ }
+ },
+ "node_modules/cac": {
+ "version": "6.7.14",
+ "resolved": "https://registry.npmjs.org/cac/-/cac-6.7.14.tgz",
+ "integrity": "sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/caniuse-lite": {
+ "version": "1.0.30001800",
+ "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001800.tgz",
+ "integrity": "sha512-MMHtuAz9Ys840zAY5F4k6fV5GaivZ9sPk+nz0mY+GYVzRBnYkN0mpqkSR92oWRQ19yQWo4HvBV/FnC16AJX8MA==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "opencollective",
+ "url": "https://opencollective.com/browserslist"
+ },
+ {
+ "type": "tidelift",
+ "url": "https://tidelift.com/funding/github/npm/caniuse-lite"
+ },
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/ai"
+ }
+ ],
+ "license": "CC-BY-4.0"
+ },
+ "node_modules/chai": {
+ "version": "5.3.3",
+ "resolved": "https://registry.npmjs.org/chai/-/chai-5.3.3.tgz",
+ "integrity": "sha512-4zNhdJD/iOjSH0A05ea+Ke6MU5mmpQcbQsSOkgdaUMJ9zTlDTD/GYlwohmIE2u0gaxHYiVHEn1Fw9mZ/ktJWgw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "assertion-error": "^2.0.1",
+ "check-error": "^2.1.1",
+ "deep-eql": "^5.0.1",
+ "loupe": "^3.1.0",
+ "pathval": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/check-error": {
+ "version": "2.1.3",
+ "resolved": "https://registry.npmjs.org/check-error/-/check-error-2.1.3.tgz",
+ "integrity": "sha512-PAJdDJusoxnwm1VwW07VWwUN1sl7smmC3OKggvndJFadxxDRyFJBX/ggnu/KE4kQAB7a3Dp8f/YXC1FlUprWmA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 16"
+ }
+ },
+ "node_modules/convert-source-map": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz",
+ "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/csstype": {
+ "version": "3.2.3",
+ "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz",
+ "integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/debug": {
+ "version": "4.4.3",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz",
+ "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "ms": "^2.1.3"
+ },
+ "engines": {
+ "node": ">=6.0"
+ },
+ "peerDependenciesMeta": {
+ "supports-color": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/deep-eql": {
+ "version": "5.0.2",
+ "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-5.0.2.tgz",
+ "integrity": "sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/electron-to-chromium": {
+ "version": "1.5.387",
+ "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.387.tgz",
+ "integrity": "sha512-TaxwufTFDufvPEoXdhwVrA3UdFWBeWGkYoJ1K8ldF1xe6gKfth6iRNS5lTQ5JPNOHdGQm8PT1QYKUqFLCiUefQ==",
+ "dev": true,
+ "license": "ISC"
+ },
+ "node_modules/es-module-lexer": {
+ "version": "1.7.0",
+ "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.7.0.tgz",
+ "integrity": "sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/esbuild": {
+ "version": "0.21.5",
+ "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.21.5.tgz",
+ "integrity": "sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==",
+ "dev": true,
+ "hasInstallScript": true,
+ "license": "MIT",
+ "bin": {
+ "esbuild": "bin/esbuild"
+ },
+ "engines": {
+ "node": ">=12"
+ },
+ "optionalDependencies": {
+ "@esbuild/aix-ppc64": "0.21.5",
+ "@esbuild/android-arm": "0.21.5",
+ "@esbuild/android-arm64": "0.21.5",
+ "@esbuild/android-x64": "0.21.5",
+ "@esbuild/darwin-arm64": "0.21.5",
+ "@esbuild/darwin-x64": "0.21.5",
+ "@esbuild/freebsd-arm64": "0.21.5",
+ "@esbuild/freebsd-x64": "0.21.5",
+ "@esbuild/linux-arm": "0.21.5",
+ "@esbuild/linux-arm64": "0.21.5",
+ "@esbuild/linux-ia32": "0.21.5",
+ "@esbuild/linux-loong64": "0.21.5",
+ "@esbuild/linux-mips64el": "0.21.5",
+ "@esbuild/linux-ppc64": "0.21.5",
+ "@esbuild/linux-riscv64": "0.21.5",
+ "@esbuild/linux-s390x": "0.21.5",
+ "@esbuild/linux-x64": "0.21.5",
+ "@esbuild/netbsd-x64": "0.21.5",
+ "@esbuild/openbsd-x64": "0.21.5",
+ "@esbuild/sunos-x64": "0.21.5",
+ "@esbuild/win32-arm64": "0.21.5",
+ "@esbuild/win32-ia32": "0.21.5",
+ "@esbuild/win32-x64": "0.21.5"
+ }
+ },
+ "node_modules/escalade": {
+ "version": "3.2.0",
+ "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz",
+ "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/estree-walker": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz",
+ "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@types/estree": "^1.0.0"
+ }
+ },
+ "node_modules/expect-type": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/expect-type/-/expect-type-1.4.0.tgz",
+ "integrity": "sha512-KfYbmpRm0VbLjEvVa9yGwCi9GI34xvi7A/HXYWQO65CSD2u3MczUJSuwXKFIxlGsgBQizV9q5J9NHj4VG0n+pA==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "engines": {
+ "node": ">=12.0.0"
+ }
+ },
+ "node_modules/fsevents": {
+ "version": "2.3.3",
+ "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
+ "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==",
+ "dev": true,
+ "hasInstallScript": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": "^8.16.0 || ^10.6.0 || >=11.0.0"
+ }
+ },
+ "node_modules/gensync": {
+ "version": "1.0.0-beta.2",
+ "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz",
+ "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/js-tokens": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
+ "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==",
+ "license": "MIT"
+ },
+ "node_modules/jsesc": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz",
+ "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==",
+ "dev": true,
+ "license": "MIT",
+ "bin": {
+ "jsesc": "bin/jsesc"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/json5": {
+ "version": "2.2.3",
+ "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz",
+ "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==",
+ "dev": true,
+ "license": "MIT",
+ "bin": {
+ "json5": "lib/cli.js"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/loose-envify": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz",
+ "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==",
+ "license": "MIT",
+ "dependencies": {
+ "js-tokens": "^3.0.0 || ^4.0.0"
+ },
+ "bin": {
+ "loose-envify": "cli.js"
+ }
+ },
+ "node_modules/loupe": {
+ "version": "3.2.1",
+ "resolved": "https://registry.npmjs.org/loupe/-/loupe-3.2.1.tgz",
+ "integrity": "sha512-CdzqowRJCeLU72bHvWqwRBBlLcMEtIvGrlvef74kMnV2AolS9Y8xUv1I0U/MNAWMhBlKIoyuEgoJ0t/bbwHbLQ==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/lru-cache": {
+ "version": "5.1.1",
+ "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz",
+ "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "yallist": "^3.0.2"
+ }
+ },
+ "node_modules/magic-string": {
+ "version": "0.30.21",
+ "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz",
+ "integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@jridgewell/sourcemap-codec": "^1.5.5"
+ }
+ },
+ "node_modules/ms": {
+ "version": "2.1.3",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
+ "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/nanoid": {
+ "version": "3.3.15",
+ "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.15.tgz",
+ "integrity": "sha512-y7Wygv/7mEOvxTuEQDB8StXdMRBWf1kR/tlhAzBRUFkB2jfcLOAxO/SHmOO2zgz1pVgK29/kyupn059/bCHdjA==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/ai"
+ }
+ ],
+ "license": "MIT",
+ "bin": {
+ "nanoid": "bin/nanoid.cjs"
+ },
+ "engines": {
+ "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1"
+ }
+ },
+ "node_modules/node-releases": {
+ "version": "2.0.50",
+ "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.50.tgz",
+ "integrity": "sha512-J6l92tKHX6w8Jy5nO1Vuc01NoIiRGi/d6qBKVxh+IQ8Cr3b6HbVNfKiF8ZpFKufTwpwxMmce2W3iQZ861ZRyTg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/pathe": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/pathe/-/pathe-1.1.2.tgz",
+ "integrity": "sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/pathval": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/pathval/-/pathval-2.0.1.tgz",
+ "integrity": "sha512-//nshmD55c46FuFw26xV/xFAaB5HF9Xdap7HJBBnrKdAd6/GxDBaNA1870O79+9ueg61cZLSVc+OaFlfmObYVQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 14.16"
+ }
+ },
+ "node_modules/picocolors": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz",
+ "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==",
+ "dev": true,
+ "license": "ISC"
+ },
+ "node_modules/postcss": {
+ "version": "8.5.16",
+ "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.16.tgz",
+ "integrity": "sha512-vuwillviilfKZsg0VGj5R/YwwcHx4SLsIOI/7K6mQkWx+l5cUHTjj5g0AasTBcyXsbfTgrwsUNmVUb5xVwyPwg==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "opencollective",
+ "url": "https://opencollective.com/postcss/"
+ },
+ {
+ "type": "tidelift",
+ "url": "https://tidelift.com/funding/github/npm/postcss"
+ },
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/ai"
+ }
+ ],
+ "license": "MIT",
+ "dependencies": {
+ "nanoid": "^3.3.12",
+ "picocolors": "^1.1.1",
+ "source-map-js": "^1.2.1"
+ },
+ "engines": {
+ "node": "^10 || ^12 || >=14"
+ }
+ },
+ "node_modules/react": {
+ "version": "18.3.1",
+ "resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz",
+ "integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==",
+ "license": "MIT",
+ "dependencies": {
+ "loose-envify": "^1.1.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/react-dom": {
+ "version": "18.3.1",
+ "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz",
+ "integrity": "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==",
+ "license": "MIT",
+ "dependencies": {
+ "loose-envify": "^1.1.0",
+ "scheduler": "^0.23.2"
+ },
+ "peerDependencies": {
+ "react": "^18.3.1"
+ }
+ },
+ "node_modules/react-refresh": {
+ "version": "0.17.0",
+ "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.17.0.tgz",
+ "integrity": "sha512-z6F7K9bV85EfseRCp2bzrpyQ0Gkw1uLoCel9XBVWPg/TjRj94SkJzUTGfOa4bs7iJvBWtQG0Wq7wnI0syw3EBQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/rollup": {
+ "version": "4.62.2",
+ "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.62.2.tgz",
+ "integrity": "sha512-RFnrW4lhXA3s3eqHDZvN654g8OTjzRfqpIRJYczCGB6HzphckVAi/Qh4tbPUbRuDi7s1Llv8g/NspLkttY3gTA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@types/estree": "1.0.9"
+ },
+ "bin": {
+ "rollup": "dist/bin/rollup"
+ },
+ "engines": {
+ "node": ">=18.0.0",
+ "npm": ">=8.0.0"
+ },
+ "optionalDependencies": {
+ "@rollup/rollup-android-arm-eabi": "4.62.2",
+ "@rollup/rollup-android-arm64": "4.62.2",
+ "@rollup/rollup-darwin-arm64": "4.62.2",
+ "@rollup/rollup-darwin-x64": "4.62.2",
+ "@rollup/rollup-freebsd-arm64": "4.62.2",
+ "@rollup/rollup-freebsd-x64": "4.62.2",
+ "@rollup/rollup-linux-arm-gnueabihf": "4.62.2",
+ "@rollup/rollup-linux-arm-musleabihf": "4.62.2",
+ "@rollup/rollup-linux-arm64-gnu": "4.62.2",
+ "@rollup/rollup-linux-arm64-musl": "4.62.2",
+ "@rollup/rollup-linux-loong64-gnu": "4.62.2",
+ "@rollup/rollup-linux-loong64-musl": "4.62.2",
+ "@rollup/rollup-linux-ppc64-gnu": "4.62.2",
+ "@rollup/rollup-linux-ppc64-musl": "4.62.2",
+ "@rollup/rollup-linux-riscv64-gnu": "4.62.2",
+ "@rollup/rollup-linux-riscv64-musl": "4.62.2",
+ "@rollup/rollup-linux-s390x-gnu": "4.62.2",
+ "@rollup/rollup-linux-x64-gnu": "4.62.2",
+ "@rollup/rollup-linux-x64-musl": "4.62.2",
+ "@rollup/rollup-openbsd-x64": "4.62.2",
+ "@rollup/rollup-openharmony-arm64": "4.62.2",
+ "@rollup/rollup-win32-arm64-msvc": "4.62.2",
+ "@rollup/rollup-win32-ia32-msvc": "4.62.2",
+ "@rollup/rollup-win32-x64-gnu": "4.62.2",
+ "@rollup/rollup-win32-x64-msvc": "4.62.2",
+ "fsevents": "~2.3.2"
+ }
+ },
+ "node_modules/scheduler": {
+ "version": "0.23.2",
+ "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.2.tgz",
+ "integrity": "sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==",
+ "license": "MIT",
+ "dependencies": {
+ "loose-envify": "^1.1.0"
+ }
+ },
+ "node_modules/semver": {
+ "version": "6.3.1",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
+ "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
+ "dev": true,
+ "license": "ISC",
+ "bin": {
+ "semver": "bin/semver.js"
+ }
+ },
+ "node_modules/siginfo": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/siginfo/-/siginfo-2.0.0.tgz",
+ "integrity": "sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==",
+ "dev": true,
+ "license": "ISC"
+ },
+ "node_modules/source-map-js": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz",
+ "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==",
+ "dev": true,
+ "license": "BSD-3-Clause",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/stackback": {
+ "version": "0.0.2",
+ "resolved": "https://registry.npmjs.org/stackback/-/stackback-0.0.2.tgz",
+ "integrity": "sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/std-env": {
+ "version": "3.10.0",
+ "resolved": "https://registry.npmjs.org/std-env/-/std-env-3.10.0.tgz",
+ "integrity": "sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/tinybench": {
+ "version": "2.9.0",
+ "resolved": "https://registry.npmjs.org/tinybench/-/tinybench-2.9.0.tgz",
+ "integrity": "sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/tinyexec": {
+ "version": "0.3.2",
+ "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-0.3.2.tgz",
+ "integrity": "sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/tinypool": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/tinypool/-/tinypool-1.1.1.tgz",
+ "integrity": "sha512-Zba82s87IFq9A9XmjiX5uZA/ARWDrB03OHlq+Vw1fSdt0I+4/Kutwy8BP4Y/y/aORMo61FQ0vIb5j44vSo5Pkg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": "^18.0.0 || >=20.0.0"
+ }
+ },
+ "node_modules/tinyrainbow": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/tinyrainbow/-/tinyrainbow-1.2.0.tgz",
+ "integrity": "sha512-weEDEq7Z5eTHPDh4xjX789+fHfF+P8boiFB+0vbWzpbnbsEr/GRaohi/uMKxg8RZMXnl1ItAi/IUHWMsjDV7kQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=14.0.0"
+ }
+ },
+ "node_modules/tinyspy": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/tinyspy/-/tinyspy-3.0.2.tgz",
+ "integrity": "sha512-n1cw8k1k0x4pgA2+9XrOkFydTerNcJ1zWCO5Nn9scWHTD+5tp8dghT2x1uduQePZTZgd3Tupf+x9BxJjeJi77Q==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=14.0.0"
+ }
+ },
+ "node_modules/typescript": {
+ "version": "5.9.3",
+ "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz",
+ "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "bin": {
+ "tsc": "bin/tsc",
+ "tsserver": "bin/tsserver"
+ },
+ "engines": {
+ "node": ">=14.17"
+ }
+ },
+ "node_modules/update-browserslist-db": {
+ "version": "1.2.3",
+ "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.2.3.tgz",
+ "integrity": "sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "opencollective",
+ "url": "https://opencollective.com/browserslist"
+ },
+ {
+ "type": "tidelift",
+ "url": "https://tidelift.com/funding/github/npm/browserslist"
+ },
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/ai"
+ }
+ ],
+ "license": "MIT",
+ "dependencies": {
+ "escalade": "^3.2.0",
+ "picocolors": "^1.1.1"
+ },
+ "bin": {
+ "update-browserslist-db": "cli.js"
+ },
+ "peerDependencies": {
+ "browserslist": ">= 4.21.0"
+ }
+ },
+ "node_modules/vite": {
+ "version": "5.4.21",
+ "resolved": "https://registry.npmjs.org/vite/-/vite-5.4.21.tgz",
+ "integrity": "sha512-o5a9xKjbtuhY6Bi5S3+HvbRERmouabWbyUcpXXUA1u+GNUKoROi9byOJ8M0nHbHYHkYICiMlqxkg1KkYmm25Sw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "esbuild": "^0.21.3",
+ "postcss": "^8.4.43",
+ "rollup": "^4.20.0"
+ },
+ "bin": {
+ "vite": "bin/vite.js"
+ },
+ "engines": {
+ "node": "^18.0.0 || >=20.0.0"
+ },
+ "funding": {
+ "url": "https://github.com/vitejs/vite?sponsor=1"
+ },
+ "optionalDependencies": {
+ "fsevents": "~2.3.3"
+ },
+ "peerDependencies": {
+ "@types/node": "^18.0.0 || >=20.0.0",
+ "less": "*",
+ "lightningcss": "^1.21.0",
+ "sass": "*",
+ "sass-embedded": "*",
+ "stylus": "*",
+ "sugarss": "*",
+ "terser": "^5.4.0"
+ },
+ "peerDependenciesMeta": {
+ "@types/node": {
+ "optional": true
+ },
+ "less": {
+ "optional": true
+ },
+ "lightningcss": {
+ "optional": true
+ },
+ "sass": {
+ "optional": true
+ },
+ "sass-embedded": {
+ "optional": true
+ },
+ "stylus": {
+ "optional": true
+ },
+ "sugarss": {
+ "optional": true
+ },
+ "terser": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/vite-node": {
+ "version": "2.1.9",
+ "resolved": "https://registry.npmjs.org/vite-node/-/vite-node-2.1.9.tgz",
+ "integrity": "sha512-AM9aQ/IPrW/6ENLQg3AGY4K1N2TGZdR5e4gu/MmmR2xR3Ll1+dib+nook92g4TV3PXVyeyxdWwtaCAiUL0hMxA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "cac": "^6.7.14",
+ "debug": "^4.3.7",
+ "es-module-lexer": "^1.5.4",
+ "pathe": "^1.1.2",
+ "vite": "^5.0.0"
+ },
+ "bin": {
+ "vite-node": "vite-node.mjs"
+ },
+ "engines": {
+ "node": "^18.0.0 || >=20.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/vitest"
+ }
+ },
+ "node_modules/vitest": {
+ "version": "2.1.9",
+ "resolved": "https://registry.npmjs.org/vitest/-/vitest-2.1.9.tgz",
+ "integrity": "sha512-MSmPM9REYqDGBI8439mA4mWhV5sKmDlBKWIYbA3lRb2PTHACE0mgKwA8yQ2xq9vxDTuk4iPrECBAEW2aoFXY0Q==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@vitest/expect": "2.1.9",
+ "@vitest/mocker": "2.1.9",
+ "@vitest/pretty-format": "^2.1.9",
+ "@vitest/runner": "2.1.9",
+ "@vitest/snapshot": "2.1.9",
+ "@vitest/spy": "2.1.9",
+ "@vitest/utils": "2.1.9",
+ "chai": "^5.1.2",
+ "debug": "^4.3.7",
+ "expect-type": "^1.1.0",
+ "magic-string": "^0.30.12",
+ "pathe": "^1.1.2",
+ "std-env": "^3.8.0",
+ "tinybench": "^2.9.0",
+ "tinyexec": "^0.3.1",
+ "tinypool": "^1.0.1",
+ "tinyrainbow": "^1.2.0",
+ "vite": "^5.0.0",
+ "vite-node": "2.1.9",
+ "why-is-node-running": "^2.3.0"
+ },
+ "bin": {
+ "vitest": "vitest.mjs"
+ },
+ "engines": {
+ "node": "^18.0.0 || >=20.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/vitest"
+ },
+ "peerDependencies": {
+ "@edge-runtime/vm": "*",
+ "@types/node": "^18.0.0 || >=20.0.0",
+ "@vitest/browser": "2.1.9",
+ "@vitest/ui": "2.1.9",
+ "happy-dom": "*",
+ "jsdom": "*"
+ },
+ "peerDependenciesMeta": {
+ "@edge-runtime/vm": {
+ "optional": true
+ },
+ "@types/node": {
+ "optional": true
+ },
+ "@vitest/browser": {
+ "optional": true
+ },
+ "@vitest/ui": {
+ "optional": true
+ },
+ "happy-dom": {
+ "optional": true
+ },
+ "jsdom": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/why-is-node-running": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/why-is-node-running/-/why-is-node-running-2.3.0.tgz",
+ "integrity": "sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "siginfo": "^2.0.0",
+ "stackback": "0.0.2"
+ },
+ "bin": {
+ "why-is-node-running": "cli.js"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/yallist": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz",
+ "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==",
+ "dev": true,
+ "license": "ISC"
+ }
+ }
+}
diff --git a/ai-act-kompass/package.json b/ai-act-kompass/package.json
new file mode 100644
index 0000000..ffd867e
--- /dev/null
+++ b/ai-act-kompass/package.json
@@ -0,0 +1,27 @@
+{
+ "name": "@shieldx/ai-act-kompass",
+ "version": "0.1.0",
+ "private": true,
+ "description": "AI-Act-Kompass â Standalone EU AI Act Compliance-Toolkit fĂŒr KMU. Local-first, keine Cloud, keine DatenĂŒbertragung.",
+ "type": "module",
+ "scripts": {
+ "dev": "vite",
+ "build": "tsc -b && vite build",
+ "preview": "vite preview",
+ "test": "vitest run",
+ "test:watch": "vitest",
+ "typecheck": "tsc --noEmit"
+ },
+ "dependencies": {
+ "react": "^18.3.1",
+ "react-dom": "^18.3.1"
+ },
+ "devDependencies": {
+ "@types/react": "^18.3.12",
+ "@types/react-dom": "^18.3.1",
+ "@vitejs/plugin-react": "^4.3.4",
+ "typescript": "^5.6.3",
+ "vite": "^5.4.11",
+ "vitest": "^2.1.8"
+ }
+}
diff --git a/ai-act-kompass/src/content/pack.ts b/ai-act-kompass/src/content/pack.ts
new file mode 100644
index 0000000..b3d5cf9
--- /dev/null
+++ b/ai-act-kompass/src/content/pack.ts
@@ -0,0 +1,389 @@
+import type { ContentPack } from '../engine/types';
+
+/**
+ * Regulatorischer Content-Pack v2026.07.
+ *
+ * Kodifiziert den Stand der Verordnung (EU) 2024/1689 (AI Act) inkl. der
+ * durch das Digital-Omnibus-Paket verschobenen Annex-III-Fristen.
+ * Dieser Pack ist bewusst als Daten (nicht Code) modelliert, damit er
+ * spĂ€ter ĂŒber einen signierten Update-Feed ausgetauscht werden kann.
+ *
+ * WICHTIG: Inhalte sind eine strukturierte Arbeitshilfe, keine Rechtsberatung.
+ */
+export const CONTENT_PACK: ContentPack = {
+ version: '2026.07.0',
+ releasedAt: '2026-07-04',
+ legalBasis: 'Verordnung (EU) 2024/1689 (AI Act), Stand Juli 2026',
+
+ aiDefinitionCriteria: [
+ {
+ id: 'def-autonomy',
+ label: 'Das System arbeitet mit einem gewissen Grad an Autonomie (nicht rein regelbasiert deterministisch durch den Nutzer gesteuert).',
+ legalRef: 'Art. 3 Nr. 1',
+ },
+ {
+ id: 'def-inference',
+ label: 'Das System leitet aus Eingaben ab, wie Ausgaben (Vorhersagen, Inhalte, Empfehlungen, Entscheidungen) erzeugt werden.',
+ legalRef: 'Art. 3 Nr. 1',
+ },
+ {
+ id: 'def-influence',
+ label: 'Die Ausgaben können physische oder virtuelle Umgebungen beeinflussen.',
+ legalRef: 'Art. 3 Nr. 1',
+ },
+ ],
+
+ prohibitedPractices: [
+ {
+ id: 'proh-manipulation',
+ label: 'Unterschwellige oder gezielt manipulative Techniken, die Verhalten wesentlich verÀndern und erheblichen Schaden verursachen (können).',
+ legalRef: 'Art. 5 Abs. 1 lit. a',
+ },
+ {
+ id: 'proh-vulnerability',
+ label: 'Ausnutzung von SchwÀchen aufgrund von Alter, Behinderung oder sozialer/wirtschaftlicher Lage mit erheblichem Schadensrisiko.',
+ legalRef: 'Art. 5 Abs. 1 lit. b',
+ },
+ {
+ id: 'proh-social-scoring',
+ label: 'Social Scoring: Bewertung von Personen anhand ihres Sozialverhaltens mit ungerechtfertigter Schlechterstellung.',
+ legalRef: 'Art. 5 Abs. 1 lit. c',
+ },
+ {
+ id: 'proh-predictive-policing',
+ label: 'Risikobewertung von Straftaten allein auf Basis von Profiling oder Persönlichkeitsmerkmalen.',
+ legalRef: 'Art. 5 Abs. 1 lit. d',
+ },
+ {
+ id: 'proh-face-scraping',
+ label: 'Ungezieltes Auslesen (Scraping) von Gesichtsbildern aus Internet oder Ăberwachungskameras zum Aufbau von Gesichtsdatenbanken.',
+ legalRef: 'Art. 5 Abs. 1 lit. e',
+ },
+ {
+ id: 'proh-emotion-workplace',
+ label: 'Emotionserkennung am Arbeitsplatz oder in Bildungseinrichtungen (auĂer aus medizinischen oder SicherheitsgrĂŒnden).',
+ legalRef: 'Art. 5 Abs. 1 lit. f',
+ },
+ {
+ id: 'proh-biometric-categorisation',
+ label: 'Biometrische Kategorisierung zur Ableitung sensibler Merkmale (z. B. Ethnie, politische Meinung, sexuelle Orientierung).',
+ legalRef: 'Art. 5 Abs. 1 lit. g',
+ },
+ {
+ id: 'proh-rbi',
+ label: 'Biometrische Echtzeit-Fernidentifizierung in öffentlich zugÀnglichen RÀumen zu Strafverfolgungszwecken (enge Ausnahmen).',
+ legalRef: 'Art. 5 Abs. 1 lit. h',
+ },
+ ],
+
+ annexIIICategories: [
+ {
+ id: 'a3-biometrics',
+ label: 'Biometrie: Fernidentifizierung, biometrische Kategorisierung, Emotionserkennung (soweit nicht verboten).',
+ legalRef: 'Annex III Nr. 1',
+ },
+ {
+ id: 'a3-critical-infra',
+ label: 'Sicherheitskomponenten kritischer Infrastruktur (Verkehr, Wasser, Gas, WĂ€rme, Strom, digitale Infrastruktur).',
+ legalRef: 'Annex III Nr. 2',
+ },
+ {
+ id: 'a3-education',
+ label: 'Bildung: Zulassung, Bewertung von Lernergebnissen, PrĂŒfungsĂŒberwachung.',
+ legalRef: 'Annex III Nr. 3',
+ },
+ {
+ id: 'a3-employment',
+ label: 'BeschĂ€ftigung: Recruiting/Bewerberauswahl, Beförderung/KĂŒndigung, Aufgabenzuweisung, LeistungsĂŒberwachung.',
+ legalRef: 'Annex III Nr. 4',
+ hint: 'HĂ€ufigster KMU-Fall: KI-gestĂŒtztes Bewerber-Screening.',
+ },
+ {
+ id: 'a3-essential-services',
+ label: 'Wesentliche Dienste: KreditwĂŒrdigkeitsprĂŒfung, Risiko-Pricing bei Lebens-/Krankenversicherung, Notruf-Triage, Sozialleistungen.',
+ legalRef: 'Annex III Nr. 5',
+ },
+ {
+ id: 'a3-law-enforcement',
+ label: 'Strafverfolgung (Beweismittelbewertung, RĂŒckfallrisiko u. a.).',
+ legalRef: 'Annex III Nr. 6',
+ },
+ {
+ id: 'a3-migration',
+ label: 'Migration, Asyl, Grenzkontrolle.',
+ legalRef: 'Annex III Nr. 7',
+ },
+ {
+ id: 'a3-justice',
+ label: 'Rechtspflege und demokratische Prozesse (UnterstĂŒtzung richterlicher Entscheidungen, Wahlbeeinflussung).',
+ legalRef: 'Annex III Nr. 8',
+ },
+ ],
+
+ transparencyTriggers: [
+ {
+ id: 'tr-chatbot',
+ label: 'Das System interagiert direkt mit Menschen (z. B. Chatbot, Voicebot).',
+ legalRef: 'Art. 50 Abs. 1',
+ hint: 'Nutzer mĂŒssen erkennen können, dass sie mit KI interagieren.',
+ },
+ {
+ id: 'tr-synthetic-content',
+ label: 'Das System erzeugt synthetische Audio-, Bild-, Video- oder Textinhalte.',
+ legalRef: 'Art. 50 Abs. 2',
+ hint: 'Maschinenlesbare Kennzeichnung der Ausgaben erforderlich.',
+ },
+ {
+ id: 'tr-emotion',
+ label: 'Emotionserkennung oder biometrische Kategorisierung wird eingesetzt (soweit erlaubt).',
+ legalRef: 'Art. 50 Abs. 3',
+ },
+ {
+ id: 'tr-deepfake',
+ label: 'Das System erzeugt oder manipuliert Deepfakes (Bild/Audio/Video realer Personen, Orte oder Ereignisse).',
+ legalRef: 'Art. 50 Abs. 4',
+ },
+ ],
+
+ obligations: [
+ // ââ Alle Risikoklassen / alle Rollen ââââââââââââââââââââââââââââââ
+ {
+ id: 'ob-ai-literacy',
+ title: 'KI-Kompetenz des Personals sicherstellen',
+ articles: 'Art. 4',
+ description:
+ 'Mitarbeitende, die KI-Systeme betreiben oder nutzen, mĂŒssen ĂŒber ausreichende KI-Kompetenz verfĂŒgen (Schulungen, Richtlinien). Gilt seit 2. Februar 2025 fĂŒr alle Anbieter und Betreiber.',
+ deadline: '2025-02-02',
+ roles: ['provider', 'deployer', 'importer', 'distributor'],
+ riskClasses: ['high', 'limited', 'minimal'],
+ },
+ // ââ Hochrisiko: Anbieter ââââââââââââââââââââââââââââââââââââââââââ
+ {
+ id: 'ob-risk-mgmt',
+ title: 'Risikomanagementsystem einrichten',
+ articles: 'Art. 9',
+ description:
+ 'Kontinuierlicher, iterativer Risikomanagementprozess ĂŒber den gesamten Lebenszyklus: Risiken identifizieren, bewerten, mindern, testen.',
+ deadline: '2027-12-02',
+ roles: ['provider'],
+ riskClasses: ['high'],
+ },
+ {
+ id: 'ob-data-governance',
+ title: 'Daten-Governance fĂŒr Trainings-/Test-/Validierungsdaten',
+ articles: 'Art. 10',
+ description:
+ 'DatensĂ€tze mĂŒssen relevant, reprĂ€sentativ, möglichst fehlerfrei und vollstĂ€ndig sein; Bias-PrĂŒfung und geeignete Erhebungsverfahren dokumentieren.',
+ deadline: '2027-12-02',
+ roles: ['provider'],
+ riskClasses: ['high'],
+ },
+ {
+ id: 'ob-tech-doc',
+ title: 'Technische Dokumentation (Annex IV) erstellen',
+ articles: 'Art. 11, Annex IV',
+ description:
+ 'VollstĂ€ndige technische Dokumentation vor Inverkehrbringen; fĂŒr KMU gelten vereinfachte Formulare. Der Dokumenten-Generator dieses Tools erzeugt das GrundgerĂŒst.',
+ deadline: '2027-12-02',
+ roles: ['provider'],
+ riskClasses: ['high'],
+ },
+ {
+ id: 'ob-logging',
+ title: 'Protokollierung (Logging) technisch ermöglichen',
+ articles: 'Art. 12',
+ description:
+ 'Automatische Aufzeichnung von Ereignissen ĂŒber den Lebenszyklus, um RĂŒckverfolgbarkeit und MarktĂŒberwachung zu ermöglichen.',
+ deadline: '2027-12-02',
+ roles: ['provider'],
+ riskClasses: ['high'],
+ },
+ {
+ id: 'ob-transparency-instructions',
+ title: 'Betriebsanleitung und Transparenzinformationen bereitstellen',
+ articles: 'Art. 13',
+ description:
+ 'Klare Gebrauchsanweisung: Zweckbestimmung, Genauigkeit, Grenzen, menschliche Aufsicht, erwartete Lebensdauer und Wartung.',
+ deadline: '2027-12-02',
+ roles: ['provider'],
+ riskClasses: ['high'],
+ },
+ {
+ id: 'ob-human-oversight',
+ title: 'Menschliche Aufsicht konzipieren',
+ articles: 'Art. 14',
+ description:
+ 'Das System muss wirksam durch Menschen beaufsichtigt werden können (Eingriffs-/Abbruchmöglichkeiten, Automation-Bias-Vorkehrungen).',
+ deadline: '2027-12-02',
+ roles: ['provider'],
+ riskClasses: ['high'],
+ },
+ {
+ id: 'ob-accuracy-robustness',
+ title: 'Genauigkeit, Robustheit und Cybersicherheit gewÀhrleisten',
+ articles: 'Art. 15',
+ description:
+ 'Angemessenes Niveau an Genauigkeit und WiderstandsfÀhigkeit, inkl. Schutz gegen KI-spezifische Angriffe (Data Poisoning, Adversarial Examples, Prompt Injection).',
+ deadline: '2027-12-02',
+ roles: ['provider'],
+ riskClasses: ['high'],
+ },
+ {
+ id: 'ob-qms',
+ title: 'QualitĂ€tsmanagementsystem einfĂŒhren',
+ articles: 'Art. 17',
+ description:
+ 'Dokumentiertes QMS: Compliance-Strategie, PrĂŒfverfahren, Datenmanagement, Risikomanagement, Meldeverfahren, Verantwortlichkeiten.',
+ deadline: '2027-12-02',
+ roles: ['provider'],
+ riskClasses: ['high'],
+ },
+ {
+ id: 'ob-conformity',
+ title: 'KonformitĂ€tsbewertung durchfĂŒhren, CE-Kennzeichnung, EU-Datenbank-Registrierung',
+ articles: 'Art. 43, 48, 49',
+ description:
+ 'KonformitĂ€tsbewertungsverfahren abschlieĂen, EU-KonformitĂ€tserklĂ€rung ausstellen, CE-Kennzeichnung anbringen und System in der EU-Datenbank registrieren.',
+ deadline: '2027-12-02',
+ roles: ['provider'],
+ riskClasses: ['high'],
+ },
+ // ââ Hochrisiko: Betreiber âââââââââââââââââââââââââââââââââââââââââ
+ {
+ id: 'ob-deployer-use',
+ title: 'Nutzung gemÀà Betriebsanleitung sicherstellen',
+ articles: 'Art. 26 Abs. 1',
+ description:
+ 'Technische und organisatorische MaĂnahmen, damit das System entsprechend der Gebrauchsanweisung des Anbieters genutzt wird.',
+ deadline: '2027-12-02',
+ roles: ['deployer'],
+ riskClasses: ['high'],
+ },
+ {
+ id: 'ob-deployer-oversight',
+ title: 'Kompetente menschliche Aufsicht zuweisen',
+ articles: 'Art. 26 Abs. 2',
+ description:
+ 'Aufsicht durch Personen mit erforderlicher Kompetenz, Ausbildung und Befugnis.',
+ deadline: '2027-12-02',
+ roles: ['deployer'],
+ riskClasses: ['high'],
+ },
+ {
+ id: 'ob-deployer-input',
+ title: 'Relevanz und ReprÀsentativitÀt der Eingabedaten sicherstellen',
+ articles: 'Art. 26 Abs. 4',
+ description:
+ 'Soweit der Betreiber die Eingabedaten kontrolliert, mĂŒssen diese fĂŒr die Zweckbestimmung relevant und hinreichend reprĂ€sentativ sein.',
+ deadline: '2027-12-02',
+ roles: ['deployer'],
+ riskClasses: ['high'],
+ },
+ {
+ id: 'ob-deployer-monitoring',
+ title: 'Betrieb ĂŒberwachen, VorfĂ€lle melden, Logs aufbewahren',
+ articles: 'Art. 26 Abs. 5â6',
+ description:
+ 'Betrieb anhand der Anleitung ĂŒberwachen; bei Risiken Anbieter/Behörden informieren; automatisch erzeugte Logs mind. 6 Monate aufbewahren.',
+ deadline: '2027-12-02',
+ roles: ['deployer'],
+ riskClasses: ['high'],
+ },
+ {
+ id: 'ob-deployer-workers',
+ title: 'BeschÀftigte vor Einsatz am Arbeitsplatz informieren',
+ articles: 'Art. 26 Abs. 7',
+ description:
+ 'Vor Inbetriebnahme eines Hochrisiko-Systems am Arbeitsplatz sind Arbeitnehmervertreter und betroffene BeschÀftigte zu informieren.',
+ deadline: '2027-12-02',
+ roles: ['deployer'],
+ riskClasses: ['high'],
+ },
+ {
+ id: 'ob-fria',
+ title: 'Grundrechte-FolgenabschĂ€tzung (FRIA) prĂŒfen',
+ articles: 'Art. 27',
+ description:
+ 'Pflicht fĂŒr öffentliche Stellen und private Anbieter öffentlicher Dienste sowie bestimmte Annex-III-FĂ€lle (z. B. KreditwĂŒrdigkeit, Versicherung): Folgen fĂŒr Grundrechte vor Einsatz bewerten.',
+ deadline: '2027-12-02',
+ roles: ['deployer'],
+ riskClasses: ['high'],
+ },
+ // ââ Importeur / HĂ€ndler âââââââââââââââââââââââââââââââââââââââââââ
+ {
+ id: 'ob-importer-verify',
+ title: 'KonformitĂ€t vor Inverkehrbringen prĂŒfen',
+ articles: 'Art. 23',
+ description:
+ 'Importeure mĂŒssen prĂŒfen: KonformitĂ€tsbewertung durchgefĂŒhrt, technische Dokumentation vorhanden, CE-Kennzeichnung und Ansprechpartner benannt.',
+ deadline: '2027-12-02',
+ roles: ['importer'],
+ riskClasses: ['high'],
+ },
+ {
+ id: 'ob-distributor-verify',
+ title: 'Sorgfaltspflichten der Vertriebskette erfĂŒllen',
+ articles: 'Art. 24',
+ description:
+ 'HĂ€ndler prĂŒfen CE-Kennzeichnung, KonformitĂ€tserklĂ€rung und Gebrauchsanweisung; bei Zweifeln keine Bereitstellung.',
+ deadline: '2027-12-02',
+ roles: ['distributor'],
+ riskClasses: ['high'],
+ },
+ // ââ Transparenzpflichten (limited) ââââââââââââââââââââââââââââââââ
+ {
+ id: 'ob-transparency-art50',
+ title: 'Transparenzpflichten nach Art. 50 umsetzen',
+ articles: 'Art. 50',
+ description:
+ 'Je nach Auslöser: KI-Interaktion offenlegen (Chatbots), synthetische Inhalte maschinenlesbar kennzeichnen, Deepfakes sichtbar kennzeichnen, ĂŒber Emotionserkennung informieren.',
+ deadline: '2026-08-02',
+ roles: ['provider', 'deployer'],
+ riskClasses: ['high', 'limited'],
+ },
+ // ââ GPAI ââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ
+ {
+ id: 'ob-gpai',
+ title: 'GPAI-Modellpflichten erfĂŒllen',
+ articles: 'Art. 53â55',
+ description:
+ 'FĂŒr Anbieter von GPAI-Modellen: technische Modell-Dokumentation, Informationen fĂŒr nachgelagerte Anbieter, Urheberrechts-Policy, Zusammenfassung der Trainingsdaten. Bei systemischem Risiko zusĂ€tzlich Evaluierungen und Incident-Meldungen.',
+ deadline: '2025-08-02',
+ roles: ['provider'],
+ riskClasses: ['high', 'limited', 'minimal'],
+ },
+ ],
+
+ deadlines: [
+ {
+ id: 'dl-prohibitions',
+ date: '2025-02-02',
+ label: 'Verbote & KI-Kompetenz',
+ description: 'Verbotene Praktiken (Art. 5) und KI-Kompetenzpflicht (Art. 4) gelten. Bereits in Kraft.',
+ },
+ {
+ id: 'dl-gpai',
+ date: '2025-08-02',
+ label: 'GPAI-Pflichten',
+ description: 'Pflichten fĂŒr Anbieter von GPAI-Modellen (Art. 53 ff.) gelten. Bereits in Kraft.',
+ },
+ {
+ id: 'dl-general',
+ date: '2026-08-02',
+ label: 'Allgemeine Geltung',
+ description: 'Transparenzpflichten (Art. 50), Sanktionsregime und Governance-Struktur gelten.',
+ },
+ {
+ id: 'dl-annex3',
+ date: '2027-12-02',
+ label: 'Hochrisiko (Annex III)',
+ description: 'Pflichten fĂŒr Annex-III-Hochrisiko-Systeme gelten (durch Digital Omnibus von Aug 2026 verschoben).',
+ },
+ {
+ id: 'dl-annex1',
+ date: '2028-08-02',
+ label: 'Hochrisiko (Annex I)',
+ description: 'Pflichten fĂŒr KI als Sicherheitsbauteil regulierter Produkte (Annex I) gelten.',
+ },
+ ],
+};
diff --git a/ai-act-kompass/src/engine/classify.test.ts b/ai-act-kompass/src/engine/classify.test.ts
new file mode 100644
index 0000000..57e2ea0
--- /dev/null
+++ b/ai-act-kompass/src/engine/classify.test.ts
@@ -0,0 +1,111 @@
+import { describe, expect, it } from 'vitest';
+import { CONTENT_PACK } from '../content/pack';
+import { classify } from './classify';
+import type { AssessmentAnswers } from './types';
+
+const base: AssessmentAnswers = {
+ isAISystem: true,
+ role: 'deployer',
+ isGPAIModel: false,
+ prohibitedPractices: [],
+ annexIIICategories: [],
+ art63Exception: false,
+ involvesProfiling: false,
+ isAnnexISafetyComponent: false,
+ transparencyTriggers: [],
+};
+
+describe('classify', () => {
+ it('stuft Nicht-KI-Systeme als out-of-scope ein', () => {
+ const result = classify({ ...base, isAISystem: false }, CONTENT_PACK);
+ expect(result.riskClass).toBe('out-of-scope');
+ expect(result.transparencyDuties).toBe(false);
+ });
+
+ it('stuft verbotene Praktiken als prohibited ein â vor allen anderen PrĂŒfungen', () => {
+ const result = classify(
+ {
+ ...base,
+ prohibitedPractices: ['proh-social-scoring'],
+ annexIIICategories: ['a3-employment'],
+ transparencyTriggers: ['tr-chatbot'],
+ },
+ CONTENT_PACK,
+ );
+ expect(result.riskClass).toBe('prohibited');
+ expect(result.reasons[0]).toContain('Art. 5');
+ });
+
+ it('stuft Annex-I-Sicherheitsbauteile als high ein', () => {
+ const result = classify({ ...base, isAnnexISafetyComponent: true }, CONTENT_PACK);
+ expect(result.riskClass).toBe('high');
+ });
+
+ it('stuft Annex-III-Bereiche als high ein', () => {
+ const result = classify({ ...base, annexIIICategories: ['a3-employment'] }, CONTENT_PACK);
+ expect(result.riskClass).toBe('high');
+ expect(result.reasons.some((r) => r.includes('Annex III'))).toBe(true);
+ });
+
+ it('lÀsst die Art.-6(3)-Ausnahme greifen, wenn kein Profiling vorliegt', () => {
+ const result = classify(
+ { ...base, annexIIICategories: ['a3-employment'], art63Exception: true },
+ CONTENT_PACK,
+ );
+ expect(result.riskClass).toBe('minimal');
+ expect(result.art64DocumentationDuty).toBe(true);
+ });
+
+ it('schlieĂt die Art.-6(3)-Ausnahme bei Profiling aus', () => {
+ const result = classify(
+ {
+ ...base,
+ annexIIICategories: ['a3-employment'],
+ art63Exception: true,
+ involvesProfiling: true,
+ },
+ CONTENT_PACK,
+ );
+ expect(result.riskClass).toBe('high');
+ });
+
+ it('kombiniert Art.-6(3)-Ausnahme mit Transparenzpflichten zu limited', () => {
+ const result = classify(
+ {
+ ...base,
+ annexIIICategories: ['a3-employment'],
+ art63Exception: true,
+ transparencyTriggers: ['tr-chatbot'],
+ },
+ CONTENT_PACK,
+ );
+ expect(result.riskClass).toBe('limited');
+ expect(result.transparencyDuties).toBe(true);
+ expect(result.art64DocumentationDuty).toBe(true);
+ });
+
+ it('stuft reine Transparenz-Auslöser als limited ein (Chatbot-Fall)', () => {
+ const result = classify({ ...base, transparencyTriggers: ['tr-chatbot'] }, CONTENT_PACK);
+ expect(result.riskClass).toBe('limited');
+ });
+
+ it('behÀlt Transparenzpflichten bei Hochrisiko-Systemen bei', () => {
+ const result = classify(
+ { ...base, annexIIICategories: ['a3-employment'], transparencyTriggers: ['tr-chatbot'] },
+ CONTENT_PACK,
+ );
+ expect(result.riskClass).toBe('high');
+ expect(result.transparencyDuties).toBe(true);
+ });
+
+ it('stuft Systeme ohne AuffÀlligkeiten als minimal ein', () => {
+ const result = classify(base, CONTENT_PACK);
+ expect(result.riskClass).toBe('minimal');
+ });
+
+ it('setzt das GPAI-Flag unabhÀngig von der Risikoklasse', () => {
+ const result = classify({ ...base, isGPAIModel: true }, CONTENT_PACK);
+ expect(result.riskClass).toBe('minimal');
+ expect(result.gpaiObligations).toBe(true);
+ });
+});
diff --git a/ai-act-kompass/src/engine/classify.ts b/ai-act-kompass/src/engine/classify.ts
new file mode 100644
index 0000000..e553b10
--- /dev/null
+++ b/ai-act-kompass/src/engine/classify.ts
@@ -0,0 +1,133 @@
+import type { AssessmentAnswers, Classification, ContentPack } from './types';
+
+/**
+ * Klassifiziert ein KI-System nach dem Risikomodell des EU AI Act.
+ *
+ * PrĂŒfreihenfolge (entspricht der Systematik der Verordnung):
+ * 1. Anwendbarkeit (KI-Definition, Art. 3 Nr. 1)
+ * 2. Verbotene Praktiken (Art. 5) â "prohibited"
+ * 3. Annex I Sicherheitsbauteil â "high"
+ * 4. Annex III Bereiche, ggf. Ausnahme Art. 6 Abs. 3 â "high"
+ * 5. Transparenzpflichten (Art. 50) â "limited"
+ * 6. Sonst â "minimal"
+ *
+ * @param answers - Antworten des Bewertungs-Wizards
+ * @param pack - Regulatorischer Content-Pack (fĂŒr BegrĂŒndungstexte)
+ * @returns UnverĂ€nderliches Klassifizierungsergebnis mit BegrĂŒndungen
+ */
+export function classify(answers: AssessmentAnswers, pack: ContentPack): Classification {
+ const reasons: string[] = [];
+ const transparencyDuties = answers.transparencyTriggers.length > 0;
+
+ if (!answers.isAISystem) {
+ return {
+ riskClass: 'out-of-scope',
+ reasons: ['Das System erfĂŒllt die KI-Definition nach Art. 3 Nr. 1 nicht â der AI Act ist nicht anwendbar.'],
+ gpaiObligations: false,
+ transparencyDuties: false,
+ art64DocumentationDuty: false,
+ };
+ }
+
+ if (answers.prohibitedPractices.length > 0) {
+ for (const id of answers.prohibitedPractices) {
+ const item = pack.prohibitedPractices.find((p) => p.id === id);
+ if (item) {
+ reasons.push(`Verbotene Praktik: ${item.label} (${item.legalRef})`);
+ }
+ }
+ return {
+ riskClass: 'prohibited',
+ reasons,
+ gpaiObligations: answers.isGPAIModel,
+ transparencyDuties: false,
+ art64DocumentationDuty: false,
+ };
+ }
+
+ if (answers.isAnnexISafetyComponent) {
+ reasons.push(
+ 'Das System ist Sicherheitsbauteil eines in Annex I regulierten Produkts bzw. selbst ein solches Produkt (Art. 6 Abs. 1) â Hochrisiko.',
+ );
+ return {
+ riskClass: 'high',
+ reasons,
+ gpaiObligations: answers.isGPAIModel,
+ transparencyDuties,
+ art64DocumentationDuty: false,
+ };
+ }
+
+ if (answers.annexIIICategories.length > 0) {
+ for (const id of answers.annexIIICategories) {
+ const item = pack.annexIIICategories.find((c) => c.id === id);
+ if (item) {
+ reasons.push(`Annex-III-Bereich: ${item.label} (${item.legalRef})`);
+ }
+ }
+
+ if (answers.involvesProfiling) {
+ reasons.push(
+ 'Das System fĂŒhrt Profiling natĂŒrlicher Personen durch â die Ausnahme nach Art. 6 Abs. 3 ist damit ausgeschlossen.',
+ );
+ return {
+ riskClass: 'high',
+ reasons,
+ gpaiObligations: answers.isGPAIModel,
+ transparencyDuties,
+ art64DocumentationDuty: false,
+ };
+ }
+
+ if (answers.art63Exception) {
+ reasons.push(
+ 'Ausnahme nach Art. 6 Abs. 3 in Anspruch genommen (eng begrenzte/vorbereitende Aufgabe ohne wesentliches Risiko). Die EinschÀtzung ist nach Art. 6 Abs. 4 zu dokumentieren.',
+ );
+ return {
+ riskClass: transparencyDuties ? 'limited' : 'minimal',
+ reasons: transparencyDuties
+ ? [...reasons, ...transparencyReasons(answers, pack)]
+ : reasons,
+ gpaiObligations: answers.isGPAIModel,
+ transparencyDuties,
+ art64DocumentationDuty: true,
+ };
+ }
+
+ return {
+ riskClass: 'high',
+ reasons,
+ gpaiObligations: answers.isGPAIModel,
+ transparencyDuties,
+ art64DocumentationDuty: false,
+ };
+ }
+
+ if (transparencyDuties) {
+ return {
+ riskClass: 'limited',
+ reasons: transparencyReasons(answers, pack),
+ gpaiObligations: answers.isGPAIModel,
+ transparencyDuties: true,
+ art64DocumentationDuty: false,
+ };
+ }
+
+ return {
+ riskClass: 'minimal',
+ reasons: [
+ 'Keine verbotene Praktik, kein Hochrisiko-Bereich, keine Transparenzpflicht-Auslöser â minimales Risiko. Es gelten die allgemeine KI-Kompetenzpflicht (Art. 4) und freiwillige Verhaltenskodizes.',
+ ],
+ gpaiObligations: answers.isGPAIModel,
+ transparencyDuties: false,
+ art64DocumentationDuty: false,
+ };
+}
+
+/** Erzeugt BegrĂŒndungstexte fĂŒr zutreffende Art.-50-Auslöser. */
+function transparencyReasons(answers: AssessmentAnswers, pack: ContentPack): string[] {
+ return answers.transparencyTriggers.flatMap((id) => {
+ const item = pack.transparencyTriggers.find((t) => t.id === id);
+ return item ? [`Transparenzpflicht: ${item.label} (${item.legalRef})`] : [];
+ });
+}
diff --git a/ai-act-kompass/src/engine/documents.test.ts b/ai-act-kompass/src/engine/documents.test.ts
new file mode 100644
index 0000000..ef8b036
--- /dev/null
+++ b/ai-act-kompass/src/engine/documents.test.ts
@@ -0,0 +1,66 @@
+import { describe, expect, it } from 'vitest';
+import { CONTENT_PACK } from '../content/pack';
+import { classify } from './classify';
+import { actionPlan, annexIVSkeleton, inventoryReport, riskReport } from './documents';
+import { deriveObligations } from './obligations';
+import type { AISystem, AssessmentAnswers } from './types';
+
+const answers: AssessmentAnswers = {
+ isAISystem: true,
+ role: 'provider',
+ isGPAIModel: false,
+ prohibitedPractices: [],
+ annexIIICategories: ['a3-employment'],
+ art63Exception: false,
+ involvesProfiling: true,
+ isAnnexISafetyComponent: false,
+ transparencyTriggers: ['tr-chatbot'],
+};
+
+const system: AISystem = {
+ id: 'sys-1',
+ name: 'HR-Screening',
+ purpose: 'Vorauswahl von Bewerbungen',
+ vendor: 'Beispiel GmbH',
+ owner: 'Jane Doe',
+ createdAt: '2026-07-01T00:00:00.000Z',
+ updatedAt: '2026-07-01T00:00:00.000Z',
+ answers,
+ classification: classify(answers, CONTENT_PACK),
+ obligationStatus: { 'ob-risk-mgmt': 'in-progress' },
+};
+
+const TODAY = '2026-07-04';
+
+describe('documents', () => {
+ it('riskReport enthĂ€lt Klassifizierung, BegrĂŒndung und Disclaimer', () => {
+ const md = riskReport(system, CONTENT_PACK, TODAY);
+ expect(md).toContain('# Risikoklassifizierung');
+ expect(md).toContain('Hochrisiko');
+ expect(md).toContain('Annex III');
+ expect(md).toContain('keine Rechtsberatung');
+ expect(md).toContain(CONTENT_PACK.version);
+ });
+
+ it('actionPlan listet Pflichten mit Status und Frist', () => {
+ const obligations = deriveObligations(system.classification, answers, CONTENT_PACK);
+ const md = actionPlan(system, obligations, CONTENT_PACK, TODAY);
+ expect(md).toContain('Risikomanagementsystem');
+ expect(md).toContain('In Umsetzung');
+ expect(md).toContain('02.12.2027');
+ });
+
+ it('annexIVSkeleton befĂŒllt bekannte Felder und markiert offene Punkte', () => {
+ const md = annexIVSkeleton(system, CONTENT_PACK, TODAY);
+ expect(md).toContain('Vorauswahl von Bewerbungen');
+ expect(md).toContain('_[AUSFĂLLEN]_');
+ expect(md).toContain('Annex IV');
+ });
+
+ it('inventoryReport listet alle Systeme tabellarisch', () => {
+ const md = inventoryReport([system], CONTENT_PACK, TODAY);
+ expect(md).toContain('HR-Screening');
+ expect(md).toContain('| System |');
+ expect(md).toContain('Registrierte KI-Systeme: **1**');
+ });
+});
diff --git a/ai-act-kompass/src/engine/documents.ts b/ai-act-kompass/src/engine/documents.ts
new file mode 100644
index 0000000..8e5d65d
--- /dev/null
+++ b/ai-act-kompass/src/engine/documents.ts
@@ -0,0 +1,217 @@
+import type { AISystem, ContentPack, Obligation } from './types';
+
+const RISK_LABELS: Record = {
+ 'out-of-scope': 'Nicht anwendbar (keine KI i. S. d. Art. 3 Nr. 1)',
+ prohibited: 'VERBOTEN (Art. 5)',
+ high: 'Hochrisiko',
+ limited: 'Begrenztes Risiko (Transparenzpflichten)',
+ minimal: 'Minimales Risiko',
+};
+
+const ROLE_LABELS: Record = {
+ provider: 'Anbieter (Provider)',
+ deployer: 'Betreiber (Deployer)',
+ importer: 'EinfĂŒhrer (Importer)',
+ distributor: 'HĂ€ndler (Distributor)',
+};
+
+const STATUS_LABELS: Record = {
+ open: 'Offen',
+ 'in-progress': 'In Umsetzung',
+ done: 'Erledigt',
+ 'not-applicable': 'Nicht anwendbar',
+};
+
+const DISCLAIMER =
+ '> **Hinweis:** Dieses Dokument wurde mit dem AI-Act-Kompass erstellt und ist eine strukturierte Arbeitshilfe â **keine Rechtsberatung**. Die rechtliche Bewertung im Einzelfall obliegt dem Unternehmen bzw. seiner Rechtsberatung.';
+
+/** Formatiert ein ISO-Datum als deutsches Datum (TT.MM.JJJJ). */
+function formatDate(iso: string): string {
+ const [y, m, d] = iso.split('-');
+ return d && m && y ? `${d}.${m}.${y}` : iso;
+}
+
+function header(title: string, system: AISystem, pack: ContentPack, today: string): string {
+ return [
+ `# ${title}`,
+ '',
+ `| | |`,
+ `|---|---|`,
+ `| **KI-System** | ${system.name} |`,
+ `| **Zweckbestimmung** | ${system.purpose || 'â'} |`,
+ `| **Hersteller/Anbieter** | ${system.vendor || 'â'} |`,
+ `| **Verantwortlich (intern)** | ${system.owner || 'â'} |`,
+ `| **Rolle des Unternehmens** | ${ROLE_LABELS[system.answers.role] ?? system.answers.role} |`,
+ `| **Risikoklasse** | ${RISK_LABELS[system.classification.riskClass] ?? system.classification.riskClass} |`,
+ `| **Erstellt am** | ${formatDate(today)} |`,
+ `| **Content-Pack** | v${pack.version} (${pack.legalBasis}) |`,
+ '',
+ DISCLAIMER,
+ '',
+ ].join('\n');
+}
+
+/**
+ * Erzeugt den Risikoklassifizierungs-Bericht fĂŒr ein System als Markdown.
+ *
+ * @param system - Bewertetes KI-System
+ * @param pack - Regulatorischer Content-Pack
+ * @param today - Stichtag im ISO-Format
+ */
+export function riskReport(system: AISystem, pack: ContentPack, today: string): string {
+ const lines = [header('Risikoklassifizierung nach EU AI Act', system, pack, today)];
+
+ lines.push('## Ergebnis', '');
+ lines.push(`**${RISK_LABELS[system.classification.riskClass] ?? system.classification.riskClass}**`, '');
+
+ lines.push('## BegrĂŒndung', '');
+ for (const reason of system.classification.reasons) {
+ lines.push(`- ${reason}`);
+ }
+ lines.push('');
+
+ if (system.classification.gpaiObligations) {
+ lines.push('## GPAI', '', 'FĂŒr dieses System sind zusĂ€tzlich GPAI-Modellpflichten (Art. 53 ff.) relevant.', '');
+ }
+ if (system.classification.art64DocumentationDuty) {
+ lines.push(
+ '## Dokumentationspflicht Art. 6 Abs. 4',
+ '',
+ 'Die Inanspruchnahme der Ausnahme nach Art. 6 Abs. 3 wurde dokumentiert. Diese EinschĂ€tzung ist auf Verlangen der MarktĂŒberwachung vorzulegen.',
+ '',
+ );
+ }
+
+ return lines.join('\n');
+}
+
+/**
+ * Erzeugt den MaĂnahmenplan (Pflichten-Checkliste) als Markdown.
+ *
+ * @param system - Bewertetes KI-System
+ * @param obligations - Anwendbare Pflichten
+ * @param pack - Regulatorischer Content-Pack
+ * @param today - Stichtag im ISO-Format
+ */
+export function actionPlan(
+ system: AISystem,
+ obligations: readonly Obligation[],
+ pack: ContentPack,
+ today: string,
+): string {
+ const lines = [header('MaĂnahmenplan EU AI Act', system, pack, today)];
+
+ if (obligations.length === 0) {
+ lines.push('FĂŒr dieses System bestehen keine umsetzbaren Pflichten (verboten oder auĂerhalb des Anwendungsbereichs).');
+ return lines.join('\n');
+ }
+
+ lines.push('## Pflichten', '');
+ lines.push('| Pflicht | Rechtsgrundlage | Frist | Status |');
+ lines.push('|---|---|---|---|');
+ for (const ob of obligations) {
+ const status = system.obligationStatus[ob.id] ?? 'open';
+ lines.push(`| ${ob.title} | ${ob.articles} | ${formatDate(ob.deadline)} | ${STATUS_LABELS[status]} |`);
+ }
+ lines.push('', '## Details', '');
+ for (const ob of obligations) {
+ lines.push(`### ${ob.title} (${ob.articles})`, '', ob.description, '');
+ }
+
+ return lines.join('\n');
+}
+
+/**
+ * Erzeugt das GrundgerĂŒst der technischen Dokumentation nach Annex IV.
+ *
+ * VorbefĂŒllte Abschnitte stammen aus den Wizard-Antworten; offene Punkte
+ * sind als Platzhalter markiert.
+ *
+ * @param system - Bewertetes KI-System
+ * @param pack - Regulatorischer Content-Pack
+ * @param today - Stichtag im ISO-Format
+ */
+export function annexIVSkeleton(system: AISystem, pack: ContentPack, today: string): string {
+ const todo = '_[AUSFĂLLEN]_';
+ const lines = [header('Technische Dokumentation (Annex IV) â GrundgerĂŒst', system, pack, today)];
+
+ lines.push(
+ '## 1. Allgemeine Beschreibung des KI-Systems',
+ '',
+ `- **Zweckbestimmung:** ${system.purpose || todo}`,
+ `- **Anbieter:** ${system.vendor || todo}`,
+ `- **Versionen und Datum des Inverkehrbringens:** ${todo}`,
+ `- **Hardware-Anforderungen / Bereitstellungsform:** ${todo}`,
+ `- **Interaktion mit externer Hard-/Software:** ${todo}`,
+ '',
+ '## 2. Detaillierte Beschreibung der Elemente und des Entwicklungsprozesses',
+ '',
+ `- **Entwicklungsmethoden und verwendete Werkzeuge:** ${todo}`,
+ `- **Systemarchitektur und Rechenressourcen:** ${todo}`,
+ `- **Datenanforderungen (Trainings-, Validierungs-, Testdaten, Herkunft, Aufbereitung):** ${todo}`,
+ `- **MaĂnahmen der menschlichen Aufsicht (Art. 14):** ${todo}`,
+ `- **Vorab festgelegte Ănderungen und KontinuitĂ€t der KonformitĂ€t:** ${todo}`,
+ '',
+ '## 3. Ăberwachung, Funktionsweise und Kontrolle',
+ '',
+ `- **FĂ€higkeiten und Leistungsgrenzen (Genauigkeitsmetriken):** ${todo}`,
+ `- **Vorhersehbare unbeabsichtigte Ergebnisse und Risikoquellen:** ${todo}`,
+ `- **Eingabedaten-Spezifikation:** ${todo}`,
+ '',
+ '## 4. Risikomanagementsystem (Art. 9)',
+ '',
+ `- **Beschreibung des Risikomanagementprozesses:** ${todo}`,
+ '',
+ '## 5. Ănderungen ĂŒber den Lebenszyklus',
+ '',
+ `- **Ănderungshistorie und Update-Prozess:** ${todo}`,
+ '',
+ '## 6. Angewandte harmonisierte Normen und Spezifikationen',
+ '',
+ `- **Liste der Normen (z. B. ISO/IEC 42001, ISO/IEC 23894):** ${todo}`,
+ '',
+ '## 7. EU-KonformitÀtserklÀrung',
+ '',
+ `- **Kopie der KonformitÀtserklÀrung (Art. 47):** ${todo}`,
+ '',
+ '## 8. Bewertung nach dem Inverkehrbringen (Art. 72)',
+ '',
+ `- **Plan zur Beobachtung nach dem Inverkehrbringen:** ${todo}`,
+ );
+
+ return lines.join('\n');
+}
+
+/**
+ * Erzeugt das KI-Inventar ĂŒber alle registrierten Systeme als Markdown.
+ *
+ * @param systems - Alle registrierten KI-Systeme
+ * @param pack - Regulatorischer Content-Pack
+ * @param today - Stichtag im ISO-Format
+ */
+export function inventoryReport(
+ systems: readonly AISystem[],
+ pack: ContentPack,
+ today: string,
+): string {
+ const lines = [
+ '# KI-Inventar (AI Asset Register)',
+ '',
+ `Stand: ${formatDate(today)} · Content-Pack v${pack.version}`,
+ '',
+ DISCLAIMER,
+ '',
+ `Registrierte KI-Systeme: **${systems.length}**`,
+ '',
+ '| System | Zweck | Rolle | Risikoklasse | Verantwortlich |',
+ '|---|---|---|---|---|',
+ ];
+ for (const s of systems) {
+ lines.push(
+ `| ${s.name} | ${s.purpose || 'â'} | ${ROLE_LABELS[s.answers.role] ?? s.answers.role} | ${
+ RISK_LABELS[s.classification.riskClass] ?? s.classification.riskClass
+ } | ${s.owner || 'â'} |`,
+ );
+ }
+ return lines.join('\n');
+}
diff --git a/ai-act-kompass/src/engine/obligations.test.ts b/ai-act-kompass/src/engine/obligations.test.ts
new file mode 100644
index 0000000..ec6c1b5
--- /dev/null
+++ b/ai-act-kompass/src/engine/obligations.test.ts
@@ -0,0 +1,92 @@
+import { describe, expect, it } from 'vitest';
+import { CONTENT_PACK } from '../content/pack';
+import { classify } from './classify';
+import { deriveObligations, nextDeadline } from './obligations';
+import type { AssessmentAnswers } from './types';
+
+const base: AssessmentAnswers = {
+ isAISystem: true,
+ role: 'deployer',
+ isGPAIModel: false,
+ prohibitedPractices: [],
+ annexIIICategories: [],
+ art63Exception: false,
+ involvesProfiling: false,
+ isAnnexISafetyComponent: false,
+ transparencyTriggers: [],
+};
+
+function obligationsFor(answers: AssessmentAnswers): readonly string[] {
+ const classification = classify(answers, CONTENT_PACK);
+ return deriveObligations(classification, answers, CONTENT_PACK).map((o) => o.id);
+}
+
+describe('deriveObligations', () => {
+ it('liefert keine Pflichten fĂŒr verbotene Systeme', () => {
+ expect(obligationsFor({ ...base, prohibitedPractices: ['proh-social-scoring'] })).toEqual([]);
+ });
+
+ it('liefert keine Pflichten fĂŒr out-of-scope', () => {
+ expect(obligationsFor({ ...base, isAISystem: false })).toEqual([]);
+ });
+
+ it('liefert Anbieter-Pflichten fĂŒr Hochrisiko-Anbieter (Art. 9â17, 43 ff.)', () => {
+ const ids = obligationsFor({
+ ...base,
+ role: 'provider',
+ annexIIICategories: ['a3-employment'],
+ });
+ expect(ids).toContain('ob-risk-mgmt');
+ expect(ids).toContain('ob-tech-doc');
+ expect(ids).toContain('ob-conformity');
+ expect(ids).not.toContain('ob-deployer-oversight');
+ });
+
+ it('liefert Betreiber-Pflichten fĂŒr Hochrisiko-Betreiber (Art. 26)', () => {
+ const ids = obligationsFor({ ...base, annexIIICategories: ['a3-employment'] });
+ expect(ids).toContain('ob-deployer-oversight');
+ expect(ids).toContain('ob-deployer-workers');
+ expect(ids).not.toContain('ob-risk-mgmt');
+ });
+
+ it('liefert Transparenzpflicht fĂŒr Chatbots (limited)', () => {
+ const ids = obligationsFor({ ...base, transparencyTriggers: ['tr-chatbot'] });
+ expect(ids).toContain('ob-transparency-art50');
+ expect(ids).toContain('ob-ai-literacy');
+ });
+
+ it('liefert GPAI-Pflichten nur fĂŒr Anbieter mit GPAI-Flag', () => {
+ expect(obligationsFor({ ...base, role: 'provider', isGPAIModel: true })).toContain('ob-gpai');
+ expect(obligationsFor({ ...base, isGPAIModel: true })).not.toContain('ob-gpai');
+ expect(obligationsFor({ ...base, role: 'provider' })).not.toContain('ob-gpai');
+ });
+
+ it('sortiert Pflichten nach Frist aufsteigend', () => {
+ const answers: AssessmentAnswers = {
+ ...base,
+ annexIIICategories: ['a3-employment'],
+ transparencyTriggers: ['tr-chatbot'],
+ };
+ const classification = classify(answers, CONTENT_PACK);
+ const deadlines = deriveObligations(classification, answers, CONTENT_PACK).map(
+ (o) => o.deadline,
+ );
+ expect(deadlines).toEqual([...deadlines].sort());
+ });
+});
+
+describe('nextDeadline', () => {
+ it('findet die nÀchste bevorstehende Frist', () => {
+ const answers: AssessmentAnswers = { ...base, annexIIICategories: ['a3-employment'] };
+ const classification = classify(answers, CONTENT_PACK);
+ const obligations = deriveObligations(classification, answers, CONTENT_PACK);
+ expect(nextDeadline(obligations, '2026-07-04')).toBe('2027-12-02');
+ });
+
+ it('liefert null, wenn alle Fristen verstrichen sind', () => {
+ const answers: AssessmentAnswers = { ...base, annexIIICategories: ['a3-employment'] };
+ const classification = classify(answers, CONTENT_PACK);
+ const obligations = deriveObligations(classification, answers, CONTENT_PACK);
+ expect(nextDeadline(obligations, '2030-01-01')).toBeNull();
+ });
+});
diff --git a/ai-act-kompass/src/engine/obligations.ts b/ai-act-kompass/src/engine/obligations.ts
new file mode 100644
index 0000000..25ea576
--- /dev/null
+++ b/ai-act-kompass/src/engine/obligations.ts
@@ -0,0 +1,55 @@
+import type { AssessmentAnswers, Classification, ContentPack, Obligation } from './types';
+
+/**
+ * Leitet die anwendbaren Pflichten fĂŒr ein klassifiziertes System ab.
+ *
+ * Auswahlkriterien je Pflicht: Risikoklasse und Rolle mĂŒssen passen;
+ * GPAI- und Transparenzpflichten werden nur bei entsprechendem Flag
+ * aufgenommen.
+ *
+ * @param classification - Ergebnis von {@link classify}
+ * @param answers - Wizard-Antworten (Rolle, GPAI-Flag)
+ * @param pack - Regulatorischer Content-Pack
+ * @returns Deduplizierte, nach Frist sortierte Pflichtenliste
+ */
+export function deriveObligations(
+ classification: Classification,
+ answers: AssessmentAnswers,
+ pack: ContentPack,
+): readonly Obligation[] {
+ if (classification.riskClass === 'out-of-scope' || classification.riskClass === 'prohibited') {
+ return [];
+ }
+
+ const applicable = pack.obligations.filter((ob) => {
+ if (ob.id === 'ob-gpai') {
+ return classification.gpaiObligations && answers.role === 'provider';
+ }
+ if (ob.id === 'ob-transparency-art50') {
+ return classification.transparencyDuties && ob.roles.includes(answers.role);
+ }
+ return (
+ ob.riskClasses.includes(classification.riskClass) && ob.roles.includes(answers.role)
+ );
+ });
+
+ return [...applicable].sort((a, b) => a.deadline.localeCompare(b.deadline));
+}
+
+/**
+ * Ermittelt die nĂ€chste noch bevorstehende Geltungsfrist fĂŒr ein System.
+ *
+ * @param obligations - Anwendbare Pflichten des Systems
+ * @param today - Stichtag im ISO-Format (YYYY-MM-DD)
+ * @returns FrĂŒheste Frist nach dem Stichtag, oder null wenn alle verstrichen
+ */
+export function nextDeadline(
+ obligations: readonly Obligation[],
+ today: string,
+): string | null {
+ const upcoming = obligations
+ .map((ob) => ob.deadline)
+ .filter((d) => d >= today)
+ .sort();
+ return upcoming[0] ?? null;
+}
diff --git a/ai-act-kompass/src/engine/types.ts b/ai-act-kompass/src/engine/types.ts
new file mode 100644
index 0000000..a1fc17b
--- /dev/null
+++ b/ai-act-kompass/src/engine/types.ts
@@ -0,0 +1,111 @@
+/**
+ * Kern-Typen des AI-Act-Kompass.
+ *
+ * Alle Datenstrukturen sind unverĂ€nderlich gedacht (immutable) â
+ * Funktionen geben neue Objekte zurĂŒck statt zu mutieren.
+ */
+
+/** Rolle des Unternehmens in Bezug auf das KI-System (Art. 3 AI Act). */
+export type Role = 'provider' | 'deployer' | 'importer' | 'distributor';
+
+/** Risikoklasse nach EU AI Act. */
+export type RiskClass =
+ | 'out-of-scope'
+ | 'prohibited'
+ | 'high'
+ | 'limited'
+ | 'minimal';
+
+/** Antworten des Bewertungs-Wizards fĂŒr ein einzelnes KI-System. */
+export interface AssessmentAnswers {
+ /** ErfĂŒllt das System die KI-Definition nach Art. 3 Nr. 1? */
+ readonly isAISystem: boolean;
+ /** Rolle des Unternehmens fĂŒr dieses System. */
+ readonly role: Role;
+ /** Handelt es sich (auch) um ein GPAI-Modell (Art. 51 ff.)? */
+ readonly isGPAIModel: boolean;
+ /** IDs der zutreffenden verbotenen Praktiken (Art. 5). */
+ readonly prohibitedPractices: readonly string[];
+ /** IDs der zutreffenden Annex-III-Hochrisiko-Bereiche. */
+ readonly annexIIICategories: readonly string[];
+ /** Greift die Ausnahme nach Art. 6 Abs. 3 (eng begrenzte Aufgabe)? */
+ readonly art63Exception: boolean;
+ /** FĂŒhrt das System Profiling natĂŒrlicher Personen durch? */
+ readonly involvesProfiling: boolean;
+ /** Sicherheitsbauteil eines regulierten Produkts (Annex I)? */
+ readonly isAnnexISafetyComponent: boolean;
+ /** IDs der zutreffenden Transparenzpflichten-Auslöser (Art. 50). */
+ readonly transparencyTriggers: readonly string[];
+}
+
+/** Ergebnis der Risikoklassifizierung. */
+export interface Classification {
+ readonly riskClass: RiskClass;
+ /** BegrĂŒndungen in PrĂŒfreihenfolge (menschenlesbar, Deutsch). */
+ readonly reasons: readonly string[];
+ /** ZusÀtzlich GPAI-Pflichten (Art. 53 ff.) relevant? */
+ readonly gpaiObligations: boolean;
+ /** Transparenzpflichten nach Art. 50 zusÀtzlich anwendbar? */
+ readonly transparencyDuties: boolean;
+ /** Dokumentationspflicht nach Art. 6 Abs. 4 (Ausnahme in Anspruch genommen)? */
+ readonly art64DocumentationDuty: boolean;
+}
+
+/** Eine konkrete Pflicht aus dem AI Act. */
+export interface Obligation {
+ readonly id: string;
+ readonly title: string;
+ readonly articles: string;
+ readonly description: string;
+ /** ISO-Datum der maĂgeblichen Geltungsfrist. */
+ readonly deadline: string;
+ readonly roles: readonly Role[];
+ readonly riskClasses: readonly RiskClass[];
+}
+
+/** Status einer Pflicht in der Umsetzung durch den Nutzer. */
+export type ObligationStatus = 'open' | 'in-progress' | 'done' | 'not-applicable';
+
+/** Ein registriertes KI-System im Inventar. */
+export interface AISystem {
+ readonly id: string;
+ readonly name: string;
+ readonly purpose: string;
+ readonly vendor: string;
+ readonly owner: string;
+ readonly createdAt: string;
+ readonly updatedAt: string;
+ readonly answers: AssessmentAnswers;
+ readonly classification: Classification;
+ /** Umsetzungsstatus je Pflicht-ID. */
+ readonly obligationStatus: Readonly>;
+}
+
+/** Eintrag im regulatorischen Content-Pack (Checklisten-Item mit Rechtsgrundlage). */
+export interface ContentItem {
+ readonly id: string;
+ readonly label: string;
+ readonly legalRef: string;
+ readonly hint?: string;
+}
+
+/** Wichtige Geltungsfrist des AI Act. */
+export interface Deadline {
+ readonly id: string;
+ readonly date: string;
+ readonly label: string;
+ readonly description: string;
+}
+
+/** Versionierter regulatorischer Content-Pack. */
+export interface ContentPack {
+ readonly version: string;
+ readonly releasedAt: string;
+ readonly legalBasis: string;
+ readonly prohibitedPractices: readonly ContentItem[];
+ readonly annexIIICategories: readonly ContentItem[];
+ readonly transparencyTriggers: readonly ContentItem[];
+ readonly aiDefinitionCriteria: readonly ContentItem[];
+ readonly obligations: readonly Obligation[];
+ readonly deadlines: readonly Deadline[];
+}
diff --git a/ai-act-kompass/src/main.tsx b/ai-act-kompass/src/main.tsx
new file mode 100644
index 0000000..394bd63
--- /dev/null
+++ b/ai-act-kompass/src/main.tsx
@@ -0,0 +1,15 @@
+import { StrictMode } from 'react';
+import { createRoot } from 'react-dom/client';
+import { App } from './ui/App';
+import './styles.css';
+
+const container = document.getElementById('root');
+if (!container) {
+ throw new Error('Root-Element #root nicht gefunden.');
+}
+
+createRoot(container).render(
+
+
+ ,
+);
diff --git a/ai-act-kompass/src/store/storage.ts b/ai-act-kompass/src/store/storage.ts
new file mode 100644
index 0000000..d42998b
--- /dev/null
+++ b/ai-act-kompass/src/store/storage.ts
@@ -0,0 +1,75 @@
+import type { AISystem } from '../engine/types';
+
+const STORAGE_KEY = 'ai-act-kompass/systems/v1';
+
+/** Format der Export-/Import-Datei. */
+export interface ExportFile {
+ readonly app: 'ai-act-kompass';
+ readonly schemaVersion: 1;
+ readonly exportedAt: string;
+ readonly systems: readonly AISystem[];
+}
+
+/**
+ * LĂ€dt alle registrierten KI-Systeme aus dem lokalen Speicher.
+ * Bei defekten Daten wird eine leere Liste zurĂŒckgegeben (fail-safe).
+ */
+export function loadSystems(): readonly AISystem[] {
+ try {
+ const raw = localStorage.getItem(STORAGE_KEY);
+ if (!raw) return [];
+ const parsed: unknown = JSON.parse(raw);
+ return Array.isArray(parsed) ? (parsed as AISystem[]) : [];
+ } catch {
+ return [];
+ }
+}
+
+/**
+ * Persistiert die Systemliste im lokalen Speicher des Browsers.
+ * Es verlassen keine Daten das GerÀt.
+ */
+export function saveSystems(systems: readonly AISystem[]): void {
+ localStorage.setItem(STORAGE_KEY, JSON.stringify(systems));
+}
+
+/**
+ * Serialisiert alle Daten als Export-Datei (JSON) fĂŒr Backup/Umzug.
+ *
+ * @param systems - Zu exportierende Systeme
+ * @param exportedAt - Zeitstempel im ISO-Format
+ */
+export function exportData(systems: readonly AISystem[], exportedAt: string): string {
+ const file: ExportFile = {
+ app: 'ai-act-kompass',
+ schemaVersion: 1,
+ exportedAt,
+ systems,
+ };
+ return JSON.stringify(file, null, 2);
+}
+
+/**
+ * Liest eine Export-Datei ein und validiert das Grundformat.
+ *
+ * @param json - Inhalt der Export-Datei
+ * @returns Systeme aus der Datei
+ * @throws Error bei unbekanntem oder defektem Format
+ */
+export function importData(json: string): readonly AISystem[] {
+ const parsed: unknown = JSON.parse(json);
+ if (
+ typeof parsed !== 'object' ||
+ parsed === null ||
+ (parsed as ExportFile).app !== 'ai-act-kompass' ||
+ !Array.isArray((parsed as ExportFile).systems)
+ ) {
+ throw new Error('Unbekanntes Dateiformat â keine gĂŒltige AI-Act-Kompass-Exportdatei.');
+ }
+ return (parsed as ExportFile).systems;
+}
+
+/** Löscht alle lokal gespeicherten Daten unwiderruflich. */
+export function clearAll(): void {
+ localStorage.removeItem(STORAGE_KEY);
+}
diff --git a/ai-act-kompass/src/styles.css b/ai-act-kompass/src/styles.css
new file mode 100644
index 0000000..e266caa
--- /dev/null
+++ b/ai-act-kompass/src/styles.css
@@ -0,0 +1,190 @@
+:root {
+ --bg: #f5f6f8;
+ --panel: #ffffff;
+ --ink: #1a2233;
+ --muted: #5b6577;
+ --line: #e3e6ec;
+ --accent: #1f4fd8;
+ --accent-ink: #ffffff;
+ --danger: #b3261e;
+ --warn: #9a6700;
+ --ok: #1a7f37;
+ --radius: 10px;
+ font-family: system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;
+}
+
+* { box-sizing: border-box; }
+body { margin: 0; background: var(--bg); color: var(--ink); }
+
+.layout { display: flex; min-height: 100vh; }
+
+.sidebar {
+ width: 240px;
+ flex-shrink: 0;
+ background: #101a33;
+ color: #d7deee;
+ padding: 20px 14px;
+ display: flex;
+ flex-direction: column;
+ gap: 4px;
+}
+.sidebar .brand {
+ font-size: 18px;
+ font-weight: 700;
+ color: #fff;
+ margin-bottom: 2px;
+}
+.sidebar .brand small { display: block; font-size: 11px; font-weight: 400; color: #8fa0c4; margin-top: 4px; }
+.sidebar nav { display: flex; flex-direction: column; gap: 2px; margin-top: 18px; }
+.sidebar button {
+ text-align: left;
+ background: none;
+ border: none;
+ color: #c3cde3;
+ padding: 9px 12px;
+ border-radius: 8px;
+ font-size: 14px;
+ cursor: pointer;
+}
+.sidebar button:hover { background: rgba(255, 255, 255, 0.08); }
+.sidebar button.active { background: var(--accent); color: #fff; }
+.sidebar .foot { margin-top: auto; font-size: 11px; color: #7787ab; line-height: 1.5; }
+
+.main { flex: 1; padding: 28px 36px; max-width: 1040px; }
+
+h1 { font-size: 22px; margin: 0 0 4px; }
+h2 { font-size: 16px; margin: 22px 0 10px; }
+.sub { color: var(--muted); font-size: 14px; margin: 0 0 20px; }
+
+.panel {
+ background: var(--panel);
+ border: 1px solid var(--line);
+ border-radius: var(--radius);
+ padding: 18px 20px;
+ margin-bottom: 16px;
+}
+
+.grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: 14px; }
+.stat { text-align: left; }
+.stat .num { font-size: 28px; font-weight: 700; }
+.stat .lbl { font-size: 13px; color: var(--muted); }
+
+table { width: 100%; border-collapse: collapse; font-size: 14px; }
+th { text-align: left; color: var(--muted); font-weight: 600; font-size: 12px; text-transform: uppercase; letter-spacing: 0.04em; }
+th, td { padding: 9px 10px; border-bottom: 1px solid var(--line); }
+tr.clickable { cursor: pointer; }
+tr.clickable:hover td { background: #f0f3fa; }
+
+.badge {
+ display: inline-block;
+ padding: 3px 10px;
+ border-radius: 99px;
+ font-size: 12px;
+ font-weight: 600;
+ white-space: nowrap;
+}
+.badge.high { background: #fde8e7; color: var(--danger); }
+.badge.prohibited { background: var(--danger); color: #fff; }
+.badge.limited { background: #fff3d6; color: var(--warn); }
+.badge.minimal { background: #e2f5e8; color: var(--ok); }
+.badge.out-of-scope { background: #e8eaf0; color: var(--muted); }
+.badge.status-open { background: #fde8e7; color: var(--danger); }
+.badge.status-in-progress { background: #fff3d6; color: var(--warn); }
+.badge.status-done { background: #e2f5e8; color: var(--ok); }
+.badge.status-not-applicable { background: #e8eaf0; color: var(--muted); }
+
+button.primary, button.ghost, button.danger {
+ border-radius: 8px;
+ padding: 9px 16px;
+ font-size: 14px;
+ cursor: pointer;
+ border: 1px solid transparent;
+}
+button.primary { background: var(--accent); color: var(--accent-ink); }
+button.primary:hover { filter: brightness(1.1); }
+button.primary:disabled { opacity: 0.5; cursor: not-allowed; }
+button.ghost { background: #fff; border-color: var(--line); color: var(--ink); }
+button.ghost:hover { border-color: var(--accent); color: var(--accent); }
+button.danger { background: #fff; border-color: var(--danger); color: var(--danger); }
+
+label.field { display: block; margin-bottom: 14px; font-size: 14px; }
+label.field span { display: block; font-weight: 600; margin-bottom: 5px; }
+input[type='text'], select, textarea {
+ width: 100%;
+ padding: 9px 11px;
+ border: 1px solid var(--line);
+ border-radius: 8px;
+ font-size: 14px;
+ font-family: inherit;
+ background: #fff;
+ color: var(--ink);
+}
+input:focus, select:focus, textarea:focus { outline: 2px solid var(--accent); outline-offset: -1px; }
+
+.check {
+ display: flex;
+ gap: 10px;
+ align-items: flex-start;
+ padding: 10px 12px;
+ border: 1px solid var(--line);
+ border-radius: 8px;
+ margin-bottom: 8px;
+ cursor: pointer;
+ font-size: 14px;
+}
+.check:hover { border-color: var(--accent); }
+.check input { margin-top: 3px; }
+.check .ref { display: block; font-size: 12px; color: var(--muted); margin-top: 2px; }
+
+.wizard-steps { display: flex; gap: 6px; margin-bottom: 18px; flex-wrap: wrap; }
+.wizard-steps .step {
+ font-size: 12px;
+ padding: 5px 11px;
+ border-radius: 99px;
+ background: #e8eaf0;
+ color: var(--muted);
+}
+.wizard-steps .step.current { background: var(--accent); color: #fff; }
+.wizard-steps .step.done { background: #cdd8f6; color: var(--accent); }
+
+.wizard-nav { display: flex; justify-content: space-between; margin-top: 20px; }
+
+.reasons li { margin-bottom: 6px; font-size: 14px; }
+.hint { font-size: 13px; color: var(--muted); }
+.disclaimer {
+ font-size: 12px;
+ color: var(--muted);
+ border-left: 3px solid var(--warn);
+ padding: 8px 12px;
+ background: #fffaf0;
+ border-radius: 0 8px 8px 0;
+ margin-top: 20px;
+}
+
+.deadline-list { list-style: none; padding: 0; margin: 0; }
+.deadline-list li {
+ display: flex;
+ gap: 12px;
+ padding: 9px 0;
+ border-bottom: 1px solid var(--line);
+ font-size: 14px;
+ align-items: baseline;
+}
+.deadline-list li:last-child { border-bottom: none; }
+.deadline-list .date { font-weight: 700; white-space: nowrap; min-width: 92px; }
+.deadline-list .past { color: var(--muted); }
+
+.doc-preview {
+ background: #0f172a;
+ color: #dbe4f5;
+ border-radius: 8px;
+ padding: 16px;
+ font-size: 12.5px;
+ overflow-x: auto;
+ white-space: pre-wrap;
+ max-height: 420px;
+ overflow-y: auto;
+}
+
+.toolbar { display: flex; gap: 8px; flex-wrap: wrap; margin: 10px 0 16px; }
+.empty { text-align: center; color: var(--muted); padding: 40px 0; font-size: 14px; }
diff --git a/ai-act-kompass/src/ui/App.tsx b/ai-act-kompass/src/ui/App.tsx
new file mode 100644
index 0000000..dd1d83d
--- /dev/null
+++ b/ai-act-kompass/src/ui/App.tsx
@@ -0,0 +1,126 @@
+import { useEffect, useState } from 'react';
+import type { AISystem } from '../engine/types';
+import { loadSystems, saveSystems } from '../store/storage';
+import { Dashboard } from './Dashboard';
+import { SettingsView } from './SettingsView';
+import { SystemDetail } from './SystemDetail';
+import { Wizard } from './Wizard';
+
+type View =
+ | { readonly kind: 'dashboard' }
+ | { readonly kind: 'wizard'; readonly systemId: string | null }
+ | { readonly kind: 'detail'; readonly systemId: string }
+ | { readonly kind: 'settings' };
+
+/** App-Shell: Navigation, State-Verwaltung und Persistenz. */
+export function App(): JSX.Element {
+ const [systems, setSystems] = useState(() => loadSystems());
+ const [view, setView] = useState({ kind: 'dashboard' });
+
+ useEffect(() => {
+ saveSystems(systems);
+ }, [systems]);
+
+ const findSystem = (id: string): AISystem | undefined => systems.find((s) => s.id === id);
+
+ const upsert = (system: AISystem): void => {
+ setSystems((prev) => {
+ const exists = prev.some((s) => s.id === system.id);
+ return exists ? prev.map((s) => (s.id === system.id ? system : s)) : [...prev, system];
+ });
+ };
+
+ const remove = (id: string): void => {
+ setSystems((prev) => prev.filter((s) => s.id !== id));
+ setView({ kind: 'dashboard' });
+ };
+
+ return (
+
+
+
+ đ§ AI-Act-Kompass
+ EU AI Act Compliance fĂŒr KMU · local-first
+
+
+ setView({ kind: 'dashboard' })}
+ >
+ Dashboard & Inventar
+
+ setView({ kind: 'wizard', systemId: null })}
+ >
+ Neues System bewerten
+
+ setView({ kind: 'settings' })}
+ >
+ Einstellungen & Backup
+
+
+
+ Keine Cloud. Keine Telemetrie.
+
+ Alle Daten bleiben auf diesem GerÀt.
+
+
+ Keine Rechtsberatung.
+
+
+
+
+ {view.kind === 'dashboard' && (
+ setView({ kind: 'detail', systemId: id })}
+ onNew={() => setView({ kind: 'wizard', systemId: null })}
+ />
+ )}
+
+ {view.kind === 'wizard' && (
+ {
+ upsert(system);
+ setView({ kind: 'detail', systemId: system.id });
+ }}
+ onCancel={() => setView({ kind: 'dashboard' })}
+ />
+ )}
+
+ {view.kind === 'detail' &&
+ (() => {
+ const system = findSystem(view.systemId);
+ if (!system) {
+ return System nicht gefunden.
;
+ }
+ return (
+ setView({ kind: 'wizard', systemId: system.id })}
+ onDelete={() => {
+ if (window.confirm(`â${system.name}" wirklich löschen?`)) {
+ remove(system.id);
+ }
+ }}
+ onBack={() => setView({ kind: 'dashboard' })}
+ />
+ );
+ })()}
+
+ {view.kind === 'settings' && (
+ setSystems(imported)}
+ onClear={() => setSystems([])}
+ />
+ )}
+
+
+ );
+}
diff --git a/ai-act-kompass/src/ui/Dashboard.tsx b/ai-act-kompass/src/ui/Dashboard.tsx
new file mode 100644
index 0000000..2e10c87
--- /dev/null
+++ b/ai-act-kompass/src/ui/Dashboard.tsx
@@ -0,0 +1,127 @@
+import { CONTENT_PACK } from '../content/pack';
+import { inventoryReport } from '../engine/documents';
+import type { AISystem } from '../engine/types';
+import { downloadText, RiskBadge, ROLE_LABELS, todayISO } from './common';
+
+interface DashboardProps {
+ readonly systems: readonly AISystem[];
+ readonly onOpen: (id: string) => void;
+ readonly onNew: () => void;
+}
+
+/** Ăbersichtsseite: Kennzahlen, Fristen und das KI-Inventar. */
+export function Dashboard({ systems, onOpen, onNew }: DashboardProps): JSX.Element {
+ const today = todayISO();
+ const count = (risk: string): number =>
+ systems.filter((s) => s.classification.riskClass === risk).length;
+
+ const openObligations = systems.reduce((acc, s) => {
+ const done = Object.values(s.obligationStatus).filter(
+ (st) => st === 'done' || st === 'not-applicable',
+ ).length;
+ return acc + Math.max(0, Object.keys(s.obligationStatus).length - done);
+ }, 0);
+
+ return (
+
+
Dashboard
+
+ EU-AI-Act-Compliance auf einen Blick. Alle Daten bleiben lokal auf diesem GerÀt.
+
+
+
+
+
{systems.length}
+
KI-Systeme im Inventar
+
+
+
{count('high')}
+
Hochrisiko-Systeme
+
+
+
{count('prohibited')}
+
Verbotene Praktiken
+
+
+
{openObligations}
+
Offene Pflichten (begonnen)
+
+
+
+
+
Geltungsfristen des AI Act
+
+ {CONTENT_PACK.deadlines.map((d) => (
+
+
+ {d.date.split('-').reverse().join('.')}
+
+
+ {d.label} â {d.description}
+
+
+ ))}
+
+
+
+
+
+
KI-Inventar
+
+ {systems.length > 0 && (
+
+ downloadText(`ki-inventar-${today}.md`, inventoryReport(systems, CONTENT_PACK, today))
+ }
+ >
+ Inventar exportieren
+
+ )}
+
+ + System bewerten
+
+
+
+ {systems.length === 0 ? (
+
+ Noch keine KI-Systeme erfasst. Starten Sie mit der Bewertung Ihres ersten Systems â
+ z. B. Ihres Chatbots, Ihres Bewerber-Screenings oder eines eingekauften KI-Tools.
+
+ ) : (
+
+
+
+ System
+ Rolle
+ Risikoklasse
+ Verantwortlich
+ Zuletzt bewertet
+
+
+
+ {systems.map((s) => (
+ onOpen(s.id)}>
+
+ {s.name}
+
+ {ROLE_LABELS[s.answers.role]}
+
+
+
+ {s.owner || 'â'}
+ {s.updatedAt.slice(0, 10).split('-').reverse().join('.')}
+
+ ))}
+
+
+ )}
+
+
+
+ Der AI-Act-Kompass ist eine strukturierte Arbeitshilfe auf Basis der Verordnung (EU) 2024/1689 â
+ keine Rechtsberatung. Content-Pack v{CONTENT_PACK.version}.
+
+
+ );
+}
diff --git a/ai-act-kompass/src/ui/SettingsView.tsx b/ai-act-kompass/src/ui/SettingsView.tsx
new file mode 100644
index 0000000..b750ecb
--- /dev/null
+++ b/ai-act-kompass/src/ui/SettingsView.tsx
@@ -0,0 +1,98 @@
+import { useRef, useState } from 'react';
+import { CONTENT_PACK } from '../content/pack';
+import type { AISystem } from '../engine/types';
+import { clearAll, exportData, importData } from '../store/storage';
+import { downloadText, todayISO } from './common';
+
+interface SettingsViewProps {
+ readonly systems: readonly AISystem[];
+ readonly onImport: (systems: readonly AISystem[]) => void;
+ readonly onClear: () => void;
+}
+
+/** Einstellungen: Datensicherung, Import, Löschen, Content-Pack-Info. */
+export function SettingsView({ systems, onImport, onClear }: SettingsViewProps): JSX.Element {
+ const fileInput = useRef(null);
+ const [message, setMessage] = useState('');
+
+ const handleImport = async (file: File): Promise => {
+ try {
+ const imported = importData(await file.text());
+ onImport(imported);
+ setMessage(`â ${imported.length} System(e) importiert.`);
+ } catch (err) {
+ setMessage(`â ïž Import fehlgeschlagen: ${err instanceof Error ? err.message : String(err)}`);
+ }
+ };
+
+ return (
+
+
Einstellungen
+
Datenhoheit: Alles liegt lokal in diesem Browser â kein Cloud-Sync, keine Telemetrie.
+
+
+
Regulatorischer Content-Pack
+
+ Version {CONTENT_PACK.version} · Stand {CONTENT_PACK.releasedAt}
+
+ {CONTENT_PACK.legalBasis}
+
+
+ Der Content-Pack (Verbote, Annex-III-Bereiche, Pflichten, Fristen) ist als austauschbares
+ Datenpaket modelliert. Updates erscheinen mit neuen App-Versionen bzw. kĂŒnftig ĂŒber einen
+ signierten Update-Feed.
+
+
+
+
+
Datensicherung
+
+
+ downloadText(
+ `ai-act-kompass-backup-${todayISO()}.json`,
+ exportData(systems, new Date().toISOString()),
+ 'application/json',
+ )
+ }
+ >
+ Backup exportieren (JSON)
+
+ fileInput.current?.click()}>
+ Backup importieren
+
+ {
+ const file = e.target.files?.[0];
+ if (file) void handleImport(file);
+ e.target.value = '';
+ }}
+ />
+
+ {message &&
{message}
}
+
+
+
+
Alle Daten löschen
+
Entfernt alle erfassten KI-Systeme unwiderruflich aus diesem Browser.
+
{
+ if (window.confirm('Wirklich alle lokalen Daten unwiderruflich löschen?')) {
+ clearAll();
+ onClear();
+ setMessage('â Alle Daten gelöscht.');
+ }
+ }}
+ >
+ Alles löschen
+
+
+
+ );
+}
diff --git a/ai-act-kompass/src/ui/SystemDetail.tsx b/ai-act-kompass/src/ui/SystemDetail.tsx
new file mode 100644
index 0000000..53655cc
--- /dev/null
+++ b/ai-act-kompass/src/ui/SystemDetail.tsx
@@ -0,0 +1,164 @@
+import { useMemo, useState } from 'react';
+import { CONTENT_PACK } from '../content/pack';
+import { actionPlan, annexIVSkeleton, riskReport } from '../engine/documents';
+import { deriveObligations } from '../engine/obligations';
+import type { AISystem, ObligationStatus } from '../engine/types';
+import { downloadText, RiskBadge, ROLE_LABELS, todayISO } from './common';
+
+interface SystemDetailProps {
+ readonly system: AISystem;
+ readonly onUpdate: (system: AISystem) => void;
+ readonly onReassess: () => void;
+ readonly onDelete: () => void;
+ readonly onBack: () => void;
+}
+
+const STATUS_OPTIONS: readonly { value: ObligationStatus; label: string }[] = [
+ { value: 'open', label: 'Offen' },
+ { value: 'in-progress', label: 'In Umsetzung' },
+ { value: 'done', label: 'Erledigt' },
+ { value: 'not-applicable', label: 'Nicht anwendbar' },
+];
+
+type DocKind = 'report' | 'plan' | 'annexIV';
+
+/** Detailansicht eines Systems: Klassifizierung, Pflichten-Checkliste, Dokumente. */
+export function SystemDetail({
+ system,
+ onUpdate,
+ onReassess,
+ onDelete,
+ onBack,
+}: SystemDetailProps): JSX.Element {
+ const today = todayISO();
+ const [preview, setPreview] = useState(null);
+
+ const obligations = useMemo(
+ () => deriveObligations(system.classification, system.answers, CONTENT_PACK),
+ [system],
+ );
+
+ const setStatus = (obligationId: string, status: ObligationStatus): void => {
+ onUpdate({
+ ...system,
+ updatedAt: new Date().toISOString(),
+ obligationStatus: { ...system.obligationStatus, [obligationId]: status },
+ });
+ };
+
+ const docs: Record string }> = {
+ report: {
+ label: 'Risikobericht',
+ file: `risikobericht-${system.name}-${today}.md`,
+ render: () => riskReport(system, CONTENT_PACK, today),
+ },
+ plan: {
+ label: 'MaĂnahmenplan',
+ file: `massnahmenplan-${system.name}-${today}.md`,
+ render: () => actionPlan(system, obligations, CONTENT_PACK, today),
+ },
+ annexIV: {
+ label: 'Annex-IV-Dokumentation',
+ file: `annex-iv-${system.name}-${today}.md`,
+ render: () => annexIVSkeleton(system, CONTENT_PACK, today),
+ },
+ };
+
+ const showAnnexIV = system.classification.riskClass === 'high' && system.answers.role === 'provider';
+
+ return (
+
+
+ â ZurĂŒck zum Dashboard
+
+
+ {system.name}
+
+
+ {ROLE_LABELS[system.answers.role]} · {system.purpose || 'Keine Zweckbestimmung erfasst'}
+
+
+
+
BegrĂŒndung der Einstufung
+
+ {system.classification.reasons.map((r) => (
+ {r}
+ ))}
+
+
+
+ Neu bewerten
+
+
+ System löschen
+
+
+
+
+ {obligations.length > 0 && (
+
+
Pflichten ({obligations.length})
+
+
+
+ Pflicht
+ Rechtsgrundlage
+ Frist
+ Status
+
+
+
+ {obligations.map((ob) => {
+ const status = system.obligationStatus[ob.id] ?? 'open';
+ return (
+
+
+ {ob.title}
+ {ob.description}
+
+ {ob.articles}
+ {ob.deadline.split('-').reverse().join('.')}
+
+ setStatus(ob.id, e.target.value as ObligationStatus)}
+ >
+ {STATUS_OPTIONS.map((o) => (
+
+ {o.label}
+
+ ))}
+
+
+
+ );
+ })}
+
+
+
+ )}
+
+
+
Dokumente generieren
+
+ {(Object.keys(docs) as DocKind[])
+ .filter((k) => k !== 'annexIV' || showAnnexIV)
+ .map((kind) => (
+
+ setPreview(preview === kind ? null : kind)}>
+ {docs[kind].label} {preview === kind ? 'ausblenden' : 'ansehen'}
+
+ downloadText(docs[kind].file, docs[kind].render())}
+ >
+ ⏠.md
+
+
+ ))}
+
+ {preview &&
{docs[preview].render()} }
+
+
+ );
+}
diff --git a/ai-act-kompass/src/ui/Wizard.tsx b/ai-act-kompass/src/ui/Wizard.tsx
new file mode 100644
index 0000000..8bcec8a
--- /dev/null
+++ b/ai-act-kompass/src/ui/Wizard.tsx
@@ -0,0 +1,355 @@
+import { useMemo, useState } from 'react';
+import { CONTENT_PACK } from '../content/pack';
+import { classify } from '../engine/classify';
+import type { AISystem, AssessmentAnswers, ContentItem, Role } from '../engine/types';
+import { RiskBadge, ROLE_LABELS } from './common';
+
+const STEPS = ['Grunddaten', 'KI-Definition', 'Verbote', 'Hochrisiko', 'Transparenz & GPAI', 'Ergebnis'] as const;
+
+interface WizardProps {
+ /** Bestehendes System bei Neubewertung, sonst null. */
+ readonly existing: AISystem | null;
+ readonly onSave: (system: AISystem) => void;
+ readonly onCancel: () => void;
+}
+
+interface Draft {
+ name: string;
+ purpose: string;
+ vendor: string;
+ owner: string;
+ role: Role;
+ defCriteria: readonly string[];
+ isGPAIModel: boolean;
+ prohibitedPractices: readonly string[];
+ annexIIICategories: readonly string[];
+ art63Exception: boolean;
+ involvesProfiling: boolean;
+ isAnnexISafetyComponent: boolean;
+ transparencyTriggers: readonly string[];
+}
+
+function initialDraft(existing: AISystem | null): Draft {
+ if (!existing) {
+ return {
+ name: '',
+ purpose: '',
+ vendor: '',
+ owner: '',
+ role: 'deployer',
+ defCriteria: CONTENT_PACK.aiDefinitionCriteria.map((c) => c.id),
+ isGPAIModel: false,
+ prohibitedPractices: [],
+ annexIIICategories: [],
+ art63Exception: false,
+ involvesProfiling: false,
+ isAnnexISafetyComponent: false,
+ transparencyTriggers: [],
+ };
+ }
+ const a = existing.answers;
+ return {
+ name: existing.name,
+ purpose: existing.purpose,
+ vendor: existing.vendor,
+ owner: existing.owner,
+ role: a.role,
+ defCriteria: a.isAISystem ? CONTENT_PACK.aiDefinitionCriteria.map((c) => c.id) : [],
+ isGPAIModel: a.isGPAIModel,
+ prohibitedPractices: a.prohibitedPractices,
+ annexIIICategories: a.annexIIICategories,
+ art63Exception: a.art63Exception,
+ involvesProfiling: a.involvesProfiling,
+ isAnnexISafetyComponent: a.isAnnexISafetyComponent,
+ transparencyTriggers: a.transparencyTriggers,
+ };
+}
+
+function toggle(list: readonly string[], id: string): readonly string[] {
+ return list.includes(id) ? list.filter((x) => x !== id) : [...list, id];
+}
+
+function CheckList({
+ items,
+ selected,
+ onToggle,
+}: {
+ readonly items: readonly ContentItem[];
+ readonly selected: readonly string[];
+ readonly onToggle: (id: string) => void;
+}): JSX.Element {
+ return (
+
+ {items.map((item) => (
+
+ onToggle(item.id)}
+ />
+
+ {item.label}
+
+ {item.legalRef}
+ {item.hint ? ` â ${item.hint}` : ''}
+
+
+
+ ))}
+
+ );
+}
+
+/** Mehrstufiger Bewertungs-Wizard: erfasst ein KI-System und klassifiziert es. */
+export function Wizard({ existing, onSave, onCancel }: WizardProps): JSX.Element {
+ const [step, setStep] = useState(0);
+ const [draft, setDraft] = useState(() => initialDraft(existing));
+
+ const isAISystem = draft.defCriteria.length === CONTENT_PACK.aiDefinitionCriteria.length;
+
+ const answers: AssessmentAnswers = useMemo(
+ () => ({
+ isAISystem,
+ role: draft.role,
+ isGPAIModel: draft.isGPAIModel,
+ prohibitedPractices: draft.prohibitedPractices,
+ annexIIICategories: draft.annexIIICategories,
+ art63Exception: draft.art63Exception,
+ involvesProfiling: draft.involvesProfiling,
+ isAnnexISafetyComponent: draft.isAnnexISafetyComponent,
+ transparencyTriggers: draft.transparencyTriggers,
+ }),
+ [draft, isAISystem],
+ );
+
+ const classification = useMemo(() => classify(answers, CONTENT_PACK), [answers]);
+
+ const canNext = step !== 0 || draft.name.trim().length > 0;
+
+ const save = (): void => {
+ const now = new Date().toISOString();
+ onSave({
+ id: existing?.id ?? crypto.randomUUID(),
+ name: draft.name.trim(),
+ purpose: draft.purpose.trim(),
+ vendor: draft.vendor.trim(),
+ owner: draft.owner.trim(),
+ createdAt: existing?.createdAt ?? now,
+ updatedAt: now,
+ answers,
+ classification,
+ obligationStatus: existing?.obligationStatus ?? {},
+ });
+ };
+
+ return (
+
+
{existing ? `Neubewertung: ${existing.name}` : 'Neues KI-System bewerten'}
+
Beantworten Sie die Fragen â die Risikoklasse wird automatisch nach der Systematik des AI Act ermittelt.
+
+
+ {STEPS.map((label, i) => (
+
+ {i + 1}. {label}
+
+ ))}
+
+
+
+ {step === 0 && (
+ <>
+
+ Name des Systems *
+ setDraft({ ...draft, name: e.target.value })}
+ />
+
+
+ Zweckbestimmung
+
+
+ Hersteller / Anbieter
+ setDraft({ ...draft, vendor: e.target.value })} />
+
+
+ Verantwortliche Person (intern)
+ setDraft({ ...draft, owner: e.target.value })} />
+
+
+ Rolle Ihres Unternehmens
+ setDraft({ ...draft, role: e.target.value as Role })}>
+ {(Object.keys(ROLE_LABELS) as Role[]).map((r) => (
+
+ {ROLE_LABELS[r]}
+
+ ))}
+
+
+ Anbieter = entwickelt/vertreibt das System unter eigenem Namen. Betreiber = setzt ein fremdes System ein (hÀufigster KMU-Fall).
+
+
+ >
+ )}
+
+ {step === 1 && (
+ <>
+
ErfĂŒllt das System die KI-Definition (Art. 3 Nr. 1)?
+
Nur wenn alle Kriterien zutreffen, fÀllt das System unter den AI Act.
+
setDraft({ ...draft, defCriteria: toggle(draft.defCriteria, id) })}
+ />
+ {!isAISystem && (
+
+ â ïž Nicht alle Kriterien erfĂŒllt â das System gilt nicht als KI-System, der AI Act ist nicht anwendbar.
+
+ )}
+ >
+ )}
+
+ {step === 2 && (
+ <>
+ Verbotene Praktiken (Art. 5)
+ Trifft einer dieser Punkte zu, ist der Einsatz seit 2. Februar 2025 verboten.
+ setDraft({ ...draft, prohibitedPractices: toggle(draft.prohibitedPractices, id) })}
+ />
+ >
+ )}
+
+ {step === 3 && (
+ <>
+ Hochrisiko-Einstufung (Art. 6)
+
+ setDraft({ ...draft, isAnnexISafetyComponent: e.target.checked })}
+ />
+
+ Das System ist Sicherheitsbauteil eines regulierten Produkts (z. B. Medizinprodukt, Maschine, Aufzug) oder selbst ein solches Produkt.
+ Art. 6 Abs. 1, Annex I
+
+
+ Einsatzbereiche nach Annex III
+ setDraft({ ...draft, annexIIICategories: toggle(draft.annexIIICategories, id) })}
+ />
+ {draft.annexIIICategories.length > 0 && (
+ <>
+ Mögliche Ausnahme (Art. 6 Abs. 3)
+
+ setDraft({ ...draft, involvesProfiling: e.target.checked })}
+ />
+
+ Das System fĂŒhrt Profiling natĂŒrlicher Personen durch.
+ Profiling schlieĂt die Ausnahme aus â immer Hochrisiko.
+
+
+
+ setDraft({ ...draft, art63Exception: e.target.checked })}
+ />
+
+ Das System erfĂŒllt nur eine eng begrenzte verfahrenstechnische oder vorbereitende Aufgabe bzw. verbessert lediglich das Ergebnis einer zuvor abgeschlossenen menschlichen TĂ€tigkeit â ohne wesentliches Risiko fĂŒr Gesundheit, Sicherheit oder Grundrechte.
+ Art. 6 Abs. 3 â die EinschĂ€tzung muss dokumentiert werden (Art. 6 Abs. 4).
+
+
+ >
+ )}
+ >
+ )}
+
+ {step === 4 && (
+ <>
+ Transparenzpflichten (Art. 50)
+ setDraft({ ...draft, transparencyTriggers: toggle(draft.transparencyTriggers, id) })}
+ />
+ General-Purpose AI
+
+ setDraft({ ...draft, isGPAIModel: e.target.checked })}
+ />
+
+ Wir stellen ein eigenes GPAI-Modell bereit (z. B. selbst trainiertes oder wesentlich verÀndertes Basismodell).
+ Art. 51 ff. â die bloĂe Nutzung von z. B. GPT/Claude ĂŒber API zĂ€hlt nicht.
+
+
+ >
+ )}
+
+ {step === 5 && (
+ <>
+
+ Ergebnis:
+
+
+ {classification.reasons.map((r) => (
+ {r}
+ ))}
+
+ {classification.gpaiObligations && ZusÀtzlich gelten GPAI-Modellpflichten (Art. 53 ff.).
}
+ {classification.riskClass === 'prohibited' && (
+
+ â ïž Der Einsatz dieses Systems ist nach Art. 5 verboten (BuĂgeld bis 35 Mio. ⏠oder 7 % des weltweiten Jahresumsatzes). Einsatz einstellen und rechtlichen Rat einholen.
+
+ )}
+ >
+ )}
+
+
+
+
+
+ Abbrechen
+
+
+
+ {step > 0 && (
+ setStep(step - 1)}>
+ ZurĂŒck
+
+ )}
+ {step < STEPS.length - 1 && (
+ setStep(isAISystem || step === 0 ? step + 1 : STEPS.length - 1)}
+ >
+ Weiter
+
+ )}
+ {step === STEPS.length - 1 && (
+
+ Speichern
+
+ )}
+
+
+
+ );
+}
diff --git a/ai-act-kompass/src/ui/common.tsx b/ai-act-kompass/src/ui/common.tsx
new file mode 100644
index 0000000..e5aa065
--- /dev/null
+++ b/ai-act-kompass/src/ui/common.tsx
@@ -0,0 +1,45 @@
+import type { RiskClass, Role } from '../engine/types';
+
+/** Deutsche Anzeige-Labels fĂŒr Risikoklassen. */
+export const RISK_LABELS: Readonly> = {
+ 'out-of-scope': 'Nicht anwendbar',
+ prohibited: 'Verboten',
+ high: 'Hochrisiko',
+ limited: 'Begrenztes Risiko',
+ minimal: 'Minimales Risiko',
+};
+
+/** Deutsche Anzeige-Labels fĂŒr Rollen. */
+export const ROLE_LABELS: Readonly> = {
+ provider: 'Anbieter',
+ deployer: 'Betreiber',
+ importer: 'EinfĂŒhrer',
+ distributor: 'HĂ€ndler',
+};
+
+/** Farbiges Badge fĂŒr die Risikoklasse eines Systems. */
+export function RiskBadge({ risk }: { readonly risk: RiskClass }): JSX.Element {
+ return {RISK_LABELS[risk]} ;
+}
+
+/**
+ * Löst einen Browser-Download fĂŒr generierten Text aus.
+ *
+ * @param filename - Zieldateiname
+ * @param content - Dateiinhalt
+ * @param mime - MIME-Type (Default: Markdown)
+ */
+export function downloadText(filename: string, content: string, mime = 'text/markdown'): void {
+ const blob = new Blob([content], { type: `${mime};charset=utf-8` });
+ const url = URL.createObjectURL(blob);
+ const a = document.createElement('a');
+ a.href = url;
+ a.download = filename;
+ a.click();
+ URL.revokeObjectURL(url);
+}
+
+/** Heutiges Datum im ISO-Format (YYYY-MM-DD). */
+export function todayISO(): string {
+ return new Date().toISOString().slice(0, 10);
+}
diff --git a/ai-act-kompass/tsconfig.json b/ai-act-kompass/tsconfig.json
new file mode 100644
index 0000000..db1188e
--- /dev/null
+++ b/ai-act-kompass/tsconfig.json
@@ -0,0 +1,21 @@
+{
+ "compilerOptions": {
+ "target": "ES2022",
+ "lib": ["ES2022", "DOM", "DOM.Iterable"],
+ "module": "ESNext",
+ "moduleResolution": "bundler",
+ "jsx": "react-jsx",
+ "strict": true,
+ "noUnusedLocals": true,
+ "noUnusedParameters": true,
+ "noFallthroughCasesInSwitch": true,
+ "noUncheckedIndexedAccess": true,
+ "exactOptionalPropertyTypes": true,
+ "skipLibCheck": true,
+ "isolatedModules": true,
+ "resolveJsonModule": true,
+ "noEmit": true,
+ "types": ["vite/client"]
+ },
+ "include": ["src"]
+}
diff --git a/ai-act-kompass/vite.config.ts b/ai-act-kompass/vite.config.ts
new file mode 100644
index 0000000..eeb1ce4
--- /dev/null
+++ b/ai-act-kompass/vite.config.ts
@@ -0,0 +1,15 @@
+import { defineConfig } from 'vitest/config';
+import react from '@vitejs/plugin-react';
+
+export default defineConfig({
+ plugins: [react()],
+ base: './',
+ build: {
+ outDir: 'dist',
+ sourcemap: false,
+ },
+ test: {
+ environment: 'node',
+ include: ['src/**/*.test.ts'],
+ },
+});