From 1b9e60eef4f2a050395296ff4fe9b1fbb6bf6029 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=7BAI=7Df=20D=2E=20M=C3=BCller?= Date: Wed, 11 Feb 2026 20:37:14 +0100 Subject: [PATCH 1/5] chore: set up ESLint + Prettier for JS/JSX ESLint 9 with flat config, React Hooks plugin, React Refresh plugin, and Prettier integration. All source files formatted. Co-Authored-By: Claude Opus 4.6 --- .prettierrc | 7 + eslint.config.js | 29 + package-lock.json | 1201 ++++++++++++++++++++++++++- package.json | 7 + src/components/DocSidebar.jsx | 34 +- src/components/MitigationCard.jsx | 8 +- src/components/RadarChart.jsx | 44 +- src/components/RiskRadar.jsx | 98 ++- src/components/RiskRadar.module.css | 6 +- src/i18n.js | 424 ++++++++-- src/index.css | 7 +- src/main.jsx | 2 +- 12 files changed, 1719 insertions(+), 148 deletions(-) create mode 100644 .prettierrc create mode 100644 eslint.config.js diff --git a/.prettierrc b/.prettierrc new file mode 100644 index 0000000..388f854 --- /dev/null +++ b/.prettierrc @@ -0,0 +1,7 @@ +{ + "semi": true, + "singleQuote": false, + "trailingComma": "all", + "printWidth": 120, + "tabWidth": 2 +} diff --git a/eslint.config.js b/eslint.config.js new file mode 100644 index 0000000..487878c --- /dev/null +++ b/eslint.config.js @@ -0,0 +1,29 @@ +import js from "@eslint/js"; +import globals from "globals"; +import reactHooks from "eslint-plugin-react-hooks"; +import reactRefresh from "eslint-plugin-react-refresh"; +import prettier from "eslint-config-prettier"; + +export default [ + { ignores: ["dist/"] }, + js.configs.recommended, + { + files: ["**/*.{js,jsx}"], + languageOptions: { + ecmaVersion: 2024, + sourceType: "module", + globals: { ...globals.browser }, + parserOptions: { ecmaFeatures: { jsx: true } }, + }, + plugins: { + "react-hooks": reactHooks, + "react-refresh": reactRefresh, + }, + rules: { + ...reactHooks.configs.recommended.rules, + "react-refresh/only-export-components": ["warn", { allowConstantExport: true }], + "no-unused-vars": ["warn", { argsIgnorePattern: "^_", varsIgnorePattern: "^[A-Z]" }], + }, + }, + prettier, +]; diff --git a/package-lock.json b/package-lock.json index 36dc358..4fa66e9 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "vibe-coding-risk-radar", - "version": "1.0.0", + "version": "1.4.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "vibe-coding-risk-radar", - "version": "1.0.0", + "version": "1.4.0", "license": "MIT", "dependencies": { "@asciidoctor/core": "^3.0.4", @@ -14,7 +14,14 @@ "react-dom": "^18.3.1" }, "devDependencies": { + "@eslint/js": "^9.39.2", "@vitejs/plugin-react": "^4.3.4", + "eslint": "^9.39.2", + "eslint-config-prettier": "^10.1.8", + "eslint-plugin-react-hooks": "^5.2.0", + "eslint-plugin-react-refresh": "^0.4.26", + "globals": "^17.3.0", + "prettier": "^3.8.1", "vite": "^6.0.0" } }, @@ -769,6 +776,263 @@ "node": ">=18" } }, + "node_modules/@eslint-community/eslint-utils": { + "version": "4.9.1", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.9.1.tgz", + "integrity": "sha512-phrYmNiYppR7znFEdqgfWHXR6NCkZEK7hwWDHZUjit/2/U0r6XvkDl0SYnoM51Hq7FhCGdLDT6zxCCOY1hexsQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "eslint-visitor-keys": "^3.4.3" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" + } + }, + "node_modules/@eslint-community/eslint-utils/node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint-community/regexpp": { + "version": "4.12.2", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.2.tgz", + "integrity": "sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + } + }, + "node_modules/@eslint/config-array": { + "version": "0.21.1", + "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.21.1.tgz", + "integrity": "sha512-aw1gNayWpdI/jSYVgzN5pL0cfzU02GT3NBpeT/DXbx1/1x7ZKxFPd9bwrzygx/qiwIQiJ1sw/zD8qY/kRvlGHA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/object-schema": "^2.1.7", + "debug": "^4.3.1", + "minimatch": "^3.1.2" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/config-array/node_modules/brace-expansion": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/@eslint/config-array/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/@eslint/config-helpers": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.4.2.tgz", + "integrity": "sha512-gBrxN88gOIf3R7ja5K9slwNayVcZgK6SOUORm2uBzTeIEfeVaIhOpCtTox3P6R7o2jLFwLFTLnC7kU/RGcYEgw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/core": "^0.17.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/core": { + "version": "0.17.0", + "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.17.0.tgz", + "integrity": "sha512-yL/sLrpmtDaFEiUj1osRP4TI2MDz1AddJL+jZ7KSqvBuliN4xqYY54IfdN8qD8Toa6g1iloph1fxQNkjOxrrpQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@types/json-schema": "^7.0.15" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/eslintrc": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.3.3.tgz", + "integrity": "sha512-Kr+LPIUVKz2qkx1HAMH8q1q6azbqBAsXJUxBl/ODDuVPX45Z9DfwB8tPjTi6nNZ8BuM3nbJxC5zCAg5elnBUTQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^10.0.1", + "globals": "^14.0.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.1", + "minimatch": "^3.1.2", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint/eslintrc/node_modules/brace-expansion": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/@eslint/eslintrc/node_modules/globals": { + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz", + "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@eslint/eslintrc/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/@eslint/js": { + "version": "9.39.2", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.39.2.tgz", + "integrity": "sha512-q1mjIoW1VX4IvSocvM/vbTiveKC4k9eLrajNEuSsmjymSDEbpGddtpfOoN7YGAqBK3NG+uqo8ia4PDTt8buCYA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://eslint.org/donate" + } + }, + "node_modules/@eslint/object-schema": { + "version": "2.1.7", + "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.7.tgz", + "integrity": "sha512-VtAOaymWVfZcmZbp6E2mympDIHvyjXs/12LqWYjVw6qjrfF+VK+fyG33kChz3nnK+SU5/NeHOqrTEHS8sXO3OA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/plugin-kit": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.4.1.tgz", + "integrity": "sha512-43/qtrDUokr7LJqoF2c3+RInu/t4zfrpYdoSDfYyhg52rwLV6TnOvdG4fXm7IkSB3wErkcmJS9iEhjVtOSEjjA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/core": "^0.17.0", + "levn": "^0.4.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@humanfs/core": { + "version": "0.19.1", + "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz", + "integrity": "sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanfs/node": { + "version": "0.16.7", + "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.7.tgz", + "integrity": "sha512-/zUx+yOsIrG4Y43Eh2peDeKCxlRt/gET6aHfaKpuq267qXdYDFViVHfMaLyygZOnl0kGWxFIgsBy8QFuTLUXEQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@humanfs/core": "^0.19.1", + "@humanwhocodes/retry": "^0.4.0" + }, + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/retry": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.3.tgz", + "integrity": "sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, "node_modules/@jridgewell/gen-mapping": { "version": "0.3.13", "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", @@ -1228,6 +1492,13 @@ "dev": true, "license": "MIT" }, + "node_modules/@types/json-schema": { + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", + "dev": true, + "license": "MIT" + }, "node_modules/@vitejs/plugin-react": { "version": "4.7.0", "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-4.7.0.tgz", @@ -1249,6 +1520,69 @@ "vite": "^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0" } }, + "node_modules/acorn": { + "version": "8.15.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz", + "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", + "dev": true, + "license": "MIT", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true, + "license": "Python-2.0" + }, "node_modules/balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", @@ -1308,6 +1642,16 @@ "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" } }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, "node_modules/caniuse-lite": { "version": "1.0.30001769", "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001769.tgz", @@ -1329,6 +1673,50 @@ ], "license": "CC-BY-4.0" }, + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true, + "license": "MIT" + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true, + "license": "MIT" + }, "node_modules/convert-source-map": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", @@ -1336,6 +1724,21 @@ "dev": true, "license": "MIT" }, + "node_modules/cross-spawn": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, "node_modules/debug": { "version": "4.4.3", "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", @@ -1354,6 +1757,13 @@ } } }, + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true, + "license": "MIT" + }, "node_modules/electron-to-chromium": { "version": "1.5.286", "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.286.tgz", @@ -1413,48 +1823,350 @@ "node": ">=6" } }, - "node_modules/fdir": { - "version": "6.5.0", - "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", - "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", "dev": true, "license": "MIT", "engines": { - "node": ">=12.0.0" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint": { + "version": "9.39.2", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.39.2.tgz", + "integrity": "sha512-LEyamqS7W5HB3ujJyvi0HQK/dtVINZvd5mAAp9eT5S/ujByGjiZLCzPcHVzuXbpJDJF/cxwHlfceVUDZ2lnSTw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.8.0", + "@eslint-community/regexpp": "^4.12.1", + "@eslint/config-array": "^0.21.1", + "@eslint/config-helpers": "^0.4.2", + "@eslint/core": "^0.17.0", + "@eslint/eslintrc": "^3.3.1", + "@eslint/js": "9.39.2", + "@eslint/plugin-kit": "^0.4.1", + "@humanfs/node": "^0.16.6", + "@humanwhocodes/module-importer": "^1.0.1", + "@humanwhocodes/retry": "^0.4.2", + "@types/estree": "^1.0.6", + "ajv": "^6.12.4", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.6", + "debug": "^4.3.2", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^8.4.0", + "eslint-visitor-keys": "^4.2.1", + "espree": "^10.4.0", + "esquery": "^1.5.0", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^8.0.0", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "ignore": "^5.2.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.2", + "natural-compare": "^1.4.0", + "optionator": "^0.9.3" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://eslint.org/donate" }, "peerDependencies": { - "picomatch": "^3 || ^4" + "jiti": "*" }, "peerDependenciesMeta": { - "picomatch": { + "jiti": { "optional": true } } }, - "node_modules/fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", - "license": "ISC" - }, - "node_modules/fsevents": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", - "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "node_modules/eslint-config-prettier": { + "version": "10.1.8", + "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-10.1.8.tgz", + "integrity": "sha512-82GZUjRS0p/jganf6q1rEO25VSoHH0hKPCTrgillPjdI/3bgBhAE1QzHrHTizjpRvy6pGAvKjDJtk2pF9NDq8w==", "dev": true, - "hasInstallScript": true, "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + "bin": { + "eslint-config-prettier": "bin/cli.js" + }, + "funding": { + "url": "https://opencollective.com/eslint-config-prettier" + }, + "peerDependencies": { + "eslint": ">=7.0.0" } }, - "node_modules/gensync": { - "version": "1.0.0-beta.2", - "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "node_modules/eslint-plugin-react-hooks": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-5.2.0.tgz", + "integrity": "sha512-+f15FfK64YQwZdJNELETdn5ibXEUQmW1DZL6KXhNnc2heoy/sg9VJJeT7n8TlMWouzWqSWavFkIhHyIbIAEapg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "eslint": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0" + } + }, + "node_modules/eslint-plugin-react-refresh": { + "version": "0.4.26", + "resolved": "https://registry.npmjs.org/eslint-plugin-react-refresh/-/eslint-plugin-react-refresh-0.4.26.tgz", + "integrity": "sha512-1RETEylht2O6FM/MvgnyvT+8K21wLqDNg4qD51Zj3guhjt433XbnnkVttHMyaVyAFD03QSV4LPS5iE3VQmO7XQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "eslint": ">=8.40" + } + }, + "node_modules/eslint-scope": { + "version": "8.4.0", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.4.0.tgz", + "integrity": "sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz", + "integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint/node_modules/brace-expansion": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/eslint/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/espree": { + "version": "10.4.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-10.4.0.tgz", + "integrity": "sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "acorn": "^8.15.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^4.2.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/esquery": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.7.0.tgz", + "integrity": "sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "dev": true, + "license": "MIT" + }, + "node_modules/fdir": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/file-entry-cache": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", + "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "flat-cache": "^4.0.0" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "license": "MIT", + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/flat-cache": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz", + "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==", + "dev": true, + "license": "MIT", + "dependencies": { + "flatted": "^3.2.9", + "keyv": "^4.5.4" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/flatted": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.3.tgz", + "integrity": "sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==", + "dev": true, + "license": "ISC" + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "license": "ISC" + }, + "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", @@ -1482,6 +2194,79 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/globals": { + "version": "17.3.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-17.3.0.tgz", + "integrity": "sha512-yMqGUQVVCkD4tqjOJf3TnrvaaHDMYp4VlUSObbkIiuCPe/ofdMBFIAcBbCSRFWOnos6qRiTVStDwqPLUclaxIw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/ignore": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/import-fresh": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz", + "integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8.19" + } + }, "node_modules/inflight": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", @@ -1499,12 +2284,55 @@ "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", "license": "ISC" }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true, + "license": "ISC" + }, "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/js-yaml": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz", + "integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==", + "dev": true, + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, "node_modules/jsesc": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", @@ -1518,6 +2346,27 @@ "node": ">=6" } }, + "node_modules/json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "dev": true, + "license": "MIT" + }, "node_modules/json5": { "version": "2.2.3", "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", @@ -1531,6 +2380,53 @@ "node": ">=6" } }, + "node_modules/keyv": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "dev": true, + "license": "MIT", + "dependencies": { + "json-buffer": "3.0.1" + } + }, + "node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true, + "license": "MIT" + }, "node_modules/loose-envify": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", @@ -1591,6 +2487,13 @@ "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" } }, + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true, + "license": "MIT" + }, "node_modules/node-releases": { "version": "2.0.27", "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.27.tgz", @@ -1607,6 +2510,89 @@ "wrappy": "1" } }, + "node_modules/optionator": { + "version": "0.9.4", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", + "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", + "dev": true, + "license": "MIT", + "dependencies": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.5" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "license": "MIT", + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, "node_modules/picocolors": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", @@ -1656,6 +2642,42 @@ "node": "^10 || ^12 || >=14" } }, + "node_modules/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/prettier": { + "version": "3.8.1", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.8.1.tgz", + "integrity": "sha512-UOnG6LftzbdaHZcKoPFtOcCKztrQ57WkHDeRD9t/PTQtmT0NHSeWWepj6pS0z/N7+08BHFDQVUrfmfMRcZwbMg==", + "dev": true, + "license": "MIT", + "bin": { + "prettier": "bin/prettier.cjs" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, "node_modules/react": { "version": "18.3.1", "resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz", @@ -1691,6 +2713,16 @@ "node": ">=0.10.0" } }, + "node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, "node_modules/rollup": { "version": "4.57.1", "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.57.1.tgz", @@ -1755,6 +2787,29 @@ "semver": "bin/semver.js" } }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "license": "MIT", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, "node_modules/source-map-js": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", @@ -1765,6 +2820,32 @@ "node": ">=0.10.0" } }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/tinyglobby": { "version": "0.2.15", "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz", @@ -1782,6 +2863,19 @@ "url": "https://github.com/sponsors/SuperchupuDev" } }, + "node_modules/type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, "node_modules/unxhr": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/unxhr/-/unxhr-1.2.0.tgz", @@ -1822,6 +2916,16 @@ "browserslist": ">= 4.21.0" } }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "punycode": "^2.1.0" + } + }, "node_modules/vite": { "version": "6.4.1", "resolved": "https://registry.npmjs.org/vite/-/vite-6.4.1.tgz", @@ -1897,6 +3001,32 @@ } } }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/word-wrap": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", + "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", @@ -1909,6 +3039,19 @@ "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", "dev": true, "license": "ISC" + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } } } } diff --git a/package.json b/package.json index 482c2fe..64181ac 100644 --- a/package.json +++ b/package.json @@ -15,7 +15,14 @@ "react-dom": "^18.3.1" }, "devDependencies": { + "@eslint/js": "^9.39.2", "@vitejs/plugin-react": "^4.3.4", + "eslint": "^9.39.2", + "eslint-config-prettier": "^10.1.8", + "eslint-plugin-react-hooks": "^5.2.0", + "eslint-plugin-react-refresh": "^0.4.26", + "globals": "^17.3.0", + "prettier": "^3.8.1", "vite": "^6.0.0" }, "license": "MIT" diff --git a/src/components/DocSidebar.jsx b/src/components/DocSidebar.jsx index 3bbf294..4b1cc31 100644 --- a/src/components/DocSidebar.jsx +++ b/src/components/DocSidebar.jsx @@ -14,7 +14,9 @@ const ADOC_SIDEBAR_STYLES = ` export default function DocSidebar({ docs, open, onClose }) { const ref = useRef(null); - useEffect(() => { if (open && ref.current) ref.current.scrollTop = 0; }, [open]); + useEffect(() => { + if (open && ref.current) ref.current.scrollTop = 0; + }, [open]); useEffect(() => { if (open && ref.current) { ref.current.querySelectorAll(".adoc-content a").forEach((a) => { @@ -24,35 +26,33 @@ export default function DocSidebar({ docs, open, onClose }) { } }); - const rendered = useMemo(() => - docs.sections.map((sec) => ({ - ...sec, - html: adoc.convert(sec.content, { safe: "safe", attributes: { showtitle: false } }), - })), - [docs.sections] + const rendered = useMemo( + () => + docs.sections.map((sec) => ({ + ...sec, + html: adoc.convert(sec.content, { safe: "safe", attributes: { showtitle: false } }), + })), + [docs.sections], ); return ( -
+
{open && (

{docs.title}

- +
{rendered.map((sec) => (

- {sec.id === "disclaimer" ? "\u26A0\uFE0F " : ""}{sec.title} + {sec.id === "disclaimer" ? "\u26A0\uFE0F " : ""} + {sec.title}

-
+
))}
diff --git a/src/components/MitigationCard.jsx b/src/components/MitigationCard.jsx index 430f356..435d0b9 100644 --- a/src/components/MitigationCard.jsx +++ b/src/components/MitigationCard.jsx @@ -20,8 +20,12 @@ export default function MitigationCard({ group, active, accent, t }) {
{group.icon}
-
{group.title}
-
{group.measures.length} {group.measures.length !== 1 ? t.measures : t.measure}
+
+ {group.title} +
+
+ {group.measures.length} {group.measures.length !== 1 ? t.measures : t.measure} +
{active && } diff --git a/src/components/RadarChart.jsx b/src/components/RadarChart.jsx index bcb2f62..f0eea72 100644 --- a/src/components/RadarChart.jsx +++ b/src/components/RadarChart.jsx @@ -3,7 +3,12 @@ import { getTierIndex, polarToCartesian } from "../utils.js"; import styles from "./RadarChart.module.css"; export default function RadarChart({ values, dimensions, size = 320 }) { - const cx = size / 2, cy = size / 2, maxR = size / 2 - 48, levels = 5, n = dimensions.length, step = 360 / n; + const cx = size / 2, + cy = size / 2, + maxR = size / 2 - 48, + levels = 5, + n = dimensions.length, + step = 360 / n; const ti = getTierIndex(values); const tc = TIER_BG[ti]; @@ -12,7 +17,15 @@ export default function RadarChart({ values, dimensions, size = 320 }) { {[1, 2, 3, 4, 5].map((l) => { const r = (maxR / levels) * l; const pts = Array.from({ length: n }, (_, i) => polarToCartesian(cx, cy, r, i * step)); - return `${p.x},${p.y}`).join(" ")} fill="none" stroke={l === 5 ? "var(--grid-line-outer)" : "var(--grid-line)"} strokeWidth={l === 5 ? 1.5 : 0.7} />; + return ( + `${p.x},${p.y}`).join(" ")} + fill="none" + stroke={l === 5 ? "var(--grid-line-outer)" : "var(--grid-line)"} + strokeWidth={l === 5 ? 1.5 : 0.7} + /> + ); })} {dimensions.map((_, i) => { const p = polarToCartesian(cx, cy, maxR, i * step); @@ -22,14 +35,35 @@ export default function RadarChart({ values, dimensions, size = 320 }) { const pts = dimensions.map((d, i) => polarToCartesian(cx, cy, (maxR / levels) * (values[d.key] + 1), i * step)); return ( <> - `${p.x},${p.y}`).join(" ")} fill={tc} fillOpacity={0.25} stroke={tc} strokeWidth={2.5} /> - {pts.map((p, i) => )} + `${p.x},${p.y}`).join(" ")} + fill={tc} + fillOpacity={0.25} + stroke={tc} + strokeWidth={2.5} + /> + {pts.map((p, i) => ( + + ))} ); })()} {dimensions.map((d, i) => { const lp = polarToCartesian(cx, cy, maxR + 26, i * step); - return {d.shortLabel}; + return ( + + {d.shortLabel} + + ); })} ); diff --git a/src/components/RiskRadar.jsx b/src/components/RiskRadar.jsx index d5cc740..fb9ad1f 100644 --- a/src/components/RiskRadar.jsx +++ b/src/components/RiskRadar.jsx @@ -14,7 +14,7 @@ export default function RiskRadar() { if (saved === "de" || saved === "en") return saved; return detectBrowserLanguage(); }); - const { theme, setTheme, isDark } = useTheme(); + const { setTheme, isDark } = useTheme(); const [docsOpen, setDocsOpen] = useState(false); const [values, setValues] = useState({ codeType: 0, language: 1, deployment: 0, data: 0, blastRadius: 0 }); const t = T[lang]; @@ -43,7 +43,11 @@ export default function RiskRadar() { @@ -75,13 +79,19 @@ export default function RiskRadar() {
-
+
+ +
{/* Tier badge */}
- {ti + 1} + + {ti + 1} +
-
{tier.label}
+
+ {tier.label} +
{tier.desc}
@@ -95,11 +105,23 @@ export default function RiskRadar() {
{dim.label} - {dim.levels[v]} + + {dim.levels[v]} +
- set(dim.key, parseInt(e.target.value))} className={styles.slider} style={{ accentColor: sc }} /> + set(dim.key, parseInt(e.target.value))} + className={styles.slider} + style={{ accentColor: sc }} + />
- {t.low}{t.high} + {t.low} + {t.high}
); @@ -110,7 +132,9 @@ export default function RiskRadar() {

{t.mitigationHeading}

- {activeCount} {t.active} + + {activeCount} {t.active} +
{Object.entries(TYPE_COLORS).map(([key, c]) => ( @@ -121,20 +145,66 @@ export default function RiskRadar() { ))}
- {t.cumulative}: {t.cumulativeNote(ti, t.mitigations[ti].title)} + {t.cumulative}:{" "} + {t.cumulativeNote(ti, t.mitigations[ti].title)}
- {t.mitigations.map((g) => )} + {t.mitigations.map((g) => ( + + ))}
- -
{t.footer.madeBy} Ralf D. Müller
+
+ v{VERSION} ·{" "} + + {t.footer.github} + {" "} + ·{" "} + + {t.footer.fullDocs} + {" "} + ·{" "} + + {t.footer.feedback} + +
+
+ {t.footer.madeBy}{" "} + + Ralf D. Müller + +
- + 💬 {t.footer.feedback} diff --git a/src/components/RiskRadar.module.css b/src/components/RiskRadar.module.css index 8fd2e58..dd5ec2f 100644 --- a/src/components/RiskRadar.module.css +++ b/src/components/RiskRadar.module.css @@ -1,5 +1,5 @@ .app { - font-family: 'Inter', system-ui, sans-serif; + font-family: "Inter", system-ui, sans-serif; background: var(--bg-main); color: var(--text-primary); min-height: 100vh; @@ -230,7 +230,7 @@ font-weight: 600; color: var(--text-secondary); cursor: pointer; - box-shadow: 0 2px 8px rgba(0,0,0,0.15); + box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15); transition: all 0.2s; text-decoration: none; z-index: 50; @@ -239,7 +239,7 @@ .fab:hover { color: var(--text-heading); border-color: var(--text-secondary); - box-shadow: 0 4px 16px rgba(0,0,0,0.2); + box-shadow: 0 4px 16px rgba(0, 0, 0, 0.2); } .fabIcon { diff --git a/src/i18n.js b/src/i18n.js index 4d15586..f4a130a 100644 --- a/src/i18n.js +++ b/src/i18n.js @@ -24,24 +24,64 @@ const T = { }, dimensions: [ { - key: "codeType", label: "Code-Typ", shortLabel: "Code", - levels: ["UI / CSS / Doku", "Build-Scripts / Tests", "Business-Logik", "API / DB-Queries", "Auth / Security / Crypto"], + key: "codeType", + label: "Code-Typ", + shortLabel: "Code", + levels: [ + "UI / CSS / Doku", + "Build-Scripts / Tests", + "Business-Logik", + "API / DB-Queries", + "Auth / Security / Crypto", + ], }, { - key: "language", label: "Sprachsicherheit", shortLabel: "Sprache", - levels: ["Statisch + Memory-safe (Rust)", "Statisch typisiert (Java, Go, TS)", "Dynamisch typisiert (Python, JS)", "Memory-unsafe managed (C#/unsafe)", "Memory-unsafe (C, C++)"], + key: "language", + label: "Sprachsicherheit", + shortLabel: "Sprache", + levels: [ + "Statisch + Memory-safe (Rust)", + "Statisch typisiert (Java, Go, TS)", + "Dynamisch typisiert (Python, JS)", + "Memory-unsafe managed (C#/unsafe)", + "Memory-unsafe (C, C++)", + ], }, { - key: "deployment", label: "Deployment-Kontext", shortLabel: "Deploy", - levels: ["Persönlich / Prototyp", "Internes Tool", "Public-facing App", "Reguliertes System", "Safety-critical (Avionik etc.)"], + key: "deployment", + label: "Deployment-Kontext", + shortLabel: "Deploy", + levels: [ + "Persönlich / Prototyp", + "Internes Tool", + "Public-facing App", + "Reguliertes System", + "Safety-critical (Avionik etc.)", + ], }, { - key: "data", label: "Datensensibilität", shortLabel: "Daten", - levels: ["Öffentliche Daten", "Interne Geschäftsdaten", "Allg. PII (Name, E-Mail)", "Sensible PII (SSN, Biometrie)", "PHI / PCI (HIPAA, Kreditkarten)"], + key: "data", + label: "Datensensibilität", + shortLabel: "Daten", + levels: [ + "Öffentliche Daten", + "Interne Geschäftsdaten", + "Allg. PII (Name, E-Mail)", + "Sensible PII (SSN, Biometrie)", + "PHI / PCI (HIPAA, Kreditkarten)", + ], }, { - key: "blastRadius", label: "Blast Radius", shortLabel: "Blast", - levels: ["Kosmetisch / Tech Debt", "Performance / DoS", "Datenverlust (wiederherstellbar)", "Systemischer Breach", "Safety (Leib & Leben)"], + key: "blastRadius", + label: "Blast Radius", + shortLabel: "Blast", + levels: [ + "Kosmetisch / Tech Debt", + "Performance / DoS", + "Datenverlust (wiederherstellbar)", + "Systemischer Breach", + "Safety (Leib & Leben)", + ], }, ], tiers: [ @@ -60,45 +100,141 @@ const T = { ], mitigations: [ { - tier: 1, title: "Automatische Gates (immer aktiv)", icon: "⚙️", + tier: 1, + title: "Automatische Gates (immer aktiv)", + icon: "⚙️", measures: [ - { name: "Linter & Formatter", desc: "ESLint, Prettier, Ruff — schnelles Feedback, null Aufwand", type: "deterministic" }, - { name: "Type Checking", desc: "TypeScript strict, mypy — ganze Fehlerklassen ausgeschlossen", type: "deterministic" }, - { name: "Pre-Commit Hooks", desc: "Secrets-Scanning (GitGuardian), Lint, Format vor jedem Commit", type: "deterministic" }, - { name: "Dependency Check", desc: "npm audit, pip-audit — bekannte CVEs in Dependencies blocken", type: "deterministic" }, - { name: "CI Build & Unit Tests", desc: "Grüner Build als Merge-Bedingung — fängt Regressionen ab", type: "deterministic" }, + { + name: "Linter & Formatter", + desc: "ESLint, Prettier, Ruff — schnelles Feedback, null Aufwand", + type: "deterministic", + }, + { + name: "Type Checking", + desc: "TypeScript strict, mypy — ganze Fehlerklassen ausgeschlossen", + type: "deterministic", + }, + { + name: "Pre-Commit Hooks", + desc: "Secrets-Scanning (GitGuardian), Lint, Format vor jedem Commit", + type: "deterministic", + }, + { + name: "Dependency Check", + desc: "npm audit, pip-audit — bekannte CVEs in Dependencies blocken", + type: "deterministic", + }, + { + name: "CI Build & Unit Tests", + desc: "Grüner Build als Merge-Bedingung — fängt Regressionen ab", + type: "deterministic", + }, ], }, { - tier: 2, title: "Erweiterte Absicherung", icon: "🔍", + tier: 2, + title: "Erweiterte Absicherung", + icon: "🔍", measures: [ - { name: "SAST (Semgrep, CodeQL)", desc: "Statische Analyse auf Vulnerability-Patterns — als CI-Gate", type: "deterministic" }, - { name: "AI Code Review", desc: "CodeRabbit, Copilot Review — unabhängig vom generierenden LLM", type: "probabilistic" }, - { name: "Property-Based Tests", desc: "Hypothesis, fast-check — 81% Bug-Detection bei Edge Cases", type: "probabilistic" }, - { name: "SonarQube Quality Gate", desc: "Coverage ≥70%, 0 Critical Vulns, 0 Blocker als Merge-Gate", type: "deterministic" }, - { name: "Stichproben-Review", desc: "Mensch reviewt ~20% der PRs (rotierend, risiko-gewichtet)", type: "organizational" }, + { + name: "SAST (Semgrep, CodeQL)", + desc: "Statische Analyse auf Vulnerability-Patterns — als CI-Gate", + type: "deterministic", + }, + { + name: "AI Code Review", + desc: "CodeRabbit, Copilot Review — unabhängig vom generierenden LLM", + type: "probabilistic", + }, + { + name: "Property-Based Tests", + desc: "Hypothesis, fast-check — 81% Bug-Detection bei Edge Cases", + type: "probabilistic", + }, + { + name: "SonarQube Quality Gate", + desc: "Coverage ≥70%, 0 Critical Vulns, 0 Blocker als Merge-Gate", + type: "deterministic", + }, + { + name: "Stichproben-Review", + desc: "Mensch reviewt ~20% der PRs (rotierend, risiko-gewichtet)", + type: "organizational", + }, ], }, { - tier: 3, title: "Pflicht-Maßnahmen für hohes Risiko", icon: "🛡️", + tier: 3, + title: "Pflicht-Maßnahmen für hohes Risiko", + icon: "🛡️", measures: [ - { name: "Pflicht Human Review", desc: "Jeder PR mit Auth/PII/Payment wird von Senior Engineer reviewt", type: "organizational" }, - { name: "Sandbox / Isolation", desc: "Firecracker microVM, Deno Sandbox — Schadensbegrenzung bei Exploit", type: "deterministic" }, - { name: "Fuzzing", desc: "Fuzz4All, AFL++ — findet Crashes und Vulns durch zufällige Inputs", type: "probabilistic" }, - { name: "Penetration Testing", desc: "Regelmäßige Security-Audits auf Auth-Flows und API-Endpoints", type: "organizational" }, - { name: "Canary Deployments", desc: "Schrittweiser Rollout mit automatischem Rollback bei Anomalien", type: "deterministic" }, - { name: "PromptBOM / Provenance", desc: "Dokumentation: welches Modell, welcher Prompt, wer hat approved", type: "organizational" }, + { + name: "Pflicht Human Review", + desc: "Jeder PR mit Auth/PII/Payment wird von Senior Engineer reviewt", + type: "organizational", + }, + { + name: "Sandbox / Isolation", + desc: "Firecracker microVM, Deno Sandbox — Schadensbegrenzung bei Exploit", + type: "deterministic", + }, + { + name: "Fuzzing", + desc: "Fuzz4All, AFL++ — findet Crashes und Vulns durch zufällige Inputs", + type: "probabilistic", + }, + { + name: "Penetration Testing", + desc: "Regelmäßige Security-Audits auf Auth-Flows und API-Endpoints", + type: "organizational", + }, + { + name: "Canary Deployments", + desc: "Schrittweiser Rollout mit automatischem Rollback bei Anomalien", + type: "deterministic", + }, + { + name: "PromptBOM / Provenance", + desc: "Dokumentation: welches Modell, welcher Prompt, wer hat approved", + type: "organizational", + }, ], }, { - tier: 4, title: "Kritisch — AI-Einsatz stark einschränken", icon: "🚨", + tier: 4, + title: "Kritisch — AI-Einsatz stark einschränken", + icon: "🚨", measures: [ - { name: "Formale Verifikation", desc: "Dafny, TLA+, SPARK — mathematischer Beweis der Korrektheit", type: "deterministic" }, - { name: "Unabhängige Re-Verifikation", desc: "Separates Team verifiziert Output — analog DO-178C DAL A", type: "organizational" }, - { name: "MC/DC Test Coverage", desc: "Modified Condition/Decision Coverage — Pflicht bei DAL A/B", type: "deterministic" }, - { name: "Contract-Based Design", desc: "Pre/Postconditions + Invarianten — Spec first, dann Generierung", type: "deterministic" }, - { name: "Zertifizierungsprozess", desc: "IEC 61508, DO-178C, ISO 26262 Compliance — kein Shortcut möglich", type: "organizational" }, - { name: "AI nur als Entwurfshilfe", desc: "LLM generiert Vorschlag, Mensch implementiert und verifiziert", type: "organizational" }, + { + name: "Formale Verifikation", + desc: "Dafny, TLA+, SPARK — mathematischer Beweis der Korrektheit", + type: "deterministic", + }, + { + name: "Unabhängige Re-Verifikation", + desc: "Separates Team verifiziert Output — analog DO-178C DAL A", + type: "organizational", + }, + { + name: "MC/DC Test Coverage", + desc: "Modified Condition/Decision Coverage — Pflicht bei DAL A/B", + type: "deterministic", + }, + { + name: "Contract-Based Design", + desc: "Pre/Postconditions + Invarianten — Spec first, dann Generierung", + type: "deterministic", + }, + { + name: "Zertifizierungsprozess", + desc: "IEC 61508, DO-178C, ISO 26262 Compliance — kein Shortcut möglich", + type: "organizational", + }, + { + name: "AI nur als Entwurfshilfe", + desc: "LLM generiert Vorschlag, Mensch implementiert und verifiziert", + type: "organizational", + }, ], }, ], @@ -193,9 +329,9 @@ Dieses Framework bietet eine https://github.com/LLM-Coding/Semantic-Anchors?tab= title: "Claude Code Skills", content: `Dieses Framework bietet zwei https://code.claude.com/docs/en/skills[Claude Code Skills], die direkt in Ihrem Projekt arbeiten: -*\/risk-assess* — Analysiert Ihr Repository automatisch, erkennt Module (Monorepo, Frontend/Backend etc.), scannt Code-Patterns und fragt gezielt nach Dimensionen, die nicht auto-detektiert werden können. Schreibt eine strukturierte Risikobewertung pro Modul in Ihre \`CLAUDE.md\`. +*/risk-assess* — Analysiert Ihr Repository automatisch, erkennt Module (Monorepo, Frontend/Backend etc.), scannt Code-Patterns und fragt gezielt nach Dimensionen, die nicht auto-detektiert werden können. Schreibt eine strukturierte Risikobewertung pro Modul in Ihre \`CLAUDE.md\`. -*\/risk-mitigate* — Liest die Risikobewertung aus \`CLAUDE.md\`, erkennt bereits vorhandene Maßnahmen (Linter, CI, SAST etc.) und hilft fehlende Mitigations Schritt für Schritt umzusetzen — von Tool-Installation bis CI-Konfiguration. +*/risk-mitigate* — Liest die Risikobewertung aus \`CLAUDE.md\`, erkennt bereits vorhandene Maßnahmen (Linter, CI, SAST etc.) und hilft fehlende Mitigations Schritt für Schritt umzusetzen — von Tool-Installation bis CI-Konfiguration. *Installation — Plugin (empfohlen):* @@ -239,24 +375,64 @@ Quellcode der Skills: https://github.com/LLM-Coding/vibe-coding-risk-radar/tree/ }, dimensions: [ { - key: "codeType", label: "Code Type", shortLabel: "Code", - levels: ["UI / CSS / Docs", "Build scripts / Tests", "Business logic", "API / DB queries", "Auth / Security / Crypto"], + key: "codeType", + label: "Code Type", + shortLabel: "Code", + levels: [ + "UI / CSS / Docs", + "Build scripts / Tests", + "Business logic", + "API / DB queries", + "Auth / Security / Crypto", + ], }, { - key: "language", label: "Language Safety", shortLabel: "Lang", - levels: ["Static + Memory-safe (Rust)", "Statically typed (Java, Go, TS)", "Dynamically typed (Python, JS)", "Memory-unsafe managed (C#/unsafe)", "Memory-unsafe (C, C++)"], + key: "language", + label: "Language Safety", + shortLabel: "Lang", + levels: [ + "Static + Memory-safe (Rust)", + "Statically typed (Java, Go, TS)", + "Dynamically typed (Python, JS)", + "Memory-unsafe managed (C#/unsafe)", + "Memory-unsafe (C, C++)", + ], }, { - key: "deployment", label: "Deployment Context", shortLabel: "Deploy", - levels: ["Personal / Prototype", "Internal tool", "Public-facing app", "Regulated system", "Safety-critical (avionics etc.)"], + key: "deployment", + label: "Deployment Context", + shortLabel: "Deploy", + levels: [ + "Personal / Prototype", + "Internal tool", + "Public-facing app", + "Regulated system", + "Safety-critical (avionics etc.)", + ], }, { - key: "data", label: "Data Sensitivity", shortLabel: "Data", - levels: ["Public data", "Internal business data", "General PII (name, email)", "Sensitive PII (SSN, biometrics)", "PHI / PCI (HIPAA, credit cards)"], + key: "data", + label: "Data Sensitivity", + shortLabel: "Data", + levels: [ + "Public data", + "Internal business data", + "General PII (name, email)", + "Sensitive PII (SSN, biometrics)", + "PHI / PCI (HIPAA, credit cards)", + ], }, { - key: "blastRadius", label: "Blast Radius", shortLabel: "Blast", - levels: ["Cosmetic / Tech debt", "Performance / DoS", "Data loss (recoverable)", "Systemic breach", "Safety (life & limb)"], + key: "blastRadius", + label: "Blast Radius", + shortLabel: "Blast", + levels: [ + "Cosmetic / Tech debt", + "Performance / DoS", + "Data loss (recoverable)", + "Systemic breach", + "Safety (life & limb)", + ], }, ], tiers: [ @@ -275,45 +451,141 @@ Quellcode der Skills: https://github.com/LLM-Coding/vibe-coding-risk-radar/tree/ ], mitigations: [ { - tier: 1, title: "Automated Gates (always active)", icon: "⚙️", + tier: 1, + title: "Automated Gates (always active)", + icon: "⚙️", measures: [ - { name: "Linter & Formatter", desc: "ESLint, Prettier, Ruff — instant feedback, zero effort", type: "deterministic" }, - { name: "Type Checking", desc: "TypeScript strict, mypy — entire error classes eliminated", type: "deterministic" }, - { name: "Pre-Commit Hooks", desc: "Secrets scanning (GitGuardian), lint, format before every commit", type: "deterministic" }, - { name: "Dependency Check", desc: "npm audit, pip-audit — block known CVEs in dependencies", type: "deterministic" }, - { name: "CI Build & Unit Tests", desc: "Green build as merge requirement — catches regressions", type: "deterministic" }, + { + name: "Linter & Formatter", + desc: "ESLint, Prettier, Ruff — instant feedback, zero effort", + type: "deterministic", + }, + { + name: "Type Checking", + desc: "TypeScript strict, mypy — entire error classes eliminated", + type: "deterministic", + }, + { + name: "Pre-Commit Hooks", + desc: "Secrets scanning (GitGuardian), lint, format before every commit", + type: "deterministic", + }, + { + name: "Dependency Check", + desc: "npm audit, pip-audit — block known CVEs in dependencies", + type: "deterministic", + }, + { + name: "CI Build & Unit Tests", + desc: "Green build as merge requirement — catches regressions", + type: "deterministic", + }, ], }, { - tier: 2, title: "Extended Assurance", icon: "🔍", + tier: 2, + title: "Extended Assurance", + icon: "🔍", measures: [ - { name: "SAST (Semgrep, CodeQL)", desc: "Static analysis for vulnerability patterns — as CI gate", type: "deterministic" }, - { name: "AI Code Review", desc: "CodeRabbit, Copilot Review — independent from generating LLM", type: "probabilistic" }, - { name: "Property-Based Tests", desc: "Hypothesis, fast-check — 81% bug detection on edge cases", type: "probabilistic" }, - { name: "SonarQube Quality Gate", desc: "Coverage ≥70%, 0 critical vulns, 0 blockers as merge gate", type: "deterministic" }, - { name: "Sampling Review", desc: "Human reviews ~20% of PRs (rotating, risk-weighted)", type: "organizational" }, + { + name: "SAST (Semgrep, CodeQL)", + desc: "Static analysis for vulnerability patterns — as CI gate", + type: "deterministic", + }, + { + name: "AI Code Review", + desc: "CodeRabbit, Copilot Review — independent from generating LLM", + type: "probabilistic", + }, + { + name: "Property-Based Tests", + desc: "Hypothesis, fast-check — 81% bug detection on edge cases", + type: "probabilistic", + }, + { + name: "SonarQube Quality Gate", + desc: "Coverage ≥70%, 0 critical vulns, 0 blockers as merge gate", + type: "deterministic", + }, + { + name: "Sampling Review", + desc: "Human reviews ~20% of PRs (rotating, risk-weighted)", + type: "organizational", + }, ], }, { - tier: 3, title: "Mandatory Measures for High Risk", icon: "🛡️", + tier: 3, + title: "Mandatory Measures for High Risk", + icon: "🛡️", measures: [ - { name: "Mandatory Human Review", desc: "Every PR touching auth/PII/payment reviewed by senior engineer", type: "organizational" }, - { name: "Sandbox / Isolation", desc: "Firecracker microVM, Deno Sandbox — containment on exploit", type: "deterministic" }, - { name: "Fuzzing", desc: "Fuzz4All, AFL++ — finds crashes and vulns via random inputs", type: "probabilistic" }, - { name: "Penetration Testing", desc: "Regular security audits on auth flows and API endpoints", type: "organizational" }, - { name: "Canary Deployments", desc: "Gradual rollout with automatic rollback on anomalies", type: "deterministic" }, - { name: "PromptBOM / Provenance", desc: "Document: which model, which prompt, who approved", type: "organizational" }, + { + name: "Mandatory Human Review", + desc: "Every PR touching auth/PII/payment reviewed by senior engineer", + type: "organizational", + }, + { + name: "Sandbox / Isolation", + desc: "Firecracker microVM, Deno Sandbox — containment on exploit", + type: "deterministic", + }, + { + name: "Fuzzing", + desc: "Fuzz4All, AFL++ — finds crashes and vulns via random inputs", + type: "probabilistic", + }, + { + name: "Penetration Testing", + desc: "Regular security audits on auth flows and API endpoints", + type: "organizational", + }, + { + name: "Canary Deployments", + desc: "Gradual rollout with automatic rollback on anomalies", + type: "deterministic", + }, + { + name: "PromptBOM / Provenance", + desc: "Document: which model, which prompt, who approved", + type: "organizational", + }, ], }, { - tier: 4, title: "Critical — Severely Restrict AI Use", icon: "🚨", + tier: 4, + title: "Critical — Severely Restrict AI Use", + icon: "🚨", measures: [ - { name: "Formal Verification", desc: "Dafny, TLA+, SPARK — mathematical proof of correctness", type: "deterministic" }, - { name: "Independent Re-Verification", desc: "Separate team verifies output — per DO-178C DAL A", type: "organizational" }, - { name: "MC/DC Test Coverage", desc: "Modified Condition/Decision Coverage — required at DAL A/B", type: "deterministic" }, - { name: "Contract-Based Design", desc: "Pre/postconditions + invariants — spec first, then generation", type: "deterministic" }, - { name: "Certification Process", desc: "IEC 61508, DO-178C, ISO 26262 compliance — no shortcut", type: "organizational" }, - { name: "AI as Draft Aid Only", desc: "LLM generates proposal, human implements and verifies", type: "organizational" }, + { + name: "Formal Verification", + desc: "Dafny, TLA+, SPARK — mathematical proof of correctness", + type: "deterministic", + }, + { + name: "Independent Re-Verification", + desc: "Separate team verifies output — per DO-178C DAL A", + type: "organizational", + }, + { + name: "MC/DC Test Coverage", + desc: "Modified Condition/Decision Coverage — required at DAL A/B", + type: "deterministic", + }, + { + name: "Contract-Based Design", + desc: "Pre/postconditions + invariants — spec first, then generation", + type: "deterministic", + }, + { + name: "Certification Process", + desc: "IEC 61508, DO-178C, ISO 26262 compliance — no shortcut", + type: "organizational", + }, + { + name: "AI as Draft Aid Only", + desc: "LLM generates proposal, human implements and verifies", + type: "organizational", + }, ], }, ], @@ -408,9 +680,9 @@ This framework provides a https://github.com/LLM-Coding/Semantic-Anchors?tab=rea title: "Claude Code Skills", content: `This framework provides two https://code.claude.com/docs/en/skills[Claude Code Skills] that work directly in your project: -*\/risk-assess* — Automatically analyzes your repository, detects modules (monorepo, frontend/backend, etc.), scans code patterns, and asks targeted questions for dimensions that can't be auto-detected. Writes a structured risk assessment per module to your \`CLAUDE.md\`. +*/risk-assess* — Automatically analyzes your repository, detects modules (monorepo, frontend/backend, etc.), scans code patterns, and asks targeted questions for dimensions that can't be auto-detected. Writes a structured risk assessment per module to your \`CLAUDE.md\`. -*\/risk-mitigate* — Reads the risk assessment from \`CLAUDE.md\`, detects already-present measures (linter, CI, SAST, etc.), and helps implement missing mitigations step by step — from tool installation to CI configuration. +*/risk-mitigate* — Reads the risk assessment from \`CLAUDE.md\`, detects already-present measures (linter, CI, SAST, etc.), and helps implement missing mitigations step by step — from tool installation to CI configuration. *Installation — Plugin (recommended):* diff --git a/src/index.css b/src/index.css index fe85bc7..a019f8e 100644 --- a/src/index.css +++ b/src/index.css @@ -7,7 +7,12 @@ } body { - font-family: system-ui, -apple-system, "Segoe UI", Roboto, sans-serif; + font-family: + system-ui, + -apple-system, + "Segoe UI", + Roboto, + sans-serif; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; } diff --git a/src/main.jsx b/src/main.jsx index fc497c6..5886490 100644 --- a/src/main.jsx +++ b/src/main.jsx @@ -6,5 +6,5 @@ import "./index.css"; ReactDOM.createRoot(document.getElementById("root")).render( - + , ); From 6d83660db4306f4610ba932fa6d5fde939827c84 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=7BAI=7Df=20D=2E=20M=C3=BCller?= Date: Wed, 11 Feb 2026 20:38:54 +0100 Subject: [PATCH 2/5] chore: set up pre-commit hooks with husky + lint-staged Runs ESLint --fix and Prettier --write on staged JS/JSX files, and Prettier on CSS/JSON/MD files before each commit. Co-Authored-By: Claude Opus 4.6 --- .husky/pre-commit | 1 + package-lock.json | 522 ++++++++++++++++++++++++++++++++++++++++++++++ package.json | 14 +- 3 files changed, 536 insertions(+), 1 deletion(-) create mode 100644 .husky/pre-commit diff --git a/.husky/pre-commit b/.husky/pre-commit new file mode 100644 index 0000000..2312dc5 --- /dev/null +++ b/.husky/pre-commit @@ -0,0 +1 @@ +npx lint-staged diff --git a/package-lock.json b/package-lock.json index 4fa66e9..60f82ca 100644 --- a/package-lock.json +++ b/package-lock.json @@ -21,6 +21,8 @@ "eslint-plugin-react-hooks": "^5.2.0", "eslint-plugin-react-refresh": "^0.4.26", "globals": "^17.3.0", + "husky": "^9.1.7", + "lint-staged": "^16.2.7", "prettier": "^3.8.1", "vite": "^6.0.0" } @@ -1560,6 +1562,35 @@ "url": "https://github.com/sponsors/epoberezkin" } }, + "node_modules/ansi-escapes": { + "version": "7.3.0", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-7.3.0.tgz", + "integrity": "sha512-BvU8nYgGQBxcmMuEeUEmNTvrMVjJNSH7RgW24vXexN4Ven6qCvy4TntnvlnwnMLTVlcRQQdbRY8NKnaIoeWDNg==", + "dev": true, + "license": "MIT", + "dependencies": { + "environment": "^1.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ansi-regex": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", + "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, "node_modules/ansi-styles": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", @@ -1608,6 +1639,19 @@ "balanced-match": "^1.0.0" } }, + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "dev": true, + "license": "MIT", + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/browserslist": { "version": "4.28.1", "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.1.tgz", @@ -1690,6 +1734,39 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, + "node_modules/cli-cursor": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-5.0.0.tgz", + "integrity": "sha512-aCj4O5wKyszjMmDT4tZj93kxyydN/K5zPWSCe6/0AV/AA1pqe5ZBIw0a2ZfPQV7lL5/yb5HsUreJ6UFAF1tEQw==", + "dev": true, + "license": "MIT", + "dependencies": { + "restore-cursor": "^5.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cli-truncate": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-5.1.1.tgz", + "integrity": "sha512-SroPvNHxUnk+vIW/dOSfNqdy1sPEFkrTk6TUtqLCnBlo3N7TNYYkzzN7uSD6+jVjrdO4+p8nH7JzH6cIvUem6A==", + "dev": true, + "license": "MIT", + "dependencies": { + "slice-ansi": "^7.1.0", + "string-width": "^8.0.0" + }, + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/color-convert": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", @@ -1710,6 +1787,23 @@ "dev": true, "license": "MIT" }, + "node_modules/colorette": { + "version": "2.0.20", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.20.tgz", + "integrity": "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==", + "dev": true, + "license": "MIT" + }, + "node_modules/commander": { + "version": "14.0.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-14.0.3.tgz", + "integrity": "sha512-H+y0Jo/T1RZ9qPP4Eh1pkcQcLRglraJaSLoyOtHxu6AapkjWVCy2Sit1QQ4x3Dng8qDlSsZEet7g5Pq06MvTgw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=20" + } + }, "node_modules/concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", @@ -1771,6 +1865,26 @@ "dev": true, "license": "ISC" }, + "node_modules/emoji-regex": { + "version": "10.6.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.6.0.tgz", + "integrity": "sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A==", + "dev": true, + "license": "MIT" + }, + "node_modules/environment": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/environment/-/environment-1.1.0.tgz", + "integrity": "sha512-xUtoPkMggbz0MPyPiIWr1Kp4aeWJjDZ6SMvURhimjdZgsRuDplF5/s9hcgGhyXMhs+6vpnuoiZ2kFiu3FMnS8Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/esbuild": { "version": "0.25.12", "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.12.tgz", @@ -2053,6 +2167,13 @@ "node": ">=0.10.0" } }, + "node_modules/eventemitter3": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.4.tgz", + "integrity": "sha512-mlsTRyGaPBjPedk6Bvw+aqbsXDtoAyAzm5MO7JgU+yVRyMQ5O8bD4Kcci7BS85f93veegeCPkL8R4GLClnjLFw==", + "dev": true, + "license": "MIT" + }, "node_modules/fast-deep-equal": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", @@ -2105,6 +2226,19 @@ "node": ">=16.0.0" } }, + "node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "dev": true, + "license": "MIT", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/find-up": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", @@ -2174,6 +2308,19 @@ "node": ">=6.9.0" } }, + "node_modules/get-east-asian-width": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/get-east-asian-width/-/get-east-asian-width-1.4.0.tgz", + "integrity": "sha512-QZjmEOC+IT1uk6Rx0sX22V6uHWVwbdbxf1faPqJ1QhLdGgsRGCZoyaQBm/piRdJy/D2um6hM1UP7ZEeQ4EkP+Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/glob": { "version": "8.1.0", "resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz", @@ -2230,6 +2377,22 @@ "node": ">=8" } }, + "node_modules/husky": { + "version": "9.1.7", + "resolved": "https://registry.npmjs.org/husky/-/husky-9.1.7.tgz", + "integrity": "sha512-5gs5ytaNjBrh5Ow3zrvdUUY+0VxIuWVL4i9irt6friV+BqdCfmV11CQTWMiBYWHbXhco+J1kHfTOUkePhCDvMA==", + "dev": true, + "license": "MIT", + "bin": { + "husky": "bin.js" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/typicode" + } + }, "node_modules/ignore": { "version": "5.3.2", "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", @@ -2294,6 +2457,22 @@ "node": ">=0.10.0" } }, + "node_modules/is-fullwidth-code-point": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-5.1.0.tgz", + "integrity": "sha512-5XHYaSyiqADb4RnZ1Bdad6cPp8Toise4TzEjcOYDHZkTCbKgiUl7WTUCpNWHuxmDt91wnsZBc9xinNzopv3JMQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "get-east-asian-width": "^1.3.1" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/is-glob": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", @@ -2307,6 +2486,16 @@ "node": ">=0.10.0" } }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } + }, "node_modules/isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", @@ -2404,6 +2593,49 @@ "node": ">= 0.8.0" } }, + "node_modules/lint-staged": { + "version": "16.2.7", + "resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-16.2.7.tgz", + "integrity": "sha512-lDIj4RnYmK7/kXMya+qJsmkRFkGolciXjrsZ6PC25GdTfWOAWetR0ZbsNXRAj1EHHImRSalc+whZFg56F5DVow==", + "dev": true, + "license": "MIT", + "dependencies": { + "commander": "^14.0.2", + "listr2": "^9.0.5", + "micromatch": "^4.0.8", + "nano-spawn": "^2.0.0", + "pidtree": "^0.6.0", + "string-argv": "^0.3.2", + "yaml": "^2.8.1" + }, + "bin": { + "lint-staged": "bin/lint-staged.js" + }, + "engines": { + "node": ">=20.17" + }, + "funding": { + "url": "https://opencollective.com/lint-staged" + } + }, + "node_modules/listr2": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/listr2/-/listr2-9.0.5.tgz", + "integrity": "sha512-ME4Fb83LgEgwNw96RKNvKV4VTLuXfoKudAmm2lP8Kk87KaMK0/Xrx/aAkMWmT8mDb+3MlFDspfbCs7adjRxA2g==", + "dev": true, + "license": "MIT", + "dependencies": { + "cli-truncate": "^5.0.0", + "colorette": "^2.0.20", + "eventemitter3": "^5.0.1", + "log-update": "^6.1.0", + "rfdc": "^1.4.1", + "wrap-ansi": "^9.0.0" + }, + "engines": { + "node": ">=20.0.0" + } + }, "node_modules/locate-path": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", @@ -2427,6 +2659,26 @@ "dev": true, "license": "MIT" }, + "node_modules/log-update": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/log-update/-/log-update-6.1.0.tgz", + "integrity": "sha512-9ie8ItPR6tjY5uYJh8K/Zrv/RMZ5VOlOWvtZdEHYSTFKZfIBPQa9tOAEeAWhd+AnIneLJ22w5fjOYtoutpWq5w==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-escapes": "^7.0.0", + "cli-cursor": "^5.0.0", + "slice-ansi": "^7.1.0", + "strip-ansi": "^7.1.0", + "wrap-ansi": "^9.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/loose-envify": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", @@ -2449,6 +2701,46 @@ "yallist": "^3.0.2" } }, + "node_modules/micromatch": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", + "dev": true, + "license": "MIT", + "dependencies": { + "braces": "^3.0.3", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/micromatch/node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/mimic-function": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/mimic-function/-/mimic-function-5.0.1.tgz", + "integrity": "sha512-VP79XUPxV2CigYP3jWwAUFSku2aKqBH7uTAapFWCBqutsbmDo96KY5o8uh6U+/YSIn5OxJnXp73beVkpqMIGhA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/minimatch": { "version": "5.1.6", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", @@ -2468,6 +2760,19 @@ "dev": true, "license": "MIT" }, + "node_modules/nano-spawn": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/nano-spawn/-/nano-spawn-2.0.0.tgz", + "integrity": "sha512-tacvGzUY5o2D8CBh2rrwxyNojUsZNU2zjNTzKQrkgGJQTbGAfArVWXSKMBokBeeg6C7OLRGUEyoFlYbfeWQIqw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=20.17" + }, + "funding": { + "url": "https://github.com/sindresorhus/nano-spawn?sponsor=1" + } + }, "node_modules/nanoid": { "version": "3.3.11", "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", @@ -2510,6 +2815,22 @@ "wrappy": "1" } }, + "node_modules/onetime": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-7.0.0.tgz", + "integrity": "sha512-VXJjc87FScF88uafS3JllDgvAm+c/Slfz06lorj2uAY34rlUu0Nt+v8wreiImcrgAjjIHp1rXpTDlLOGw29WwQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "mimic-function": "^5.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/optionator": { "version": "0.9.4", "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", @@ -2613,6 +2934,19 @@ "url": "https://github.com/sponsors/jonschlinkert" } }, + "node_modules/pidtree": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/pidtree/-/pidtree-0.6.0.tgz", + "integrity": "sha512-eG2dWTVw5bzqGRztnHExczNxt5VGsE6OwTeCG3fdUf9KBsZzO3R5OIIIzWR+iZA0NtZ+RDVdaoE2dK1cn6jH4g==", + "dev": true, + "license": "MIT", + "bin": { + "pidtree": "bin/pidtree.js" + }, + "engines": { + "node": ">=0.10" + } + }, "node_modules/postcss": { "version": "8.5.6", "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz", @@ -2723,6 +3057,30 @@ "node": ">=4" } }, + "node_modules/restore-cursor": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-5.1.0.tgz", + "integrity": "sha512-oMA2dcrw6u0YfxJQXm342bFKX/E4sG9rbTzO9ptUcR/e8A33cHuvStiYOwH7fszkZlZ1z/ta9AAoPk2F4qIOHA==", + "dev": true, + "license": "MIT", + "dependencies": { + "onetime": "^7.0.0", + "signal-exit": "^4.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/rfdc": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.4.1.tgz", + "integrity": "sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==", + "dev": true, + "license": "MIT" + }, "node_modules/rollup": { "version": "4.57.1", "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.57.1.tgz", @@ -2810,6 +3168,49 @@ "node": ">=8" } }, + "node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/slice-ansi": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-7.1.2.tgz", + "integrity": "sha512-iOBWFgUX7caIZiuutICxVgX1SdxwAVFFKwt1EvMYYec/NWO5meOJ6K5uQxhrYBdQJne4KxiqZc+KptFOWFSI9w==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^6.2.1", + "is-fullwidth-code-point": "^5.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/chalk/slice-ansi?sponsor=1" + } + }, + "node_modules/slice-ansi/node_modules/ansi-styles": { + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz", + "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, "node_modules/source-map-js": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", @@ -2820,6 +3221,49 @@ "node": ">=0.10.0" } }, + "node_modules/string-argv": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/string-argv/-/string-argv-0.3.2.tgz", + "integrity": "sha512-aqD2Q0144Z+/RqG52NeHEkZauTAUWJO8c6yTftGJKO3Tja5tUgIfmIl6kExvhtxSDP7fXB6DvzkfMpCd/F3G+Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.6.19" + } + }, + "node_modules/string-width": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-8.1.1.tgz", + "integrity": "sha512-KpqHIdDL9KwYk22wEOg/VIqYbrnLeSApsKT/bSj6Ez7pn3CftUiLAv2Lccpq1ALcpLV9UX1Ppn92npZWu2w/aw==", + "dev": true, + "license": "MIT", + "dependencies": { + "get-east-asian-width": "^1.3.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/strip-ansi": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.2.tgz", + "integrity": "sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, "node_modules/strip-json-comments": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", @@ -2863,6 +3307,19 @@ "url": "https://github.com/sponsors/SuperchupuDev" } }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, "node_modules/type-check": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", @@ -3027,6 +3484,55 @@ "node": ">=0.10.0" } }, + "node_modules/wrap-ansi": { + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-9.0.2.tgz", + "integrity": "sha512-42AtmgqjV+X1VpdOfyTGOYRi0/zsoLqtXQckTmqTeybT+BDIbM/Guxo7x3pE2vtpr1ok6xRqM9OpBe+Jyoqyww==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^6.2.1", + "string-width": "^7.0.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi/node_modules/ansi-styles": { + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz", + "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/wrap-ansi/node_modules/string-width": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz", + "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^10.3.0", + "get-east-asian-width": "^1.0.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", @@ -3040,6 +3546,22 @@ "dev": true, "license": "ISC" }, + "node_modules/yaml": { + "version": "2.8.2", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.2.tgz", + "integrity": "sha512-mplynKqc1C2hTVYxd0PU2xQAc22TI1vShAYGksCCfxbn/dFwnHTNi1bvYsBTkhdUNtGIf5xNOg938rrSSYvS9A==", + "dev": true, + "license": "ISC", + "bin": { + "yaml": "bin.mjs" + }, + "engines": { + "node": ">= 14.6" + }, + "funding": { + "url": "https://github.com/sponsors/eemeli" + } + }, "node_modules/yocto-queue": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", diff --git a/package.json b/package.json index 64181ac..5ccb135 100644 --- a/package.json +++ b/package.json @@ -7,7 +7,8 @@ "dev": "vite", "build": "vite build", "preview": "vite preview", - "docs": "asciidoctor -a icons=font -a source-highlighter=highlight.js -a linkcss -a stylesheet=asciidoctor.css -D dist/docs docs/risk-radar.adoc docs/risk-radar-en.adoc" + "docs": "asciidoctor -a icons=font -a source-highlighter=highlight.js -a linkcss -a stylesheet=asciidoctor.css -D dist/docs docs/risk-radar.adoc docs/risk-radar-en.adoc", + "prepare": "husky" }, "dependencies": { "@asciidoctor/core": "^3.0.4", @@ -22,8 +23,19 @@ "eslint-plugin-react-hooks": "^5.2.0", "eslint-plugin-react-refresh": "^0.4.26", "globals": "^17.3.0", + "husky": "^9.1.7", + "lint-staged": "^16.2.7", "prettier": "^3.8.1", "vite": "^6.0.0" }, + "lint-staged": { + "*.{js,jsx}": [ + "eslint --fix", + "prettier --write" + ], + "*.{css,json,md}": [ + "prettier --write" + ] + }, "license": "MIT" } From ec6813176cde636c94f5f6eb95d3dd1c7b040744 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=7BAI=7Df=20D=2E=20M=C3=BCller?= Date: Wed, 11 Feb 2026 20:39:11 +0100 Subject: [PATCH 3/5] chore: add CI workflow with lint, format check, dependency audit, and build GitHub Actions workflow that runs ESLint, Prettier check, npm audit (high severity), and production build on push/PR to main. Co-Authored-By: Claude Opus 4.6 --- .github/workflows/ci.yml | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 .github/workflows/ci.yml diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..2e0be43 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,32 @@ +name: CI + +on: + push: + branches: [main] + pull_request: + branches: [main] + +jobs: + lint-and-build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - uses: actions/setup-node@v4 + with: + node-version: 20 + cache: npm + + - run: npm ci + + - name: Lint + run: npx eslint src/ + + - name: Format check + run: npx prettier --check src/ + + - name: Dependency audit + run: npm audit --audit-level=high + + - name: Build + run: npm run build From 7dcc0e120eebdf178ccd7db2bb0e949b7a54eec0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=7BAI=7Df=20D=2E=20M=C3=BCller?= Date: Wed, 11 Feb 2026 20:39:21 +0100 Subject: [PATCH 4/5] chore: add CodeQL SAST workflow for security analysis Runs GitHub CodeQL on push/PR to main and weekly (Monday 6am UTC). Scans JavaScript for security vulnerabilities. Co-Authored-By: Claude Opus 4.6 --- .github/workflows/codeql.yml | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 .github/workflows/codeql.yml diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml new file mode 100644 index 0000000..ffc914f --- /dev/null +++ b/.github/workflows/codeql.yml @@ -0,0 +1,31 @@ +name: CodeQL + +on: + push: + branches: [main] + pull_request: + branches: [main] + schedule: + - cron: "0 6 * * 1" + +jobs: + analyze: + runs-on: ubuntu-latest + permissions: + security-events: write + strategy: + matrix: + language: [javascript] + steps: + - uses: actions/checkout@v4 + + - name: Initialize CodeQL + uses: github/codeql-action/init@v3 + with: + languages: ${{ matrix.language }} + + - name: Autobuild + uses: github/codeql-action/autobuild@v3 + + - name: Perform CodeQL Analysis + uses: github/codeql-action/analyze@v3 From b229d2a57bed7a3a958b80554eced7618ec5e688 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=7BAI=7Df=20D=2E=20M=C3=BCller?= Date: Wed, 11 Feb 2026 20:39:46 +0100 Subject: [PATCH 5/5] docs: update mitigation status in CLAUDE.md Updated by /risk-mitigate: ESLint, Prettier, pre-commit hooks, dependency audit, CI workflow, and CodeQL SAST now set up. Co-Authored-By: Claude Opus 4.6 --- CLAUDE.md | 44 ++++++++++++++++++++++++-------------------- 1 file changed, 24 insertions(+), 20 deletions(-) diff --git a/CLAUDE.md b/CLAUDE.md index 8f89111..79aeaf0 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -12,7 +12,7 @@ npm run preview # Preview production build locally npm run docs # Render AsciiDoc docs with Asciidoctor ``` -No test framework is configured. No linter is configured. +No test framework is configured. ESLint + Prettier are configured (see `eslint.config.js`, `.prettierrc`). Pre-commit hooks via husky + lint-staged. ## Architecture @@ -48,26 +48,30 @@ GitHub Actions workflow (`.github/workflows/deploy.yml`) builds the React app an _Generated by `/risk-assess` on 2026-02-11_ ### Module: vibe-coding-risk-radar -| Dimension | Score | Level | Evidence | -|-----------|-------|-------|----------| -| Code Type | 0 | UI / CSS / Docs | Only .jsx components, .css styling, .js config — no auth, API, or DB code | -| Language | 2 | Dynamically typed | 5 .jsx + 4 .js files (JavaScript) | -| Deployment | 2 | Public-facing app | Static site on GitHub Pages, publicly accessible | -| Data Sensitivity | 0 | Public data | No real data processing, PII/PHI mentions only in documentation text | -| Blast Radius | 0 | Cosmetic / Tech debt | Static visualization tool, no data storage or user accounts | + +| Dimension | Score | Level | Evidence | +| ---------------- | ----- | -------------------- | ------------------------------------------------------------------------- | +| Code Type | 0 | UI / CSS / Docs | Only .jsx components, .css styling, .js config — no auth, API, or DB code | +| Language | 2 | Dynamically typed | 5 .jsx + 4 .js files (JavaScript) | +| Deployment | 2 | Public-facing app | Static site on GitHub Pages, publicly accessible | +| Data Sensitivity | 0 | Public data | No real data processing, PII/PHI mentions only in documentation text | +| Blast Radius | 0 | Cosmetic / Tech debt | Static visualization tool, no data storage or user accounts | **Tier: 2 — Moderat** (determined by Language = 2 and Deployment = 2) ### Mitigations: vibe-coding-risk-radar (Tier 2) -| Measure | Status | Details | -|---------|--------|---------| -| Linter & Formatter | ❌ Missing | No .eslintrc, .prettierrc, or lint script | -| Type Checking | ❌ Missing | No tsconfig.json (plain JS, not TS) | -| Pre-Commit Hooks | ❌ Missing | No .husky/, no .pre-commit-config.yaml | -| Dependency Check | ❌ Missing | No audit step in CI | -| CI Build & Unit Tests | ⚠️ Partial | CI builds (deploy.yml) but no test framework configured | -| SAST (Semgrep/CodeQL) | ❌ Missing | No SAST in CI workflows | -| AI Code Review | ✅ Present | claude-code-review.yml workflow | -| Property-Based Tests | ❌ Missing | No test framework at all | -| SonarQube Quality Gate | ❌ Missing | No sonar-project.properties | -| Sampling Review | ❌ Missing | No branch protection / review requirement | + +_Updated by `/risk-mitigate` on 2026-02-11_ + +| Measure | Status | Details | +| ---------------------- | ---------- | ---------------------------------------------------- | +| Linter & Formatter | ✅ Set up | eslint.config.js + .prettierrc | +| Type Checking | ⬜ N/A | Plain JS project, no TypeScript | +| Pre-Commit Hooks | ✅ Set up | husky + lint-staged (eslint --fix, prettier --write) | +| Dependency Check | ✅ Set up | npm audit --audit-level=high in ci.yml | +| CI Build & Unit Tests | ✅ Set up | ci.yml: lint, format check, audit, build | +| SAST (CodeQL) | ✅ Set up | codeql.yml: weekly + on push/PR | +| AI Code Review | ✅ Present | claude-code-review.yml | +| Property-Based Tests | ⬜ Pending | No test framework configured | +| SonarQube Quality Gate | ⬜ Pending | Needs SonarCloud account | +| Sampling Review | ⬜ Pending | No branch protection configured |