diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 00000000..4a7ea303 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,12 @@ +root = true + +[*] +indent_style = space +indent_size = 2 +end_of_line = lf +charset = utf-8 +trim_trailing_whitespace = true +insert_final_newline = true + +[*.md] +trim_trailing_whitespace = false diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 00000000..97be4ba9 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,36 @@ +name: CI + +on: + push: + branches: [master, main] + pull_request: + +jobs: + ci: + name: Typecheck & Lint + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: 22 + cache: 'npm' + + - name: Install dependencies + run: npm ci + + - name: Type check + run: npm run typecheck + + - name: Lint + run: npm run lint + + - name: Format check + run: npm run format:check + +# Note: The test suite is intentionally excluded from CI. +# Tests spawn real tmux sessions and require a full system environment. +# Run tests locally with: npx vitest run test/.test.ts diff --git a/.gitignore b/.gitignore index 603da534..9e1deb67 100644 --- a/.gitignore +++ b/.gitignore @@ -41,6 +41,14 @@ Thumbs.db *.tmp *.temp +# Generated output +out/ +screenshots-echo-diag/ +tools/remotion/out/ + +# Claude Code plan tracking +plan.json + # Unfinished TUI (local development only) src/tui/ .claude/ diff --git a/.nvmrc b/.nvmrc new file mode 100644 index 00000000..2bd5a0a9 --- /dev/null +++ b/.nvmrc @@ -0,0 +1 @@ +22 diff --git a/.prettierignore b/.prettierignore new file mode 100644 index 00000000..7ac646ba --- /dev/null +++ b/.prettierignore @@ -0,0 +1,9 @@ +dist/ +coverage/ +node_modules/ +src/web/public/vendor/ +src/web/public/app.js +src/web/public/styles.css +src/web/public/mobile.css +src/web/public/index.html +tools/ diff --git a/.prettierrc b/.prettierrc new file mode 100644 index 00000000..4ed049da --- /dev/null +++ b/.prettierrc @@ -0,0 +1,8 @@ +{ + "singleQuote": true, + "semi": true, + "tabWidth": 2, + "printWidth": 120, + "trailingComma": "es5", + "endOfLine": "lf" +} diff --git a/CLAUDE.md b/CLAUDE.md index 1f2698f0..bc88851a 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -64,7 +64,7 @@ Codeman is a Claude Code session manager with web interface and autonomous Ralph ## Commands -**CRITICAL**: `npm run dev` shows CLI help, NOT the web server. +**Note**: `npm run dev` starts the web server (equivalent to `npx tsx src/index.ts web`). **Default port**: `3000` (web UI at `http://localhost:3000`) @@ -92,7 +92,6 @@ journalctl --user -u codeman-web -f ## Common Gotchas -- **`npm run dev` is NOT the web server** — it shows CLI help. Use `npx tsx src/index.ts web` - **Single-line prompts only** — `writeViaMux()` sends text and Enter separately; multi-line breaks Ink - **Don't kill tmux sessions blindly** — Check `$CODEMAN_TMUX` first; you might be inside one - **Never run full test suite** — `npx vitest run` spawns/kills tmux sessions and will crash your Codeman session. Run individual test files only. diff --git a/eslint.config.js b/eslint.config.js new file mode 100644 index 00000000..4d594b25 --- /dev/null +++ b/eslint.config.js @@ -0,0 +1,29 @@ +// @ts-check +import eslint from '@eslint/js'; +import tseslint from 'typescript-eslint'; + +export default tseslint.config( + eslint.configs.recommended, + tseslint.configs.recommended, + { + rules: { + 'no-console': 'off', + 'no-debugger': 'error', + // Relax some rules that conflict with existing patterns + '@typescript-eslint/no-explicit-any': 'warn', + '@typescript-eslint/no-unused-vars': 'off', // TypeScript compiler already handles this + }, + }, + { + ignores: [ + 'dist/**', + 'node_modules/**', + 'coverage/**', + 'src/web/public/vendor/**', + 'src/web/public/app.js', + 'scripts/**/*.mjs', + 'tools/**', + 'remotion/**', + ], + } +); diff --git a/package-lock.json b/package-lock.json index 9e348367..62e9f710 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,27 +1,27 @@ { "name": "codeman", - "version": "0.2.0", + "version": "0.2.1", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "codeman", - "version": "0.2.0", + "version": "0.2.1", "hasInstallScript": true, "license": "MIT", + "workspaces": [ + "packages/*" + ], "dependencies": { "@fastify/compress": "^8.3.1", "@fastify/cookie": "^11.0.2", "@fastify/static": "^8.0.0", - "@remotion/cli": "4.0.429", - "@remotion/transitions": "4.0.429", "chalk": "^5.3.0", "chokidar": "^3.6.0", "commander": "^12.1.0", "fastify": "^5.1.0", "node-pty": "^1.1.0", "qrcode": "^1.5.4", - "remotion": "4.0.429", "uuid": "^10.0.0", "web-push": "^3.6.7", "xterm": "^5.3.0", @@ -35,6 +35,9 @@ }, "devDependencies": { "@changesets/cli": "^2.29.8", + "@eslint/js": "^9.0.0", + "@remotion/cli": "4.0.429", + "@remotion/transitions": "4.0.429", "@types/node": "^20.19.33", "@types/pngjs": "^6.0.5", "@types/react": "^19.2.14", @@ -43,12 +46,16 @@ "@vitest/coverage-v8": "^4.0.18", "agent-browser": "^0.6.0", "esbuild": "^0.27.3", + "eslint": "^9.0.0", "pixelmatch": "^6.0.0", "playwright": "^1.58.0", "pngjs": "^7.0.0", + "prettier": "^3.4.0", "puppeteer": "^24.36.0", + "remotion": "4.0.429", "tsx": "^4.15.0", "typescript": "^5.9.3", + "typescript-eslint": "^8.0.0", "vitest": "^4.0.18" }, "engines": { @@ -57,12 +64,8 @@ }, "node_modules/@asamuzakjp/css-color": { "version": "3.2.0", - "resolved": "https://registry.npmjs.org/@asamuzakjp/css-color/-/css-color-3.2.0.tgz", - "integrity": "sha512-K1A6z8tS3XsmCMM86xoWdn7Fkdn9m6RSVtocUrJYIwZnFVkng/PvkEoWtOWmP+Scc6saYWHWZYbndEEXxl24jw==", "dev": true, "license": "MIT", - "optional": true, - "peer": true, "dependencies": { "@csstools/css-calc": "^2.1.3", "@csstools/css-color-parser": "^3.0.9", @@ -73,17 +76,11 @@ }, "node_modules/@asamuzakjp/css-color/node_modules/lru-cache": { "version": "10.4.3", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", - "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", "dev": true, - "license": "ISC", - "optional": true, - "peer": true + "license": "ISC" }, "node_modules/@babel/code-frame": { "version": "7.29.0", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.0.tgz", - "integrity": "sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw==", "dev": true, "license": "MIT", "dependencies": { @@ -97,15 +94,11 @@ }, "node_modules/@babel/code-frame/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==", "dev": true, "license": "MIT" }, "node_modules/@babel/helper-string-parser": { "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz", - "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==", "dev": true, "license": "MIT", "engines": { @@ -114,8 +107,6 @@ }, "node_modules/@babel/helper-validator-identifier": { "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz", - "integrity": "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==", "dev": true, "license": "MIT", "engines": { @@ -124,8 +115,6 @@ }, "node_modules/@babel/parser": { "version": "7.29.0", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.0.tgz", - "integrity": "sha512-IyDgFV5GeDUVX4YdF/3CPULtVGSXXMLh1xVIgdCgxApktqnQV0r7/8Nqthg+8YLGaAtdyIlo2qIdZrbCv4+7ww==", "dev": true, "license": "MIT", "dependencies": { @@ -150,8 +139,6 @@ }, "node_modules/@babel/types": { "version": "7.29.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.0.tgz", - "integrity": "sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==", "dev": true, "license": "MIT", "dependencies": { @@ -164,8 +151,6 @@ }, "node_modules/@bcoe/v8-coverage": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-1.0.2.tgz", - "integrity": "sha512-6zABk/ECA/QYSCQ1NGiVwwbQerUCZ+TQbp64Q3AgmfNvurHH0j8TtXa1qbShXA6qqkpAj4V5W8pP6mLe1mcMqA==", "dev": true, "license": "MIT", "engines": { @@ -469,8 +454,6 @@ }, "node_modules/@csstools/color-helpers": { "version": "5.1.0", - "resolved": "https://registry.npmjs.org/@csstools/color-helpers/-/color-helpers-5.1.0.tgz", - "integrity": "sha512-S11EXWJyy0Mz5SYvRmY8nJYTFFd1LCNV+7cXyAgQtOOuzb4EsgfqDufL+9esx72/eLhsRdGZwaldu/h+E4t4BA==", "dev": true, "funding": [ { @@ -483,16 +466,12 @@ } ], "license": "MIT-0", - "optional": true, - "peer": true, "engines": { "node": ">=18" } }, "node_modules/@csstools/css-calc": { "version": "2.1.4", - "resolved": "https://registry.npmjs.org/@csstools/css-calc/-/css-calc-2.1.4.tgz", - "integrity": "sha512-3N8oaj+0juUw/1H3YwmDDJXCgTB1gKU6Hc/bB502u9zR0q2vd786XJH9QfrKIEgFlZmhZiq6epXl4rHqhzsIgQ==", "dev": true, "funding": [ { @@ -505,8 +484,6 @@ } ], "license": "MIT", - "optional": true, - "peer": true, "engines": { "node": ">=18" }, @@ -517,8 +494,6 @@ }, "node_modules/@csstools/css-color-parser": { "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@csstools/css-color-parser/-/css-color-parser-3.1.0.tgz", - "integrity": "sha512-nbtKwh3a6xNVIp/VRuXV64yTKnb1IjTAEEh3irzS+HkKjAOYLTGNb9pmVNntZ8iVBHcWDA2Dof0QtPgFI1BaTA==", "dev": true, "funding": [ { @@ -531,8 +506,6 @@ } ], "license": "MIT", - "optional": true, - "peer": true, "dependencies": { "@csstools/color-helpers": "^5.1.0", "@csstools/css-calc": "^2.1.4" @@ -547,8 +520,6 @@ }, "node_modules/@csstools/css-parser-algorithms": { "version": "3.0.5", - "resolved": "https://registry.npmjs.org/@csstools/css-parser-algorithms/-/css-parser-algorithms-3.0.5.tgz", - "integrity": "sha512-DaDeUkXZKjdGhgYaHNJTV9pV7Y9B3b644jCLs9Upc3VeNGg6LWARAT6O+Q+/COo+2gg/bM5rhpMAtf70WqfBdQ==", "dev": true, "funding": [ { @@ -561,8 +532,6 @@ } ], "license": "MIT", - "optional": true, - "peer": true, "engines": { "node": ">=18" }, @@ -572,8 +541,6 @@ }, "node_modules/@csstools/css-tokenizer": { "version": "3.0.4", - "resolved": "https://registry.npmjs.org/@csstools/css-tokenizer/-/css-tokenizer-3.0.4.tgz", - "integrity": "sha512-Vd/9EVDiu6PPJt9yAh6roZP6El1xHrdvIVGjyBsHR0RYwNHgL7FJPyIIW4fANJNG6FtyZfvlRPpFI4ZM/lubvw==", "dev": true, "funding": [ { @@ -586,489 +553,221 @@ } ], "license": "MIT", - "optional": true, - "peer": true, "engines": { "node": ">=18" } }, - "node_modules/@emnapi/core": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.8.1.tgz", - "integrity": "sha512-AvT9QFpxK0Zd8J0jopedNm+w/2fIzvtPKPjqyw9jwvBaReTTqPBk9Hixaz7KbjimP+QNz605/XnjFcDAL2pqBg==", - "license": "MIT", - "optional": true, - "dependencies": { - "@emnapi/wasi-threads": "1.1.0", - "tslib": "^2.4.0" - } - }, - "node_modules/@emnapi/runtime": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.8.1.tgz", - "integrity": "sha512-mehfKSMWjjNol8659Z8KxEMrdSJDDot5SXMq00dM8BN4o+CLNXQ0xH2V7EchNHV4RmbZLmmPdEaXZc5H2FXmDg==", - "license": "MIT", - "optional": true, - "dependencies": { - "tslib": "^2.4.0" - } - }, - "node_modules/@emnapi/wasi-threads": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.1.0.tgz", - "integrity": "sha512-WI0DdZ8xFSbgMjR1sFsKABJ/C5OnRrjT06JXbZKexJGrDuPTzZdDYfFlsgcCXCyf+suG5QU2e/y1Wo2V/OapLQ==", - "license": "MIT", - "optional": true, - "dependencies": { - "tslib": "^2.4.0" - } - }, - "node_modules/@esbuild/aix-ppc64": { + "node_modules/@esbuild/darwin-arm64": { "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.27.3.tgz", - "integrity": "sha512-9fJMTNFTWZMh5qwrBItuziu834eOCUcEqymSH7pY+zoMVEZg3gcPuBNxH1EvfVYe9h0x/Ptw8KBzv7qxb7l8dg==", "cpu": [ - "ppc64" + "arm64" ], "dev": true, "license": "MIT", "optional": true, "os": [ - "aix" + "darwin" ], "engines": { "node": ">=18" } }, - "node_modules/@esbuild/android-arm": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.27.3.tgz", - "integrity": "sha512-i5D1hPY7GIQmXlXhs2w8AWHhenb00+GxjxRncS2ZM7YNVGNfaMxgzSGuO8o8SJzRc/oZwU2bcScvVERk03QhzA==", - "cpu": [ - "arm" - ], + "node_modules/@eslint-community/eslint-utils": { + "version": "4.9.1", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "android" - ], + "dependencies": { + "eslint-visitor-keys": "^3.4.3" + }, "engines": { - "node": ">=18" + "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/@esbuild/android-arm64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.27.3.tgz", - "integrity": "sha512-YdghPYUmj/FX2SYKJ0OZxf+iaKgMsKHVPF1MAq/P8WirnSpCStzKJFjOjzsW0QQ7oIAiccHdcqjbHmJxRb/dmg==", - "cpu": [ - "arm64" - ], + "node_modules/@eslint-community/eslint-utils/node_modules/eslint-visitor-keys": { + "version": "3.4.3", "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], + "license": "Apache-2.0", "engines": { - "node": ">=18" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" } }, - "node_modules/@esbuild/android-x64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.27.3.tgz", - "integrity": "sha512-IN/0BNTkHtk8lkOM8JWAYFg4ORxBkZQf9zXiEOfERX/CzxW3Vg1ewAhU7QSWQpVIzTW+b8Xy+lGzdYXV6UZObQ==", - "cpu": [ - "x64" - ], + "node_modules/@eslint-community/regexpp": { + "version": "4.12.2", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "android" - ], "engines": { - "node": ">=18" + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" } }, - "node_modules/@esbuild/darwin-arm64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.27.3.tgz", - "integrity": "sha512-Re491k7ByTVRy0t3EKWajdLIr0gz2kKKfzafkth4Q8A5n1xTHrkqZgLLjFEHVD+AXdUGgQMq+Godfq45mGpCKg==", - "cpu": [ - "arm64" - ], + "node_modules/@eslint/config-array": { + "version": "0.21.1", "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], + "license": "Apache-2.0", + "dependencies": { + "@eslint/object-schema": "^2.1.7", + "debug": "^4.3.1", + "minimatch": "^3.1.2" + }, "engines": { - "node": ">=18" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, - "node_modules/@esbuild/darwin-x64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.27.3.tgz", - "integrity": "sha512-vHk/hA7/1AckjGzRqi6wbo+jaShzRowYip6rt6q7VYEDX4LEy1pZfDpdxCBnGtl+A5zq8iXDcyuxwtv3hNtHFg==", - "cpu": [ - "x64" - ], + "node_modules/@eslint/config-array/node_modules/balanced-match": { + "version": "1.0.2", "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=18" - } + "license": "MIT" }, - "node_modules/@esbuild/freebsd-arm64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.27.3.tgz", - "integrity": "sha512-ipTYM2fjt3kQAYOvo6vcxJx3nBYAzPjgTCk7QEgZG8AUO3ydUhvelmhrbOheMnGOlaSFUoHXB6un+A7q4ygY9w==", - "cpu": [ - "arm64" - ], + "node_modules/@eslint/config-array/node_modules/brace-expansion": { + "version": "1.1.12", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=18" + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" } }, - "node_modules/@esbuild/freebsd-x64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.27.3.tgz", - "integrity": "sha512-dDk0X87T7mI6U3K9VjWtHOXqwAMJBNN2r7bejDsc+j03SEjtD9HrOl8gVFByeM0aJksoUuUVU9TBaZa2rgj0oA==", - "cpu": [ - "x64" - ], + "node_modules/@eslint/config-array/node_modules/minimatch": { + "version": "3.1.5", "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, "engines": { - "node": ">=18" + "node": "*" } }, - "node_modules/@esbuild/linux-arm": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.27.3.tgz", - "integrity": "sha512-s6nPv2QkSupJwLYyfS+gwdirm0ukyTFNl3KTgZEAiJDd+iHZcbTPPcWCcRYH+WlNbwChgH2QkE9NSlNrMT8Gfw==", - "cpu": [ - "arm" - ], + "node_modules/@eslint/config-helpers": { + "version": "0.4.2", "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], + "license": "Apache-2.0", + "dependencies": { + "@eslint/core": "^0.17.0" + }, "engines": { - "node": ">=18" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, - "node_modules/@esbuild/linux-arm64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.27.3.tgz", - "integrity": "sha512-sZOuFz/xWnZ4KH3YfFrKCf1WyPZHakVzTiqji3WDc0BCl2kBwiJLCXpzLzUBLgmp4veFZdvN5ChW4Eq/8Fc2Fg==", - "cpu": [ - "arm64" - ], + "node_modules/@eslint/core": { + "version": "0.17.0", "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], + "license": "Apache-2.0", + "dependencies": { + "@types/json-schema": "^7.0.15" + }, "engines": { - "node": ">=18" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, - "node_modules/@esbuild/linux-ia32": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.27.3.tgz", - "integrity": "sha512-yGlQYjdxtLdh0a3jHjuwOrxQjOZYD/C9PfdbgJJF3TIZWnm/tMd/RcNiLngiu4iwcBAOezdnSLAwQDPqTmtTYg==", - "cpu": [ - "ia32" - ], + "node_modules/@eslint/eslintrc": { + "version": "3.3.4", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "linux" - ], + "dependencies": { + "ajv": "^6.14.0", + "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.3", + "strip-json-comments": "^3.1.1" + }, "engines": { - "node": ">=18" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" } }, - "node_modules/@esbuild/linux-loong64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.27.3.tgz", - "integrity": "sha512-WO60Sn8ly3gtzhyjATDgieJNet/KqsDlX5nRC5Y3oTFcS1l0KWba+SEa9Ja1GfDqSF1z6hif/SkpQJbL63cgOA==", - "cpu": [ - "loong64" - ], + "node_modules/@eslint/eslintrc/node_modules/ajv": { + "version": "6.14.0", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" + "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/@esbuild/linux-mips64el": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.27.3.tgz", - "integrity": "sha512-APsymYA6sGcZ4pD6k+UxbDjOFSvPWyZhjaiPyl/f79xKxwTnrn5QUnXR5prvetuaSMsb4jgeHewIDCIWljrSxw==", - "cpu": [ - "mips64el" - ], + "node_modules/@eslint/eslintrc/node_modules/balanced-match": { + "version": "1.0.2", "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } + "license": "MIT" }, - "node_modules/@esbuild/linux-ppc64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.27.3.tgz", - "integrity": "sha512-eizBnTeBefojtDb9nSh4vvVQ3V9Qf9Df01PfawPcRzJH4gFSgrObw+LveUyDoKU3kxi5+9RJTCWlj4FjYXVPEA==", - "cpu": [ - "ppc64" - ], + "node_modules/@eslint/eslintrc/node_modules/brace-expansion": { + "version": "1.1.12", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" } }, - "node_modules/@esbuild/linux-riscv64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.27.3.tgz", - "integrity": "sha512-3Emwh0r5wmfm3ssTWRQSyVhbOHvqegUDRd0WhmXKX2mkHJe1SFCMJhagUleMq+Uci34wLSipf8Lagt4LlpRFWQ==", - "cpu": [ - "riscv64" - ], + "node_modules/@eslint/eslintrc/node_modules/json-schema-traverse": { + "version": "0.4.1", "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], + "license": "MIT" + }, + "node_modules/@eslint/eslintrc/node_modules/minimatch": { + "version": "3.1.5", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, "engines": { - "node": ">=18" + "node": "*" } }, - "node_modules/@esbuild/linux-s390x": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.27.3.tgz", - "integrity": "sha512-pBHUx9LzXWBc7MFIEEL0yD/ZVtNgLytvx60gES28GcWMqil8ElCYR4kvbV2BDqsHOvVDRrOxGySBM9Fcv744hw==", - "cpu": [ - "s390x" - ], + "node_modules/@eslint/js": { + "version": "9.39.3", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "linux" - ], "engines": { - "node": ">=18" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://eslint.org/donate" } }, - "node_modules/@esbuild/linux-x64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.27.3.tgz", - "integrity": "sha512-Czi8yzXUWIQYAtL/2y6vogER8pvcsOsk5cpwL4Gk5nJqH5UZiVByIY8Eorm5R13gq+DQKYg0+JyQoytLQas4dA==", - "cpu": [ - "x64" - ], + "node_modules/@eslint/object-schema": { + "version": "2.1.7", "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], + "license": "Apache-2.0", "engines": { - "node": ">=18" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, - "node_modules/@esbuild/netbsd-arm64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.27.3.tgz", - "integrity": "sha512-sDpk0RgmTCR/5HguIZa9n9u+HVKf40fbEUt+iTzSnCaGvY9kFP0YKBWZtJaraonFnqef5SlJ8/TiPAxzyS+UoA==", - "cpu": [ - "arm64" - ], + "node_modules/@eslint/plugin-kit": { + "version": "0.4.1", "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "netbsd" - ], + "license": "Apache-2.0", + "dependencies": { + "@eslint/core": "^0.17.0", + "levn": "^0.4.1" + }, "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/netbsd-x64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.27.3.tgz", - "integrity": "sha512-P14lFKJl/DdaE00LItAukUdZO5iqNH7+PjoBm+fLQjtxfcfFE20Xf5CrLsmZdq5LFFZzb5JMZ9grUwvtVYzjiA==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "netbsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/openbsd-arm64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.27.3.tgz", - "integrity": "sha512-AIcMP77AvirGbRl/UZFTq5hjXK+2wC7qFRGoHSDrZ5v5b8DK/GYpXW3CPRL53NkvDqb9D+alBiC/dV0Fb7eJcw==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "openbsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/openbsd-x64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.27.3.tgz", - "integrity": "sha512-DnW2sRrBzA+YnE70LKqnM3P+z8vehfJWHXECbwBmH/CU51z6FiqTQTHFenPlHmo3a8UgpLyH3PT+87OViOh1AQ==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "openbsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/openharmony-arm64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.27.3.tgz", - "integrity": "sha512-NinAEgr/etERPTsZJ7aEZQvvg/A6IsZG/LgZy+81wON2huV7SrK3e63dU0XhyZP4RKGyTm7aOgmQk0bGp0fy2g==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "openharmony" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/sunos-x64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.27.3.tgz", - "integrity": "sha512-PanZ+nEz+eWoBJ8/f8HKxTTD172SKwdXebZ0ndd953gt1HRBbhMsaNqjTyYLGLPdoWHy4zLU7bDVJztF5f3BHA==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "sunos" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/win32-arm64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.27.3.tgz", - "integrity": "sha512-B2t59lWWYrbRDw/tjiWOuzSsFh1Y/E95ofKz7rIVYSQkUYBjfSgf6oeYPNWHToFRr2zx52JKApIcAS/D5TUBnA==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/win32-ia32": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.27.3.tgz", - "integrity": "sha512-QLKSFeXNS8+tHW7tZpMtjlNb7HKau0QDpwm49u0vUp9y1WOF+PEzkU84y9GqYaAVW8aH8f3GcBck26jh54cX4Q==", - "cpu": [ - "ia32" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/win32-x64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.27.3.tgz", - "integrity": "sha512-4uJGhsxuptu3OcpVAzli+/gWusVGwZZHTlS63hh++ehExkVT8SgiEf7/uC/PclrPPkLhZqGgCTjd0VWLo6xMqA==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=18" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, "node_modules/@fastify/accept-negotiator": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@fastify/accept-negotiator/-/accept-negotiator-2.0.1.tgz", - "integrity": "sha512-/c/TW2bO/v9JeEgoD/g1G5GxGeCF1Hafdf79WPmUlgYiBXummY0oX3VVq4yFkKKVBKDNlaDUYoab7g38RpPqCQ==", "funding": [ { "type": "github", @@ -1083,8 +782,6 @@ }, "node_modules/@fastify/ajv-compiler": { "version": "4.0.5", - "resolved": "https://registry.npmjs.org/@fastify/ajv-compiler/-/ajv-compiler-4.0.5.tgz", - "integrity": "sha512-KoWKW+MhvfTRWL4qrhUwAAZoaChluo0m0vbiJlGMt2GXvL4LVPQEjt8kSpHI3IBq5Rez8fg+XeH3cneztq+C7A==", "funding": [ { "type": "github", @@ -1104,8 +801,6 @@ }, "node_modules/@fastify/compress": { "version": "8.3.1", - "resolved": "https://registry.npmjs.org/@fastify/compress/-/compress-8.3.1.tgz", - "integrity": "sha512-BUpItLr6MUX9e9ukg5Y6xekyA/7pBFG8QWtFCrUDm9ctoBc3R2/nA16yOaOWtVoccpXGjdDEYA/MxAb5+8cxag==", "funding": [ { "type": "github", @@ -1130,8 +825,6 @@ }, "node_modules/@fastify/cookie": { "version": "11.0.2", - "resolved": "https://registry.npmjs.org/@fastify/cookie/-/cookie-11.0.2.tgz", - "integrity": "sha512-GWdwdGlgJxyvNv+QcKiGNevSspMQXncjMZ1J8IvuDQk0jvkzgWWZFNC2En3s+nHndZBGV8IbLwOI/sxCZw/mzA==", "funding": [ { "type": "github", @@ -1150,8 +843,6 @@ }, "node_modules/@fastify/error": { "version": "4.2.0", - "resolved": "https://registry.npmjs.org/@fastify/error/-/error-4.2.0.tgz", - "integrity": "sha512-RSo3sVDXfHskiBZKBPRgnQTtIqpi/7zhJOEmAxCiBcM7d0uwdGdxLlsCaLzGs8v8NnxIRlfG0N51p5yFaOentQ==", "funding": [ { "type": "github", @@ -1166,8 +857,6 @@ }, "node_modules/@fastify/fast-json-stringify-compiler": { "version": "5.0.3", - "resolved": "https://registry.npmjs.org/@fastify/fast-json-stringify-compiler/-/fast-json-stringify-compiler-5.0.3.tgz", - "integrity": "sha512-uik7yYHkLr6fxd8hJSZ8c+xF4WafPK+XzneQDPU+D10r5X19GW8lJcom2YijX2+qtFF1ENJlHXKFM9ouXNJYgQ==", "funding": [ { "type": "github", @@ -1185,8 +874,6 @@ }, "node_modules/@fastify/forwarded": { "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@fastify/forwarded/-/forwarded-3.0.1.tgz", - "integrity": "sha512-JqDochHFqXs3C3Ml3gOY58zM7OqO9ENqPo0UqAjAjH8L01fRZqwX9iLeX34//kiJubF7r2ZQHtBRU36vONbLlw==", "funding": [ { "type": "github", @@ -1201,8 +888,6 @@ }, "node_modules/@fastify/merge-json-schemas": { "version": "0.2.1", - "resolved": "https://registry.npmjs.org/@fastify/merge-json-schemas/-/merge-json-schemas-0.2.1.tgz", - "integrity": "sha512-OA3KGBCy6KtIvLf8DINC5880o5iBlDX4SxzLQS8HorJAbqluzLRn80UXU0bxZn7UOFhFgpRJDasfwn9nG4FG4A==", "funding": [ { "type": "github", @@ -1220,8 +905,6 @@ }, "node_modules/@fastify/proxy-addr": { "version": "5.1.0", - "resolved": "https://registry.npmjs.org/@fastify/proxy-addr/-/proxy-addr-5.1.0.tgz", - "integrity": "sha512-INS+6gh91cLUjB+PVHfu1UqcB76Sqtpyp7bnL+FYojhjygvOPA9ctiD/JDKsyD9Xgu4hUhCSJBPig/w7duNajw==", "funding": [ { "type": "github", @@ -1240,8 +923,6 @@ }, "node_modules/@fastify/send": { "version": "4.1.0", - "resolved": "https://registry.npmjs.org/@fastify/send/-/send-4.1.0.tgz", - "integrity": "sha512-TMYeQLCBSy2TOFmV95hQWkiTYgC/SEx7vMdV+wnZVX4tt8VBLKzmH8vV9OzJehV0+XBfg+WxPMt5wp+JBUKsVw==", "funding": [ { "type": "github", @@ -1263,8 +944,6 @@ }, "node_modules/@fastify/static": { "version": "8.3.0", - "resolved": "https://registry.npmjs.org/@fastify/static/-/static-8.3.0.tgz", - "integrity": "sha512-yKxviR5PH1OKNnisIzZKmgZSus0r2OZb8qCSbqmw34aolT4g3UlzYfeBRym+HJ1J471CR8e2ldNub4PubD1coA==", "funding": [ { "type": "github", @@ -1285,6 +964,50 @@ "glob": "^11.0.0" } }, + "node_modules/@humanfs/core": { + "version": "0.19.1", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanfs/node": { + "version": "0.16.7", + "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", + "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", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, "node_modules/@inquirer/external-editor": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/@inquirer/external-editor/-/external-editor-1.0.3.tgz", @@ -1307,10 +1030,25 @@ } } }, + "node_modules/@inquirer/external-editor/node_modules/iconv-lite": { + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.7.2.tgz", + "integrity": "sha512-im9DjEDQ55s9fL4EYzOAv0yMqmMBSZp6G0VvFyTMPKWxiSBHUj9NW/qqLmXUwXrrM7AvqSlTCfvqRb0cM8yYqw==", + "dev": true, + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, "node_modules/@isaacs/cliui": { "version": "9.0.0", - "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-9.0.0.tgz", - "integrity": "sha512-AokJm4tuBHillT+FpMtxQ60n8ObyXBatq7jD2/JA9dxbDDokKQm8KMht5ibGzLVU9IJDIKK4TPKgMHEYMn3lMg==", "license": "BlueOak-1.0.0", "engines": { "node": ">=18" @@ -1318,8 +1056,7 @@ }, "node_modules/@jridgewell/gen-mapping": { "version": "0.3.13", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", - "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", + "dev": true, "license": "MIT", "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.0", @@ -1328,8 +1065,7 @@ }, "node_modules/@jridgewell/resolve-uri": { "version": "3.1.2", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", - "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "dev": true, "license": "MIT", "engines": { "node": ">=6.0.0" @@ -1337,8 +1073,7 @@ }, "node_modules/@jridgewell/source-map": { "version": "0.3.11", - "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.11.tgz", - "integrity": "sha512-ZMp1V8ZFcPG5dIWnQLr3NSI1MiCU7UETdS/A0G8V/XWHvJv3ZsFqutJn1Y5RPmAPX6F3BiE397OqveU/9NCuIA==", + "dev": true, "license": "MIT", "dependencies": { "@jridgewell/gen-mapping": "^0.3.5", @@ -1347,14 +1082,12 @@ }, "node_modules/@jridgewell/sourcemap-codec": { "version": "1.5.5", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", - "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", + "dev": true, "license": "MIT" }, "node_modules/@jridgewell/trace-mapping": { "version": "0.3.31", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", - "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", + "dev": true, "license": "MIT", "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", @@ -1363,8 +1096,6 @@ }, "node_modules/@lukeed/ms": { "version": "2.0.2", - "resolved": "https://registry.npmjs.org/@lukeed/ms/-/ms-2.0.2.tgz", - "integrity": "sha512-9I2Zn6+NJLfaGoz9jN3lpwDgAYvfGeNYdbAIjJOqzs4Tpc+VU3Jqq4IofSUBKajiDS8k9fZIg18/z13mpk1bsA==", "license": "MIT", "engines": { "node": ">=8" @@ -1405,6 +1136,16 @@ "node": ">=6 <7 || >=8" } }, + "node_modules/@manypkg/find-root/node_modules/universalify": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", + "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4.0.0" + } + }, "node_modules/@manypkg/get-packages": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/@manypkg/get-packages/-/get-packages-1.1.3.tgz", @@ -1442,16 +1183,24 @@ "node": ">=6 <7 || >=8" } }, + "node_modules/@manypkg/get-packages/node_modules/universalify": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", + "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4.0.0" + } + }, "node_modules/@module-federation/error-codes": { "version": "0.22.0", - "resolved": "https://registry.npmjs.org/@module-federation/error-codes/-/error-codes-0.22.0.tgz", - "integrity": "sha512-xF9SjnEy7vTdx+xekjPCV5cIHOGCkdn3pIxo9vU7gEZMIw0SvAEdsy6Uh17xaCpm8V0FWvR0SZoK9Ik6jGOaug==", + "dev": true, "license": "MIT" }, "node_modules/@module-federation/runtime": { "version": "0.22.0", - "resolved": "https://registry.npmjs.org/@module-federation/runtime/-/runtime-0.22.0.tgz", - "integrity": "sha512-38g5iPju2tPC3KHMPxRKmy4k4onNp6ypFPS1eKGsNLUkXgHsPMBFqAjDw96iEcjri91BrahG4XcdyKi97xZzlA==", + "dev": true, "license": "MIT", "dependencies": { "@module-federation/error-codes": "0.22.0", @@ -1461,8 +1210,7 @@ }, "node_modules/@module-federation/runtime-core": { "version": "0.22.0", - "resolved": "https://registry.npmjs.org/@module-federation/runtime-core/-/runtime-core-0.22.0.tgz", - "integrity": "sha512-GR1TcD6/s7zqItfhC87zAp30PqzvceoeDGYTgF3Vx2TXvsfDrhP6Qw9T4vudDQL3uJRne6t7CzdT29YyVxlgIA==", + "dev": true, "license": "MIT", "dependencies": { "@module-federation/error-codes": "0.22.0", @@ -1471,8 +1219,7 @@ }, "node_modules/@module-federation/runtime-tools": { "version": "0.22.0", - "resolved": "https://registry.npmjs.org/@module-federation/runtime-tools/-/runtime-tools-0.22.0.tgz", - "integrity": "sha512-4ScUJ/aUfEernb+4PbLdhM/c60VHl698Gn1gY21m9vyC1Ucn69fPCA1y2EwcCB7IItseRMoNhdcWQnzt/OPCNA==", + "dev": true, "license": "MIT", "dependencies": { "@module-federation/runtime": "0.22.0", @@ -1481,32 +1228,18 @@ }, "node_modules/@module-federation/sdk": { "version": "0.22.0", - "resolved": "https://registry.npmjs.org/@module-federation/sdk/-/sdk-0.22.0.tgz", - "integrity": "sha512-x4aFNBKn2KVQRuNVC5A7SnrSCSqyfIWmm1DvubjbO9iKFe7ith5niw8dqSFBekYBg2Fwy+eMg4sEFNVvCAdo6g==", + "dev": true, "license": "MIT" }, "node_modules/@module-federation/webpack-bundler-runtime": { "version": "0.22.0", - "resolved": "https://registry.npmjs.org/@module-federation/webpack-bundler-runtime/-/webpack-bundler-runtime-0.22.0.tgz", - "integrity": "sha512-aM8gCqXu+/4wBmJtVeMeeMN5guw3chf+2i6HajKtQv7SJfxV/f4IyNQJUeUQu9HfiAZHjqtMV5Lvq/Lvh8LdyA==", + "dev": true, "license": "MIT", "dependencies": { "@module-federation/runtime": "0.22.0", "@module-federation/sdk": "0.22.0" } }, - "node_modules/@napi-rs/wasm-runtime": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.0.7.tgz", - "integrity": "sha512-SeDnOO0Tk7Okiq6DbXmmBODgOAb9dp9gjlphokTUxmt8U3liIP1ZsozBahH69j/RJv+Rfs6IwUKHTgQYJ/HBAw==", - "license": "MIT", - "optional": true, - "dependencies": { - "@emnapi/core": "^1.5.0", - "@emnapi/runtime": "^1.5.0", - "@tybys/wasm-util": "^0.10.1" - } - }, "node_modules/@nodelib/fs.scandir": { "version": "2.1.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", @@ -1547,14 +1280,10 @@ }, "node_modules/@pinojs/redact": { "version": "0.4.0", - "resolved": "https://registry.npmjs.org/@pinojs/redact/-/redact-0.4.0.tgz", - "integrity": "sha512-k2ENnmBugE/rzQfEcdWHcCY+/FM3VLzH9cYEsbdsoqrvzAKRhUZeRNhAZvB8OitQJ1TBed3yqWtdjzS6wJKBwg==", "license": "MIT" }, "node_modules/@puppeteer/browsers": { "version": "2.13.0", - "resolved": "https://registry.npmjs.org/@puppeteer/browsers/-/browsers-2.13.0.tgz", - "integrity": "sha512-46BZJYJjc/WwmKjsvDFykHtXrtomsCIrwYQPOP7VfMJoZY2bsDF9oROBABR3paDjDcmkUye1Pb1BqdcdiipaWA==", "dev": true, "license": "Apache-2.0", "dependencies": { @@ -1575,8 +1304,7 @@ }, "node_modules/@remotion/bundler": { "version": "4.0.429", - "resolved": "https://registry.npmjs.org/@remotion/bundler/-/bundler-4.0.429.tgz", - "integrity": "sha512-5jm+/3Z6Zh+Ymn6ijXUPSkqr7/voscTx76jL84s5o4rW6OjiKcJlHw0WE01use8HZPXNT1OeR9NMnULBa8NLVQ==", + "dev": true, "license": "SEE LICENSE IN LICENSE.md", "dependencies": { "@remotion/media-parser": "4.0.429", @@ -1597,1394 +1325,449 @@ "react-dom": ">=16.8.0" } }, - "node_modules/@remotion/bundler/node_modules/@esbuild/aix-ppc64": { + "node_modules/@remotion/bundler/node_modules/@esbuild/darwin-arm64": { "version": "0.25.0", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.0.tgz", - "integrity": "sha512-O7vun9Sf8DFjH2UtqK8Ku3LkquL9SZL8OLY1T5NZkA34+wG3OQF7cl4Ql8vdNzM6fzBbYfLaiRLIOZ+2FOCgBQ==", "cpu": [ - "ppc64" + "arm64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ - "aix" + "darwin" ], "engines": { "node": ">=18" } }, - "node_modules/@remotion/bundler/node_modules/@esbuild/android-arm": { + "node_modules/@remotion/bundler/node_modules/esbuild": { "version": "0.25.0", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.0.tgz", - "integrity": "sha512-PTyWCYYiU0+1eJKmw21lWtC+d08JDZPQ5g+kFyxP0V+es6VPPSUhM6zk8iImp2jbV6GwjX4pap0JFbUQN65X1g==", - "cpu": [ - "arm" - ], + "dev": true, + "hasInstallScript": true, "license": "MIT", - "optional": true, - "os": [ - "android" - ], + "bin": { + "esbuild": "bin/esbuild" + }, "engines": { "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.25.0", + "@esbuild/android-arm": "0.25.0", + "@esbuild/android-arm64": "0.25.0", + "@esbuild/android-x64": "0.25.0", + "@esbuild/darwin-arm64": "0.25.0", + "@esbuild/darwin-x64": "0.25.0", + "@esbuild/freebsd-arm64": "0.25.0", + "@esbuild/freebsd-x64": "0.25.0", + "@esbuild/linux-arm": "0.25.0", + "@esbuild/linux-arm64": "0.25.0", + "@esbuild/linux-ia32": "0.25.0", + "@esbuild/linux-loong64": "0.25.0", + "@esbuild/linux-mips64el": "0.25.0", + "@esbuild/linux-ppc64": "0.25.0", + "@esbuild/linux-riscv64": "0.25.0", + "@esbuild/linux-s390x": "0.25.0", + "@esbuild/linux-x64": "0.25.0", + "@esbuild/netbsd-arm64": "0.25.0", + "@esbuild/netbsd-x64": "0.25.0", + "@esbuild/openbsd-arm64": "0.25.0", + "@esbuild/openbsd-x64": "0.25.0", + "@esbuild/sunos-x64": "0.25.0", + "@esbuild/win32-arm64": "0.25.0", + "@esbuild/win32-ia32": "0.25.0", + "@esbuild/win32-x64": "0.25.0" } }, - "node_modules/@remotion/bundler/node_modules/@esbuild/android-arm64": { - "version": "0.25.0", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.0.tgz", - "integrity": "sha512-grvv8WncGjDSyUBjN9yHXNt+cq0snxXbDxy5pJtzMKGmmpPxeAmAhWxXI+01lU5rwZomDgD3kJwulEnhTRUd6g==", - "cpu": [ - "arm64" - ], + "node_modules/@remotion/bundler/node_modules/react-refresh": { + "version": "0.9.0", + "dev": true, "license": "MIT", - "optional": true, - "os": [ - "android" - ], "engines": { - "node": ">=18" + "node": ">=0.10.0" } }, - "node_modules/@remotion/bundler/node_modules/@esbuild/android-x64": { - "version": "0.25.0", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.0.tgz", - "integrity": "sha512-m/ix7SfKG5buCnxasr52+LI78SQ+wgdENi9CqyCXwjVR2X4Jkz+BpC3le3AoBPYTC9NHklwngVXvbJ9/Akhrfg==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "android" - ], + "node_modules/@remotion/bundler/node_modules/source-map": { + "version": "0.7.3", + "dev": true, + "license": "BSD-3-Clause", "engines": { - "node": ">=18" + "node": ">= 8" } }, - "node_modules/@remotion/bundler/node_modules/@esbuild/darwin-arm64": { - "version": "0.25.0", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.0.tgz", - "integrity": "sha512-mVwdUb5SRkPayVadIOI78K7aAnPamoeFR2bT5nszFUZ9P8UpK4ratOdYbZZXYSqPKMHfS1wdHCJk1P1EZpRdvw==", - "cpu": [ - "arm64" - ], - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=18" - } + "node_modules/@remotion/cli": { + "version": "4.0.429", + "dev": true, + "license": "SEE LICENSE IN LICENSE.md", + "dependencies": { + "@remotion/bundler": "4.0.429", + "@remotion/media-utils": "4.0.429", + "@remotion/player": "4.0.429", + "@remotion/renderer": "4.0.429", + "@remotion/studio": "4.0.429", + "@remotion/studio-server": "4.0.429", + "@remotion/studio-shared": "4.0.429", + "dotenv": "17.3.1", + "minimist": "1.2.6", + "prompts": "2.4.2", + "remotion": "4.0.429" + }, + "bin": { + "remotion": "remotion-cli.js", + "remotionb": "remotionb-cli.js", + "remotiond": "remotiond-cli.js" + }, + "peerDependencies": { + "react": ">=16.8.0", + "react-dom": ">=16.8.0" + } }, - "node_modules/@remotion/bundler/node_modules/@esbuild/darwin-x64": { - "version": "0.25.0", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.0.tgz", - "integrity": "sha512-DgDaYsPWFTS4S3nWpFcMn/33ZZwAAeAFKNHNa1QN0rI4pUjgqf0f7ONmXf6d22tqTY+H9FNdgeaAa+YIFUn2Rg==", + "node_modules/@remotion/compositor-darwin-arm64": { + "version": "4.0.429", "cpu": [ - "x64" + "arm64" ], - "license": "MIT", + "dev": true, "optional": true, "os": [ "darwin" - ], - "engines": { - "node": ">=18" - } + ] }, - "node_modules/@remotion/bundler/node_modules/@esbuild/freebsd-arm64": { - "version": "0.25.0", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.0.tgz", - "integrity": "sha512-VN4ocxy6dxefN1MepBx/iD1dH5K8qNtNe227I0mnTRjry8tj5MRk4zprLEdG8WPyAPb93/e4pSgi1SoHdgOa4w==", - "cpu": [ - "arm64" - ], + "node_modules/@remotion/licensing": { + "version": "4.0.429", + "dev": true, + "license": "MIT" + }, + "node_modules/@remotion/media-parser": { + "version": "4.0.429", + "dev": true, + "license": "Remotion License https://remotion.dev/license" + }, + "node_modules/@remotion/media-utils": { + "version": "4.0.429", + "dev": true, "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=18" + "dependencies": { + "@remotion/media-parser": "4.0.429", + "@remotion/webcodecs": "4.0.429", + "mediabunny": "1.34.5", + "remotion": "4.0.429" + }, + "peerDependencies": { + "react": ">=16.8.0", + "react-dom": ">=16.8.0" } }, - "node_modules/@remotion/bundler/node_modules/@esbuild/freebsd-x64": { - "version": "0.25.0", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.0.tgz", - "integrity": "sha512-mrSgt7lCh07FY+hDD1TxiTyIHyttn6vnjesnPoVDNmDfOmggTLXRv8Id5fNZey1gl/V2dyVK1VXXqVsQIiAk+A==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=18" + "node_modules/@remotion/paths": { + "version": "4.0.429", + "dev": true, + "license": "MIT" + }, + "node_modules/@remotion/player": { + "version": "4.0.429", + "dev": true, + "license": "SEE LICENSE IN LICENSE.md", + "dependencies": { + "remotion": "4.0.429" + }, + "peerDependencies": { + "react": ">=16.8.0", + "react-dom": ">=16.8.0" } }, - "node_modules/@remotion/bundler/node_modules/@esbuild/linux-arm": { - "version": "0.25.0", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.0.tgz", - "integrity": "sha512-vkB3IYj2IDo3g9xX7HqhPYxVkNQe8qTK55fraQyTzTX/fxaDtXiEnavv9geOsonh2Fd2RMB+i5cbhu2zMNWJwg==", - "cpu": [ - "arm" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" + "node_modules/@remotion/renderer": { + "version": "4.0.429", + "dev": true, + "license": "SEE LICENSE IN LICENSE.md", + "dependencies": { + "@remotion/licensing": "4.0.429", + "@remotion/streaming": "4.0.429", + "execa": "5.1.1", + "extract-zip": "2.0.1", + "remotion": "4.0.429", + "source-map": "^0.8.0-beta.0", + "ws": "8.17.1" + }, + "optionalDependencies": { + "@remotion/compositor-darwin-arm64": "4.0.429", + "@remotion/compositor-darwin-x64": "4.0.429", + "@remotion/compositor-linux-arm64-gnu": "4.0.429", + "@remotion/compositor-linux-arm64-musl": "4.0.429", + "@remotion/compositor-linux-x64-gnu": "4.0.429", + "@remotion/compositor-linux-x64-musl": "4.0.429", + "@remotion/compositor-win32-x64-msvc": "4.0.429" + }, + "peerDependencies": { + "react": ">=16.8.0", + "react-dom": ">=16.8.0" } }, - "node_modules/@remotion/bundler/node_modules/@esbuild/linux-arm64": { - "version": "0.25.0", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.0.tgz", - "integrity": "sha512-9QAQjTWNDM/Vk2bgBl17yWuZxZNQIF0OUUuPZRKoDtqF2k4EtYbpyiG5/Dk7nqeK6kIJWPYldkOcBqjXjrUlmg==", - "cpu": [ - "arm64" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], + "node_modules/@remotion/renderer/node_modules/source-map": { + "version": "0.8.0-beta.0", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "whatwg-url": "^7.0.0" + }, "engines": { - "node": ">=18" + "node": ">= 8" } }, - "node_modules/@remotion/bundler/node_modules/@esbuild/linux-ia32": { - "version": "0.25.0", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.0.tgz", - "integrity": "sha512-43ET5bHbphBegyeqLb7I1eYn2P/JYGNmzzdidq/w0T8E2SsYL1U6un2NFROFRg1JZLTzdCoRomg8Rvf9M6W6Gg==", - "cpu": [ - "ia32" - ], + "node_modules/@remotion/renderer/node_modules/ws": { + "version": "8.17.1", + "dev": true, "license": "MIT", - "optional": true, - "os": [ - "linux" - ], "engines": { - "node": ">=18" + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } } }, - "node_modules/@remotion/bundler/node_modules/@esbuild/linux-loong64": { - "version": "0.25.0", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.0.tgz", - "integrity": "sha512-fC95c/xyNFueMhClxJmeRIj2yrSMdDfmqJnyOY4ZqsALkDrrKJfIg5NTMSzVBr5YW1jf+l7/cndBfP3MSDpoHw==", - "cpu": [ - "loong64" - ], + "node_modules/@remotion/shapes": { + "version": "4.0.429", + "dev": true, "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" + "dependencies": { + "@remotion/paths": "4.0.429" + }, + "peerDependencies": { + "react": ">=16.8.0", + "react-dom": ">=16.8.0" } }, - "node_modules/@remotion/bundler/node_modules/@esbuild/linux-mips64el": { - "version": "0.25.0", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.0.tgz", - "integrity": "sha512-nkAMFju7KDW73T1DdH7glcyIptm95a7Le8irTQNO/qtkoyypZAnjchQgooFUDQhNAy4iu08N79W4T4pMBwhPwQ==", - "cpu": [ - "mips64el" - ], + "node_modules/@remotion/streaming": { + "version": "4.0.429", + "dev": true, + "license": "MIT" + }, + "node_modules/@remotion/studio": { + "version": "4.0.429", + "dev": true, "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" + "dependencies": { + "@remotion/media-utils": "4.0.429", + "@remotion/player": "4.0.429", + "@remotion/renderer": "4.0.429", + "@remotion/studio-shared": "4.0.429", + "@remotion/web-renderer": "4.0.429", + "@remotion/zod-types": "4.0.429", + "mediabunny": "1.34.5", + "memfs": "3.4.3", + "open": "^8.4.2", + "remotion": "4.0.429", + "semver": "7.5.3", + "source-map": "0.7.3", + "zod": "4.3.6" + }, + "peerDependencies": { + "react": ">=16.8.0", + "react-dom": ">=16.8.0" } }, - "node_modules/@remotion/bundler/node_modules/@esbuild/linux-ppc64": { - "version": "0.25.0", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.0.tgz", - "integrity": "sha512-NhyOejdhRGS8Iwv+KKR2zTq2PpysF9XqY+Zk77vQHqNbo/PwZCzB5/h7VGuREZm1fixhs4Q/qWRSi5zmAiO4Fw==", - "cpu": [ - "ppc64" - ], + "node_modules/@remotion/studio-server": { + "version": "4.0.429", + "dev": true, "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" + "dependencies": { + "@babel/parser": "7.24.1", + "@remotion/bundler": "4.0.429", + "@remotion/renderer": "4.0.429", + "@remotion/studio-shared": "4.0.429", + "memfs": "3.4.3", + "open": "^8.4.2", + "prettier": "3.8.1", + "recast": "0.23.11", + "remotion": "4.0.429", + "semver": "7.5.3", + "source-map": "0.7.3" } }, - "node_modules/@remotion/bundler/node_modules/@esbuild/linux-riscv64": { - "version": "0.25.0", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.0.tgz", - "integrity": "sha512-5S/rbP5OY+GHLC5qXp1y/Mx//e92L1YDqkiBbO9TQOvuFXM+iDqUNG5XopAnXoRH3FjIUDkeGcY1cgNvnXp/kA==", - "cpu": [ - "riscv64" - ], + "node_modules/@remotion/studio-server/node_modules/@babel/parser": { + "version": "7.24.1", + "dev": true, "license": "MIT", - "optional": true, - "os": [ - "linux" - ], + "bin": { + "parser": "bin/babel-parser.js" + }, "engines": { - "node": ">=18" + "node": ">=6.0.0" } }, - "node_modules/@remotion/bundler/node_modules/@esbuild/linux-s390x": { - "version": "0.25.0", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.0.tgz", - "integrity": "sha512-XM2BFsEBz0Fw37V0zU4CXfcfuACMrppsMFKdYY2WuTS3yi8O1nFOhil/xhKTmE1nPmVyvQJjJivgDT+xh8pXJA==", - "cpu": [ - "s390x" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@remotion/bundler/node_modules/@esbuild/linux-x64": { - "version": "0.25.0", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.0.tgz", - "integrity": "sha512-9yl91rHw/cpwMCNytUDxwj2XjFpxML0y9HAOH9pNVQDpQrBxHy01Dx+vaMu0N1CKa/RzBD2hB4u//nfc+Sd3Cw==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@remotion/bundler/node_modules/@esbuild/netbsd-arm64": { - "version": "0.25.0", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.0.tgz", - "integrity": "sha512-RuG4PSMPFfrkH6UwCAqBzauBWTygTvb1nxWasEJooGSJ/NwRw7b2HOwyRTQIU97Hq37l3npXoZGYMy3b3xYvPw==", - "cpu": [ - "arm64" - ], - "license": "MIT", - "optional": true, - "os": [ - "netbsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@remotion/bundler/node_modules/@esbuild/netbsd-x64": { - "version": "0.25.0", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.0.tgz", - "integrity": "sha512-jl+qisSB5jk01N5f7sPCsBENCOlPiS/xptD5yxOx2oqQfyourJwIKLRA2yqWdifj3owQZCL2sn6o08dBzZGQzA==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "netbsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@remotion/bundler/node_modules/@esbuild/openbsd-arm64": { - "version": "0.25.0", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.0.tgz", - "integrity": "sha512-21sUNbq2r84YE+SJDfaQRvdgznTD8Xc0oc3p3iW/a1EVWeNj/SdUCbm5U0itZPQYRuRTW20fPMWMpcrciH2EJw==", - "cpu": [ - "arm64" - ], - "license": "MIT", - "optional": true, - "os": [ - "openbsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@remotion/bundler/node_modules/@esbuild/openbsd-x64": { - "version": "0.25.0", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.0.tgz", - "integrity": "sha512-2gwwriSMPcCFRlPlKx3zLQhfN/2WjJ2NSlg5TKLQOJdV0mSxIcYNTMhk3H3ulL/cak+Xj0lY1Ym9ysDV1igceg==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "openbsd" - ], + "node_modules/@remotion/studio-server/node_modules/lru-cache": { + "version": "6.0.0", + "dev": true, + "license": "ISC", + "dependencies": { + "yallist": "^4.0.0" + }, "engines": { - "node": ">=18" + "node": ">=10" } }, - "node_modules/@remotion/bundler/node_modules/@esbuild/sunos-x64": { - "version": "0.25.0", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.0.tgz", - "integrity": "sha512-bxI7ThgLzPrPz484/S9jLlvUAHYMzy6I0XiU1ZMeAEOBcS0VePBFxh1JjTQt3Xiat5b6Oh4x7UC7IwKQKIJRIg==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "sunos" - ], + "node_modules/@remotion/studio-server/node_modules/semver": { + "version": "7.5.3", + "dev": true, + "license": "ISC", + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, "engines": { - "node": ">=18" + "node": ">=10" } }, - "node_modules/@remotion/bundler/node_modules/@esbuild/win32-arm64": { - "version": "0.25.0", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.0.tgz", - "integrity": "sha512-ZUAc2YK6JW89xTbXvftxdnYy3m4iHIkDtK3CLce8wg8M2L+YZhIvO1DKpxrd0Yr59AeNNkTiic9YLf6FTtXWMw==", - "cpu": [ - "arm64" - ], - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], + "node_modules/@remotion/studio-server/node_modules/source-map": { + "version": "0.7.3", + "dev": true, + "license": "BSD-3-Clause", "engines": { - "node": ">=18" + "node": ">= 8" } }, - "node_modules/@remotion/bundler/node_modules/@esbuild/win32-ia32": { - "version": "0.25.0", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.0.tgz", - "integrity": "sha512-eSNxISBu8XweVEWG31/JzjkIGbGIJN/TrRoiSVZwZ6pkC6VX4Im/WV2cz559/TXLcYbcrDN8JtKgd9DJVIo8GA==", - "cpu": [ - "ia32" - ], + "node_modules/@remotion/studio-shared": { + "version": "4.0.429", + "dev": true, "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=18" + "dependencies": { + "remotion": "4.0.429" } }, - "node_modules/@remotion/bundler/node_modules/@esbuild/win32-x64": { - "version": "0.25.0", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.0.tgz", - "integrity": "sha512-ZENoHJBxA20C2zFzh6AI4fT6RraMzjYw4xKWemRTRmRVtN9c5DcH9r/f2ihEkMjOW5eGgrwCslG/+Y/3bL+DHQ==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], + "node_modules/@remotion/studio/node_modules/lru-cache": { + "version": "6.0.0", + "dev": true, + "license": "ISC", + "dependencies": { + "yallist": "^4.0.0" + }, "engines": { - "node": ">=18" + "node": ">=10" } }, - "node_modules/@remotion/bundler/node_modules/esbuild": { - "version": "0.25.0", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.0.tgz", - "integrity": "sha512-BXq5mqc8ltbaN34cDqWuYKyNhX8D/Z0J1xdtdQ8UcIIIyJyz+ZMKUt58tF3SrZ85jcfN/PZYhjR5uDQAYNVbuw==", - "hasInstallScript": true, - "license": "MIT", - "bin": { - "esbuild": "bin/esbuild" + "node_modules/@remotion/studio/node_modules/semver": { + "version": "7.5.3", + "dev": true, + "license": "ISC", + "dependencies": { + "lru-cache": "^6.0.0" }, - "engines": { - "node": ">=18" + "bin": { + "semver": "bin/semver.js" }, - "optionalDependencies": { - "@esbuild/aix-ppc64": "0.25.0", - "@esbuild/android-arm": "0.25.0", - "@esbuild/android-arm64": "0.25.0", - "@esbuild/android-x64": "0.25.0", - "@esbuild/darwin-arm64": "0.25.0", - "@esbuild/darwin-x64": "0.25.0", - "@esbuild/freebsd-arm64": "0.25.0", - "@esbuild/freebsd-x64": "0.25.0", - "@esbuild/linux-arm": "0.25.0", - "@esbuild/linux-arm64": "0.25.0", - "@esbuild/linux-ia32": "0.25.0", - "@esbuild/linux-loong64": "0.25.0", - "@esbuild/linux-mips64el": "0.25.0", - "@esbuild/linux-ppc64": "0.25.0", - "@esbuild/linux-riscv64": "0.25.0", - "@esbuild/linux-s390x": "0.25.0", - "@esbuild/linux-x64": "0.25.0", - "@esbuild/netbsd-arm64": "0.25.0", - "@esbuild/netbsd-x64": "0.25.0", - "@esbuild/openbsd-arm64": "0.25.0", - "@esbuild/openbsd-x64": "0.25.0", - "@esbuild/sunos-x64": "0.25.0", - "@esbuild/win32-arm64": "0.25.0", - "@esbuild/win32-ia32": "0.25.0", - "@esbuild/win32-x64": "0.25.0" - } - }, - "node_modules/@remotion/bundler/node_modules/react-refresh": { - "version": "0.9.0", - "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.9.0.tgz", - "integrity": "sha512-Gvzk7OZpiqKSkxsQvO/mbTN1poglhmAV7gR/DdIrRrSMXraRQQlfikRJOr3Nb9GTMPC5kof948Zy6jJZIFtDvQ==", - "license": "MIT", "engines": { - "node": ">=0.10.0" + "node": ">=10" } }, - "node_modules/@remotion/bundler/node_modules/source-map": { + "node_modules/@remotion/studio/node_modules/source-map": { "version": "0.7.3", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz", - "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==", + "dev": true, "license": "BSD-3-Clause", "engines": { "node": ">= 8" } }, - "node_modules/@remotion/cli": { + "node_modules/@remotion/transitions": { "version": "4.0.429", - "resolved": "https://registry.npmjs.org/@remotion/cli/-/cli-4.0.429.tgz", - "integrity": "sha512-J6d+WyLlE4+Hu9iZNtnGMi1EqC6cUbi0Y1bVqAzPlVjOc1IOsuyutik1CDRkG7KiVLWO+JmlXV697Sk24STtuw==", - "license": "SEE LICENSE IN LICENSE.md", + "dev": true, + "license": "UNLICENSED", "dependencies": { - "@remotion/bundler": "4.0.429", - "@remotion/media-utils": "4.0.429", - "@remotion/player": "4.0.429", - "@remotion/renderer": "4.0.429", - "@remotion/studio": "4.0.429", - "@remotion/studio-server": "4.0.429", - "@remotion/studio-shared": "4.0.429", - "dotenv": "17.3.1", - "minimist": "1.2.6", - "prompts": "2.4.2", + "@remotion/paths": "4.0.429", + "@remotion/shapes": "4.0.429", "remotion": "4.0.429" }, - "bin": { - "remotion": "remotion-cli.js", - "remotionb": "remotionb-cli.js", - "remotiond": "remotiond-cli.js" - }, "peerDependencies": { "react": ">=16.8.0", "react-dom": ">=16.8.0" } }, - "node_modules/@remotion/compositor-darwin-arm64": { - "version": "4.0.429", - "resolved": "https://registry.npmjs.org/@remotion/compositor-darwin-arm64/-/compositor-darwin-arm64-4.0.429.tgz", - "integrity": "sha512-V3Cv7TZyKulBPOBQJu2GONiKA+DDjGT6rWAc3WX4M9J9EDUwKiFFTDuTEpC7s4mcUDoAUXbnYE8ZlnWGaAuJhQ==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "darwin" - ] - }, - "node_modules/@remotion/compositor-darwin-x64": { - "version": "4.0.429", - "resolved": "https://registry.npmjs.org/@remotion/compositor-darwin-x64/-/compositor-darwin-x64-4.0.429.tgz", - "integrity": "sha512-vB8NM0j7gvCniu1dZ0p4MmTDN44Dvgd2iq6vStigzEQ1P2vlcx7qHEdVfaZBHsjdjMXD/UdwNmb34+lw3v6KEw==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "darwin" - ] - }, - "node_modules/@remotion/compositor-linux-arm64-gnu": { + "node_modules/@remotion/web-renderer": { "version": "4.0.429", - "resolved": "https://registry.npmjs.org/@remotion/compositor-linux-arm64-gnu/-/compositor-linux-arm64-gnu-4.0.429.tgz", - "integrity": "sha512-F8N1HsRiCDw1EWWWI9hLNFTQy1mY7QLsWh0ywnrNCx62aF+8NpdYdW4pt/e7s4SQmkLh7enrkuqI0a6aGw4rpw==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "linux" - ] + "dev": true, + "license": "UNLICENSED", + "dependencies": { + "@remotion/licensing": "4.0.429", + "mediabunny": "1.34.5", + "remotion": "4.0.429" + }, + "peerDependencies": { + "react": ">=18.0.0", + "react-dom": ">=18.0.0" + } }, - "node_modules/@remotion/compositor-linux-arm64-musl": { + "node_modules/@remotion/webcodecs": { "version": "4.0.429", - "resolved": "https://registry.npmjs.org/@remotion/compositor-linux-arm64-musl/-/compositor-linux-arm64-musl-4.0.429.tgz", - "integrity": "sha512-rvDjjascY9HAQ1nfbrdlVxyQ/xYj84jf0LylLmWJgr0kZVw5l8D/QXH4HTQeoPKhM3cBsCMKpW7oseHMoDyM5A==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "linux" - ] + "dev": true, + "license": "Remotion License (See https://remotion.dev/docs/webcodecs#license)", + "dependencies": { + "@remotion/media-parser": "4.0.429" + } }, - "node_modules/@remotion/compositor-linux-x64-gnu": { + "node_modules/@remotion/zod-types": { "version": "4.0.429", - "resolved": "https://registry.npmjs.org/@remotion/compositor-linux-x64-gnu/-/compositor-linux-x64-gnu-4.0.429.tgz", - "integrity": "sha512-YRe6+oSnNFpc2jgkrmAISAO2xUA0LqzE49ykqe0zCH3MXKtof76lMwDPoFJT1C4vDKErjSedltQNnnG7bPQGlw==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@remotion/compositor-linux-x64-musl": { - "version": "4.0.429", - "resolved": "https://registry.npmjs.org/@remotion/compositor-linux-x64-musl/-/compositor-linux-x64-musl-4.0.429.tgz", - "integrity": "sha512-tlgWyrOWFDw1Z8IyPGDrQhd2B3saZ/sGRC7nN0XhcbMnaq3wxWe+cUSCJPT9kFNR9tKNCZ0y/jG/B8h6Z0GiHQ==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@remotion/compositor-win32-x64-msvc": { - "version": "4.0.429", - "resolved": "https://registry.npmjs.org/@remotion/compositor-win32-x64-msvc/-/compositor-win32-x64-msvc-4.0.429.tgz", - "integrity": "sha512-YnpRTVwrOnDA8nYCZEP6Tdx+Ea+LQO4kXm9sjg2Rxe3s55lt+dUURl1yvOSKTW8nKZlfDAqldI1YDVvfD8NnCQ==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "win32" - ] - }, - "node_modules/@remotion/licensing": { - "version": "4.0.429", - "resolved": "https://registry.npmjs.org/@remotion/licensing/-/licensing-4.0.429.tgz", - "integrity": "sha512-dZxojOI2+MVKIFDF74t3EkRuD5AGtgzVGFbFbsbLPR4RbdeLhsCF7mtw/Y6ZhcWRfVPqZhjl56ALPqXq+1CYCw==", - "license": "MIT" - }, - "node_modules/@remotion/media-parser": { - "version": "4.0.429", - "resolved": "https://registry.npmjs.org/@remotion/media-parser/-/media-parser-4.0.429.tgz", - "integrity": "sha512-wWKdVsq+ex142ylJuCMHGh9wc4mjXNXXEMFPONZciIbOa5wxm8TF+OG9sQfjDBRcCfxxSScHYYszl8P7SvlQ5A==", - "license": "Remotion License https://remotion.dev/license" - }, - "node_modules/@remotion/media-utils": { - "version": "4.0.429", - "resolved": "https://registry.npmjs.org/@remotion/media-utils/-/media-utils-4.0.429.tgz", - "integrity": "sha512-E65j/DjaWrYjkUoF/fJimJnK6KN/4X3bDduf0e+ukm3SfzOpVXDSJg3HH9vreOT1/1RHrX45Ifr95tQxuO04Ug==", - "license": "MIT", - "dependencies": { - "@remotion/media-parser": "4.0.429", - "@remotion/webcodecs": "4.0.429", - "mediabunny": "1.34.5", - "remotion": "4.0.429" - }, - "peerDependencies": { - "react": ">=16.8.0", - "react-dom": ">=16.8.0" - } - }, - "node_modules/@remotion/paths": { - "version": "4.0.429", - "resolved": "https://registry.npmjs.org/@remotion/paths/-/paths-4.0.429.tgz", - "integrity": "sha512-24z1yXQQoIHALn7b2xFSWcsrWhLWs5xLygrOBWXg/a0ywFuyCf3/J0XXv1zs2lZ/VsC4Rw2oSxjkvbcmhjsipA==", - "license": "MIT" - }, - "node_modules/@remotion/player": { - "version": "4.0.429", - "resolved": "https://registry.npmjs.org/@remotion/player/-/player-4.0.429.tgz", - "integrity": "sha512-OJM08HvKxwEn8tCS4LphiBLMgTnDcfq+BWwmfkpu1FhbWFxWZPRO5A8RhWokxRgurL4mEwtWLeHYCsZ48JfAvw==", - "license": "SEE LICENSE IN LICENSE.md", - "dependencies": { - "remotion": "4.0.429" - }, - "peerDependencies": { - "react": ">=16.8.0", - "react-dom": ">=16.8.0" - } - }, - "node_modules/@remotion/renderer": { - "version": "4.0.429", - "resolved": "https://registry.npmjs.org/@remotion/renderer/-/renderer-4.0.429.tgz", - "integrity": "sha512-rxrAvvIWs8iCakXI4jYfusBBgR8Iet3obWiau/wy7bQ7rolXY3gARD5qJU/P0K9+gAqC3ds15M8Z2Av5lEhccw==", - "license": "SEE LICENSE IN LICENSE.md", - "dependencies": { - "@remotion/licensing": "4.0.429", - "@remotion/streaming": "4.0.429", - "execa": "5.1.1", - "extract-zip": "2.0.1", - "remotion": "4.0.429", - "source-map": "^0.8.0-beta.0", - "ws": "8.17.1" - }, - "optionalDependencies": { - "@remotion/compositor-darwin-arm64": "4.0.429", - "@remotion/compositor-darwin-x64": "4.0.429", - "@remotion/compositor-linux-arm64-gnu": "4.0.429", - "@remotion/compositor-linux-arm64-musl": "4.0.429", - "@remotion/compositor-linux-x64-gnu": "4.0.429", - "@remotion/compositor-linux-x64-musl": "4.0.429", - "@remotion/compositor-win32-x64-msvc": "4.0.429" - }, - "peerDependencies": { - "react": ">=16.8.0", - "react-dom": ">=16.8.0" - } - }, - "node_modules/@remotion/renderer/node_modules/source-map": { - "version": "0.8.0-beta.0", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.8.0-beta.0.tgz", - "integrity": "sha512-2ymg6oRBpebeZi9UUNsgQ89bhx01TcTkmNTGnNO88imTmbSgy4nfujrgVEFKWpMTEGA11EDkTt7mqObTPdigIA==", - "deprecated": "The work that was done in this beta branch won't be included in future versions", - "license": "BSD-3-Clause", - "dependencies": { - "whatwg-url": "^7.0.0" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@remotion/renderer/node_modules/ws": { - "version": "8.17.1", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.17.1.tgz", - "integrity": "sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ==", - "license": "MIT", - "engines": { - "node": ">=10.0.0" - }, - "peerDependencies": { - "bufferutil": "^4.0.1", - "utf-8-validate": ">=5.0.2" - }, - "peerDependenciesMeta": { - "bufferutil": { - "optional": true - }, - "utf-8-validate": { - "optional": true - } - } - }, - "node_modules/@remotion/shapes": { - "version": "4.0.429", - "resolved": "https://registry.npmjs.org/@remotion/shapes/-/shapes-4.0.429.tgz", - "integrity": "sha512-tfulMYS8PUqYxBRvhA+s/sPCLOYSfe6qnR+6/cj8TZF96yAgZD7OWiPAXM3qy40ZdWP/Y18DpBOEiOMNwHEHBA==", - "license": "MIT", - "dependencies": { - "@remotion/paths": "4.0.429" - }, - "peerDependencies": { - "react": ">=16.8.0", - "react-dom": ">=16.8.0" - } - }, - "node_modules/@remotion/streaming": { - "version": "4.0.429", - "resolved": "https://registry.npmjs.org/@remotion/streaming/-/streaming-4.0.429.tgz", - "integrity": "sha512-A83QJVX1titE7Eaq80XRf7bj3Vdml/91Kar2ETBkINSsDgKEUmwW42EG/fYk6JMrdm9qkPQs2WWKLZX5uNyF4A==", - "license": "MIT" - }, - "node_modules/@remotion/studio": { - "version": "4.0.429", - "resolved": "https://registry.npmjs.org/@remotion/studio/-/studio-4.0.429.tgz", - "integrity": "sha512-hEieMtT8DV0X5OeTSNc4GKebEuXhJNnZfyiqySp0YnCh28W5z/mnQyZMp5JMq2XTRISm+iE9yxnHp0xTRFywJA==", - "license": "MIT", - "dependencies": { - "@remotion/media-utils": "4.0.429", - "@remotion/player": "4.0.429", - "@remotion/renderer": "4.0.429", - "@remotion/studio-shared": "4.0.429", - "@remotion/web-renderer": "4.0.429", - "@remotion/zod-types": "4.0.429", - "mediabunny": "1.34.5", - "memfs": "3.4.3", - "open": "^8.4.2", - "remotion": "4.0.429", - "semver": "7.5.3", - "source-map": "0.7.3", - "zod": "4.3.6" - }, - "peerDependencies": { - "react": ">=16.8.0", - "react-dom": ">=16.8.0" - } - }, - "node_modules/@remotion/studio-server": { - "version": "4.0.429", - "resolved": "https://registry.npmjs.org/@remotion/studio-server/-/studio-server-4.0.429.tgz", - "integrity": "sha512-UCf07W/hdm14uuXmD2NW+1rXbQmi3NOw2WfFkx0dy2R4J7l8PUW/NqgEl2UluFsOc78m5/l+tzWgGC/yVH//cg==", - "license": "MIT", - "dependencies": { - "@babel/parser": "7.24.1", - "@remotion/bundler": "4.0.429", - "@remotion/renderer": "4.0.429", - "@remotion/studio-shared": "4.0.429", - "memfs": "3.4.3", - "open": "^8.4.2", - "prettier": "3.8.1", - "recast": "0.23.11", - "remotion": "4.0.429", - "semver": "7.5.3", - "source-map": "0.7.3" - } - }, - "node_modules/@remotion/studio-server/node_modules/@babel/parser": { - "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.24.1.tgz", - "integrity": "sha512-Zo9c7N3xdOIQrNip7Lc9wvRPzlRtovHVE4lkz8WEDr7uYh/GMQhSiIgFxGIArRHYdJE5kxtZjAf8rT0xhdLCzg==", - "license": "MIT", - "bin": { - "parser": "bin/babel-parser.js" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@remotion/studio-server/node_modules/lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "license": "ISC", - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/@remotion/studio-server/node_modules/semver": { - "version": "7.5.3", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.3.tgz", - "integrity": "sha512-QBlUtyVk/5EeHbi7X0fw6liDZc7BBmEaSYn01fMU1OUYbf6GPsbTtd8WmnqbI20SeycoHSeiybkE/q1Q+qlThQ==", - "license": "ISC", - "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/@remotion/studio-server/node_modules/source-map": { - "version": "0.7.3", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz", - "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==", - "license": "BSD-3-Clause", - "engines": { - "node": ">= 8" - } - }, - "node_modules/@remotion/studio-shared": { - "version": "4.0.429", - "resolved": "https://registry.npmjs.org/@remotion/studio-shared/-/studio-shared-4.0.429.tgz", - "integrity": "sha512-dnBG5EDDNb039At/c6Qv0u46RazcViqhQidlIMKGOOj76SWS+50Pn/P6F80hr9ia3sRNhkMIf3ckugw1oIH6AA==", - "license": "MIT", - "dependencies": { - "remotion": "4.0.429" - } - }, - "node_modules/@remotion/studio/node_modules/lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "license": "ISC", - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/@remotion/studio/node_modules/semver": { - "version": "7.5.3", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.3.tgz", - "integrity": "sha512-QBlUtyVk/5EeHbi7X0fw6liDZc7BBmEaSYn01fMU1OUYbf6GPsbTtd8WmnqbI20SeycoHSeiybkE/q1Q+qlThQ==", - "license": "ISC", - "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/@remotion/studio/node_modules/source-map": { - "version": "0.7.3", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz", - "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==", - "license": "BSD-3-Clause", - "engines": { - "node": ">= 8" - } - }, - "node_modules/@remotion/transitions": { - "version": "4.0.429", - "resolved": "https://registry.npmjs.org/@remotion/transitions/-/transitions-4.0.429.tgz", - "integrity": "sha512-rWPn2oD7zO1DI8/Q2TcK2RzLMl28EvSE82yUX/sY6BfaUNi/Z39VLHa1TCK6TgrXKYHupClOmmi6ho8PYxiUVg==", - "license": "UNLICENSED", - "dependencies": { - "@remotion/paths": "4.0.429", - "@remotion/shapes": "4.0.429", - "remotion": "4.0.429" - }, - "peerDependencies": { - "react": ">=16.8.0", - "react-dom": ">=16.8.0" - } - }, - "node_modules/@remotion/web-renderer": { - "version": "4.0.429", - "resolved": "https://registry.npmjs.org/@remotion/web-renderer/-/web-renderer-4.0.429.tgz", - "integrity": "sha512-dRKvWK40aeOn5vapJi62TbPQ+4Mz1lvU2cCPL5vHTQ/nSvBOC/rWmHJCuzyEHOblAWLOPOqaTdK0ztvEL40TAw==", - "license": "UNLICENSED", - "dependencies": { - "@remotion/licensing": "4.0.429", - "mediabunny": "1.34.5", - "remotion": "4.0.429" - }, - "peerDependencies": { - "react": ">=18.0.0", - "react-dom": ">=18.0.0" - } - }, - "node_modules/@remotion/webcodecs": { - "version": "4.0.429", - "resolved": "https://registry.npmjs.org/@remotion/webcodecs/-/webcodecs-4.0.429.tgz", - "integrity": "sha512-2bBZftrnXCNOdZiqYZBUTPgJolCgEKpBdnkYEc4tEeIzmVmtVtx88Ts2fUXBE6UvQ5bwaf2KohFYyQXH3/rYrg==", - "license": "Remotion License (See https://remotion.dev/docs/webcodecs#license)", - "dependencies": { - "@remotion/media-parser": "4.0.429" - } - }, - "node_modules/@remotion/zod-types": { - "version": "4.0.429", - "resolved": "https://registry.npmjs.org/@remotion/zod-types/-/zod-types-4.0.429.tgz", - "integrity": "sha512-Fk0o+ueKZuBjNlEs1pVXMvpre3v9POcuxp2pNLDHFcqcplNidqJmGc+J0EXE/FmBJtN8h1FhXSd2x4NPNCIsTQ==", - "license": "MIT", - "dependencies": { - "remotion": "4.0.429" - }, - "peerDependencies": { - "zod": "4.3.6" - } - }, - "node_modules/@rollup/rollup-android-arm-eabi": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.59.0.tgz", - "integrity": "sha512-upnNBkA6ZH2VKGcBj9Fyl9IGNPULcjXRlg0LLeaioQWueH30p6IXtJEbKAgvyv+mJaMxSm1l6xwDXYjpEMiLMg==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ] - }, - "node_modules/@rollup/rollup-android-arm64": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.59.0.tgz", - "integrity": "sha512-hZ+Zxj3SySm4A/DylsDKZAeVg0mvi++0PYVceVyX7hemkw7OreKdCvW2oQ3T1FMZvCaQXqOTHb8qmBShoqk69Q==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ] - }, - "node_modules/@rollup/rollup-darwin-arm64": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.59.0.tgz", - "integrity": "sha512-W2Psnbh1J8ZJw0xKAd8zdNgF9HRLkdWwwdWqubSVk0pUuQkoHnv7rx4GiF9rT4t5DIZGAsConRE3AxCdJ4m8rg==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ] - }, - "node_modules/@rollup/rollup-darwin-x64": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.59.0.tgz", - "integrity": "sha512-ZW2KkwlS4lwTv7ZVsYDiARfFCnSGhzYPdiOU4IM2fDbL+QGlyAbjgSFuqNRbSthybLbIJ915UtZBtmuLrQAT/w==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ] - }, - "node_modules/@rollup/rollup-freebsd-arm64": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.59.0.tgz", - "integrity": "sha512-EsKaJ5ytAu9jI3lonzn3BgG8iRBjV4LxZexygcQbpiU0wU0ATxhNVEpXKfUa0pS05gTcSDMKpn3Sx+QB9RlTTA==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ] - }, - "node_modules/@rollup/rollup-freebsd-x64": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.59.0.tgz", - "integrity": "sha512-d3DuZi2KzTMjImrxoHIAODUZYoUUMsuUiY4SRRcJy6NJoZ6iIqWnJu9IScV9jXysyGMVuW+KNzZvBLOcpdl3Vg==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ] - }, - "node_modules/@rollup/rollup-linux-arm-gnueabihf": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.59.0.tgz", - "integrity": "sha512-t4ONHboXi/3E0rT6OZl1pKbl2Vgxf9vJfWgmUoCEVQVxhW6Cw/c8I6hbbu7DAvgp82RKiH7TpLwxnJeKv2pbsw==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-arm-musleabihf": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.59.0.tgz", - "integrity": "sha512-CikFT7aYPA2ufMD086cVORBYGHffBo4K8MQ4uPS/ZnY54GKj36i196u8U+aDVT2LX4eSMbyHtyOh7D7Zvk2VvA==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-arm64-gnu": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.59.0.tgz", - "integrity": "sha512-jYgUGk5aLd1nUb1CtQ8E+t5JhLc9x5WdBKew9ZgAXg7DBk0ZHErLHdXM24rfX+bKrFe+Xp5YuJo54I5HFjGDAA==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-arm64-musl": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.59.0.tgz", - "integrity": "sha512-peZRVEdnFWZ5Bh2KeumKG9ty7aCXzzEsHShOZEFiCQlDEepP1dpUl/SrUNXNg13UmZl+gzVDPsiCwnV1uI0RUA==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-loong64-gnu": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.59.0.tgz", - "integrity": "sha512-gbUSW/97f7+r4gHy3Jlup8zDG190AuodsWnNiXErp9mT90iCy9NKKU0Xwx5k8VlRAIV2uU9CsMnEFg/xXaOfXg==", - "cpu": [ - "loong64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-loong64-musl": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.59.0.tgz", - "integrity": "sha512-yTRONe79E+o0FWFijasoTjtzG9EBedFXJMl888NBEDCDV9I2wGbFFfJQQe63OijbFCUZqxpHz1GzpbtSFikJ4Q==", - "cpu": [ - "loong64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-ppc64-gnu": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.59.0.tgz", - "integrity": "sha512-sw1o3tfyk12k3OEpRddF68a1unZ5VCN7zoTNtSn2KndUE+ea3m3ROOKRCZxEpmT9nsGnogpFP9x6mnLTCaoLkA==", - "cpu": [ - "ppc64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-ppc64-musl": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.59.0.tgz", - "integrity": "sha512-+2kLtQ4xT3AiIxkzFVFXfsmlZiG5FXYW7ZyIIvGA7Bdeuh9Z0aN4hVyXS/G1E9bTP/vqszNIN/pUKCk/BTHsKA==", - "cpu": [ - "ppc64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-riscv64-gnu": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.59.0.tgz", - "integrity": "sha512-NDYMpsXYJJaj+I7UdwIuHHNxXZ/b/N2hR15NyH3m2qAtb/hHPA4g4SuuvrdxetTdndfj9b1WOmy73kcPRoERUg==", - "cpu": [ - "riscv64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-riscv64-musl": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.59.0.tgz", - "integrity": "sha512-nLckB8WOqHIf1bhymk+oHxvM9D3tyPndZH8i8+35p/1YiVoVswPid2yLzgX7ZJP0KQvnkhM4H6QZ5m0LzbyIAg==", - "cpu": [ - "riscv64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-s390x-gnu": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.59.0.tgz", - "integrity": "sha512-oF87Ie3uAIvORFBpwnCvUzdeYUqi2wY6jRFWJAy1qus/udHFYIkplYRW+wo+GRUP4sKzYdmE1Y3+rY5Gc4ZO+w==", - "cpu": [ - "s390x" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-x64-gnu": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.59.0.tgz", - "integrity": "sha512-3AHmtQq/ppNuUspKAlvA8HtLybkDflkMuLK4DPo77DfthRb71V84/c4MlWJXixZz4uruIH4uaa07IqoAkG64fg==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-x64-musl": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.59.0.tgz", - "integrity": "sha512-2UdiwS/9cTAx7qIUZB/fWtToJwvt0Vbo0zmnYt7ED35KPg13Q0ym1g442THLC7VyI6JfYTP4PiSOWyoMdV2/xg==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-openbsd-x64": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.59.0.tgz", - "integrity": "sha512-M3bLRAVk6GOwFlPTIxVBSYKUaqfLrn8l0psKinkCFxl4lQvOSz8ZrKDz2gxcBwHFpci0B6rttydI4IpS4IS/jQ==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "openbsd" - ] - }, - "node_modules/@rollup/rollup-openharmony-arm64": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.59.0.tgz", - "integrity": "sha512-tt9KBJqaqp5i5HUZzoafHZX8b5Q2Fe7UjYERADll83O4fGqJ49O1FsL6LpdzVFQcpwvnyd0i+K/VSwu/o/nWlA==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "openharmony" - ] - }, - "node_modules/@rollup/rollup-win32-arm64-msvc": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.59.0.tgz", - "integrity": "sha512-V5B6mG7OrGTwnxaNUzZTDTjDS7F75PO1ae6MJYdiMu60sq0CqN5CVeVsbhPxalupvTX8gXVSU9gq+Rx1/hvu6A==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ] - }, - "node_modules/@rollup/rollup-win32-ia32-msvc": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.59.0.tgz", - "integrity": "sha512-UKFMHPuM9R0iBegwzKF4y0C4J9u8C6MEJgFuXTBerMk7EJ92GFVFYBfOZaSGLu6COf7FxpQNqhNS4c4icUPqxA==", - "cpu": [ - "ia32" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ] - }, - "node_modules/@rollup/rollup-win32-x64-gnu": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.59.0.tgz", - "integrity": "sha512-laBkYlSS1n2L8fSo1thDNGrCTQMmxjYY5G0WFWjFFYZkKPjsMBsgJfGf4TLxXrF6RyhI60L8TMOjBMvXiTcxeA==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ] - }, - "node_modules/@rollup/rollup-win32-x64-msvc": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.59.0.tgz", - "integrity": "sha512-2HRCml6OztYXyJXAvdDXPKcawukWY2GpR5/nxKp4iBgiO3wcoEGkAaqctIbZcNB6KlUQBIqt8VYkNSj2397EfA==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ] - }, - "node_modules/@rspack/binding": { - "version": "1.7.6", - "resolved": "https://registry.npmjs.org/@rspack/binding/-/binding-1.7.6.tgz", - "integrity": "sha512-/NrEcfo8Gx22hLGysanrV6gHMuqZSxToSci/3M4kzEQtF5cPjfOv5pqeLK/+B6cr56ul/OmE96cCdWcXeVnFjQ==", - "license": "MIT", - "optionalDependencies": { - "@rspack/binding-darwin-arm64": "1.7.6", - "@rspack/binding-darwin-x64": "1.7.6", - "@rspack/binding-linux-arm64-gnu": "1.7.6", - "@rspack/binding-linux-arm64-musl": "1.7.6", - "@rspack/binding-linux-x64-gnu": "1.7.6", - "@rspack/binding-linux-x64-musl": "1.7.6", - "@rspack/binding-wasm32-wasi": "1.7.6", - "@rspack/binding-win32-arm64-msvc": "1.7.6", - "@rspack/binding-win32-ia32-msvc": "1.7.6", - "@rspack/binding-win32-x64-msvc": "1.7.6" - } - }, - "node_modules/@rspack/binding-darwin-arm64": { - "version": "1.7.6", - "resolved": "https://registry.npmjs.org/@rspack/binding-darwin-arm64/-/binding-darwin-arm64-1.7.6.tgz", - "integrity": "sha512-NZ9AWtB1COLUX1tA9HQQvWpTy07NSFfKBU8A6ylWd5KH8AePZztpNgLLAVPTuNO4CZXYpwcoclf8jG/luJcQdQ==", - "cpu": [ - "arm64" - ], - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ] - }, - "node_modules/@rspack/binding-darwin-x64": { - "version": "1.7.6", - "resolved": "https://registry.npmjs.org/@rspack/binding-darwin-x64/-/binding-darwin-x64-1.7.6.tgz", - "integrity": "sha512-J2g6xk8ZS7uc024dNTGTHxoFzFovAZIRixUG7PiciLKTMP78svbSSWrmW6N8oAsAkzYfJWwQpVgWfFNRHvYxSw==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ] - }, - "node_modules/@rspack/binding-linux-arm64-gnu": { - "version": "1.7.6", - "resolved": "https://registry.npmjs.org/@rspack/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.7.6.tgz", - "integrity": "sha512-eQfcsaxhFrv5FmtaA7+O1F9/2yFDNIoPZzV/ZvqvFz5bBXVc4FAm/1fVpBg8Po/kX1h0chBc7Xkpry3cabFW8w==", - "cpu": [ - "arm64" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rspack/binding-linux-arm64-musl": { - "version": "1.7.6", - "resolved": "https://registry.npmjs.org/@rspack/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.7.6.tgz", - "integrity": "sha512-DfQXKiyPIl7i1yECHy4eAkSmlUzzsSAbOjgMuKn7pudsWf483jg0UUYutNgXSlBjc/QSUp7906Cg8oty9OfwPA==", - "cpu": [ - "arm64" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rspack/binding-linux-x64-gnu": { - "version": "1.7.6", - "resolved": "https://registry.npmjs.org/@rspack/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.7.6.tgz", - "integrity": "sha512-NdA+2X3lk2GGrMMnTGyYTzM3pn+zNjaqXqlgKmFBXvjfZqzSsKq3pdD1KHZCd5QHN+Fwvoszj0JFsquEVhE1og==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rspack/binding-linux-x64-musl": { - "version": "1.7.6", - "resolved": "https://registry.npmjs.org/@rspack/binding-linux-x64-musl/-/binding-linux-x64-musl-1.7.6.tgz", - "integrity": "sha512-rEy6MHKob02t/77YNgr6dREyJ0e0tv1X6Xsg8Z5E7rPXead06zefUbfazj4RELYySWnM38ovZyJAkPx/gOn3VA==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rspack/binding-wasm32-wasi": { - "version": "1.7.6", - "resolved": "https://registry.npmjs.org/@rspack/binding-wasm32-wasi/-/binding-wasm32-wasi-1.7.6.tgz", - "integrity": "sha512-YupOrz0daSG+YBbCIgpDgzfMM38YpChv+afZpaxx5Ml7xPeAZIIdgWmLHnQ2rts73N2M1NspAiBwV00Xx0N4Vg==", - "cpu": [ - "wasm32" - ], + "dev": true, "license": "MIT", - "optional": true, "dependencies": { - "@napi-rs/wasm-runtime": "1.0.7" + "remotion": "4.0.429" + }, + "peerDependencies": { + "zod": "4.3.6" } }, - "node_modules/@rspack/binding-win32-arm64-msvc": { - "version": "1.7.6", - "resolved": "https://registry.npmjs.org/@rspack/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.7.6.tgz", - "integrity": "sha512-INj7aVXjBvlZ84kEhSK4kJ484ub0i+BzgnjDWOWM1K+eFYDZjLdAsQSS3fGGXwVc3qKbPIssFfnftATDMTEJHQ==", + "node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.59.0", "cpu": [ "arm64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ - "win32" + "darwin" ] }, - "node_modules/@rspack/binding-win32-ia32-msvc": { + "node_modules/@rspack/binding": { "version": "1.7.6", - "resolved": "https://registry.npmjs.org/@rspack/binding-win32-ia32-msvc/-/binding-win32-ia32-msvc-1.7.6.tgz", - "integrity": "sha512-lXGvC+z67UMcw58In12h8zCa9IyYRmuptUBMItQJzu+M278aMuD1nETyGLL7e4+OZ2lvrnnBIcjXN1hfw2yRzw==", - "cpu": [ - "ia32" - ], + "dev": true, "license": "MIT", - "optional": true, - "os": [ - "win32" - ] + "optionalDependencies": { + "@rspack/binding-darwin-arm64": "1.7.6", + "@rspack/binding-darwin-x64": "1.7.6", + "@rspack/binding-linux-arm64-gnu": "1.7.6", + "@rspack/binding-linux-arm64-musl": "1.7.6", + "@rspack/binding-linux-x64-gnu": "1.7.6", + "@rspack/binding-linux-x64-musl": "1.7.6", + "@rspack/binding-wasm32-wasi": "1.7.6", + "@rspack/binding-win32-arm64-msvc": "1.7.6", + "@rspack/binding-win32-ia32-msvc": "1.7.6", + "@rspack/binding-win32-x64-msvc": "1.7.6" + } }, - "node_modules/@rspack/binding-win32-x64-msvc": { + "node_modules/@rspack/binding-darwin-arm64": { "version": "1.7.6", - "resolved": "https://registry.npmjs.org/@rspack/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.7.6.tgz", - "integrity": "sha512-zeUxEc0ZaPpmaYlCeWcjSJUPuRRySiSHN23oJ2Xyw0jsQ01Qm4OScPdr0RhEOFuK/UE+ANyRtDo4zJsY52Hadw==", "cpu": [ - "x64" + "arm64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ - "win32" + "darwin" ] }, "node_modules/@rspack/core": { "version": "1.7.6", - "resolved": "https://registry.npmjs.org/@rspack/core/-/core-1.7.6.tgz", - "integrity": "sha512-Iax6UhrfZqJajA778c1d5DBFbSIqPOSrI34kpNIiNpWd8Jq7mFIa+Z60SQb5ZQDZuUxcCZikjz5BxinFjTkg7Q==", + "dev": true, "license": "MIT", "dependencies": { "@module-federation/runtime-tools": "0.22.0", @@ -3005,14 +1788,12 @@ }, "node_modules/@rspack/lite-tapable": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@rspack/lite-tapable/-/lite-tapable-1.1.0.tgz", - "integrity": "sha512-E2B0JhYFmVAwdDiG14+DW0Di4Ze4Jg10Pc4/lILUrd5DRCaklduz2OvJ5HYQ6G+hd+WTzqQb3QnDNfK4yvAFYw==", + "dev": true, "license": "MIT" }, "node_modules/@rspack/plugin-react-refresh": { "version": "1.6.1", - "resolved": "https://registry.npmjs.org/@rspack/plugin-react-refresh/-/plugin-react-refresh-1.6.1.tgz", - "integrity": "sha512-eqqW5645VG3CzGzFgNg5HqNdHVXY+567PGjtDhhrM8t67caxmsSzRmT5qfoEIfBcGgFkH9vEg7kzXwmCYQdQDw==", + "dev": true, "license": "MIT", "dependencies": { "error-stack-parser": "^2.1.4", @@ -3030,32 +1811,16 @@ }, "node_modules/@standard-schema/spec": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@standard-schema/spec/-/spec-1.1.0.tgz", - "integrity": "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==", "dev": true, "license": "MIT" }, "node_modules/@tootallnate/quickjs-emscripten": { "version": "0.23.0", - "resolved": "https://registry.npmjs.org/@tootallnate/quickjs-emscripten/-/quickjs-emscripten-0.23.0.tgz", - "integrity": "sha512-C5Mc6rdnsaJDjO3UpGW/CQTHtCKaYlScZTly4JIu97Jxo/odCiH0ITnDXSJPTOrEKk/ycSZ0AOgTmkDtkOsvIA==", "dev": true, "license": "MIT" }, - "node_modules/@tybys/wasm-util": { - "version": "0.10.1", - "resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.1.tgz", - "integrity": "sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg==", - "license": "MIT", - "optional": true, - "dependencies": { - "tslib": "^2.4.0" - } - }, "node_modules/@types/chai": { "version": "5.2.3", - "resolved": "https://registry.npmjs.org/@types/chai/-/chai-5.2.3.tgz", - "integrity": "sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA==", "dev": true, "license": "MIT", "dependencies": { @@ -3065,15 +1830,12 @@ }, "node_modules/@types/deep-eql": { "version": "4.0.2", - "resolved": "https://registry.npmjs.org/@types/deep-eql/-/deep-eql-4.0.2.tgz", - "integrity": "sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==", "dev": true, "license": "MIT" }, "node_modules/@types/dom-mediacapture-transform": { "version": "0.1.11", - "resolved": "https://registry.npmjs.org/@types/dom-mediacapture-transform/-/dom-mediacapture-transform-0.1.11.tgz", - "integrity": "sha512-Y2p+nGf1bF2XMttBnsVPHUWzRRZzqUoJAKmiP10b5umnO6DDrWI0BrGDJy1pOHoOULVmGSfFNkQrAlC5dcj6nQ==", + "dev": true, "license": "MIT", "dependencies": { "@types/dom-webcodecs": "*" @@ -3081,14 +1843,12 @@ }, "node_modules/@types/dom-webcodecs": { "version": "0.1.13", - "resolved": "https://registry.npmjs.org/@types/dom-webcodecs/-/dom-webcodecs-0.1.13.tgz", - "integrity": "sha512-O5hkiFIcjjszPIYyUSyvScyvrBoV3NOEEZx/pMlsu44TKzWNkLVBBxnxJz42in5n3QIolYOcBYFCPZZ0h8SkwQ==", + "dev": true, "license": "MIT" }, "node_modules/@types/eslint": { "version": "9.6.1", - "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-9.6.1.tgz", - "integrity": "sha512-FXx2pKgId/WyYo2jXw63kk7/+TY7u7AziEJxJAnSFzHlqTAS3Ync6SvgYAN/k4/PQpnnVuzoMuVnByKK2qp0ag==", + "dev": true, "license": "MIT", "dependencies": { "@types/estree": "*", @@ -3097,8 +1857,7 @@ }, "node_modules/@types/eslint-scope": { "version": "3.7.7", - "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.7.tgz", - "integrity": "sha512-MzMFlSLBqNF2gcHWO0G1vP/YQyfvrxZ0bF+u7mzUdZ1/xK4A4sru+nraZz5i3iEIk1l1uyicaDVTB4QbbEkAYg==", + "dev": true, "license": "MIT", "dependencies": { "@types/eslint": "*", @@ -3107,20 +1866,17 @@ }, "node_modules/@types/estree": { "version": "1.0.8", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", - "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", + "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/@types/node": { "version": "20.19.33", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.33.tgz", - "integrity": "sha512-Rs1bVAIdBs5gbTIKza/tgpMuG1k3U/UMJLWecIMxNdJFDMzcM5LOiLVRYh3PilWEYDIeUDv7bpiHPLPsbydGcw==", + "dev": true, "license": "MIT", "dependencies": { "undici-types": "~6.21.0" @@ -3128,8 +1884,6 @@ }, "node_modules/@types/pngjs": { "version": "6.0.5", - "resolved": "https://registry.npmjs.org/@types/pngjs/-/pngjs-6.0.5.tgz", - "integrity": "sha512-0k5eKfrA83JOZPppLtS2C7OUtyNAl2wKNxfyYl9Q5g9lPkgBl/9hNyAu6HuEH2J4XmIv2znEpkDd0SaZVxW6iQ==", "dev": true, "license": "MIT", "dependencies": { @@ -3138,8 +1892,6 @@ }, "node_modules/@types/react": { "version": "19.2.14", - "resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.14.tgz", - "integrity": "sha512-ilcTH/UniCkMdtexkoCN0bI7pMcJDvmQFPvuPvmEaYA/NSfFTAgdUSLAoVjaRJm7+6PvcM+q1zYOwS4wTYMF9w==", "dev": true, "license": "MIT", "dependencies": { @@ -3148,15 +1900,11 @@ }, "node_modules/@types/uuid": { "version": "10.0.0", - "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-10.0.0.tgz", - "integrity": "sha512-7gqG38EyHgyP1S+7+xomFtL+ZNHcKv6DwNaCZmJmo1vgMugyF3TCnXVg4t1uk89mLNwnLtnY3TpOpCOyp1/xHQ==", "dev": true, "license": "MIT" }, "node_modules/@types/web-push": { "version": "3.6.4", - "resolved": "https://registry.npmjs.org/@types/web-push/-/web-push-3.6.4.tgz", - "integrity": "sha512-GnJmSr40H3RAnj0s34FNTcJi1hmWFV5KXugE0mYWnYhgTAHLJ/dJKAwDmvPJYMke0RplY2XE9LnM4hqSqKIjhQ==", "dev": true, "license": "MIT", "dependencies": { @@ -3165,18 +1913,234 @@ }, "node_modules/@types/yauzl": { "version": "2.10.3", - "resolved": "https://registry.npmjs.org/@types/yauzl/-/yauzl-2.10.3.tgz", - "integrity": "sha512-oJoftv0LSuaDZE3Le4DbKX+KS9G36NzOeSap90UIK0yMA/NhKJhqlSGtNDORNRaIbQfzjXDrQa0ytJ6mNRGz/Q==", + "dev": true, "license": "MIT", "optional": true, "dependencies": { "@types/node": "*" } }, + "node_modules/@typescript-eslint/eslint-plugin": { + "version": "8.56.1", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/regexpp": "^4.12.2", + "@typescript-eslint/scope-manager": "8.56.1", + "@typescript-eslint/type-utils": "8.56.1", + "@typescript-eslint/utils": "8.56.1", + "@typescript-eslint/visitor-keys": "8.56.1", + "ignore": "^7.0.5", + "natural-compare": "^1.4.0", + "ts-api-utils": "^2.4.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "@typescript-eslint/parser": "^8.56.1", + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/ignore": { + "version": "7.0.5", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/@typescript-eslint/parser": { + "version": "8.56.1", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/scope-manager": "8.56.1", + "@typescript-eslint/types": "8.56.1", + "@typescript-eslint/typescript-estree": "8.56.1", + "@typescript-eslint/visitor-keys": "8.56.1", + "debug": "^4.4.3" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/project-service": { + "version": "8.56.1", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/tsconfig-utils": "^8.56.1", + "@typescript-eslint/types": "^8.56.1", + "debug": "^4.4.3" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/scope-manager": { + "version": "8.56.1", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.56.1", + "@typescript-eslint/visitor-keys": "8.56.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/tsconfig-utils": { + "version": "8.56.1", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/type-utils": { + "version": "8.56.1", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.56.1", + "@typescript-eslint/typescript-estree": "8.56.1", + "@typescript-eslint/utils": "8.56.1", + "debug": "^4.4.3", + "ts-api-utils": "^2.4.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/types": { + "version": "8.56.1", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/typescript-estree": { + "version": "8.56.1", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/project-service": "8.56.1", + "@typescript-eslint/tsconfig-utils": "8.56.1", + "@typescript-eslint/types": "8.56.1", + "@typescript-eslint/visitor-keys": "8.56.1", + "debug": "^4.4.3", + "minimatch": "^10.2.2", + "semver": "^7.7.3", + "tinyglobby": "^0.2.15", + "ts-api-utils": "^2.4.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/utils": { + "version": "8.56.1", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.9.1", + "@typescript-eslint/scope-manager": "8.56.1", + "@typescript-eslint/types": "8.56.1", + "@typescript-eslint/typescript-estree": "8.56.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/visitor-keys": { + "version": "8.56.1", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.56.1", + "eslint-visitor-keys": "^5.0.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/visitor-keys/node_modules/eslint-visitor-keys": { + "version": "5.0.1", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, "node_modules/@vitest/coverage-v8": { "version": "4.0.18", - "resolved": "https://registry.npmjs.org/@vitest/coverage-v8/-/coverage-v8-4.0.18.tgz", - "integrity": "sha512-7i+N2i0+ME+2JFZhfuz7Tg/FqKtilHjGyGvoHYQ6iLV0zahbsJ9sljC9OcFcPDbhYKCet+sG8SsVqlyGvPflZg==", "dev": true, "license": "MIT", "dependencies": { @@ -3206,8 +2170,6 @@ }, "node_modules/@vitest/expect": { "version": "4.0.18", - "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-4.0.18.tgz", - "integrity": "sha512-8sCWUyckXXYvx4opfzVY03EOiYVxyNrHS5QxX3DAIi5dpJAAkyJezHCP77VMX4HKA2LDT/Jpfo8i2r5BE3GnQQ==", "dev": true, "license": "MIT", "dependencies": { @@ -3224,8 +2186,6 @@ }, "node_modules/@vitest/mocker": { "version": "4.0.18", - "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-4.0.18.tgz", - "integrity": "sha512-HhVd0MDnzzsgevnOWCBj5Otnzobjy5wLBe4EdeeFGv8luMsGcYqDuFRMcttKWZA5vVO8RFjexVovXvAM4JoJDQ==", "dev": true, "license": "MIT", "dependencies": { @@ -3251,8 +2211,6 @@ }, "node_modules/@vitest/pretty-format": { "version": "4.0.18", - "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-4.0.18.tgz", - "integrity": "sha512-P24GK3GulZWC5tz87ux0m8OADrQIUVDPIjjj65vBXYG17ZeU3qD7r+MNZ1RNv4l8CGU2vtTRqixrOi9fYk/yKw==", "dev": true, "license": "MIT", "dependencies": { @@ -3264,8 +2222,6 @@ }, "node_modules/@vitest/runner": { "version": "4.0.18", - "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-4.0.18.tgz", - "integrity": "sha512-rpk9y12PGa22Jg6g5M3UVVnTS7+zycIGk9ZNGN+m6tZHKQb7jrP7/77WfZy13Y/EUDd52NDsLRQhYKtv7XfPQw==", "dev": true, "license": "MIT", "dependencies": { @@ -3278,8 +2234,6 @@ }, "node_modules/@vitest/snapshot": { "version": "4.0.18", - "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-4.0.18.tgz", - "integrity": "sha512-PCiV0rcl7jKQjbgYqjtakly6T1uwv/5BQ9SwBLekVg/EaYeQFPiXcgrC2Y7vDMA8dM1SUEAEV82kgSQIlXNMvA==", "dev": true, "license": "MIT", "dependencies": { @@ -3293,8 +2247,6 @@ }, "node_modules/@vitest/spy": { "version": "4.0.18", - "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-4.0.18.tgz", - "integrity": "sha512-cbQt3PTSD7P2OARdVW3qWER5EGq7PHlvE+QfzSC0lbwO+xnt7+XH06ZzFjFRgzUX//JmpxrCu92VdwvEPlWSNw==", "dev": true, "license": "MIT", "funding": { @@ -3303,8 +2255,6 @@ }, "node_modules/@vitest/utils": { "version": "4.0.18", - "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-4.0.18.tgz", - "integrity": "sha512-msMRKLMVLWygpK3u2Hybgi4MNjcYJvwTb0Ru09+fOyCXIgT5raYP041DRRdiJiI3k/2U6SEbAETB3YtBrUkCFA==", "dev": true, "license": "MIT", "dependencies": { @@ -3317,8 +2267,7 @@ }, "node_modules/@webassemblyjs/ast": { "version": "1.14.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.14.1.tgz", - "integrity": "sha512-nuBEDgQfm1ccRp/8bCQrx1frohyufl4JlbMMZ4P1wpeOfDhF6FQkxZJ1b/e+PLwr6X1Nhw6OLme5usuBWYBvuQ==", + "dev": true, "license": "MIT", "dependencies": { "@webassemblyjs/helper-numbers": "1.13.2", @@ -3327,26 +2276,22 @@ }, "node_modules/@webassemblyjs/floating-point-hex-parser": { "version": "1.13.2", - "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.13.2.tgz", - "integrity": "sha512-6oXyTOzbKxGH4steLbLNOu71Oj+C8Lg34n6CqRvqfS2O71BxY6ByfMDRhBytzknj9yGUPVJ1qIKhRlAwO1AovA==", + "dev": true, "license": "MIT" }, "node_modules/@webassemblyjs/helper-api-error": { "version": "1.13.2", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.13.2.tgz", - "integrity": "sha512-U56GMYxy4ZQCbDZd6JuvvNV/WFildOjsaWD3Tzzvmw/mas3cXzRJPMjP83JqEsgSbyrmaGjBfDtV7KDXV9UzFQ==", + "dev": true, "license": "MIT" }, "node_modules/@webassemblyjs/helper-buffer": { "version": "1.14.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.14.1.tgz", - "integrity": "sha512-jyH7wtcHiKssDtFPRB+iQdxlDf96m0E39yb0k5uJVhFGleZFoNw1c4aeIcVUPPbXUVJ94wwnMOAqUHyzoEPVMA==", + "dev": true, "license": "MIT" }, "node_modules/@webassemblyjs/helper-numbers": { "version": "1.13.2", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.13.2.tgz", - "integrity": "sha512-FE8aCmS5Q6eQYcV3gI35O4J789wlQA+7JrqTTpJqn5emA4U2hvwJmvFRC0HODS+3Ye6WioDklgd6scJ3+PLnEA==", + "dev": true, "license": "MIT", "dependencies": { "@webassemblyjs/floating-point-hex-parser": "1.13.2", @@ -3356,14 +2301,12 @@ }, "node_modules/@webassemblyjs/helper-wasm-bytecode": { "version": "1.13.2", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.13.2.tgz", - "integrity": "sha512-3QbLKy93F0EAIXLh0ogEVR6rOubA9AoZ+WRYhNbFyuB70j3dRdwH9g+qXhLAO0kiYGlg3TxDV+I4rQTr/YNXkA==", + "dev": true, "license": "MIT" }, "node_modules/@webassemblyjs/helper-wasm-section": { "version": "1.14.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.14.1.tgz", - "integrity": "sha512-ds5mXEqTJ6oxRoqjhWDU83OgzAYjwsCV8Lo/N+oRsNDmx/ZDpqalmrtgOMkHwxsG0iI//3BwWAErYRHtgn0dZw==", + "dev": true, "license": "MIT", "dependencies": { "@webassemblyjs/ast": "1.14.1", @@ -3374,8 +2317,7 @@ }, "node_modules/@webassemblyjs/ieee754": { "version": "1.13.2", - "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.13.2.tgz", - "integrity": "sha512-4LtOzh58S/5lX4ITKxnAK2USuNEvpdVV9AlgGQb8rJDHaLeHciwG4zlGr0j/SNWlr7x3vO1lDEsuePvtcDNCkw==", + "dev": true, "license": "MIT", "dependencies": { "@xtuc/ieee754": "^1.2.0" @@ -3383,8 +2325,7 @@ }, "node_modules/@webassemblyjs/leb128": { "version": "1.13.2", - "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.13.2.tgz", - "integrity": "sha512-Lde1oNoIdzVzdkNEAWZ1dZ5orIbff80YPdHx20mrHwHrVNNTjNr8E3xz9BdpcGqRQbAEa+fkrCb+fRFTl/6sQw==", + "dev": true, "license": "Apache-2.0", "dependencies": { "@xtuc/long": "4.2.2" @@ -3392,14 +2333,12 @@ }, "node_modules/@webassemblyjs/utf8": { "version": "1.13.2", - "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.13.2.tgz", - "integrity": "sha512-3NQWGjKTASY1xV5m7Hr0iPeXD9+RDobLll3T9d2AO+g3my8xy5peVyjSag4I50mR1bBSN/Ct12lo+R9tJk0NZQ==", + "dev": true, "license": "MIT" }, "node_modules/@webassemblyjs/wasm-edit": { "version": "1.14.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.14.1.tgz", - "integrity": "sha512-RNJUIQH/J8iA/1NzlE4N7KtyZNHi3w7at7hDjvRNm5rcUXa00z1vRz3glZoULfJ5mpvYhLybmVcwcjGrC1pRrQ==", + "dev": true, "license": "MIT", "dependencies": { "@webassemblyjs/ast": "1.14.1", @@ -3414,8 +2353,7 @@ }, "node_modules/@webassemblyjs/wasm-gen": { "version": "1.14.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.14.1.tgz", - "integrity": "sha512-AmomSIjP8ZbfGQhumkNvgC33AY7qtMCXnN6bL2u2Js4gVCg8fp735aEiMSBbDR7UQIj90n4wKAFUSEd0QN2Ukg==", + "dev": true, "license": "MIT", "dependencies": { "@webassemblyjs/ast": "1.14.1", @@ -3427,8 +2365,7 @@ }, "node_modules/@webassemblyjs/wasm-opt": { "version": "1.14.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.14.1.tgz", - "integrity": "sha512-PTcKLUNvBqnY2U6E5bdOQcSM+oVP/PmrDY9NzowJjislEjwP/C4an2303MCVS2Mg9d3AJpIGdUFIQQWbPds0Sw==", + "dev": true, "license": "MIT", "dependencies": { "@webassemblyjs/ast": "1.14.1", @@ -3439,8 +2376,7 @@ }, "node_modules/@webassemblyjs/wasm-parser": { "version": "1.14.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.14.1.tgz", - "integrity": "sha512-JLBl+KZ0R5qB7mCnud/yyX08jWFw5MsoalJ1pQ4EdFlgj9VdXKGuENGsiCIjegI1W7p91rUlcB/LB5yRJKNTcQ==", + "dev": true, "license": "MIT", "dependencies": { "@webassemblyjs/ast": "1.14.1", @@ -3453,8 +2389,7 @@ }, "node_modules/@webassemblyjs/wast-printer": { "version": "1.14.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.14.1.tgz", - "integrity": "sha512-kPSSXE6De1XOR820C90RIo2ogvZG+c3KiHzqUoO/F34Y2shGzesfqv7o57xrxovZJH/MetF5UjroJ/R/3isoiw==", + "dev": true, "license": "MIT", "dependencies": { "@webassemblyjs/ast": "1.14.1", @@ -3463,20 +2398,16 @@ }, "node_modules/@xtuc/ieee754": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", - "integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==", + "dev": true, "license": "BSD-3-Clause" }, "node_modules/@xtuc/long": { "version": "4.2.2", - "resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz", - "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==", + "dev": true, "license": "Apache-2.0" }, "node_modules/abort-controller": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz", - "integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==", "license": "MIT", "dependencies": { "event-target-shim": "^5.0.0" @@ -3487,14 +2418,11 @@ }, "node_modules/abstract-logging": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/abstract-logging/-/abstract-logging-2.0.1.tgz", - "integrity": "sha512-2BjRTZxTPvheOvGbBslFSYOUkr+SjPtOnrLP33f+VIWLzezQpZcqVg7ja3L4dBXmzzgwT+a029jRx5PCi3JuiA==", "license": "MIT" }, "node_modules/acorn": { "version": "8.16.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.16.0.tgz", - "integrity": "sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==", + "dev": true, "license": "MIT", "bin": { "acorn": "bin/acorn" @@ -3505,8 +2433,7 @@ }, "node_modules/acorn-import-phases": { "version": "1.0.4", - "resolved": "https://registry.npmjs.org/acorn-import-phases/-/acorn-import-phases-1.0.4.tgz", - "integrity": "sha512-wKmbr/DDiIXzEOiWrTTUcDm24kQ2vGfZQvM2fwg2vXqR5uW6aapr7ObPtj1th32b9u90/Pf4AItvdTh42fBmVQ==", + "dev": true, "license": "MIT", "engines": { "node": ">=10.13.0" @@ -3515,10 +2442,16 @@ "acorn": "^8.14.0" } }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "dev": true, + "license": "MIT", + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, "node_modules/agent-base": { "version": "7.1.4", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.4.tgz", - "integrity": "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==", "license": "MIT", "engines": { "node": ">= 14" @@ -3526,8 +2459,6 @@ }, "node_modules/agent-browser": { "version": "0.6.0", - "resolved": "https://registry.npmjs.org/agent-browser/-/agent-browser-0.6.0.tgz", - "integrity": "sha512-C4Mtxfvyi/m04hyD2XdUNKc878RPZqbhXFIPEUJElZW6RhZJ1QG1/L5PSgIAhRSi4TF/EkB8iq4IAWoecMvGdg==", "dev": true, "hasInstallScript": true, "license": "Apache-2.0", @@ -3542,8 +2473,6 @@ }, "node_modules/agent-browser/node_modules/zod": { "version": "3.25.76", - "resolved": "https://registry.npmjs.org/zod/-/zod-3.25.76.tgz", - "integrity": "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==", "dev": true, "license": "MIT", "funding": { @@ -3552,8 +2481,6 @@ }, "node_modules/ajv": { "version": "8.18.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.18.0.tgz", - "integrity": "sha512-PlXPeEWMXMZ7sPYOHqmDyCJzcfNrUr3fGNKtezX14ykXOEIvyK81d+qydx89KY5O71FKMPaQ2vBfBFI5NHR63A==", "license": "MIT", "dependencies": { "fast-deep-equal": "^3.1.3", @@ -3568,8 +2495,6 @@ }, "node_modules/ajv-formats": { "version": "3.0.1", - "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-3.0.1.tgz", - "integrity": "sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ==", "license": "MIT", "dependencies": { "ajv": "^8.0.0" @@ -3585,8 +2510,7 @@ }, "node_modules/ajv-keywords": { "version": "5.1.0", - "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", - "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", + "dev": true, "license": "MIT", "dependencies": { "fast-deep-equal": "^3.1.3" @@ -3607,8 +2531,6 @@ }, "node_modules/ansi-regex": { "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", "license": "MIT", "engines": { "node": ">=8" @@ -3616,8 +2538,6 @@ }, "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==", "license": "MIT", "dependencies": { "color-convert": "^2.0.1" @@ -3629,10 +2549,13 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, + "node_modules/any-promise": { + "version": "1.3.0", + "dev": true, + "license": "MIT" + }, "node_modules/anymatch": { "version": "3.1.3", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", - "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", "license": "ISC", "dependencies": { "normalize-path": "^3.0.0", @@ -3644,8 +2567,6 @@ }, "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" }, @@ -3661,8 +2582,6 @@ }, "node_modules/asn1.js": { "version": "5.4.1", - "resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-5.4.1.tgz", - "integrity": "sha512-+I//4cYPccV8LdmBLiX8CYvf9Sp3vQsrqu2QNXRcrbiWvcx/UdlFiqUJJzxRQxgsZmvhXhn4cSKeSmoFjVdupA==", "license": "MIT", "dependencies": { "bn.js": "^4.0.0", @@ -3673,8 +2592,6 @@ }, "node_modules/assertion-error": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-2.0.1.tgz", - "integrity": "sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==", "dev": true, "license": "MIT", "engines": { @@ -3683,8 +2600,6 @@ }, "node_modules/ast-types": { "version": "0.13.4", - "resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.13.4.tgz", - "integrity": "sha512-x1FCFnFifvYDDzTaLII71vG5uvDwgtmDTEVWAxrgeiR8VjMONcCXJx7E+USjDtHlwFmt9MysbqgF9b9Vjr6w+w==", "dev": true, "license": "MIT", "dependencies": { @@ -3696,8 +2611,6 @@ }, "node_modules/ast-v8-to-istanbul": { "version": "0.3.11", - "resolved": "https://registry.npmjs.org/ast-v8-to-istanbul/-/ast-v8-to-istanbul-0.3.11.tgz", - "integrity": "sha512-Qya9fkoofMjCBNVdWINMjB5KZvkYfaO9/anwkWnjxibpWUxo5iHl2sOdP7/uAqaRuUYuoo8rDwnbaaKVFxoUvw==", "dev": true, "license": "MIT", "dependencies": { @@ -3708,17 +2621,11 @@ }, "node_modules/asynckit": { "version": "0.4.0", - "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", "dev": true, - "license": "MIT", - "optional": true, - "peer": true + "license": "MIT" }, "node_modules/atomic-sleep": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/atomic-sleep/-/atomic-sleep-1.0.0.tgz", - "integrity": "sha512-kNOjDqAh7px0XWNI+4QbzoiR/nTkHAWNud2uvnJquD1/x5a7EQZMJT0AczqK0Qn67oY/TTQ1LbUKajZpp3I9tQ==", "license": "MIT", "engines": { "node": ">=8.0.0" @@ -3726,8 +2633,6 @@ }, "node_modules/avvio": { "version": "9.2.0", - "resolved": "https://registry.npmjs.org/avvio/-/avvio-9.2.0.tgz", - "integrity": "sha512-2t/sy01ArdHHE0vRH5Hsay+RtCZt3dLPji7W7/MMOCEgze5b7SNDC4j5H6FnVgPkI1MTNFGzHdHrVXDDl7QSSQ==", "funding": [ { "type": "github", @@ -3746,8 +2651,6 @@ }, "node_modules/b4a": { "version": "1.8.0", - "resolved": "https://registry.npmjs.org/b4a/-/b4a-1.8.0.tgz", - "integrity": "sha512-qRuSmNSkGQaHwNbM7J78Wwy+ghLEYF1zNrSeMxj4Kgw6y33O3mXcQ6Ie9fRvfU/YnxWkOchPXbaLb73TkIsfdg==", "dev": true, "license": "Apache-2.0", "peerDependencies": { @@ -3761,8 +2664,6 @@ }, "node_modules/balanced-match": { "version": "4.0.3", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.3.tgz", - "integrity": "sha512-1pHv8LX9CpKut1Zp4EXey7Z8OfH11ONNH6Dhi2WDUt31VVZFXZzKwXcysBgqSumFCmR+0dqjMK5v5JiFHzi0+g==", "license": "MIT", "engines": { "node": "20 || >=22" @@ -3770,8 +2671,6 @@ }, "node_modules/bare-events": { "version": "2.8.2", - "resolved": "https://registry.npmjs.org/bare-events/-/bare-events-2.8.2.tgz", - "integrity": "sha512-riJjyv1/mHLIPX4RwiK+oW9/4c3TEUeORHKefKAKnZ5kyslbN+HXowtbaVEqt4IMUB7OXlfixcs6gsFeo/jhiQ==", "dev": true, "license": "Apache-2.0", "peerDependencies": { @@ -3785,8 +2684,6 @@ }, "node_modules/bare-fs": { "version": "4.5.4", - "resolved": "https://registry.npmjs.org/bare-fs/-/bare-fs-4.5.4.tgz", - "integrity": "sha512-POK4oplfA7P7gqvetNmCs4CNtm9fNsx+IAh7jH7GgU0OJdge2rso0R20TNWVq6VoWcCvsTdlNDaleLHGaKx8CA==", "dev": true, "license": "Apache-2.0", "optional": true, @@ -3811,8 +2708,6 @@ }, "node_modules/bare-os": { "version": "3.6.2", - "resolved": "https://registry.npmjs.org/bare-os/-/bare-os-3.6.2.tgz", - "integrity": "sha512-T+V1+1srU2qYNBmJCXZkUY5vQ0B4FSlL3QDROnKQYOqeiQR8UbjNHlPa+TIbM4cuidiN9GaTaOZgSEgsvPbh5A==", "dev": true, "license": "Apache-2.0", "optional": true, @@ -3822,8 +2717,6 @@ }, "node_modules/bare-path": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/bare-path/-/bare-path-3.0.0.tgz", - "integrity": "sha512-tyfW2cQcB5NN8Saijrhqn0Zh7AnFNsnczRcuWODH0eYAXBsJ5gVxAUuNr7tsHSC6IZ77cA0SitzT+s47kot8Mw==", "dev": true, "license": "Apache-2.0", "optional": true, @@ -3833,8 +2726,6 @@ }, "node_modules/bare-stream": { "version": "2.8.0", - "resolved": "https://registry.npmjs.org/bare-stream/-/bare-stream-2.8.0.tgz", - "integrity": "sha512-reUN0M2sHRqCdG4lUK3Fw8w98eeUIZHL5c3H7Mbhk2yVBL+oofgaIp0ieLfD5QXwPCypBpmEEKU2WZKzbAk8GA==", "dev": true, "license": "Apache-2.0", "optional": true, @@ -3857,8 +2748,6 @@ }, "node_modules/bare-url": { "version": "2.3.2", - "resolved": "https://registry.npmjs.org/bare-url/-/bare-url-2.3.2.tgz", - "integrity": "sha512-ZMq4gd9ngV5aTMa5p9+UfY0b3skwhHELaDkhEHetMdX0LRkW9kzaym4oo/Eh+Ghm0CCDuMTsRIGM/ytUc1ZYmw==", "dev": true, "license": "Apache-2.0", "optional": true, @@ -3868,8 +2757,6 @@ }, "node_modules/base64-js": { "version": "1.5.1", - "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", - "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", "funding": [ { "type": "github", @@ -3888,8 +2775,7 @@ }, "node_modules/baseline-browser-mapping": { "version": "2.10.0", - "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.10.0.tgz", - "integrity": "sha512-lIyg0szRfYbiy67j9KN8IyeD7q7hcmqnJ1ddWmNt19ItGpNN64mnllmxUNFIOdOm6by97jlL6wfpTTJrmnjWAA==", + "dev": true, "license": "Apache-2.0", "bin": { "baseline-browser-mapping": "dist/cli.cjs" @@ -3900,8 +2786,6 @@ }, "node_modules/basic-ftp": { "version": "5.1.0", - "resolved": "https://registry.npmjs.org/basic-ftp/-/basic-ftp-5.1.0.tgz", - "integrity": "sha512-RkaJzeJKDbaDWTIPiJwubyljaEPwpVWkm9Rt5h9Nd6h7tEXTJ3VB4qxdZBioV7JO5yLUaOKwz7vDOzlncUsegw==", "dev": true, "license": "MIT", "engines": { @@ -3923,8 +2807,7 @@ }, "node_modules/big.js": { "version": "5.2.2", - "resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz", - "integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==", + "dev": true, "license": "MIT", "engines": { "node": "*" @@ -3932,8 +2815,6 @@ }, "node_modules/binary-extensions": { "version": "2.3.0", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", - "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", "license": "MIT", "engines": { "node": ">=8" @@ -3944,14 +2825,10 @@ }, "node_modules/bn.js": { "version": "4.12.3", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.3.tgz", - "integrity": "sha512-fGTi3gxV/23FTYdAoUtLYp6qySe2KE3teyZitipKNRuVYcBkoP/bB3guXN/XVKUe9mxCHXnc9C4ocyz8OmgN0g==", "license": "MIT" }, "node_modules/brace-expansion": { "version": "5.0.2", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.2.tgz", - "integrity": "sha512-Pdk8c9poy+YhOgVWw1JNN22/HcivgKWwpxKq04M/jTmHyCZn12WPJebZxdjSa5TmBqISrUSgNYU3eRORljfCCw==", "license": "MIT", "dependencies": { "balanced-match": "^4.0.2" @@ -3962,8 +2839,6 @@ }, "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==", "license": "MIT", "dependencies": { "fill-range": "^7.1.1" @@ -3974,8 +2849,7 @@ }, "node_modules/browserslist": { "version": "4.28.1", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.1.tgz", - "integrity": "sha512-ZC5Bd0LgJXgwGqUknZY/vkUQ04r8NXnJZ3yYi4vDmSiZmC/pdSN0NbNRPxZpbtO4uAfDUAFffO8IZoM3Gj8IkA==", + "dev": true, "funding": [ { "type": "opencollective", @@ -4007,8 +2881,6 @@ }, "node_modules/buffer": { "version": "6.0.3", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", - "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", "funding": [ { "type": "github", @@ -4031,8 +2903,7 @@ }, "node_modules/buffer-crc32": { "version": "0.2.13", - "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", - "integrity": "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==", + "dev": true, "license": "MIT", "engines": { "node": "*" @@ -4040,24 +2911,38 @@ }, "node_modules/buffer-equal-constant-time": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", - "integrity": "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==", "license": "BSD-3-Clause" }, "node_modules/buffer-from": { "version": "1.1.2", - "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", - "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", "license": "MIT" }, + "node_modules/bundle-require": { + "version": "5.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "load-tsconfig": "^0.2.3" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "peerDependencies": { + "esbuild": ">=0.18" + } + }, + "node_modules/cac": { + "version": "6.7.14", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, "node_modules/call-bind-apply-helpers": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", - "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", "dev": true, "license": "MIT", - "optional": true, - "peer": true, "dependencies": { "es-errors": "^1.3.0", "function-bind": "^1.1.2" @@ -4068,8 +2953,6 @@ }, "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": { @@ -4078,8 +2961,6 @@ }, "node_modules/camelcase": { "version": "5.3.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", - "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", "license": "MIT", "engines": { "node": ">=6" @@ -4087,8 +2968,7 @@ }, "node_modules/caniuse-lite": { "version": "1.0.30001774", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001774.tgz", - "integrity": "sha512-DDdwPGz99nmIEv216hKSgLD+D4ikHQHjBC/seF98N9CPqRX4M5mSxT9eTV6oyisnJcuzxtZy4n17yKKQYmYQOA==", + "dev": true, "funding": [ { "type": "opencollective", @@ -4107,8 +2987,6 @@ }, "node_modules/chai": { "version": "6.2.2", - "resolved": "https://registry.npmjs.org/chai/-/chai-6.2.2.tgz", - "integrity": "sha512-NUPRluOfOiTKBKvWPtSD4PhFvWCqOi0BGStNWs57X9js7XGTprSmFoz5F0tWhR4WPjNeR9jXqdC7/UpSJTnlRg==", "dev": true, "license": "MIT", "engines": { @@ -4117,8 +2995,6 @@ }, "node_modules/chalk": { "version": "5.6.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.6.2.tgz", - "integrity": "sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA==", "license": "MIT", "engines": { "node": "^12.17.0 || ^14.13 || >=16.0.0" @@ -4134,10 +3010,16 @@ "dev": true, "license": "MIT" }, + "node_modules/check-error": { + "version": "2.1.3", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 16" + } + }, "node_modules/chokidar": { "version": "3.6.0", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", - "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", "license": "MIT", "dependencies": { "anymatch": "~3.1.2", @@ -4160,8 +3042,7 @@ }, "node_modules/chrome-trace-event": { "version": "1.0.4", - "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.4.tgz", - "integrity": "sha512-rNjApaLzuwaOTjCiT8lSDdGN1APCiqkChLMJxJPWLunPAt5fy8xgU9/jNOchV84wfIxrA0lRQB7oCT8jrn/wrQ==", + "dev": true, "license": "MIT", "engines": { "node": ">=6.0" @@ -4169,8 +3050,6 @@ }, "node_modules/chromium-bidi": { "version": "14.0.0", - "resolved": "https://registry.npmjs.org/chromium-bidi/-/chromium-bidi-14.0.0.tgz", - "integrity": "sha512-9gYlLtS6tStdRWzrtXaTMnqcM4dudNegMXJxkR0I/CXObHalYeYcAMPrL19eroNZHtJ8DQmu1E+ZNOYu/IXMXw==", "dev": true, "license": "Apache-2.0", "dependencies": { @@ -4183,8 +3062,6 @@ }, "node_modules/chromium-bidi/node_modules/zod": { "version": "3.25.76", - "resolved": "https://registry.npmjs.org/zod/-/zod-3.25.76.tgz", - "integrity": "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==", "dev": true, "license": "MIT", "funding": { @@ -4209,8 +3086,6 @@ }, "node_modules/cliui": { "version": "8.0.1", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", - "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", "dev": true, "license": "ISC", "dependencies": { @@ -4224,8 +3099,6 @@ }, "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==", "license": "MIT", "dependencies": { "color-name": "~1.1.4" @@ -4236,18 +3109,12 @@ }, "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==", "license": "MIT" }, "node_modules/combined-stream": { "version": "1.0.8", - "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", - "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", "dev": true, "license": "MIT", - "optional": true, - "peer": true, "dependencies": { "delayed-stream": "~1.0.0" }, @@ -4257,17 +3124,31 @@ }, "node_modules/commander": { "version": "12.1.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-12.1.0.tgz", - "integrity": "sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA==", "license": "MIT", "engines": { - "node": ">=18" + "node": ">=18" + } + }, + "node_modules/concat-map": { + "version": "0.0.1", + "dev": true, + "license": "MIT" + }, + "node_modules/confbox": { + "version": "0.1.8", + "dev": true, + "license": "MIT" + }, + "node_modules/consola": { + "version": "3.4.2", + "dev": true, + "license": "MIT", + "engines": { + "node": "^14.18.0 || >=16.10.0" } }, "node_modules/content-disposition": { "version": "0.5.4", - "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", - "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", "license": "MIT", "dependencies": { "safe-buffer": "5.2.1" @@ -4278,8 +3159,6 @@ }, "node_modules/cookie": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-1.1.1.tgz", - "integrity": "sha512-ei8Aos7ja0weRpFzJnEA9UHJ/7XQmqglbRwnf2ATjcB9Wq874VKH9kfjjirM6UhU2/E5fFYadylyhFldcqSidQ==", "license": "MIT", "engines": { "node": ">=18" @@ -4291,14 +3170,10 @@ }, "node_modules/core-util-is": { "version": "1.0.3", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", - "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", "license": "MIT" }, "node_modules/cosmiconfig": { "version": "9.0.0", - "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-9.0.0.tgz", - "integrity": "sha512-itvL5h8RETACmOTFc4UfIyB2RfEHi71Ax6E/PivVxq9NseKbOWpeyHEOIbmAw1rs8Ak0VursQNww7lf7YtUwzg==", "dev": true, "license": "MIT", "dependencies": { @@ -4324,8 +3199,6 @@ }, "node_modules/cross-spawn": { "version": "7.0.6", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", - "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", "license": "MIT", "dependencies": { "path-key": "^3.1.0", @@ -4338,8 +3211,7 @@ }, "node_modules/css-loader": { "version": "5.2.7", - "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-5.2.7.tgz", - "integrity": "sha512-Q7mOvpBNBG7YrVGMxRxcBJZFL75o+cH2abNASdibkj/fffYD8qWbInZrD0S9ccI6vZclF3DsHE7njGlLtaHbhg==", + "dev": true, "license": "MIT", "dependencies": { "icss-utils": "^5.1.0", @@ -4366,8 +3238,7 @@ }, "node_modules/cssesc": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", - "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", + "dev": true, "license": "MIT", "bin": { "cssesc": "bin/cssesc" @@ -4378,12 +3249,8 @@ }, "node_modules/cssstyle": { "version": "4.6.0", - "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-4.6.0.tgz", - "integrity": "sha512-2z+rWdzbbSZv6/rhtvzvqeZQHrBaqgogqt85sqFNbabZOuFbCVFb8kPeEtZjiKkbrm395irpNKiYeFeLiQnFPg==", "dev": true, "license": "MIT", - "optional": true, - "peer": true, "dependencies": { "@asamuzakjp/css-color": "^3.2.0", "rrweb-cssom": "^0.8.0" @@ -4394,24 +3261,16 @@ }, "node_modules/cssstyle/node_modules/rrweb-cssom": { "version": "0.8.0", - "resolved": "https://registry.npmjs.org/rrweb-cssom/-/rrweb-cssom-0.8.0.tgz", - "integrity": "sha512-guoltQEx+9aMf2gDZ0s62EcV8lsXR+0w8915TC3ITdn2YueuNjdAYh/levpU9nFaoChh9RUS5ZdQMrKfVEN9tw==", "dev": true, - "license": "MIT", - "optional": true, - "peer": true + "license": "MIT" }, "node_modules/csstype": { "version": "3.2.3", - "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz", - "integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==", "dev": true, "license": "MIT" }, "node_modules/data-uri-to-buffer": { "version": "6.0.2", - "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-6.0.2.tgz", - "integrity": "sha512-7hvf7/GW8e86rW0ptuwS3OcBGDjIi6SZva7hCyWC0yYry2cOPmLIjXAUHI6DK2HsnwJd9ifmt57i8eV2n4YNpw==", "dev": true, "license": "MIT", "engines": { @@ -4420,12 +3279,8 @@ }, "node_modules/data-urls": { "version": "5.0.0", - "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-5.0.0.tgz", - "integrity": "sha512-ZYP5VBHshaDAiVZxjbRVcFJpc+4xGgT0bK3vzy1HLN8jTO975HEbuYzZJcHoQEY5K1a0z8YayJkyVETa08eNTg==", "dev": true, "license": "MIT", - "optional": true, - "peer": true, "dependencies": { "whatwg-mimetype": "^4.0.0", "whatwg-url": "^14.0.0" @@ -4436,12 +3291,8 @@ }, "node_modules/data-urls/node_modules/tr46": { "version": "5.1.1", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-5.1.1.tgz", - "integrity": "sha512-hdF5ZgjTqgAntKkklYw0R03MG2x/bSzTtkxmIRw/sTNV8YXsCJ1tfLAX23lhxhHJlEf3CRCOCGGWw3vI3GaSPw==", "dev": true, "license": "MIT", - "optional": true, - "peer": true, "dependencies": { "punycode": "^2.3.1" }, @@ -4451,24 +3302,16 @@ }, "node_modules/data-urls/node_modules/webidl-conversions": { "version": "7.0.0", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz", - "integrity": "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==", "dev": true, "license": "BSD-2-Clause", - "optional": true, - "peer": true, "engines": { "node": ">=12" } }, "node_modules/data-urls/node_modules/whatwg-url": { "version": "14.2.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-14.2.0.tgz", - "integrity": "sha512-De72GdQZzNTUBBChsXueQUnPKDkg/5A5zp7pFDuQAj5UFoENpiACU0wlCvzpAGnTkj++ihpKwKyYewn/XNUbKw==", "dev": true, "license": "MIT", - "optional": true, - "peer": true, "dependencies": { "tr46": "^5.1.0", "webidl-conversions": "^7.0.0" @@ -4479,8 +3322,6 @@ }, "node_modules/debug": { "version": "4.4.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", - "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", "license": "MIT", "dependencies": { "ms": "^2.1.3" @@ -4496,8 +3337,6 @@ }, "node_modules/decamelize": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", - "integrity": "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==", "license": "MIT", "engines": { "node": ">=0.10.0" @@ -4505,17 +3344,25 @@ }, "node_modules/decimal.js": { "version": "10.6.0", - "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.6.0.tgz", - "integrity": "sha512-YpgQiITW3JXGntzdUmyUR1V812Hn8T1YVXhCu+wO3OpS4eU9l4YdD3qjyiKdV6mvV29zapkMeD390UVEf2lkUg==", + "dev": true, + "license": "MIT" + }, + "node_modules/deep-eql": { + "version": "5.0.2", "dev": true, "license": "MIT", - "optional": true, - "peer": true + "engines": { + "node": ">=6" + } + }, + "node_modules/deep-is": { + "version": "0.1.4", + "dev": true, + "license": "MIT" }, "node_modules/define-lazy-prop": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz", - "integrity": "sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==", + "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -4523,8 +3370,6 @@ }, "node_modules/degenerator": { "version": "5.0.1", - "resolved": "https://registry.npmjs.org/degenerator/-/degenerator-5.0.1.tgz", - "integrity": "sha512-TllpMR/t0M5sqCXfj85i4XaAzxmS5tVA16dqvdkMwGmzI+dXLXnw3J+3Vdv7VKw+ThlTMboK6i9rnZ6Nntj5CQ==", "dev": true, "license": "MIT", "dependencies": { @@ -4538,20 +3383,14 @@ }, "node_modules/delayed-stream": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", - "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", "dev": true, "license": "MIT", - "optional": true, - "peer": true, "engines": { "node": ">=0.4.0" } }, "node_modules/depd": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", - "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", "license": "MIT", "engines": { "node": ">= 0.8" @@ -4559,8 +3398,6 @@ }, "node_modules/dequal": { "version": "2.0.3", - "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", - "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==", "license": "MIT", "engines": { "node": ">=6" @@ -4578,15 +3415,11 @@ }, "node_modules/devtools-protocol": { "version": "0.0.1566079", - "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.1566079.tgz", - "integrity": "sha512-MJfAEA1UfVhSs7fbSQOG4czavUp1ajfg6prlAN0+cmfa2zNjaIbvq8VneP7do1WAQQIvgNJWSMeP6UyI90gIlQ==", "dev": true, "license": "BSD-3-Clause" }, "node_modules/dijkstrajs": { "version": "1.0.3", - "resolved": "https://registry.npmjs.org/dijkstrajs/-/dijkstrajs-1.0.3.tgz", - "integrity": "sha512-qiSlmBq9+BCdCA/L46dw8Uy93mloxsPSbwnm5yrKn2vMPiy8KyAskTF6zuV/j5BMsmOGZDPs7KjU+mjb670kfA==", "license": "MIT" }, "node_modules/dir-glob": { @@ -4604,8 +3437,7 @@ }, "node_modules/dotenv": { "version": "17.3.1", - "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-17.3.1.tgz", - "integrity": "sha512-IO8C/dzEb6O3F9/twg6ZLXz164a2fhTnEWb95H23Dm4OuN+92NmEAlTrupP9VW6Jm3sO26tQlqyvyi4CsnY9GA==", + "dev": true, "license": "BSD-2-Clause", "engines": { "node": ">=12" @@ -4616,12 +3448,8 @@ }, "node_modules/dunder-proto": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", - "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", "dev": true, "license": "MIT", - "optional": true, - "peer": true, "dependencies": { "call-bind-apply-helpers": "^1.0.1", "es-errors": "^1.3.0", @@ -4633,8 +3461,6 @@ }, "node_modules/duplexify": { "version": "3.7.1", - "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-3.7.1.tgz", - "integrity": "sha512-07z8uv2wMyS51kKhD1KsdXJg5WQ6t93RneqRxUHnskXVtlYYkLqM0gqStQZ3pj073g687jPCHrqNfCzawLYh5g==", "license": "MIT", "dependencies": { "end-of-stream": "^1.0.0", @@ -4645,8 +3471,6 @@ }, "node_modules/duplexify/node_modules/readable-stream": { "version": "2.3.8", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", - "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", "license": "MIT", "dependencies": { "core-util-is": "~1.0.0", @@ -4660,14 +3484,10 @@ }, "node_modules/duplexify/node_modules/safe-buffer": { "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", "license": "MIT" }, "node_modules/duplexify/node_modules/string_decoder": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "license": "MIT", "dependencies": { "safe-buffer": "~5.1.0" @@ -4675,8 +3495,6 @@ }, "node_modules/ecdsa-sig-formatter": { "version": "1.0.11", - "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", - "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==", "license": "Apache-2.0", "dependencies": { "safe-buffer": "^5.0.1" @@ -4684,20 +3502,16 @@ }, "node_modules/electron-to-chromium": { "version": "1.5.302", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.302.tgz", - "integrity": "sha512-sM6HAN2LyK82IyPBpznDRqlTQAtuSaO+ShzFiWTvoMJLHyZ+Y39r8VMfHzwbU8MVBzQ4Wdn85+wlZl2TLGIlwg==", + "dev": true, "license": "ISC" }, "node_modules/emoji-regex": { "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", "license": "MIT" }, "node_modules/emojis-list": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-3.0.0.tgz", - "integrity": "sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==", + "dev": true, "license": "MIT", "engines": { "node": ">= 4" @@ -4705,8 +3519,6 @@ }, "node_modules/end-of-stream": { "version": "1.4.5", - "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.5.tgz", - "integrity": "sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg==", "license": "MIT", "dependencies": { "once": "^1.4.0" @@ -4714,8 +3526,7 @@ }, "node_modules/enhanced-resolve": { "version": "5.19.0", - "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.19.0.tgz", - "integrity": "sha512-phv3E1Xl4tQOShqSte26C7Fl84EwUdZsyOuSSk9qtAGyyQs2s3jJzComh+Abf4g187lUUAvH+H26omrqia2aGg==", + "dev": true, "license": "MIT", "dependencies": { "graceful-fs": "^4.2.4", @@ -4741,12 +3552,8 @@ }, "node_modules/entities": { "version": "6.0.1", - "resolved": "https://registry.npmjs.org/entities/-/entities-6.0.1.tgz", - "integrity": "sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==", "dev": true, "license": "BSD-2-Clause", - "optional": true, - "peer": true, "engines": { "node": ">=0.12" }, @@ -4756,202 +3563,408 @@ }, "node_modules/env-paths": { "version": "2.2.1", - "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz", - "integrity": "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==", "dev": true, "license": "MIT", "engines": { "node": ">=6" } }, - "node_modules/error-ex": { - "version": "1.3.4", - "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.4.tgz", - "integrity": "sha512-sqQamAnR14VgCr1A618A3sGrygcpK+HEbenA/HiEAkkUwcZIIB/tgWqHFxWgOyDh4nB4JCRimh79dR5Ywc9MDQ==", + "node_modules/error-ex": { + "version": "1.3.4", + "dev": true, + "license": "MIT", + "dependencies": { + "is-arrayish": "^0.2.1" + } + }, + "node_modules/error-stack-parser": { + "version": "2.1.4", + "dev": true, + "license": "MIT", + "dependencies": { + "stackframe": "^1.3.4" + } + }, + "node_modules/es-define-property": { + "version": "1.0.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-module-lexer": { + "version": "1.7.0", + "dev": true, + "license": "MIT" + }, + "node_modules/es-object-atoms": { + "version": "1.1.1", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-set-tostringtag": { + "version": "2.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/esbuild": { + "version": "0.27.3", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.27.3", + "@esbuild/android-arm": "0.27.3", + "@esbuild/android-arm64": "0.27.3", + "@esbuild/android-x64": "0.27.3", + "@esbuild/darwin-arm64": "0.27.3", + "@esbuild/darwin-x64": "0.27.3", + "@esbuild/freebsd-arm64": "0.27.3", + "@esbuild/freebsd-x64": "0.27.3", + "@esbuild/linux-arm": "0.27.3", + "@esbuild/linux-arm64": "0.27.3", + "@esbuild/linux-ia32": "0.27.3", + "@esbuild/linux-loong64": "0.27.3", + "@esbuild/linux-mips64el": "0.27.3", + "@esbuild/linux-ppc64": "0.27.3", + "@esbuild/linux-riscv64": "0.27.3", + "@esbuild/linux-s390x": "0.27.3", + "@esbuild/linux-x64": "0.27.3", + "@esbuild/netbsd-arm64": "0.27.3", + "@esbuild/netbsd-x64": "0.27.3", + "@esbuild/openbsd-arm64": "0.27.3", + "@esbuild/openbsd-x64": "0.27.3", + "@esbuild/openharmony-arm64": "0.27.3", + "@esbuild/sunos-x64": "0.27.3", + "@esbuild/win32-arm64": "0.27.3", + "@esbuild/win32-ia32": "0.27.3", + "@esbuild/win32-x64": "0.27.3" + } + }, + "node_modules/escalade": { + "version": "3.2.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-html": { + "version": "1.0.3", + "license": "MIT" + }, + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/escodegen": { + "version": "2.1.0", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "esprima": "^4.0.1", + "estraverse": "^5.2.0", + "esutils": "^2.0.2" + }, + "bin": { + "escodegen": "bin/escodegen.js", + "esgenerate": "bin/esgenerate.js" + }, + "engines": { + "node": ">=6.0" + }, + "optionalDependencies": { + "source-map": "~0.6.1" + } + }, + "node_modules/eslint": { + "version": "9.39.3", + "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.3", + "@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": { + "jiti": "*" + }, + "peerDependenciesMeta": { + "jiti": { + "optional": true + } + } + }, + "node_modules/eslint-scope": { + "version": "5.1.1", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/eslint-scope/node_modules/estraverse": { + "version": "4.3.0", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "4.2.1", + "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/ajv": { + "version": "6.14.0", + "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/eslint/node_modules/balanced-match": { + "version": "1.0.2", + "dev": true, + "license": "MIT" + }, + "node_modules/eslint/node_modules/brace-expansion": { + "version": "1.1.12", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/eslint/node_modules/chalk": { + "version": "4.1.2", "dev": true, "license": "MIT", "dependencies": { - "is-arrayish": "^0.2.1" + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/error-stack-parser": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/error-stack-parser/-/error-stack-parser-2.1.4.tgz", - "integrity": "sha512-Sk5V6wVazPhq5MhpO+AUxJn5x7XSXGl1R93Vn7i+zS15KDVxQijejNCrz8340/2bgLBjR9GtEG8ZVKONDjcqGQ==", - "license": "MIT", + "node_modules/eslint/node_modules/eslint-scope": { + "version": "8.4.0", + "dev": true, + "license": "BSD-2-Clause", "dependencies": { - "stackframe": "^1.3.4" + "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/es-define-property": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", - "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", + "node_modules/eslint/node_modules/find-up": { + "version": "5.0.0", "dev": true, "license": "MIT", - "optional": true, - "peer": true, + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, "engines": { - "node": ">= 0.4" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/es-errors": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", - "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "node_modules/eslint/node_modules/glob-parent": { + "version": "6.0.2", "dev": true, - "license": "MIT", - "optional": true, - "peer": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.3" + }, "engines": { - "node": ">= 0.4" + "node": ">=10.13.0" } }, - "node_modules/es-module-lexer": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.7.0.tgz", - "integrity": "sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==", + "node_modules/eslint/node_modules/json-schema-traverse": { + "version": "0.4.1", "dev": true, "license": "MIT" }, - "node_modules/es-object-atoms": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", - "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", + "node_modules/eslint/node_modules/locate-path": { + "version": "6.0.0", "dev": true, "license": "MIT", - "optional": true, - "peer": true, "dependencies": { - "es-errors": "^1.3.0" + "p-locate": "^5.0.0" }, "engines": { - "node": ">= 0.4" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/es-set-tostringtag": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz", - "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==", + "node_modules/eslint/node_modules/minimatch": { + "version": "3.1.5", "dev": true, - "license": "MIT", - "optional": true, - "peer": true, + "license": "ISC", "dependencies": { - "es-errors": "^1.3.0", - "get-intrinsic": "^1.2.6", - "has-tostringtag": "^1.0.2", - "hasown": "^2.0.2" + "brace-expansion": "^1.1.7" }, "engines": { - "node": ">= 0.4" + "node": "*" } }, - "node_modules/esbuild": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.27.3.tgz", - "integrity": "sha512-8VwMnyGCONIs6cWue2IdpHxHnAjzxnw2Zr7MkVxB2vjmQ2ivqGFb4LEG3SMnv0Gb2F/G/2yA8zUaiL1gywDCCg==", + "node_modules/eslint/node_modules/p-limit": { + "version": "3.1.0", "dev": true, - "hasInstallScript": true, "license": "MIT", - "bin": { - "esbuild": "bin/esbuild" + "dependencies": { + "yocto-queue": "^0.1.0" }, "engines": { - "node": ">=18" + "node": ">=10" }, - "optionalDependencies": { - "@esbuild/aix-ppc64": "0.27.3", - "@esbuild/android-arm": "0.27.3", - "@esbuild/android-arm64": "0.27.3", - "@esbuild/android-x64": "0.27.3", - "@esbuild/darwin-arm64": "0.27.3", - "@esbuild/darwin-x64": "0.27.3", - "@esbuild/freebsd-arm64": "0.27.3", - "@esbuild/freebsd-x64": "0.27.3", - "@esbuild/linux-arm": "0.27.3", - "@esbuild/linux-arm64": "0.27.3", - "@esbuild/linux-ia32": "0.27.3", - "@esbuild/linux-loong64": "0.27.3", - "@esbuild/linux-mips64el": "0.27.3", - "@esbuild/linux-ppc64": "0.27.3", - "@esbuild/linux-riscv64": "0.27.3", - "@esbuild/linux-s390x": "0.27.3", - "@esbuild/linux-x64": "0.27.3", - "@esbuild/netbsd-arm64": "0.27.3", - "@esbuild/netbsd-x64": "0.27.3", - "@esbuild/openbsd-arm64": "0.27.3", - "@esbuild/openbsd-x64": "0.27.3", - "@esbuild/openharmony-arm64": "0.27.3", - "@esbuild/sunos-x64": "0.27.3", - "@esbuild/win32-arm64": "0.27.3", - "@esbuild/win32-ia32": "0.27.3", - "@esbuild/win32-x64": "0.27.3" - } - }, - "node_modules/escalade": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", - "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", - "license": "MIT", - "engines": { - "node": ">=6" + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/escape-html": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", - "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==", - "license": "MIT" - }, - "node_modules/escodegen": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-2.1.0.tgz", - "integrity": "sha512-2NlIDTwUWJN0mRPQOdtQBzbUHvdGY2P1VXSyU83Q3xKxM7WHX2Ql8dKq782Q9TgQUNOLEzEYu9bzLNj1q88I5w==", + "node_modules/eslint/node_modules/p-locate": { + "version": "5.0.0", "dev": true, - "license": "BSD-2-Clause", + "license": "MIT", "dependencies": { - "esprima": "^4.0.1", - "estraverse": "^5.2.0", - "esutils": "^2.0.2" - }, - "bin": { - "escodegen": "bin/escodegen.js", - "esgenerate": "bin/esgenerate.js" + "p-limit": "^3.0.2" }, "engines": { - "node": ">=6.0" + "node": ">=10" }, - "optionalDependencies": { - "source-map": "~0.6.1" + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/eslint-scope": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", - "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "node_modules/espree": { + "version": "10.4.0", + "dev": true, "license": "BSD-2-Clause", "dependencies": { - "esrecurse": "^4.3.0", - "estraverse": "^4.1.1" + "acorn": "^8.15.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^4.2.1" }, "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/eslint-scope/node_modules/estraverse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", - "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", - "license": "BSD-2-Clause", - "engines": { - "node": ">=4.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" } }, "node_modules/esprima": { "version": "4.0.1", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", - "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true, "license": "BSD-2-Clause", "bin": { "esparse": "bin/esparse.js", @@ -4961,10 +3974,20 @@ "node": ">=4" } }, + "node_modules/esquery": { + "version": "1.7.0", + "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" @@ -4975,8 +3998,7 @@ }, "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" @@ -4984,8 +4006,6 @@ }, "node_modules/estree-walker": { "version": "3.0.3", - "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz", - "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==", "dev": true, "license": "MIT", "dependencies": { @@ -4994,8 +4014,6 @@ }, "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": { @@ -5004,8 +4022,6 @@ }, "node_modules/event-target-shim": { "version": "5.0.1", - "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz", - "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==", "license": "MIT", "engines": { "node": ">=6" @@ -5013,8 +4029,6 @@ }, "node_modules/events": { "version": "3.3.0", - "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", - "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", "license": "MIT", "engines": { "node": ">=0.8.x" @@ -5022,8 +4036,6 @@ }, "node_modules/events-universal": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/events-universal/-/events-universal-1.0.1.tgz", - "integrity": "sha512-LUd5euvbMLpwOF8m6ivPCbhQeSiYVNb8Vs0fQ8QjXo0JTkEHpz8pxdQf0gStltaPpw0Cca8b39KxvK9cfKRiAw==", "dev": true, "license": "Apache-2.0", "dependencies": { @@ -5032,8 +4044,7 @@ }, "node_modules/execa": { "version": "5.1.1", - "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", - "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", + "dev": true, "license": "MIT", "dependencies": { "cross-spawn": "^7.0.3", @@ -5055,8 +4066,7 @@ }, "node_modules/execa/node_modules/get-stream": { "version": "6.0.1", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", - "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", + "dev": true, "license": "MIT", "engines": { "node": ">=10" @@ -5067,14 +4077,11 @@ }, "node_modules/execa/node_modules/signal-exit": { "version": "3.0.7", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", - "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "dev": true, "license": "ISC" }, "node_modules/expect-type": { "version": "1.3.0", - "resolved": "https://registry.npmjs.org/expect-type/-/expect-type-1.3.0.tgz", - "integrity": "sha512-knvyeauYhqjOYvQ66MznSMs83wmHrCycNEN6Ao+2AeYEfxUIkuiVxdEa1qlGEPK+We3n0THiDciYSsCcgW/DoA==", "dev": true, "license": "Apache-2.0", "engines": { @@ -5090,8 +4097,7 @@ }, "node_modules/extract-zip": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extract-zip/-/extract-zip-2.0.1.tgz", - "integrity": "sha512-GDhU9ntwuKyGXdZBUgTIe+vXnWj0fppUEtMDL0+idd5Sta8TGpHssn/eusA9mrPr9qNDym6SxAYZjNvCn/9RBg==", + "dev": true, "license": "BSD-2-Clause", "dependencies": { "debug": "^4.1.1", @@ -5110,20 +4116,14 @@ }, "node_modules/fast-decode-uri-component": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/fast-decode-uri-component/-/fast-decode-uri-component-1.0.1.tgz", - "integrity": "sha512-WKgKWg5eUxvRZGwW8FvfbaH7AXSh2cL+3j5fMGzUMCxWBJ3dV3a7Wz8y2f/uQ0e3B6WmodD3oS54jTQ9HVTIIg==", "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", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", "license": "MIT" }, "node_modules/fast-fifo": { "version": "1.3.2", - "resolved": "https://registry.npmjs.org/fast-fifo/-/fast-fifo-1.3.2.tgz", - "integrity": "sha512-/d9sfos4yxzpwkDkuN7k2SqFKtYNmCTzgfEpz82x34IM9/zc8KGxQoXg1liNC/izpRM/MBdt44Nmx41ZWqk+FQ==", "dev": true, "license": "MIT" }, @@ -5146,14 +4146,11 @@ }, "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-json-stringify": { "version": "6.3.0", - "resolved": "https://registry.npmjs.org/fast-json-stringify/-/fast-json-stringify-6.3.0.tgz", - "integrity": "sha512-oRCntNDY/329HJPlmdNLIdogNtt6Vyjb1WuT01Soss3slIdyUp8kAcDU3saQTOquEK8KFVfwIIF7FebxUAu+yA==", "funding": [ { "type": "github", @@ -5174,10 +4171,13 @@ "rfdc": "^1.2.0" } }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "dev": true, + "license": "MIT" + }, "node_modules/fast-querystring": { "version": "1.1.2", - "resolved": "https://registry.npmjs.org/fast-querystring/-/fast-querystring-1.1.2.tgz", - "integrity": "sha512-g6KuKWmFXc0fID8WWH0jit4g0AGBoJhCkJMb1RmbsSEUNvQ+ZC8D6CUZ+GtF8nMzSPXnhiePyyqqipzNNEnHjg==", "license": "MIT", "dependencies": { "fast-decode-uri-component": "^1.0.1" @@ -5185,8 +4185,6 @@ }, "node_modules/fast-uri": { "version": "3.1.0", - "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.0.tgz", - "integrity": "sha512-iPeeDKJSWf4IEOasVVrknXpaBV0IApz/gp7S2bb7Z4Lljbl2MGJRqInZiUrQwV16cpzw/D3S5j5Julj/gT52AA==", "funding": [ { "type": "github", @@ -5201,8 +4199,6 @@ }, "node_modules/fastify": { "version": "5.7.4", - "resolved": "https://registry.npmjs.org/fastify/-/fastify-5.7.4.tgz", - "integrity": "sha512-e6l5NsRdaEP8rdD8VR0ErJASeyaRbzXYpmkrpr2SuvuMq6Si3lvsaVy5C+7gLanEkvjpMDzBXWE5HPeb/hgTxA==", "funding": [ { "type": "github", @@ -5234,8 +4230,6 @@ }, "node_modules/fastify-plugin": { "version": "5.1.0", - "resolved": "https://registry.npmjs.org/fastify-plugin/-/fastify-plugin-5.1.0.tgz", - "integrity": "sha512-FAIDA8eovSt5qcDgcBvDuX/v0Cjz0ohGhENZ/wpc3y+oZCY2afZ9Baqql3g/lC+OHRnciQol4ww7tuthOb9idw==", "funding": [ { "type": "github", @@ -5250,8 +4244,6 @@ }, "node_modules/fastq": { "version": "1.20.1", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.20.1.tgz", - "integrity": "sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw==", "license": "ISC", "dependencies": { "reusify": "^1.0.4" @@ -5259,17 +4251,25 @@ }, "node_modules/fd-slicer": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz", - "integrity": "sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==", + "dev": true, "license": "MIT", "dependencies": { "pend": "~1.2.0" } }, + "node_modules/file-entry-cache": { + "version": "8.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "flat-cache": "^4.0.0" + }, + "engines": { + "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==", "license": "MIT", "dependencies": { "to-regex-range": "^5.0.1" @@ -5280,8 +4280,6 @@ }, "node_modules/find-my-way": { "version": "9.5.0", - "resolved": "https://registry.npmjs.org/find-my-way/-/find-my-way-9.5.0.tgz", - "integrity": "sha512-VW2RfnmscZO5KgBY5XVyKREMW5nMZcxDy+buTOsL+zIPnBlbKm+00sgzoQzq1EVh4aALZLfKdwv6atBGcjvjrQ==", "license": "MIT", "dependencies": { "fast-deep-equal": "^3.1.3", @@ -5294,8 +4292,6 @@ }, "node_modules/find-up": { "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", "license": "MIT", "dependencies": { "locate-path": "^5.0.0", @@ -5305,10 +4301,35 @@ "node": ">=8" } }, + "node_modules/fix-dts-default-cjs-exports": { + "version": "1.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "magic-string": "^0.30.17", + "mlly": "^1.7.4", + "rollup": "^4.34.8" + } + }, + "node_modules/flat-cache": { + "version": "4.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "flatted": "^3.2.9", + "keyv": "^4.5.4" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/flatted": { + "version": "3.3.3", + "dev": true, + "license": "ISC" + }, "node_modules/foreground-child": { "version": "3.3.1", - "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.1.tgz", - "integrity": "sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==", "license": "ISC", "dependencies": { "cross-spawn": "^7.0.6", @@ -5323,12 +4344,8 @@ }, "node_modules/form-data": { "version": "4.0.5", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.5.tgz", - "integrity": "sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==", "dev": true, "license": "MIT", - "optional": true, - "peer": true, "dependencies": { "asynckit": "^0.4.0", "combined-stream": "^1.0.8", @@ -5355,17 +4372,23 @@ "node": ">=6 <7 || >=8" } }, + "node_modules/fs-extra/node_modules/universalify": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", + "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4.0.0" + } + }, "node_modules/fs-monkey": { "version": "1.0.3", - "resolved": "https://registry.npmjs.org/fs-monkey/-/fs-monkey-1.0.3.tgz", - "integrity": "sha512-cybjIfiiE+pTWicSCLFHSrXZ6EilF30oh91FDP9S2B051prEa7QWfrVTQm10/dDpswBDXZugPa1Ogu8Yh+HV0Q==", + "dev": true, "license": "Unlicense" }, "node_modules/fsevents": { "version": "2.3.3", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", - "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", - "hasInstallScript": true, "license": "MIT", "optional": true, "os": [ @@ -5377,20 +4400,14 @@ }, "node_modules/function-bind": { "version": "1.1.2", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", - "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", "dev": true, "license": "MIT", - "optional": true, - "peer": true, "funding": { "url": "https://github.com/sponsors/ljharb" } }, "node_modules/get-caller-file": { "version": "2.0.5", - "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", - "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", "license": "ISC", "engines": { "node": "6.* || 8.* || >= 10.*" @@ -5398,12 +4415,8 @@ }, "node_modules/get-intrinsic": { "version": "1.3.0", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", - "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", "dev": true, "license": "MIT", - "optional": true, - "peer": true, "dependencies": { "call-bind-apply-helpers": "^1.0.2", "es-define-property": "^1.0.1", @@ -5425,12 +4438,8 @@ }, "node_modules/get-proto": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", - "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", "dev": true, "license": "MIT", - "optional": true, - "peer": true, "dependencies": { "dunder-proto": "^1.0.1", "es-object-atoms": "^1.0.0" @@ -5441,8 +4450,7 @@ }, "node_modules/get-stream": { "version": "5.2.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", - "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", + "dev": true, "license": "MIT", "dependencies": { "pump": "^3.0.0" @@ -5456,8 +4464,6 @@ }, "node_modules/get-tsconfig": { "version": "4.13.6", - "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.13.6.tgz", - "integrity": "sha512-shZT/QMiSHc/YBLxxOkMtgSid5HFoauqCE3/exfsEcwg1WkeqjG+V40yBbBrsD+jW2HDXcs28xOfcbm2jI8Ddw==", "dev": true, "license": "MIT", "dependencies": { @@ -5469,8 +4475,6 @@ }, "node_modules/get-uri": { "version": "6.0.5", - "resolved": "https://registry.npmjs.org/get-uri/-/get-uri-6.0.5.tgz", - "integrity": "sha512-b1O07XYq8eRuVzBNgJLstU6FYc1tS6wnMtF1I1D9lE8LxZSOGZ7LhxN54yPP6mGw5f2CkXY2BQUL9Fx41qvcIg==", "dev": true, "license": "MIT", "dependencies": { @@ -5484,9 +4488,6 @@ }, "node_modules/glob": { "version": "11.1.0", - "resolved": "https://registry.npmjs.org/glob/-/glob-11.1.0.tgz", - "integrity": "sha512-vuNwKSaKiqm7g0THUBu2x7ckSs3XJLXE+2ssL7/MfTGPLLcrJQ/4Uq1CjPTtO5cCIiRxqvN6Twy1qOwhL0Xjcw==", - "deprecated": "Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me", "license": "BlueOak-1.0.0", "dependencies": { "foreground-child": "^3.3.1", @@ -5508,8 +4509,6 @@ }, "node_modules/glob-parent": { "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", "license": "ISC", "dependencies": { "is-glob": "^4.0.1" @@ -5520,10 +4519,20 @@ }, "node_modules/glob-to-regexp": { "version": "0.4.1", - "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz", - "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==", + "dev": true, "license": "BSD-2-Clause" }, + "node_modules/globals": { + "version": "14.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/globby": { "version": "11.1.0", "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", @@ -5547,12 +4556,8 @@ }, "node_modules/gopd": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", - "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", "dev": true, "license": "MIT", - "optional": true, - "peer": true, "engines": { "node": ">= 0.4" }, @@ -5562,14 +4567,12 @@ }, "node_modules/graceful-fs": { "version": "4.2.11", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", - "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "dev": true, "license": "ISC" }, "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" @@ -5577,12 +4580,8 @@ }, "node_modules/has-symbols": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", - "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", "dev": true, "license": "MIT", - "optional": true, - "peer": true, "engines": { "node": ">= 0.4" }, @@ -5592,12 +4591,8 @@ }, "node_modules/has-tostringtag": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", - "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", "dev": true, "license": "MIT", - "optional": true, - "peer": true, "dependencies": { "has-symbols": "^1.0.3" }, @@ -5610,12 +4605,8 @@ }, "node_modules/hasown": { "version": "2.0.2", - "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", - "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", "dev": true, "license": "MIT", - "optional": true, - "peer": true, "dependencies": { "function-bind": "^1.1.2" }, @@ -5625,12 +4616,8 @@ }, "node_modules/html-encoding-sniffer": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-4.0.0.tgz", - "integrity": "sha512-Y22oTqIU4uuPgEemfz7NDJz6OeKf12Lsu+QC+s3BVpda64lTiMYCyGwg5ki4vFxkMwQdeZDl2adZoqUgdFuTgQ==", "dev": true, "license": "MIT", - "optional": true, - "peer": true, "dependencies": { "whatwg-encoding": "^3.1.1" }, @@ -5640,8 +4627,7 @@ }, "node_modules/html-entities": { "version": "2.6.0", - "resolved": "https://registry.npmjs.org/html-entities/-/html-entities-2.6.0.tgz", - "integrity": "sha512-kig+rMn/QOVRvr7c86gQ8lWXq+Hkv6CbAH1hLu+RG338StTpE8Z0b44SDVaqVu7HGKf27frdmUYEs9hTUX/cLQ==", + "dev": true, "funding": [ { "type": "github", @@ -5656,15 +4642,11 @@ }, "node_modules/html-escaper": { "version": "2.0.2", - "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", - "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", "dev": true, "license": "MIT" }, "node_modules/http_ece": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/http_ece/-/http_ece-1.2.0.tgz", - "integrity": "sha512-JrF8SSLVmcvc5NducxgyOrKXe3EsyHMgBFgSaIUGmArKe+rwr0uphRkRXvwiom3I+fpIfoItveHrfudL8/rxuA==", "license": "MIT", "engines": { "node": ">=16" @@ -5672,8 +4654,6 @@ }, "node_modules/http-errors": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.1.tgz", - "integrity": "sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==", "license": "MIT", "dependencies": { "depd": "~2.0.0", @@ -5692,8 +4672,6 @@ }, "node_modules/http-proxy-agent": { "version": "7.0.2", - "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz", - "integrity": "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==", "dev": true, "license": "MIT", "dependencies": { @@ -5706,8 +4684,6 @@ }, "node_modules/https-proxy-agent": { "version": "7.0.6", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz", - "integrity": "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==", "license": "MIT", "dependencies": { "agent-base": "^7.1.2", @@ -5729,17 +4705,14 @@ }, "node_modules/human-signals": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", - "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", + "dev": true, "license": "Apache-2.0", "engines": { "node": ">=10.17.0" } }, "node_modules/iconv-lite": { - "version": "0.7.2", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.7.2.tgz", - "integrity": "sha512-im9DjEDQ55s9fL4EYzOAv0yMqmMBSZp6G0VvFyTMPKWxiSBHUj9NW/qqLmXUwXrrM7AvqSlTCfvqRb0cM8yYqw==", + "version": "0.6.3", "dev": true, "license": "MIT", "dependencies": { @@ -5747,16 +4720,11 @@ }, "engines": { "node": ">=0.10.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" } }, "node_modules/icss-utils": { "version": "5.1.0", - "resolved": "https://registry.npmjs.org/icss-utils/-/icss-utils-5.1.0.tgz", - "integrity": "sha512-soFhflCVWLfRNOPU3iv5Z9VUdT44xFRbzjLsEzSr5AQmgqPMTHdU3PMT1Cf1ssx8fLNJDA1juftYl+PUcv3MqA==", + "dev": true, "license": "ISC", "engines": { "node": "^10 || ^12 || >= 14" @@ -5767,8 +4735,6 @@ }, "node_modules/ieee754": { "version": "1.2.1", - "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", - "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", "funding": [ { "type": "github", @@ -5787,8 +4753,6 @@ }, "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": { @@ -5797,8 +4761,6 @@ }, "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": { @@ -5812,16 +4774,20 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8.19" + } + }, "node_modules/inherits": { "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", "license": "ISC" }, "node_modules/ip-address": { "version": "10.1.0", - "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-10.1.0.tgz", - "integrity": "sha512-XXADHxXmvT9+CRxhXg56LJovE+bmWnEWB78LB83VZTprKTmaC5QfruXocxzTZ2Kl0DNwKuBdlIhjL8LeY8Sf8Q==", "dev": true, "license": "MIT", "engines": { @@ -5830,8 +4796,6 @@ }, "node_modules/ipaddr.js": { "version": "2.3.0", - "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-2.3.0.tgz", - "integrity": "sha512-Zv/pA+ciVFbCSBBjGfaKUya/CcGmUHzTydLMaTwrUUEM2DIEO3iZvueGxmacvmN50fGpGVKeTXpb2LcYQxeVdg==", "license": "MIT", "engines": { "node": ">= 10" @@ -5839,15 +4803,11 @@ }, "node_modules/is-arrayish": { "version": "0.2.1", - "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", - "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", "dev": true, "license": "MIT" }, "node_modules/is-binary-path": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", - "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", "license": "MIT", "dependencies": { "binary-extensions": "^2.0.0" @@ -5858,8 +4818,7 @@ }, "node_modules/is-docker": { "version": "2.2.1", - "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", - "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==", + "dev": true, "license": "MIT", "bin": { "is-docker": "cli.js" @@ -5873,8 +4832,6 @@ }, "node_modules/is-extglob": { "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", "license": "MIT", "engines": { "node": ">=0.10.0" @@ -5882,8 +4839,6 @@ }, "node_modules/is-fullwidth-code-point": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", "license": "MIT", "engines": { "node": ">=8" @@ -5891,8 +4846,6 @@ }, "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==", "license": "MIT", "dependencies": { "is-extglob": "^2.1.1" @@ -5903,8 +4856,6 @@ }, "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==", "license": "MIT", "engines": { "node": ">=0.12.0" @@ -5912,17 +4863,12 @@ }, "node_modules/is-potential-custom-element-name": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz", - "integrity": "sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==", "dev": true, - "license": "MIT", - "optional": true, - "peer": true + "license": "MIT" }, "node_modules/is-stream": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", - "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -5956,8 +4902,7 @@ }, "node_modules/is-wsl": { "version": "2.2.0", - "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", - "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", + "dev": true, "license": "MIT", "dependencies": { "is-docker": "^2.0.0" @@ -5968,20 +4913,14 @@ }, "node_modules/isarray": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", "license": "MIT" }, "node_modules/isexe": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", "license": "ISC" }, "node_modules/istanbul-lib-coverage": { "version": "3.2.2", - "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz", - "integrity": "sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==", "dev": true, "license": "BSD-3-Clause", "engines": { @@ -5990,8 +4929,6 @@ }, "node_modules/istanbul-lib-report": { "version": "3.0.1", - "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz", - "integrity": "sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==", "dev": true, "license": "BSD-3-Clause", "dependencies": { @@ -6005,8 +4942,6 @@ }, "node_modules/istanbul-reports": { "version": "3.2.0", - "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.2.0.tgz", - "integrity": "sha512-HGYWWS/ehqTV3xN10i23tkPkpH46MLCIMFNCaaKNavAXTF1RkqxawEPtnjnGZ6XKSInBKkiOA5BKS+aZiY3AvA==", "dev": true, "license": "BSD-3-Clause", "dependencies": { @@ -6019,8 +4954,6 @@ }, "node_modules/jackspeak": { "version": "4.2.3", - "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-4.2.3.tgz", - "integrity": "sha512-ykkVRwrYvFm1nb2AJfKKYPr0emF6IiXDYUaFx4Zn9ZuIH7MrzEZ3sD5RlqGXNRpHtvUHJyOnCEFxOlNDtGo7wg==", "license": "BlueOak-1.0.0", "dependencies": { "@isaacs/cliui": "^9.0.0" @@ -6034,8 +4967,7 @@ }, "node_modules/jest-worker": { "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz", - "integrity": "sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==", + "dev": true, "license": "MIT", "dependencies": { "@types/node": "*", @@ -6048,8 +4980,7 @@ }, "node_modules/jest-worker/node_modules/supports-color": { "version": "8.1.1", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", - "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, "license": "MIT", "dependencies": { "has-flag": "^4.0.0" @@ -6061,17 +4992,21 @@ "url": "https://github.com/chalk/supports-color?sponsor=1" } }, + "node_modules/joycon": { + "version": "3.1.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + } + }, "node_modules/js-tokens": { "version": "10.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-10.0.0.tgz", - "integrity": "sha512-lM/UBzQmfJRo9ABXbPWemivdCW8V2G8FHaHdypQaIy523snUjog0W71ayWXTjiR+ixeMyVHN2XcpnTd/liPg/Q==", "dev": true, "license": "MIT" }, "node_modules/js-yaml": { "version": "4.1.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz", - "integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==", "dev": true, "license": "MIT", "dependencies": { @@ -6083,12 +5018,8 @@ }, "node_modules/jsdom": { "version": "24.1.3", - "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-24.1.3.tgz", - "integrity": "sha512-MyL55p3Ut3cXbeBEG7Hcv0mVM8pp8PBNWxRqchZnSfAiES1v1mRnMeFfaHWIPULpwsYfvO+ZmMZz5tGCnjzDUQ==", "dev": true, "license": "MIT", - "optional": true, - "peer": true, "dependencies": { "cssstyle": "^4.0.1", "data-urls": "^5.0.0", @@ -6126,12 +5057,8 @@ }, "node_modules/jsdom/node_modules/tr46": { "version": "5.1.1", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-5.1.1.tgz", - "integrity": "sha512-hdF5ZgjTqgAntKkklYw0R03MG2x/bSzTtkxmIRw/sTNV8YXsCJ1tfLAX23lhxhHJlEf3CRCOCGGWw3vI3GaSPw==", "dev": true, "license": "MIT", - "optional": true, - "peer": true, "dependencies": { "punycode": "^2.3.1" }, @@ -6141,24 +5068,16 @@ }, "node_modules/jsdom/node_modules/webidl-conversions": { "version": "7.0.0", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz", - "integrity": "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==", "dev": true, "license": "BSD-2-Clause", - "optional": true, - "peer": true, "engines": { "node": ">=12" } }, "node_modules/jsdom/node_modules/whatwg-url": { "version": "14.2.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-14.2.0.tgz", - "integrity": "sha512-De72GdQZzNTUBBChsXueQUnPKDkg/5A5zp7pFDuQAj5UFoENpiACU0wlCvzpAGnTkj++ihpKwKyYewn/XNUbKw==", "dev": true, "license": "MIT", - "optional": true, - "peer": true, "dependencies": { "tr46": "^5.1.0", "webidl-conversions": "^7.0.0" @@ -6167,16 +5086,18 @@ "node": ">=18" } }, + "node_modules/json-buffer": { + "version": "3.0.1", + "dev": true, + "license": "MIT" + }, "node_modules/json-parse-even-better-errors": { "version": "2.3.1", - "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", - "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", + "dev": true, "license": "MIT" }, "node_modules/json-schema-ref-resolver": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/json-schema-ref-resolver/-/json-schema-ref-resolver-3.0.0.tgz", - "integrity": "sha512-hOrZIVL5jyYFjzk7+y7n5JDzGlU8rfWDuYyHwGa2WA8/pcmMHezp2xsVwxrebD/Q9t8Nc5DboieySDpCp4WG4A==", "funding": [ { "type": "github", @@ -6194,14 +5115,16 @@ }, "node_modules/json-schema-traverse": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "license": "MIT" + }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "dev": true, "license": "MIT" }, "node_modules/json5": { "version": "2.2.3", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", - "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "dev": true, "license": "MIT", "bin": { "json5": "lib/cli.js" @@ -6222,8 +5145,6 @@ }, "node_modules/jwa": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/jwa/-/jwa-2.0.1.tgz", - "integrity": "sha512-hRF04fqJIP8Abbkq5NKGN0Bbr3JxlQ+qhZufXVr0DvujKy93ZCbXZMHDL4EOtodSbCWxOqR8MS1tXA5hwqCXDg==", "license": "MIT", "dependencies": { "buffer-equal-constant-time": "^1.0.1", @@ -6233,27 +5154,42 @@ }, "node_modules/jws": { "version": "4.0.1", - "resolved": "https://registry.npmjs.org/jws/-/jws-4.0.1.tgz", - "integrity": "sha512-EKI/M/yqPncGUUh44xz0PxSidXFr/+r0pA70+gIYhjv+et7yxM+s29Y+VGDkovRofQem0fs7Uvf4+YmAdyRduA==", "license": "MIT", "dependencies": { "jwa": "^2.0.1", "safe-buffer": "^5.0.1" } }, + "node_modules/keyv": { + "version": "4.5.4", + "dev": true, + "license": "MIT", + "dependencies": { + "json-buffer": "3.0.1" + } + }, "node_modules/kleur": { "version": "3.0.3", - "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", - "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==", + "dev": true, "license": "MIT", "engines": { "node": ">=6" } }, + "node_modules/levn": { + "version": "0.4.1", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, "node_modules/light-my-request": { "version": "6.6.0", - "resolved": "https://registry.npmjs.org/light-my-request/-/light-my-request-6.6.0.tgz", - "integrity": "sha512-CHYbu8RtboSIoVsHZ6Ye4cj4Aw/yg2oAFimlF7mNvfDV192LR7nDiKtSIfCuLT7KokPSTn/9kfVLm5OGN0A28A==", "funding": [ { "type": "github", @@ -6273,8 +5209,6 @@ }, "node_modules/light-my-request/node_modules/process-warning": { "version": "4.0.1", - "resolved": "https://registry.npmjs.org/process-warning/-/process-warning-4.0.1.tgz", - "integrity": "sha512-3c2LzQ3rY9d0hc1emcsHhfT9Jwz0cChib/QN89oME2R451w5fy3f0afAhERFZAwrbDU43wk12d0ORBpDVME50Q==", "funding": [ { "type": "github", @@ -6287,17 +5221,33 @@ ], "license": "MIT" }, + "node_modules/lilconfig": { + "version": "3.1.3", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/antonk52" + } + }, "node_modules/lines-and-columns": { "version": "1.2.4", - "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", - "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", "dev": true, "license": "MIT" }, + "node_modules/load-tsconfig": { + "version": "0.2.5", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + } + }, "node_modules/loader-runner": { "version": "4.3.1", - "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.3.1.tgz", - "integrity": "sha512-IWqP2SCPhyVFTBtRcgMHdzlf9ul25NwaFx4wCEH/KjAXuuHY4yNjvPXsBokp8jCB936PyWRaPKUNh8NvylLp2Q==", + "dev": true, "license": "MIT", "engines": { "node": ">=6.11.5" @@ -6309,8 +5259,7 @@ }, "node_modules/loader-utils": { "version": "2.0.4", - "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.4.tgz", - "integrity": "sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==", + "dev": true, "license": "MIT", "dependencies": { "big.js": "^5.2.2", @@ -6323,8 +5272,6 @@ }, "node_modules/locate-path": { "version": "5.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", "license": "MIT", "dependencies": { "p-locate": "^4.1.0" @@ -6333,10 +5280,14 @@ "node": ">=8" } }, + "node_modules/lodash.merge": { + "version": "4.6.2", + "dev": true, + "license": "MIT" + }, "node_modules/lodash.sortby": { "version": "4.7.0", - "resolved": "https://registry.npmjs.org/lodash.sortby/-/lodash.sortby-4.7.0.tgz", - "integrity": "sha512-HDWXG8isMntAyRF5vZ7xKuEvOhT4AhlRt/3czTSjvGUxjYCBVRQY48ViDHyfYz9VIoBkW4TMGQNapx+l3RUwdA==", + "dev": true, "license": "MIT" }, "node_modules/lodash.startcase": { @@ -6346,10 +5297,13 @@ "dev": true, "license": "MIT" }, + "node_modules/loupe": { + "version": "3.2.1", + "dev": true, + "license": "MIT" + }, "node_modules/lru-cache": { "version": "11.2.6", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.2.6.tgz", - "integrity": "sha512-ESL2CrkS/2wTPfuend7Zhkzo2u0daGJ/A2VucJOgQ/C48S/zB8MMeMHSGKYpXhIjbPxfuezITkaBH1wqv00DDQ==", "license": "BlueOak-1.0.0", "engines": { "node": "20 || >=22" @@ -6357,8 +5311,6 @@ }, "node_modules/magic-string": { "version": "0.30.21", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz", - "integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==", "dev": true, "license": "MIT", "dependencies": { @@ -6367,8 +5319,6 @@ }, "node_modules/magicast": { "version": "0.5.2", - "resolved": "https://registry.npmjs.org/magicast/-/magicast-0.5.2.tgz", - "integrity": "sha512-E3ZJh4J3S9KfwdjZhe2afj6R9lGIN5Pher1pF39UGrXRqq/VDaGVIGN13BjHd2u8B61hArAGOnso7nBOouW3TQ==", "dev": true, "license": "MIT", "dependencies": { @@ -6379,8 +5329,6 @@ }, "node_modules/make-dir": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-4.0.0.tgz", - "integrity": "sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==", "dev": true, "license": "MIT", "dependencies": { @@ -6395,20 +5343,15 @@ }, "node_modules/math-intrinsics": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", - "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", "dev": true, "license": "MIT", - "optional": true, - "peer": true, "engines": { "node": ">= 0.4" } }, "node_modules/mediabunny": { "version": "1.34.5", - "resolved": "https://registry.npmjs.org/mediabunny/-/mediabunny-1.34.5.tgz", - "integrity": "sha512-Hs31rd+ane6GQJClM77KfNnf49DenK7yRU9MC4JeHwpNIFCSww/XUoGyKleAVrylw6Snrep2Sm+BhD2CS5ARkg==", + "dev": true, "license": "MPL-2.0", "workspaces": [ "packages/*" @@ -6424,8 +5367,7 @@ }, "node_modules/memfs": { "version": "3.4.3", - "resolved": "https://registry.npmjs.org/memfs/-/memfs-3.4.3.tgz", - "integrity": "sha512-eivjfi7Ahr6eQTn44nvTnR60e4a1Fs1Via2kCR5lHo/kyNoiMWaXCNJ/GpSd0ilXas2JSOl9B5FTIhflXu0hlg==", + "dev": true, "license": "Unlicense", "dependencies": { "fs-monkey": "1.0.3" @@ -6436,8 +5378,7 @@ }, "node_modules/merge-stream": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", - "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "dev": true, "license": "MIT" }, "node_modules/merge2": { @@ -6466,8 +5407,6 @@ }, "node_modules/mime": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/mime/-/mime-3.0.0.tgz", - "integrity": "sha512-jSCU7/VB1loIWBZe14aEYHU/+1UMEHoaO7qxCOVJOw9GgH72VAWppxNcjU+x9a2k3GSIBXNKxXQFqRvvZ7vr3A==", "license": "MIT", "bin": { "mime": "cli.js" @@ -6478,8 +5417,6 @@ }, "node_modules/mime-db": { "version": "1.54.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz", - "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==", "license": "MIT", "engines": { "node": ">= 0.6" @@ -6487,8 +5424,7 @@ }, "node_modules/mime-types": { "version": "2.1.35", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", - "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dev": true, "license": "MIT", "dependencies": { "mime-db": "1.52.0" @@ -6499,8 +5435,7 @@ }, "node_modules/mime-types/node_modules/mime-db": { "version": "1.52.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", - "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "dev": true, "license": "MIT", "engines": { "node": ">= 0.6" @@ -6508,8 +5443,7 @@ }, "node_modules/mimic-fn": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", - "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "dev": true, "license": "MIT", "engines": { "node": ">=6" @@ -6517,14 +5451,10 @@ }, "node_modules/minimalistic-assert": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", - "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==", "license": "ISC" }, "node_modules/minimatch": { "version": "10.2.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.2.tgz", - "integrity": "sha512-+G4CpNBxa5MprY+04MbgOw1v7So6n5JY166pFi9KfYwT78fxScCeSNQSNzp6dpPSW2rONOps6Ocam1wFhCgoVw==", "license": "BlueOak-1.0.0", "dependencies": { "brace-expansion": "^5.0.2" @@ -6538,14 +5468,10 @@ }, "node_modules/minimist": { "version": "1.2.6", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz", - "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==", "license": "MIT" }, "node_modules/minipass": { "version": "7.1.3", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.3.tgz", - "integrity": "sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A==", "license": "BlueOak-1.0.0", "engines": { "node": ">=16 || 14 >=14.17" @@ -6553,11 +5479,20 @@ }, "node_modules/mitt": { "version": "3.0.1", - "resolved": "https://registry.npmjs.org/mitt/-/mitt-3.0.1.tgz", - "integrity": "sha512-vKivATfr97l2/QBCYAkXYDbrIWPM2IIKEl7YPhjCvKlG3kE2gm+uBo6nEXK3M5/Ffh/FLpKExzOQ3JJoJGFKBw==", "dev": true, "license": "MIT" }, + "node_modules/mlly": { + "version": "1.8.0", + "dev": true, + "license": "MIT", + "dependencies": { + "acorn": "^8.15.0", + "pathe": "^2.0.3", + "pkg-types": "^1.3.1", + "ufo": "^1.6.1" + } + }, "node_modules/mri": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/mri/-/mri-1.2.0.tgz", @@ -6570,14 +5505,21 @@ }, "node_modules/ms": { "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", "license": "MIT" }, + "node_modules/mz": { + "version": "2.7.0", + "dev": true, + "license": "MIT", + "dependencies": { + "any-promise": "^1.0.0", + "object-assign": "^4.0.1", + "thenify-all": "^1.0.0" + } + }, "node_modules/nanoid": { "version": "3.3.11", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", - "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", + "dev": true, "funding": [ { "type": "github", @@ -6592,16 +5534,18 @@ "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" } }, + "node_modules/natural-compare": { + "version": "1.4.0", + "dev": true, + "license": "MIT" + }, "node_modules/neo-async": { "version": "2.6.2", - "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", - "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", + "dev": true, "license": "MIT" }, "node_modules/netmask": { "version": "2.0.2", - "resolved": "https://registry.npmjs.org/netmask/-/netmask-2.0.2.tgz", - "integrity": "sha512-dBpDMdxv9Irdq66304OLfEmQ9tbNRFnFTuZiLo+bD+r332bBmMJ8GBLXklIXXgxd3+v9+KUnZaUR5PJMa75Gsg==", "dev": true, "license": "MIT", "engines": { @@ -6610,14 +5554,10 @@ }, "node_modules/node-addon-api": { "version": "7.1.1", - "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-7.1.1.tgz", - "integrity": "sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==", "license": "MIT" }, "node_modules/node-pty": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/node-pty/-/node-pty-1.1.0.tgz", - "integrity": "sha512-20JqtutY6JPXTUnL0ij1uad7Qe1baT46lyolh2sSENDd4sTzKZ4nmAFkeAARDKwmlLjPx6XKRlwRUxwjOy+lUg==", "hasInstallScript": true, "license": "MIT", "dependencies": { @@ -6626,14 +5566,11 @@ }, "node_modules/node-releases": { "version": "2.0.27", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.27.tgz", - "integrity": "sha512-nmh3lCkYZ3grZvqcCH+fjmQ7X+H0OeZgP40OierEaAptX4XofMh5kwNbWh7lBduUzCcV/8kZ+NDLCwm2iorIlA==", + "dev": true, "license": "MIT" }, "node_modules/normalize-path": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", - "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", "license": "MIT", "engines": { "node": ">=0.10.0" @@ -6641,8 +5578,7 @@ }, "node_modules/npm-run-path": { "version": "4.0.1", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", - "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", + "dev": true, "license": "MIT", "dependencies": { "path-key": "^3.0.0" @@ -6653,17 +5589,19 @@ }, "node_modules/nwsapi": { "version": "2.2.23", - "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.23.tgz", - "integrity": "sha512-7wfH4sLbt4M0gCDzGE6vzQBo0bfTKjU7Sfpqy/7gs1qBfYz2vEJH6vXcBKpO3+6Yu1telwd0t9HpyOoLEQQbIQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/object-assign": { + "version": "4.1.1", "dev": true, "license": "MIT", - "optional": true, - "peer": true + "engines": { + "node": ">=0.10.0" + } }, "node_modules/obug": { "version": "2.1.1", - "resolved": "https://registry.npmjs.org/obug/-/obug-2.1.1.tgz", - "integrity": "sha512-uTqF9MuPraAQ+IsnPf366RG4cP9RtUi7MLO1N3KEc+wb0a6yKpeL0lmk2IB1jY5KHPAlTc6T/JRdC/YqxHNwkQ==", "dev": true, "funding": [ "https://github.com/sponsors/sxzz", @@ -6673,8 +5611,6 @@ }, "node_modules/on-exit-leak-free": { "version": "2.1.2", - "resolved": "https://registry.npmjs.org/on-exit-leak-free/-/on-exit-leak-free-2.1.2.tgz", - "integrity": "sha512-0eJJY6hXLGf1udHwfNftBqH+g73EU4B504nZeKpz1sYRKafAghwxEJunB2O7rDZkL4PGfsMVnTXZ2EjibbqcsA==", "license": "MIT", "engines": { "node": ">=14.0.0" @@ -6682,8 +5618,6 @@ }, "node_modules/once": { "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", "license": "ISC", "dependencies": { "wrappy": "1" @@ -6691,8 +5625,7 @@ }, "node_modules/onetime": { "version": "5.1.2", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", - "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "dev": true, "license": "MIT", "dependencies": { "mimic-fn": "^2.1.0" @@ -6706,8 +5639,7 @@ }, "node_modules/open": { "version": "8.4.2", - "resolved": "https://registry.npmjs.org/open/-/open-8.4.2.tgz", - "integrity": "sha512-7x81NCL719oNbsq/3mh+hVrAWmFuEYUqrq/Iw3kUzH8ReypT9QQ0BLoJS7/G9k6N81XjW4qHWtjWwe/9eLy1EQ==", + "dev": true, "license": "MIT", "dependencies": { "define-lazy-prop": "^2.0.0", @@ -6721,6 +5653,22 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/optionator": { + "version": "0.9.4", + "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/outdent": { "version": "0.5.0", "resolved": "https://registry.npmjs.org/outdent/-/outdent-0.5.0.tgz", @@ -6743,8 +5691,6 @@ }, "node_modules/p-limit": { "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", "license": "MIT", "dependencies": { "p-try": "^2.0.0" @@ -6758,8 +5704,6 @@ }, "node_modules/p-locate": { "version": "4.1.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", "license": "MIT", "dependencies": { "p-limit": "^2.2.0" @@ -6780,8 +5724,6 @@ }, "node_modules/p-try": { "version": "2.2.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", - "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", "license": "MIT", "engines": { "node": ">=6" @@ -6789,8 +5731,6 @@ }, "node_modules/pac-proxy-agent": { "version": "7.2.0", - "resolved": "https://registry.npmjs.org/pac-proxy-agent/-/pac-proxy-agent-7.2.0.tgz", - "integrity": "sha512-TEB8ESquiLMc0lV8vcd5Ql/JAKAoyzHFXaStwjkzpOpC5Yv+pIzLfHvjTSdf3vpa2bMiUQrg9i6276yn8666aA==", "dev": true, "license": "MIT", "dependencies": { @@ -6809,8 +5749,6 @@ }, "node_modules/pac-resolver": { "version": "7.0.1", - "resolved": "https://registry.npmjs.org/pac-resolver/-/pac-resolver-7.0.1.tgz", - "integrity": "sha512-5NPgf87AT2STgwa2ntRMr45jTKrYBGkVU36yT0ig/n/GMAa3oPqhZfIQ2kMEimReg0+t9kZViDVZ83qfVUlckg==", "dev": true, "license": "MIT", "dependencies": { @@ -6823,8 +5761,6 @@ }, "node_modules/package-json-from-dist": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz", - "integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==", "license": "BlueOak-1.0.0" }, "node_modules/package-manager-detector": { @@ -6839,8 +5775,6 @@ }, "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": { @@ -6852,8 +5786,6 @@ }, "node_modules/parse-json": { "version": "5.2.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", - "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", "dev": true, "license": "MIT", "dependencies": { @@ -6871,12 +5803,8 @@ }, "node_modules/parse5": { "version": "7.3.0", - "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.3.0.tgz", - "integrity": "sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw==", "dev": true, "license": "MIT", - "optional": true, - "peer": true, "dependencies": { "entities": "^6.0.0" }, @@ -6886,8 +5814,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==", "license": "MIT", "engines": { "node": ">=8" @@ -6895,8 +5821,6 @@ }, "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==", "license": "MIT", "engines": { "node": ">=8" @@ -6904,8 +5828,6 @@ }, "node_modules/path-scurry": { "version": "2.0.2", - "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-2.0.2.tgz", - "integrity": "sha512-3O/iVVsJAPsOnpwWIeD+d6z/7PmqApyQePUtCndjatj/9I5LylHvt5qluFaBT3I5h3r1ejfR056c+FCv+NnNXg==", "license": "BlueOak-1.0.0", "dependencies": { "lru-cache": "^11.0.0", @@ -6930,15 +5852,19 @@ }, "node_modules/pathe": { "version": "2.0.3", - "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz", - "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==", "dev": true, "license": "MIT" }, + "node_modules/pathval": { + "version": "2.0.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 14.16" + } + }, "node_modules/peek-stream": { "version": "1.1.3", - "resolved": "https://registry.npmjs.org/peek-stream/-/peek-stream-1.1.3.tgz", - "integrity": "sha512-FhJ+YbOSBb9/rIl2ZeE/QHEsWn7PqNYt8ARAY3kIgNGOk13g9FGyIY6JIl/xB/3TFRVoTv5as0l11weORrTekA==", "license": "MIT", "dependencies": { "buffer-from": "^1.0.0", @@ -6948,20 +5874,16 @@ }, "node_modules/pend": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", - "integrity": "sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==", + "dev": true, "license": "MIT" }, "node_modules/picocolors": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", - "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "dev": true, "license": "ISC" }, "node_modules/picomatch": { "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", "license": "MIT", "engines": { "node": ">=8.6" @@ -6982,8 +5904,6 @@ }, "node_modules/pino": { "version": "10.3.1", - "resolved": "https://registry.npmjs.org/pino/-/pino-10.3.1.tgz", - "integrity": "sha512-r34yH/GlQpKZbU1BvFFqOjhISRo1MNx1tWYsYvmj6KIRHSPMT2+yHOEb1SG6NMvRoHRF0a07kCOox/9yakl1vg==", "license": "MIT", "dependencies": { "@pinojs/redact": "^0.4.0", @@ -7004,8 +5924,6 @@ }, "node_modules/pino-abstract-transport": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pino-abstract-transport/-/pino-abstract-transport-3.0.0.tgz", - "integrity": "sha512-wlfUczU+n7Hy/Ha5j9a/gZNy7We5+cXp8YL+X+PG8S0KXxw7n/JXA3c46Y0zQznIJ83URJiwy7Lh56WLokNuxg==", "license": "MIT", "dependencies": { "split2": "^4.0.0" @@ -7013,14 +5931,18 @@ }, "node_modules/pino-std-serializers": { "version": "7.1.0", - "resolved": "https://registry.npmjs.org/pino-std-serializers/-/pino-std-serializers-7.1.0.tgz", - "integrity": "sha512-BndPH67/JxGExRgiX1dX0w1FvZck5Wa4aal9198SrRhZjH3GxKQUKIBnYJTdj2HDN3UQAS06HlfcSbQj2OHmaw==", "license": "MIT" }, + "node_modules/pirates": { + "version": "4.0.7", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 6" + } + }, "node_modules/pixelmatch": { "version": "6.0.0", - "resolved": "https://registry.npmjs.org/pixelmatch/-/pixelmatch-6.0.0.tgz", - "integrity": "sha512-FYpL4XiIWakTnIqLqvt3uN4L9B3TsuHIvhLILzTiJZMJUsGvmKNeL4H3b6I99LRyerK9W4IuOXw+N28AtRgK2g==", "dev": true, "license": "ISC", "dependencies": { @@ -7030,10 +5952,18 @@ "pixelmatch": "bin/pixelmatch" } }, + "node_modules/pkg-types": { + "version": "1.3.1", + "dev": true, + "license": "MIT", + "dependencies": { + "confbox": "^0.1.8", + "mlly": "^1.7.4", + "pathe": "^2.0.1" + } + }, "node_modules/playwright": { "version": "1.58.2", - "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.58.2.tgz", - "integrity": "sha512-vA30H8Nvkq/cPBnNw4Q8TWz1EJyqgpuinBcHET0YVJVFldr8JDNiU9LaWAE1KqSkRYazuaBhTpB5ZzShOezQ6A==", "dev": true, "license": "Apache-2.0", "dependencies": { @@ -7051,8 +5981,6 @@ }, "node_modules/playwright-core": { "version": "1.58.2", - "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.58.2.tgz", - "integrity": "sha512-yZkEtftgwS8CsfYo7nm0KE8jsvm6i/PTgVtB8DL726wNf6H2IMsDuxCpJj59KDaxCtSnrWan2AeDqM7JBaultg==", "dev": true, "license": "Apache-2.0", "bin": { @@ -7064,10 +5992,7 @@ }, "node_modules/playwright/node_modules/fsevents": { "version": "2.3.2", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", - "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", "dev": true, - "hasInstallScript": true, "license": "MIT", "optional": true, "os": [ @@ -7079,8 +6004,6 @@ }, "node_modules/pngjs": { "version": "7.0.0", - "resolved": "https://registry.npmjs.org/pngjs/-/pngjs-7.0.0.tgz", - "integrity": "sha512-LKWqWJRhstyYo9pGvgor/ivk2w94eSjE3RGVuzLGlr3NmD8bf7RcYGze1mNdEHRP6TRP6rMuDHk5t44hnTRyow==", "dev": true, "license": "MIT", "engines": { @@ -7089,8 +6012,7 @@ }, "node_modules/postcss": { "version": "8.5.6", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz", - "integrity": "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==", + "dev": true, "funding": [ { "type": "opencollective", @@ -7115,10 +6037,50 @@ "node": "^10 || ^12 || >=14" } }, + "node_modules/postcss-load-config": { + "version": "6.0.1", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "lilconfig": "^3.1.1" + }, + "engines": { + "node": ">= 18" + }, + "peerDependencies": { + "jiti": ">=1.21.0", + "postcss": ">=8.0.9", + "tsx": "^4.8.1", + "yaml": "^2.4.2" + }, + "peerDependenciesMeta": { + "jiti": { + "optional": true + }, + "postcss": { + "optional": true + }, + "tsx": { + "optional": true + }, + "yaml": { + "optional": true + } + } + }, "node_modules/postcss-modules-extract-imports": { "version": "3.1.0", - "resolved": "https://registry.npmjs.org/postcss-modules-extract-imports/-/postcss-modules-extract-imports-3.1.0.tgz", - "integrity": "sha512-k3kNe0aNFQDAZGbin48pL2VNidTF0w4/eASDsxlyspobzU3wZQLOGj7L9gfRe0Jo9/4uud09DsjFNH7winGv8Q==", + "dev": true, "license": "ISC", "engines": { "node": "^10 || ^12 || >= 14" @@ -7129,8 +6091,7 @@ }, "node_modules/postcss-modules-local-by-default": { "version": "4.2.0", - "resolved": "https://registry.npmjs.org/postcss-modules-local-by-default/-/postcss-modules-local-by-default-4.2.0.tgz", - "integrity": "sha512-5kcJm/zk+GJDSfw+V/42fJ5fhjL5YbFDl8nVdXkJPLLW+Vf9mTD5Xe0wqIaDnLuL2U6cDNpTr+UQ+v2HWIBhzw==", + "dev": true, "license": "MIT", "dependencies": { "icss-utils": "^5.0.0", @@ -7146,8 +6107,7 @@ }, "node_modules/postcss-modules-scope": { "version": "3.2.1", - "resolved": "https://registry.npmjs.org/postcss-modules-scope/-/postcss-modules-scope-3.2.1.tgz", - "integrity": "sha512-m9jZstCVaqGjTAuny8MdgE88scJnCiQSlSrOWcTQgM2t32UBe+MUmFSO5t7VMSfAf/FJKImAxBav8ooCHJXCJA==", + "dev": true, "license": "ISC", "dependencies": { "postcss-selector-parser": "^7.0.0" @@ -7161,8 +6121,7 @@ }, "node_modules/postcss-modules-values": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/postcss-modules-values/-/postcss-modules-values-4.0.0.tgz", - "integrity": "sha512-RDxHkAiEGI78gS2ofyvCsu7iycRv7oqw5xMWn9iMoR0N/7mf9D50ecQqUo5BZ9Zh2vH4bCUR/ktCqbB9m8vJjQ==", + "dev": true, "license": "ISC", "dependencies": { "icss-utils": "^5.0.0" @@ -7176,8 +6135,7 @@ }, "node_modules/postcss-selector-parser": { "version": "7.1.1", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.1.tgz", - "integrity": "sha512-orRsuYpJVw8LdAwqqLykBj9ecS5/cRHlI5+nvTo8LcCKmzDmqVORXtOIYEEQuL9D4BxtA1lm5isAqzQZCoQ6Eg==", + "dev": true, "license": "MIT", "dependencies": { "cssesc": "^3.0.0", @@ -7189,14 +6147,20 @@ }, "node_modules/postcss-value-parser": { "version": "4.2.0", - "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", - "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", + "dev": true, "license": "MIT" }, + "node_modules/prelude-ls": { + "version": "1.2.1", + "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" @@ -7210,8 +6174,6 @@ }, "node_modules/process": { "version": "0.11.10", - "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", - "integrity": "sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==", "license": "MIT", "engines": { "node": ">= 0.6.0" @@ -7219,14 +6181,10 @@ }, "node_modules/process-nextick-args": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", - "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", "license": "MIT" }, "node_modules/process-warning": { "version": "5.0.0", - "resolved": "https://registry.npmjs.org/process-warning/-/process-warning-5.0.0.tgz", - "integrity": "sha512-a39t9ApHNx2L4+HBnQKqxxHNs1r7KF+Intd8Q/g1bUh6q0WIp9voPXJ/x0j+ZL45KF1pJd9+q2jLIRMfvEshkA==", "funding": [ { "type": "github", @@ -7241,8 +6199,6 @@ }, "node_modules/progress": { "version": "2.0.3", - "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", - "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", "dev": true, "license": "MIT", "engines": { @@ -7251,8 +6207,7 @@ }, "node_modules/prompts": { "version": "2.4.2", - "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz", - "integrity": "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==", + "dev": true, "license": "MIT", "dependencies": { "kleur": "^3.0.3", @@ -7264,8 +6219,6 @@ }, "node_modules/proxy-agent": { "version": "6.5.0", - "resolved": "https://registry.npmjs.org/proxy-agent/-/proxy-agent-6.5.0.tgz", - "integrity": "sha512-TmatMXdr2KlRiA2CyDu8GqR8EjahTG3aY3nXjdzFyoZbmB8hrBsTyMezhULIXKnC0jpfjlmiZ3+EaCzoInSu/A==", "dev": true, "license": "MIT", "dependencies": { @@ -7284,8 +6237,6 @@ }, "node_modules/proxy-agent/node_modules/lru-cache": { "version": "7.18.3", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", - "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", "dev": true, "license": "ISC", "engines": { @@ -7294,19 +6245,13 @@ }, "node_modules/proxy-from-env": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", - "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==", "dev": true, "license": "MIT" }, "node_modules/psl": { "version": "1.15.0", - "resolved": "https://registry.npmjs.org/psl/-/psl-1.15.0.tgz", - "integrity": "sha512-JZd3gMVBAVQkSs6HdNZo9Sdo0LNcQeMNP3CozBJb3JYC/QUYZTnKxP+f8oWRX4rHP5EurWxqAHTSwUCjlNKa1w==", "dev": true, "license": "MIT", - "optional": true, - "peer": true, "dependencies": { "punycode": "^2.3.1" }, @@ -7316,8 +6261,6 @@ }, "node_modules/pump": { "version": "3.0.3", - "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.3.tgz", - "integrity": "sha512-todwxLMY7/heScKmntwQG8CXVkWUOdYxIvY2s0VWAAMh/nd8SoYiRaKjlr7+iCs984f2P8zvrfWcDDYVb73NfA==", "license": "MIT", "dependencies": { "end-of-stream": "^1.1.0", @@ -7326,8 +6269,6 @@ }, "node_modules/pumpify": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/pumpify/-/pumpify-2.0.1.tgz", - "integrity": "sha512-m7KOje7jZxrmutanlkS1daj1dS6z6BgslzOXmcSEpIlCxM3VJH7lG5QLeck/6hgF6F4crFf01UtQmNsJfweTAw==", "license": "MIT", "dependencies": { "duplexify": "^4.1.1", @@ -7337,8 +6278,6 @@ }, "node_modules/pumpify/node_modules/duplexify": { "version": "4.1.3", - "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-4.1.3.tgz", - "integrity": "sha512-M3BmBhwJRZsSx38lZyhE53Csddgzl5R7xGJNk7CVddZD6CcmwMCH8J+7AprIrQKH7TonKxaCjcv27Qmf+sQ+oA==", "license": "MIT", "dependencies": { "end-of-stream": "^1.4.1", @@ -7349,8 +6288,6 @@ }, "node_modules/pumpify/node_modules/readable-stream": { "version": "3.6.2", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", - "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", "license": "MIT", "dependencies": { "inherits": "^2.0.3", @@ -7363,8 +6300,7 @@ }, "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" @@ -7372,8 +6308,6 @@ }, "node_modules/puppeteer": { "version": "24.37.5", - "resolved": "https://registry.npmjs.org/puppeteer/-/puppeteer-24.37.5.tgz", - "integrity": "sha512-3PAOIQLceyEmn1Fi76GkGO2EVxztv5OtdlB1m8hMUZL3f8KDHnlvXbvCXv+Ls7KzF1R0KdKBqLuT/Hhrok12hQ==", "dev": true, "hasInstallScript": true, "license": "Apache-2.0", @@ -7394,8 +6328,6 @@ }, "node_modules/puppeteer-core": { "version": "24.37.5", - "resolved": "https://registry.npmjs.org/puppeteer-core/-/puppeteer-core-24.37.5.tgz", - "integrity": "sha512-ybL7iE78YPN4T6J+sPLO7r0lSByp/0NN6PvfBEql219cOnttoTFzCWKiBOjstXSqi/OKpwae623DWAsL7cn2MQ==", "dev": true, "license": "Apache-2.0", "dependencies": { @@ -7413,8 +6345,6 @@ }, "node_modules/qrcode": { "version": "1.5.4", - "resolved": "https://registry.npmjs.org/qrcode/-/qrcode-1.5.4.tgz", - "integrity": "sha512-1ca71Zgiu6ORjHqFBDpnSMTR2ReToX4l1Au1VFLyVeBTFavzQnv5JxMFr3ukHVKpSrSA2MCk0lNJSykjUfz7Zg==", "license": "MIT", "dependencies": { "dijkstrajs": "^1.0.1", @@ -7430,8 +6360,6 @@ }, "node_modules/qrcode/node_modules/cliui": { "version": "6.0.0", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz", - "integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==", "license": "ISC", "dependencies": { "string-width": "^4.2.0", @@ -7441,8 +6369,6 @@ }, "node_modules/qrcode/node_modules/pngjs": { "version": "5.0.0", - "resolved": "https://registry.npmjs.org/pngjs/-/pngjs-5.0.0.tgz", - "integrity": "sha512-40QW5YalBNfQo5yRYmiw7Yz6TKKVr3h6970B2YE+3fQpsWcrbj1PzJgxeJ19DRQjhMbKPIuMY8rFaXc8moolVw==", "license": "MIT", "engines": { "node": ">=10.13.0" @@ -7450,8 +6376,6 @@ }, "node_modules/qrcode/node_modules/wrap-ansi": { "version": "6.2.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", - "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", "license": "MIT", "dependencies": { "ansi-styles": "^4.0.0", @@ -7464,14 +6388,10 @@ }, "node_modules/qrcode/node_modules/y18n": { "version": "4.0.3", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz", - "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==", "license": "ISC" }, "node_modules/qrcode/node_modules/yargs": { "version": "15.4.1", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.4.1.tgz", - "integrity": "sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==", "license": "MIT", "dependencies": { "cliui": "^6.0.0", @@ -7492,8 +6412,6 @@ }, "node_modules/qrcode/node_modules/yargs-parser": { "version": "18.1.3", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz", - "integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==", "license": "ISC", "dependencies": { "camelcase": "^5.0.0", @@ -7522,12 +6440,8 @@ }, "node_modules/querystringify": { "version": "2.2.0", - "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz", - "integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==", "dev": true, - "license": "MIT", - "optional": true, - "peer": true + "license": "MIT" }, "node_modules/queue-microtask": { "version": "1.2.3", @@ -7552,14 +6466,11 @@ }, "node_modules/quick-format-unescaped": { "version": "4.0.4", - "resolved": "https://registry.npmjs.org/quick-format-unescaped/-/quick-format-unescaped-4.0.4.tgz", - "integrity": "sha512-tYC1Q1hgyRuHgloV/YXs2w15unPVh8qfu/qCTfhTYamaw7fyhumKa2yGpdSo87vY32rIclj+4fWYQXUMs9EHvg==", "license": "MIT" }, "node_modules/randombytes": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", - "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "dev": true, "license": "MIT", "dependencies": { "safe-buffer": "^5.1.0" @@ -7567,8 +6478,7 @@ }, "node_modules/react": { "version": "19.2.4", - "resolved": "https://registry.npmjs.org/react/-/react-19.2.4.tgz", - "integrity": "sha512-9nfp2hYpCwOjAN+8TZFGhtWEwgvWHXqESH8qT89AT/lWklpLON22Lc8pEtnpsZz7VmawabSU0gCjnj8aC0euHQ==", + "dev": true, "license": "MIT", "peer": true, "engines": { @@ -7577,8 +6487,7 @@ }, "node_modules/react-dom": { "version": "19.2.4", - "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.4.tgz", - "integrity": "sha512-AXJdLo8kgMbimY95O2aKQqsz2iWi9jMgKJhRBAxECE4IFxfcazB2LmzloIoibJI3C12IlY20+KFaLv+71bUJeQ==", + "dev": true, "license": "MIT", "peer": true, "dependencies": { @@ -7590,8 +6499,7 @@ }, "node_modules/react-refresh": { "version": "0.18.0", - "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.18.0.tgz", - "integrity": "sha512-QgT5//D3jfjJb6Gsjxv0Slpj23ip+HtOpnNgnb2S5zU3CB26G/IDPGoy4RJB42wzFE46DRsstbW6tKHoKbhAxw==", + "dev": true, "license": "MIT", "peer": true, "engines": { @@ -7640,8 +6548,6 @@ }, "node_modules/readable-stream": { "version": "4.7.0", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-4.7.0.tgz", - "integrity": "sha512-oIGGmcpTLwPga8Bn6/Z75SVaH1z5dUut2ibSyAMVhmUggWpmDn2dapB0n7f8nwaSiRtepAsfJyfXIO5DCVAODg==", "license": "MIT", "dependencies": { "abort-controller": "^3.0.0", @@ -7656,8 +6562,6 @@ }, "node_modules/readdirp": { "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", - "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", "license": "MIT", "dependencies": { "picomatch": "^2.2.1" @@ -7668,8 +6572,6 @@ }, "node_modules/real-require": { "version": "0.2.0", - "resolved": "https://registry.npmjs.org/real-require/-/real-require-0.2.0.tgz", - "integrity": "sha512-57frrGM/OCTLqLOAh0mhVA9VBMHd+9U7Zb2THMGdBUoZVOtGbJzjxsYGDJ3A9AYYCP4hn6y1TVbaOfzWtm5GFg==", "license": "MIT", "engines": { "node": ">= 12.13.0" @@ -7677,8 +6579,7 @@ }, "node_modules/recast": { "version": "0.23.11", - "resolved": "https://registry.npmjs.org/recast/-/recast-0.23.11.tgz", - "integrity": "sha512-YTUo+Flmw4ZXiWfQKGcwwc11KnoRAYgzAE2E7mXKCjSviTKShtxBsN6YUUBB2gtaBzKzeKunxhUwNHQuRryhWA==", + "dev": true, "license": "MIT", "dependencies": { "ast-types": "^0.16.1", @@ -7693,8 +6594,7 @@ }, "node_modules/recast/node_modules/ast-types": { "version": "0.16.1", - "resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.16.1.tgz", - "integrity": "sha512-6t10qk83GOG8p0vKmaCr8eiilZwO171AvbROMtvvNiwrTly62t+7XkA8RdIIVbpMhCASAsxgAzdRSwh6nw/5Dg==", + "dev": true, "license": "MIT", "dependencies": { "tslib": "^2.0.1" @@ -7705,8 +6605,7 @@ }, "node_modules/remotion": { "version": "4.0.429", - "resolved": "https://registry.npmjs.org/remotion/-/remotion-4.0.429.tgz", - "integrity": "sha512-SkYwttZ0q/3S28qm/s8eFqmNadTEnZA5U328F7e7kziT48TCFWPyBA9RQ+eUd8g7VmAcv+5AccS8n7cZvB91VA==", + "dev": true, "license": "SEE LICENSE IN LICENSE.md", "peerDependencies": { "react": ">=16.8.0", @@ -7715,8 +6614,6 @@ }, "node_modules/require-directory": { "version": "2.1.1", - "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", - "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", "license": "MIT", "engines": { "node": ">=0.10.0" @@ -7724,8 +6621,6 @@ }, "node_modules/require-from-string": { "version": "2.0.2", - "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", - "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", "license": "MIT", "engines": { "node": ">=0.10.0" @@ -7733,23 +6628,15 @@ }, "node_modules/require-main-filename": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", - "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==", "license": "ISC" }, "node_modules/requires-port": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", - "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==", "dev": true, - "license": "MIT", - "optional": true, - "peer": true + "license": "MIT" }, "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": { @@ -7758,8 +6645,6 @@ }, "node_modules/resolve-pkg-maps": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz", - "integrity": "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==", "dev": true, "license": "MIT", "funding": { @@ -7768,8 +6653,6 @@ }, "node_modules/ret": { "version": "0.5.0", - "resolved": "https://registry.npmjs.org/ret/-/ret-0.5.0.tgz", - "integrity": "sha512-I1XxrZSQ+oErkRR4jYbAyEEu2I0avBvvMM5JN+6EBprOGRCs63ENqZ3vjavq8fBw2+62G5LF5XelKwuJpcvcxw==", "license": "MIT", "engines": { "node": ">=10" @@ -7777,8 +6660,6 @@ }, "node_modules/reusify": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz", - "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==", "license": "MIT", "engines": { "iojs": ">=1.0.0", @@ -7787,14 +6668,10 @@ }, "node_modules/rfdc": { "version": "1.4.1", - "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.4.1.tgz", - "integrity": "sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==", "license": "MIT" }, "node_modules/rollup": { "version": "4.59.0", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.59.0.tgz", - "integrity": "sha512-2oMpl67a3zCH9H79LeMcbDhXW/UmWG/y2zuqnF2jQq5uq9TbM9TVyXvA4+t+ne2IIkBdrLpAaRQAvo7YI/Yyeg==", "dev": true, "license": "MIT", "dependencies": { @@ -7838,12 +6715,8 @@ }, "node_modules/rrweb-cssom": { "version": "0.7.1", - "resolved": "https://registry.npmjs.org/rrweb-cssom/-/rrweb-cssom-0.7.1.tgz", - "integrity": "sha512-TrEMa7JGdVm0UThDJSx7ddw5nVm3UJS9o9CCIZ72B1vSyEZoziDqBYP3XIoi/12lKrJR8rE3jeFHMok2F/Mnsg==", "dev": true, - "license": "MIT", - "optional": true, - "peer": true + "license": "MIT" }, "node_modules/run-parallel": { "version": "1.2.0", @@ -7871,8 +6744,6 @@ }, "node_modules/safe-buffer": { "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", "funding": [ { "type": "github", @@ -7891,8 +6762,6 @@ }, "node_modules/safe-regex2": { "version": "5.0.0", - "resolved": "https://registry.npmjs.org/safe-regex2/-/safe-regex2-5.0.0.tgz", - "integrity": "sha512-YwJwe5a51WlK7KbOJREPdjNrpViQBI3p4T50lfwPuDhZnE3XGVTlGvi+aolc5+RvxDD6bnUmjVsU9n1eboLUYw==", "funding": [ { "type": "github", @@ -7910,8 +6779,6 @@ }, "node_modules/safe-stable-stringify": { "version": "2.5.0", - "resolved": "https://registry.npmjs.org/safe-stable-stringify/-/safe-stable-stringify-2.5.0.tgz", - "integrity": "sha512-b3rppTKm9T+PsVCBEOUR46GWI7fdOs00VKZ1+9c1EWDaDMvjQc6tUwuFyIprgGgTcWoVHSKrU8H31ZHA2e0RHA==", "license": "MIT", "engines": { "node": ">=10" @@ -7919,18 +6786,12 @@ }, "node_modules/safer-buffer": { "version": "2.1.2", - "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", "license": "MIT" }, "node_modules/saxes": { "version": "6.0.0", - "resolved": "https://registry.npmjs.org/saxes/-/saxes-6.0.0.tgz", - "integrity": "sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==", "dev": true, "license": "ISC", - "optional": true, - "peer": true, "dependencies": { "xmlchars": "^2.2.0" }, @@ -7940,15 +6801,13 @@ }, "node_modules/scheduler": { "version": "0.27.0", - "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.27.0.tgz", - "integrity": "sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==", + "dev": true, "license": "MIT", "peer": true }, "node_modules/schema-utils": { "version": "3.3.0", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz", - "integrity": "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==", + "dev": true, "license": "MIT", "dependencies": { "@types/json-schema": "^7.0.8", @@ -7965,8 +6824,7 @@ }, "node_modules/schema-utils/node_modules/ajv": { "version": "6.14.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.14.0.tgz", - "integrity": "sha512-IWrosm/yrn43eiKqkfkHis7QioDleaXQHdDVPKg0FSwwd/DuvyX79TZnFOnYpB7dcsFAMmtFztZuXPDvSePkFw==", + "dev": true, "license": "MIT", "dependencies": { "fast-deep-equal": "^3.1.1", @@ -7981,8 +6839,7 @@ }, "node_modules/schema-utils/node_modules/ajv-keywords": { "version": "3.5.2", - "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", - "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", + "dev": true, "license": "MIT", "peerDependencies": { "ajv": "^6.9.1" @@ -7990,14 +6847,11 @@ }, "node_modules/schema-utils/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/secure-json-parse": { "version": "4.1.0", - "resolved": "https://registry.npmjs.org/secure-json-parse/-/secure-json-parse-4.1.0.tgz", - "integrity": "sha512-l4KnYfEyqYJxDwlNVyRfO2E4NTHfMKAWdUuA8J0yve2Dz/E/PdBepY03RvyJpssIpRFwJoCD55wA+mEDs6ByWA==", "funding": [ { "type": "github", @@ -8012,8 +6866,6 @@ }, "node_modules/semver": { "version": "7.7.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz", - "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==", "license": "ISC", "bin": { "semver": "bin/semver.js" @@ -8024,8 +6876,7 @@ }, "node_modules/serialize-javascript": { "version": "6.0.2", - "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.2.tgz", - "integrity": "sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==", + "dev": true, "license": "BSD-3-Clause", "dependencies": { "randombytes": "^2.1.0" @@ -8033,26 +6884,18 @@ }, "node_modules/set-blocking": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", - "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==", "license": "ISC" }, "node_modules/set-cookie-parser": { "version": "2.7.2", - "resolved": "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-2.7.2.tgz", - "integrity": "sha512-oeM1lpU/UvhTxw+g3cIfxXHyJRc/uidd3yK1P242gzHds0udQBYzs3y8j4gCCW+ZJ7ad0yctld8RYO+bdurlvw==", "license": "MIT" }, "node_modules/setprototypeof": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", - "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", "license": "ISC" }, "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==", "license": "MIT", "dependencies": { "shebang-regex": "^3.0.0" @@ -8063,8 +6906,6 @@ }, "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==", "license": "MIT", "engines": { "node": ">=8" @@ -8072,15 +6913,11 @@ }, "node_modules/siginfo": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/siginfo/-/siginfo-2.0.0.tgz", - "integrity": "sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==", "dev": true, "license": "ISC" }, "node_modules/signal-exit": { "version": "4.1.0", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", - "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", "license": "ISC", "engines": { "node": ">=14" @@ -8091,8 +6928,7 @@ }, "node_modules/sisteransi": { "version": "1.0.5", - "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", - "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==", + "dev": true, "license": "MIT" }, "node_modules/slash": { @@ -8107,8 +6943,6 @@ }, "node_modules/smart-buffer": { "version": "4.2.0", - "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz", - "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==", "dev": true, "license": "MIT", "engines": { @@ -8118,8 +6952,6 @@ }, "node_modules/socks": { "version": "2.8.7", - "resolved": "https://registry.npmjs.org/socks/-/socks-2.8.7.tgz", - "integrity": "sha512-HLpt+uLy/pxB+bum/9DzAgiKS8CX1EvbWxI4zlmgGCExImLdiad2iCwXT5Z4c9c3Eq8rP2318mPW2c+QbtjK8A==", "dev": true, "license": "MIT", "dependencies": { @@ -8133,8 +6965,6 @@ }, "node_modules/socks-proxy-agent": { "version": "8.0.5", - "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-8.0.5.tgz", - "integrity": "sha512-HehCEsotFqbPW9sJ8WVYB6UbmIMv7kUUORIF2Nncq4VQvBfNBLibW9YZR5dlYCSUhwcD628pRllm7n+E+YTzJw==", "dev": true, "license": "MIT", "dependencies": { @@ -8148,8 +6978,6 @@ }, "node_modules/sonic-boom": { "version": "4.2.1", - "resolved": "https://registry.npmjs.org/sonic-boom/-/sonic-boom-4.2.1.tgz", - "integrity": "sha512-w6AxtubXa2wTXAUsZMMWERrsIRAdrK0Sc+FUytWvYAhBJLyuI4llrMIC1DtlNSdI99EI86KZum2MMq3EAZlF9Q==", "license": "MIT", "dependencies": { "atomic-sleep": "^1.0.0" @@ -8157,8 +6985,7 @@ }, "node_modules/source-map": { "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, "license": "BSD-3-Clause", "engines": { "node": ">=0.10.0" @@ -8166,8 +6993,7 @@ }, "node_modules/source-map-js": { "version": "1.2.1", - "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", - "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "dev": true, "license": "BSD-3-Clause", "engines": { "node": ">=0.10.0" @@ -8175,8 +7001,7 @@ }, "node_modules/source-map-support": { "version": "0.5.21", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", - "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", + "dev": true, "license": "MIT", "dependencies": { "buffer-from": "^1.0.0", @@ -8196,8 +7021,6 @@ }, "node_modules/split2": { "version": "4.2.0", - "resolved": "https://registry.npmjs.org/split2/-/split2-4.2.0.tgz", - "integrity": "sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==", "license": "ISC", "engines": { "node": ">= 10.x" @@ -8212,21 +7035,16 @@ }, "node_modules/stackback": { "version": "0.0.2", - "resolved": "https://registry.npmjs.org/stackback/-/stackback-0.0.2.tgz", - "integrity": "sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==", "dev": true, "license": "MIT" }, "node_modules/stackframe": { "version": "1.3.4", - "resolved": "https://registry.npmjs.org/stackframe/-/stackframe-1.3.4.tgz", - "integrity": "sha512-oeVtt7eWQS+Na6F//S4kJ2K2VbRlS9D43mAlMyVpVWovy9o+jfgH8O9agzANzaiLjclA0oYzUXEM4PurhSUChw==", + "dev": true, "license": "MIT" }, "node_modules/statuses": { "version": "2.0.2", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.2.tgz", - "integrity": "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==", "license": "MIT", "engines": { "node": ">= 0.8" @@ -8234,21 +7052,15 @@ }, "node_modules/std-env": { "version": "3.10.0", - "resolved": "https://registry.npmjs.org/std-env/-/std-env-3.10.0.tgz", - "integrity": "sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg==", "dev": true, "license": "MIT" }, "node_modules/stream-shift": { "version": "1.0.3", - "resolved": "https://registry.npmjs.org/stream-shift/-/stream-shift-1.0.3.tgz", - "integrity": "sha512-76ORR0DO1o1hlKwTbi/DM3EXWGf3ZJYO8cXX5RJwnul2DEg2oyoZyjLNoQM8WsvZiFKCRfC1O0J7iCvie3RZmQ==", "license": "MIT" }, "node_modules/streamx": { "version": "2.23.0", - "resolved": "https://registry.npmjs.org/streamx/-/streamx-2.23.0.tgz", - "integrity": "sha512-kn+e44esVfn2Fa/O0CPFcex27fjIL6MkVae0Mm6q+E6f0hWv578YCERbv+4m02cjxvDsPKLnmxral/rR6lBMAg==", "dev": true, "license": "MIT", "dependencies": { @@ -8259,8 +7071,6 @@ }, "node_modules/string_decoder": { "version": "1.3.0", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", - "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", "license": "MIT", "dependencies": { "safe-buffer": "~5.2.0" @@ -8268,8 +7078,6 @@ }, "node_modules/string-width": { "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", "license": "MIT", "dependencies": { "emoji-regex": "^8.0.0", @@ -8282,8 +7090,6 @@ }, "node_modules/strip-ansi": { "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", "license": "MIT", "dependencies": { "ansi-regex": "^5.0.1" @@ -8304,17 +7110,26 @@ }, "node_modules/strip-final-newline": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", - "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", + "dev": true, "license": "MIT", "engines": { "node": ">=6" } }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/style-loader": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/style-loader/-/style-loader-4.0.0.tgz", - "integrity": "sha512-1V4WqhhZZgjVAVJyt7TdDPZoPBPNHbekX4fWnCJL1yQukhCeZhJySUL+gL9y6sNdN95uEOS83Y55SqHcP7MzLA==", + "dev": true, "license": "MIT", "engines": { "node": ">= 18.12.0" @@ -8327,10 +7142,37 @@ "webpack": "^5.27.0" } }, + "node_modules/sucrase": { + "version": "3.35.1", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.2", + "commander": "^4.0.0", + "lines-and-columns": "^1.1.6", + "mz": "^2.7.0", + "pirates": "^4.0.1", + "tinyglobby": "^0.2.11", + "ts-interface-checker": "^0.1.9" + }, + "bin": { + "sucrase": "bin/sucrase", + "sucrase-node": "bin/sucrase-node" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/sucrase/node_modules/commander": { + "version": "4.1.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 6" + } + }, "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": { @@ -8342,17 +7184,12 @@ }, "node_modules/symbol-tree": { "version": "3.2.4", - "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz", - "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==", "dev": true, - "license": "MIT", - "optional": true, - "peer": true + "license": "MIT" }, "node_modules/tapable": { "version": "2.3.0", - "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.3.0.tgz", - "integrity": "sha512-g9ljZiwki/LfxmQADO3dEY1CbpmXT5Hm2fJ+QaGKwSXUylMybePR7/67YW7jOrrvjEgL1Fmz5kzyAjWVWLlucg==", + "dev": true, "license": "MIT", "engines": { "node": ">=6" @@ -8364,8 +7201,6 @@ }, "node_modules/tar-fs": { "version": "3.1.1", - "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-3.1.1.tgz", - "integrity": "sha512-LZA0oaPOc2fVo82Txf3gw+AkEd38szODlptMYejQUhndHMLQ9M059uXR+AfS7DNo0NpINvSqDsvyaCrBVkptWg==", "dev": true, "license": "MIT", "dependencies": { @@ -8379,8 +7214,6 @@ }, "node_modules/tar-stream": { "version": "3.1.7", - "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-3.1.7.tgz", - "integrity": "sha512-qJj60CXt7IU1Ffyc3NJMjh6EkuCFej46zUqJ4J7pqYlThyd9bO0XBTmcOIhSzZJVWfsLks0+nle/j538YAW9RQ==", "dev": true, "license": "MIT", "dependencies": { @@ -8391,8 +7224,6 @@ }, "node_modules/teex": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/teex/-/teex-1.0.1.tgz", - "integrity": "sha512-eYE6iEI62Ni1H8oIa7KlDU6uQBtqr4Eajni3wX7rpfXD8ysFx8z0+dri+KWEPWpBsxXfxu58x/0jvTVT1ekOSg==", "dev": true, "license": "MIT", "optional": true, @@ -8415,8 +7246,7 @@ }, "node_modules/terser": { "version": "5.46.0", - "resolved": "https://registry.npmjs.org/terser/-/terser-5.46.0.tgz", - "integrity": "sha512-jTwoImyr/QbOWFFso3YoU3ik0jBBDJ6JTOQiy/J2YxVJdZCc+5u7skhNwiOR3FQIygFqVUPHl7qbbxtjW2K3Qg==", + "dev": true, "license": "BSD-2-Clause", "dependencies": { "@jridgewell/source-map": "^0.3.3", @@ -8433,8 +7263,7 @@ }, "node_modules/terser-webpack-plugin": { "version": "5.3.16", - "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.16.tgz", - "integrity": "sha512-h9oBFCWrq78NyWWVcSwZarJkZ01c2AyGrzs1crmHZO3QUg9D61Wu4NPjBy69n7JqylFF5y+CsUZYmYEIZ3mR+Q==", + "dev": true, "license": "MIT", "dependencies": { "@jridgewell/trace-mapping": "^0.3.25", @@ -8467,8 +7296,7 @@ }, "node_modules/terser-webpack-plugin/node_modules/ajv-formats": { "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz", - "integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==", + "dev": true, "license": "MIT", "dependencies": { "ajv": "^8.0.0" @@ -8484,8 +7312,7 @@ }, "node_modules/terser-webpack-plugin/node_modules/schema-utils": { "version": "4.3.3", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.3.3.tgz", - "integrity": "sha512-eflK8wEtyOE6+hsaRVPxvUKYCpRgzLqDTb8krvAsRIwOGlHoSgYLgBXoubGgLd2fT41/OUYdb48v4k4WWHQurA==", + "dev": true, "license": "MIT", "dependencies": { "@types/json-schema": "^7.0.9", @@ -8503,24 +7330,38 @@ }, "node_modules/terser/node_modules/commander": { "version": "2.20.3", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", - "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "dev": true, "license": "MIT" }, "node_modules/text-decoder": { "version": "1.2.7", - "resolved": "https://registry.npmjs.org/text-decoder/-/text-decoder-1.2.7.tgz", - "integrity": "sha512-vlLytXkeP4xvEq2otHeJfSQIRyWxo/oZGEbXrtEEF9Hnmrdly59sUbzZ/QgyWuLYHctCHxFF4tRQZNQ9k60ExQ==", "dev": true, "license": "Apache-2.0", "dependencies": { "b4a": "^1.6.4" } }, + "node_modules/thenify": { + "version": "3.3.1", + "dev": true, + "license": "MIT", + "dependencies": { + "any-promise": "^1.0.0" + } + }, + "node_modules/thenify-all": { + "version": "1.6.0", + "dev": true, + "license": "MIT", + "dependencies": { + "thenify": ">= 3.1.0 < 4" + }, + "engines": { + "node": ">=0.8" + } + }, "node_modules/thread-stream": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/thread-stream/-/thread-stream-4.0.0.tgz", - "integrity": "sha512-4iMVL6HAINXWf1ZKZjIPcz5wYaOdPhtO8ATvZ+Xqp3BTdaqtAwQkNmKORqcIo5YkQqGXq5cwfswDwMqqQNrpJA==", "license": "MIT", "dependencies": { "real-require": "^0.2.0" @@ -8531,8 +7372,6 @@ }, "node_modules/through2": { "version": "2.0.5", - "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", - "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", "license": "MIT", "dependencies": { "readable-stream": "~2.3.6", @@ -8541,8 +7380,6 @@ }, "node_modules/through2/node_modules/readable-stream": { "version": "2.3.8", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", - "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", "license": "MIT", "dependencies": { "core-util-is": "~1.0.0", @@ -8556,14 +7393,10 @@ }, "node_modules/through2/node_modules/safe-buffer": { "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", "license": "MIT" }, "node_modules/through2/node_modules/string_decoder": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "license": "MIT", "dependencies": { "safe-buffer": "~5.1.0" @@ -8571,21 +7404,16 @@ }, "node_modules/tiny-invariant": { "version": "1.3.3", - "resolved": "https://registry.npmjs.org/tiny-invariant/-/tiny-invariant-1.3.3.tgz", - "integrity": "sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg==", + "dev": true, "license": "MIT" }, "node_modules/tinybench": { "version": "2.9.0", - "resolved": "https://registry.npmjs.org/tinybench/-/tinybench-2.9.0.tgz", - "integrity": "sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==", "dev": true, "license": "MIT" }, "node_modules/tinyexec": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-1.0.2.tgz", - "integrity": "sha512-W/KYk+NFhkmsYpuHq5JykngiOCnxeVL8v8dFnqxSD8qEEdRfXk1SDM6JzNqcERbcGYj9tMrDQBYV9cjgnunFIg==", "dev": true, "license": "MIT", "engines": { @@ -8594,8 +7422,6 @@ }, "node_modules/tinyglobby": { "version": "0.2.15", - "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz", - "integrity": "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==", "dev": true, "license": "MIT", "dependencies": { @@ -8611,8 +7437,6 @@ }, "node_modules/tinyglobby/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": { @@ -8629,8 +7453,6 @@ }, "node_modules/tinyglobby/node_modules/picomatch": { "version": "4.0.3", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", - "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", "dev": true, "license": "MIT", "engines": { @@ -8640,10 +7462,24 @@ "url": "https://github.com/sponsors/jonschlinkert" } }, + "node_modules/tinypool": { + "version": "1.1.1", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.0.0 || >=20.0.0" + } + }, "node_modules/tinyrainbow": { "version": "3.0.3", - "resolved": "https://registry.npmjs.org/tinyrainbow/-/tinyrainbow-3.0.3.tgz", - "integrity": "sha512-PSkbLUoxOFRzJYjjxHJt9xro7D+iilgMX/C9lawzVuYiIdcihh9DXmVibBe8lmcFrRi/VzlPjBxbN7rH24q8/Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/tinyspy": { + "version": "3.0.2", "dev": true, "license": "MIT", "engines": { @@ -8652,8 +7488,6 @@ }, "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==", "license": "MIT", "dependencies": { "is-number": "^7.0.0" @@ -8664,8 +7498,6 @@ }, "node_modules/toad-cache": { "version": "3.7.0", - "resolved": "https://registry.npmjs.org/toad-cache/-/toad-cache-3.7.0.tgz", - "integrity": "sha512-/m8M+2BJUpoJdgAHoG+baCwBT+tf2VraSfkBgl0Y00qIWt41DJ8R5B8nsEw0I58YwF5IZH6z24/2TobDKnqSWw==", "license": "MIT", "engines": { "node": ">=12" @@ -8673,8 +7505,6 @@ }, "node_modules/toidentifier": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", - "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", "license": "MIT", "engines": { "node": ">=0.6" @@ -8682,12 +7512,8 @@ }, "node_modules/tough-cookie": { "version": "4.1.4", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.1.4.tgz", - "integrity": "sha512-Loo5UUvLD9ScZ6jh8beX1T6sO1w2/MpCRpEP7V280GKMVUQ0Jzar2U3UJPsrdbziLEMMhu3Ujnq//rhiFuIeag==", "dev": true, "license": "BSD-3-Clause", - "optional": true, - "peer": true, "dependencies": { "psl": "^1.1.33", "punycode": "^2.1.1", @@ -8698,37 +7524,143 @@ "node": ">=6" } }, - "node_modules/tough-cookie/node_modules/universalify": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.2.0.tgz", - "integrity": "sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==", - "dev": true, - "license": "MIT", - "optional": true, - "peer": true, - "engines": { - "node": ">= 4.0.0" - } - }, "node_modules/tr46": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-1.0.1.tgz", - "integrity": "sha512-dTpowEjclQ7Kgx5SdBkqRzVhERQXov8/l9Ft9dVM9fmg0W0KQSVaXX9T4i6twCPNtYiZM53lpSSUAwJbFPOHxA==", + "dev": true, "license": "MIT", "dependencies": { "punycode": "^2.1.0" } }, + "node_modules/tree-kill": { + "version": "1.2.2", + "dev": true, + "license": "MIT", + "bin": { + "tree-kill": "cli.js" + } + }, + "node_modules/ts-api-utils": { + "version": "2.4.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18.12" + }, + "peerDependencies": { + "typescript": ">=4.8.4" + } + }, + "node_modules/ts-interface-checker": { + "version": "0.1.13", + "dev": true, + "license": "Apache-2.0" + }, "node_modules/tslib": { "version": "2.8.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", - "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "dev": true, "license": "0BSD" }, + "node_modules/tsup": { + "version": "8.5.1", + "dev": true, + "license": "MIT", + "dependencies": { + "bundle-require": "^5.1.0", + "cac": "^6.7.14", + "chokidar": "^4.0.3", + "consola": "^3.4.0", + "debug": "^4.4.0", + "esbuild": "^0.27.0", + "fix-dts-default-cjs-exports": "^1.0.0", + "joycon": "^3.1.1", + "picocolors": "^1.1.1", + "postcss-load-config": "^6.0.1", + "resolve-from": "^5.0.0", + "rollup": "^4.34.8", + "source-map": "^0.7.6", + "sucrase": "^3.35.0", + "tinyexec": "^0.3.2", + "tinyglobby": "^0.2.11", + "tree-kill": "^1.2.2" + }, + "bin": { + "tsup": "dist/cli-default.js", + "tsup-node": "dist/cli-node.js" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@microsoft/api-extractor": "^7.36.0", + "@swc/core": "^1", + "postcss": "^8.4.12", + "typescript": ">=4.5.0" + }, + "peerDependenciesMeta": { + "@microsoft/api-extractor": { + "optional": true + }, + "@swc/core": { + "optional": true + }, + "postcss": { + "optional": true + }, + "typescript": { + "optional": true + } + } + }, + "node_modules/tsup/node_modules/chokidar": { + "version": "4.0.3", + "dev": true, + "license": "MIT", + "dependencies": { + "readdirp": "^4.0.1" + }, + "engines": { + "node": ">= 14.16.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/tsup/node_modules/readdirp": { + "version": "4.1.2", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 14.18.0" + }, + "funding": { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/tsup/node_modules/resolve-from": { + "version": "5.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/tsup/node_modules/source-map": { + "version": "0.7.6", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">= 12" + } + }, + "node_modules/tsup/node_modules/tinyexec": { + "version": "0.3.2", + "dev": true, + "license": "MIT" + }, "node_modules/tsx": { "version": "4.21.0", - "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.21.0.tgz", - "integrity": "sha512-5C1sg4USs1lfG0GFb2RLXsdpXqBSEhAaA/0kPL01wxzpMqLILNxIxIOKiILz+cdg/pLnOUxFYOR5yhHU666wbw==", "dev": true, "license": "MIT", "dependencies": { @@ -8745,17 +7677,24 @@ "fsevents": "~2.3.3" } }, + "node_modules/type-check": { + "version": "0.4.0", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, "node_modules/typed-query-selector": { "version": "2.12.0", - "resolved": "https://registry.npmjs.org/typed-query-selector/-/typed-query-selector-2.12.0.tgz", - "integrity": "sha512-SbklCd1F0EiZOyPiW192rrHZzZ5sBijB6xM+cpmrwDqObvdtunOHHIk9fCGsoK5JVIYXoyEp4iEdE3upFH3PAg==", "dev": true, "license": "MIT" }, "node_modules/typescript": { "version": "5.9.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", - "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", "dev": true, "license": "Apache-2.0", "bin": { @@ -8766,16 +7705,40 @@ "node": ">=14.17" } }, + "node_modules/typescript-eslint": { + "version": "8.56.1", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/eslint-plugin": "8.56.1", + "@typescript-eslint/parser": "8.56.1", + "@typescript-eslint/typescript-estree": "8.56.1", + "@typescript-eslint/utils": "8.56.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/ufo": { + "version": "1.6.3", + "dev": true, + "license": "MIT" + }, "node_modules/undici-types": { "version": "6.21.0", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", - "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==", + "dev": true, "license": "MIT" }, "node_modules/universalify": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", - "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", + "version": "0.2.0", "dev": true, "license": "MIT", "engines": { @@ -8784,8 +7747,7 @@ }, "node_modules/update-browserslist-db": { "version": "1.2.3", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.2.3.tgz", - "integrity": "sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==", + "dev": true, "funding": [ { "type": "opencollective", @@ -8814,8 +7776,7 @@ }, "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" @@ -8823,12 +7784,8 @@ }, "node_modules/url-parse": { "version": "1.5.10", - "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.10.tgz", - "integrity": "sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==", "dev": true, "license": "MIT", - "optional": true, - "peer": true, "dependencies": { "querystringify": "^2.1.1", "requires-port": "^1.0.0" @@ -8836,14 +7793,10 @@ }, "node_modules/util-deprecate": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", "license": "MIT" }, "node_modules/uuid": { "version": "10.0.0", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-10.0.0.tgz", - "integrity": "sha512-8XkAphELsDnEGrDxUOHB3RGvXz6TeuYSGEZBOjtTtPm2lwhGBjLgOzLHB63IUWfBpNucQjND6d3AOudO+H3RWQ==", "funding": [ "https://github.com/sponsors/broofa", "https://github.com/sponsors/ctavan" @@ -8855,8 +7808,6 @@ }, "node_modules/vite": { "version": "7.3.1", - "resolved": "https://registry.npmjs.org/vite/-/vite-7.3.1.tgz", - "integrity": "sha512-w+N7Hifpc3gRjZ63vYBXA56dvvRlNWRczTdmCBBa+CotUzAPf5b7YMdMR/8CQoeYE5LX3W4wj6RYTgonm1b9DA==", "dev": true, "license": "MIT", "dependencies": { @@ -8919,19 +7870,153 @@ }, "terser": { "optional": true - }, - "tsx": { - "optional": true - }, - "yaml": { - "optional": true + }, + "tsx": { + "optional": true + }, + "yaml": { + "optional": true + } + } + }, + "node_modules/vite-node": { + "version": "2.1.9", + "dev": true, + "license": "MIT", + "dependencies": { + "cac": "^6.7.14", + "debug": "^4.3.7", + "es-module-lexer": "^1.5.4", + "pathe": "^1.1.2", + "vite": "^5.0.0" + }, + "bin": { + "vite-node": "vite-node.mjs" + }, + "engines": { + "node": "^18.0.0 || >=20.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/vite-node/node_modules/@esbuild/darwin-arm64": { + "version": "0.21.5", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite-node/node_modules/esbuild": { + "version": "0.21.5", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=12" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.21.5", + "@esbuild/android-arm": "0.21.5", + "@esbuild/android-arm64": "0.21.5", + "@esbuild/android-x64": "0.21.5", + "@esbuild/darwin-arm64": "0.21.5", + "@esbuild/darwin-x64": "0.21.5", + "@esbuild/freebsd-arm64": "0.21.5", + "@esbuild/freebsd-x64": "0.21.5", + "@esbuild/linux-arm": "0.21.5", + "@esbuild/linux-arm64": "0.21.5", + "@esbuild/linux-ia32": "0.21.5", + "@esbuild/linux-loong64": "0.21.5", + "@esbuild/linux-mips64el": "0.21.5", + "@esbuild/linux-ppc64": "0.21.5", + "@esbuild/linux-riscv64": "0.21.5", + "@esbuild/linux-s390x": "0.21.5", + "@esbuild/linux-x64": "0.21.5", + "@esbuild/netbsd-x64": "0.21.5", + "@esbuild/openbsd-x64": "0.21.5", + "@esbuild/sunos-x64": "0.21.5", + "@esbuild/win32-arm64": "0.21.5", + "@esbuild/win32-ia32": "0.21.5", + "@esbuild/win32-x64": "0.21.5" + } + }, + "node_modules/vite-node/node_modules/pathe": { + "version": "1.1.2", + "dev": true, + "license": "MIT" + }, + "node_modules/vite-node/node_modules/vite": { + "version": "5.4.21", + "dev": true, + "license": "MIT", + "dependencies": { + "esbuild": "^0.21.3", + "postcss": "^8.4.43", + "rollup": "^4.20.0" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^18.0.0 || >=20.0.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^18.0.0 || >=20.0.0", + "less": "*", + "lightningcss": "^1.21.0", + "sass": "*", + "sass-embedded": "*", + "stylus": "*", + "sugarss": "*", + "terser": "^5.4.0" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "less": { + "optional": true + }, + "lightningcss": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true } } }, "node_modules/vite/node_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": { @@ -8948,8 +8033,6 @@ }, "node_modules/vite/node_modules/picomatch": { "version": "4.0.3", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", - "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", "dev": true, "license": "MIT", "engines": { @@ -8961,8 +8044,6 @@ }, "node_modules/vitest": { "version": "4.0.18", - "resolved": "https://registry.npmjs.org/vitest/-/vitest-4.0.18.tgz", - "integrity": "sha512-hOQuK7h0FGKgBAas7v0mSAsnvrIgAvWmRFjmzpJ7SwFHH3g1k2u37JtYwOwmEKhK6ZO3v9ggDBBm0La1LCK4uQ==", "dev": true, "license": "MIT", "dependencies": { @@ -9039,8 +8120,6 @@ }, "node_modules/vitest/node_modules/picomatch": { "version": "4.0.3", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", - "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", "dev": true, "license": "MIT", "engines": { @@ -9052,12 +8131,8 @@ }, "node_modules/w3c-xmlserializer": { "version": "5.0.0", - "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-5.0.0.tgz", - "integrity": "sha512-o8qghlI8NZHU1lLPrpi2+Uq7abh4GGPpYANlalzWxyWteJOCsr/P+oPBA49TOLu5FTZO4d3F9MnWJfiMo4BkmA==", "dev": true, "license": "MIT", - "optional": true, - "peer": true, "dependencies": { "xml-name-validator": "^5.0.0" }, @@ -9067,8 +8142,7 @@ }, "node_modules/watchpack": { "version": "2.5.1", - "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.5.1.tgz", - "integrity": "sha512-Zn5uXdcFNIA1+1Ei5McRd+iRzfhENPCe7LeABkJtNulSxjma+l7ltNx55BWZkRlwRnpOgHqxnjyaDgJnNXnqzg==", + "dev": true, "license": "MIT", "dependencies": { "glob-to-regexp": "^0.4.1", @@ -9080,8 +8154,6 @@ }, "node_modules/web-push": { "version": "3.6.7", - "resolved": "https://registry.npmjs.org/web-push/-/web-push-3.6.7.tgz", - "integrity": "sha512-OpiIUe8cuGjrj3mMBFWY+e4MMIkW3SVT+7vEIjvD9kejGUypv8GPDf84JdPWskK8zMRIJ6xYGm+Kxr8YkPyA0A==", "license": "MPL-2.0", "dependencies": { "asn1.js": "^5.3.0", @@ -9099,21 +8171,17 @@ }, "node_modules/webdriver-bidi-protocol": { "version": "0.4.1", - "resolved": "https://registry.npmjs.org/webdriver-bidi-protocol/-/webdriver-bidi-protocol-0.4.1.tgz", - "integrity": "sha512-ARrjNjtWRRs2w4Tk7nqrf2gBI0QXWuOmMCx2hU+1jUt6d00MjMxURrhxhGbrsoiZKJrhTSTzbIrc554iKI10qw==", "dev": true, "license": "Apache-2.0" }, "node_modules/webidl-conversions": { "version": "4.0.2", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-4.0.2.tgz", - "integrity": "sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg==", + "dev": true, "license": "BSD-2-Clause" }, "node_modules/webpack": { "version": "5.105.0", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.105.0.tgz", - "integrity": "sha512-gX/dMkRQc7QOMzgTe6KsYFM7DxeIONQSui1s0n/0xht36HvrgbxtM1xBlgx596NbpHuQU8P7QpKwrZYwUX48nw==", + "dev": true, "license": "MIT", "dependencies": { "@types/eslint-scope": "^3.7.7", @@ -9160,8 +8228,7 @@ }, "node_modules/webpack-sources": { "version": "3.3.4", - "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.3.4.tgz", - "integrity": "sha512-7tP1PdV4vF+lYPnkMR0jMY5/la2ub5Fc/8VQrrU+lXkiM6C4TjVfGw7iKfyhnTQOsD+6Q/iKw0eFciziRgD58Q==", + "dev": true, "license": "MIT", "engines": { "node": ">=10.13.0" @@ -9169,8 +8236,7 @@ }, "node_modules/webpack/node_modules/ajv-formats": { "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz", - "integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==", + "dev": true, "license": "MIT", "dependencies": { "ajv": "^8.0.0" @@ -9186,14 +8252,12 @@ }, "node_modules/webpack/node_modules/es-module-lexer": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-2.0.0.tgz", - "integrity": "sha512-5POEcUuZybH7IdmGsD8wlf0AI55wMecM9rVBTI/qEAy2c1kTOm3DjFYjrBdI2K3BaJjJYfYFeRtM0t9ssnRuxw==", + "dev": true, "license": "MIT" }, "node_modules/webpack/node_modules/schema-utils": { "version": "4.3.3", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.3.3.tgz", - "integrity": "sha512-eflK8wEtyOE6+hsaRVPxvUKYCpRgzLqDTb8krvAsRIwOGlHoSgYLgBXoubGgLd2fT41/OUYdb48v4k4WWHQurA==", + "dev": true, "license": "MIT", "dependencies": { "@types/json-schema": "^7.0.9", @@ -9211,13 +8275,8 @@ }, "node_modules/whatwg-encoding": { "version": "3.1.1", - "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-3.1.1.tgz", - "integrity": "sha512-6qN4hJdMwfYBtE3YBTTHhoeuUrDBPZmbQaxWAqSALV/MeEnR5z1xd8UKud2RAkFoPkmB+hli1TZSnyi84xz1vQ==", - "deprecated": "Use @exodus/bytes instead for a more spec-conformant and faster implementation", "dev": true, "license": "MIT", - "optional": true, - "peer": true, "dependencies": { "iconv-lite": "0.6.3" }, @@ -9225,37 +8284,17 @@ "node": ">=18" } }, - "node_modules/whatwg-encoding/node_modules/iconv-lite": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", - "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", - "dev": true, - "license": "MIT", - "optional": true, - "peer": true, - "dependencies": { - "safer-buffer": ">= 2.1.2 < 3.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/whatwg-mimetype": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-4.0.0.tgz", - "integrity": "sha512-QaKxh0eNIi2mE9p2vEdzfagOKHCcj1pJ56EEHGQOVxp8r9/iszLUUV7v89x9O1p/T+NlTM5W7jW6+cz4Fq1YVg==", "dev": true, "license": "MIT", - "optional": true, - "peer": true, "engines": { "node": ">=18" } }, "node_modules/whatwg-url": { "version": "7.1.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-7.1.0.tgz", - "integrity": "sha512-WUu7Rg1DroM7oQvGWfOiAK21n74Gg+T4elXEQYkOhtyLeWiJFoOGLXPKI/9gzIie9CtwVLm8wtw6YJdKyxSjeg==", + "dev": true, "license": "MIT", "dependencies": { "lodash.sortby": "^4.7.0", @@ -9265,8 +8304,6 @@ }, "node_modules/which": { "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", "license": "ISC", "dependencies": { "isexe": "^2.0.0" @@ -9280,14 +8317,10 @@ }, "node_modules/which-module": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.1.tgz", - "integrity": "sha512-iBdZ57RDvnOR9AGBhML2vFZf7h8vmBjhoaZqODJBFWHVtKkDmKuHai3cx5PgVMrX5YDNp27AofYbAwctSS+vhQ==", "license": "ISC" }, "node_modules/why-is-node-running": { "version": "2.3.0", - "resolved": "https://registry.npmjs.org/why-is-node-running/-/why-is-node-running-2.3.0.tgz", - "integrity": "sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==", "dev": true, "license": "MIT", "dependencies": { @@ -9301,10 +8334,16 @@ "node": ">=8" } }, + "node_modules/word-wrap": { + "version": "1.2.5", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/wrap-ansi": { "version": "7.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", "dev": true, "license": "MIT", "dependencies": { @@ -9321,14 +8360,10 @@ }, "node_modules/wrappy": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", "license": "ISC" }, "node_modules/ws": { "version": "8.19.0", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.19.0.tgz", - "integrity": "sha512-blAT2mjOEIi0ZzruJfIhb3nps74PRWTCz1IjglWEEpQl5XS/UNama6u2/rjFkDDouqr4L67ry+1aGIALViWjDg==", "dev": true, "license": "MIT", "engines": { @@ -9349,29 +8384,19 @@ }, "node_modules/xml-name-validator": { "version": "5.0.0", - "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-5.0.0.tgz", - "integrity": "sha512-EvGK8EJ3DhaHfbRlETOWAS5pO9MZITeauHKJyb8wyajUfQUenkIg2MvLDTZ4T/TgIcm3HU0TFBgWWboAZ30UHg==", "dev": true, "license": "Apache-2.0", - "optional": true, - "peer": true, "engines": { "node": ">=18" } }, "node_modules/xmlchars": { "version": "2.2.0", - "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz", - "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==", "dev": true, - "license": "MIT", - "optional": true, - "peer": true + "license": "MIT" }, "node_modules/xtend": { "version": "4.0.2", - "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", - "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", "license": "MIT", "engines": { "node": ">=0.4" @@ -9379,16 +8404,10 @@ }, "node_modules/xterm": { "version": "5.3.0", - "resolved": "https://registry.npmjs.org/xterm/-/xterm-5.3.0.tgz", - "integrity": "sha512-8QqjlekLUFTrU6x7xck1MsPzPA571K5zNqWm0M0oroYEWVOptZ0+ubQSkQ3uxIEhcIHRujJy6emDWX4A7qyFzg==", - "deprecated": "This package is now deprecated. Move to @xterm/xterm instead.", "license": "MIT" }, "node_modules/xterm-addon-fit": { "version": "0.8.0", - "resolved": "https://registry.npmjs.org/xterm-addon-fit/-/xterm-addon-fit-0.8.0.tgz", - "integrity": "sha512-yj3Np7XlvxxhYF/EJ7p3KHaMt6OdwQ+HDu573Vx1lRXsVxOcnVJs51RgjZOouIZOczTsskaS+CpXspK81/DLqw==", - "deprecated": "This package is now deprecated. Move to @xterm/addon-fit instead.", "license": "MIT", "peerDependencies": { "xterm": "^5.0.0" @@ -9396,9 +8415,6 @@ }, "node_modules/xterm-addon-unicode11": { "version": "0.6.0", - "resolved": "https://registry.npmjs.org/xterm-addon-unicode11/-/xterm-addon-unicode11-0.6.0.tgz", - "integrity": "sha512-5pkb8YoS/deRtNqQRw8t640mu+Ga8B2MG3RXGQu0bwgcfr8XiXIRI880TWM49ICAHhTmnOLPzIIBIjEnCq7k2A==", - "deprecated": "This package is now deprecated. Move to @xterm/addon-unicode11 instead.", "license": "MIT", "peerDependencies": { "xterm": "^5.0.0" @@ -9406,18 +8422,17 @@ }, "node_modules/xterm-addon-webgl": { "version": "0.16.0", - "resolved": "https://registry.npmjs.org/xterm-addon-webgl/-/xterm-addon-webgl-0.16.0.tgz", - "integrity": "sha512-E8cq1AiqNOv0M/FghPT+zPAEnvIQRDbAbkb04rRYSxUym69elPWVJ4sv22FCLBqM/3LcrmBLl/pELnBebVFKgA==", - "deprecated": "This package is now deprecated. Move to @xterm/addon-webgl instead.", "license": "MIT", "peerDependencies": { "xterm": "^5.0.0" } }, + "node_modules/xterm-zerolag-input": { + "resolved": "packages/xterm-zerolag-input", + "link": true + }, "node_modules/y18n": { "version": "5.0.8", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", - "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", "dev": true, "license": "ISC", "engines": { @@ -9426,14 +8441,11 @@ }, "node_modules/yallist": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true, "license": "ISC" }, "node_modules/yargs": { "version": "17.7.2", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", - "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", "dev": true, "license": "MIT", "dependencies": { @@ -9451,8 +8463,6 @@ }, "node_modules/yargs-parser": { "version": "21.1.1", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", - "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", "dev": true, "license": "ISC", "engines": { @@ -9461,18 +8471,26 @@ }, "node_modules/yauzl": { "version": "2.10.0", - "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz", - "integrity": "sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g==", + "dev": true, "license": "MIT", "dependencies": { "buffer-crc32": "~0.2.3", "fd-slicer": "~1.1.0" } }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/zod": { "version": "4.3.6", - "resolved": "https://registry.npmjs.org/zod/-/zod-4.3.6.tgz", - "integrity": "sha512-rftlrkhHZOcjDwkGlnUtZZkvaPHCsDATp4pGpuOOMDaTdDDXF91wuVDJoWoPsKX/3YPQ5fHuF3STjcYyKr+Qhg==", "license": "MIT", "funding": { "url": "https://github.com/sponsors/colinhacks" @@ -9480,7 +8498,6 @@ }, "packages/xterm-zerolag-input": { "version": "0.1.4", - "extraneous": true, "license": "MIT", "devDependencies": { "jsdom": "^24.1.3", @@ -9488,6 +8505,312 @@ "typescript": "^5.5.0", "vitest": "^2.1.9" } + }, + "packages/xterm-zerolag-input/node_modules/@esbuild/darwin-arm64": { + "version": "0.21.5", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "packages/xterm-zerolag-input/node_modules/@vitest/expect": { + "version": "2.1.9", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/spy": "2.1.9", + "@vitest/utils": "2.1.9", + "chai": "^5.1.2", + "tinyrainbow": "^1.2.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "packages/xterm-zerolag-input/node_modules/@vitest/mocker": { + "version": "2.1.9", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/spy": "2.1.9", + "estree-walker": "^3.0.3", + "magic-string": "^0.30.12" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "msw": "^2.4.9", + "vite": "^5.0.0" + }, + "peerDependenciesMeta": { + "msw": { + "optional": true + }, + "vite": { + "optional": true + } + } + }, + "packages/xterm-zerolag-input/node_modules/@vitest/pretty-format": { + "version": "2.1.9", + "dev": true, + "license": "MIT", + "dependencies": { + "tinyrainbow": "^1.2.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "packages/xterm-zerolag-input/node_modules/@vitest/runner": { + "version": "2.1.9", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/utils": "2.1.9", + "pathe": "^1.1.2" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "packages/xterm-zerolag-input/node_modules/@vitest/snapshot": { + "version": "2.1.9", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/pretty-format": "2.1.9", + "magic-string": "^0.30.12", + "pathe": "^1.1.2" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "packages/xterm-zerolag-input/node_modules/@vitest/spy": { + "version": "2.1.9", + "dev": true, + "license": "MIT", + "dependencies": { + "tinyspy": "^3.0.2" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "packages/xterm-zerolag-input/node_modules/@vitest/utils": { + "version": "2.1.9", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/pretty-format": "2.1.9", + "loupe": "^3.1.2", + "tinyrainbow": "^1.2.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "packages/xterm-zerolag-input/node_modules/chai": { + "version": "5.3.3", + "dev": true, + "license": "MIT", + "dependencies": { + "assertion-error": "^2.0.1", + "check-error": "^2.1.1", + "deep-eql": "^5.0.1", + "loupe": "^3.1.0", + "pathval": "^2.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "packages/xterm-zerolag-input/node_modules/esbuild": { + "version": "0.21.5", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=12" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.21.5", + "@esbuild/android-arm": "0.21.5", + "@esbuild/android-arm64": "0.21.5", + "@esbuild/android-x64": "0.21.5", + "@esbuild/darwin-arm64": "0.21.5", + "@esbuild/darwin-x64": "0.21.5", + "@esbuild/freebsd-arm64": "0.21.5", + "@esbuild/freebsd-x64": "0.21.5", + "@esbuild/linux-arm": "0.21.5", + "@esbuild/linux-arm64": "0.21.5", + "@esbuild/linux-ia32": "0.21.5", + "@esbuild/linux-loong64": "0.21.5", + "@esbuild/linux-mips64el": "0.21.5", + "@esbuild/linux-ppc64": "0.21.5", + "@esbuild/linux-riscv64": "0.21.5", + "@esbuild/linux-s390x": "0.21.5", + "@esbuild/linux-x64": "0.21.5", + "@esbuild/netbsd-x64": "0.21.5", + "@esbuild/openbsd-x64": "0.21.5", + "@esbuild/sunos-x64": "0.21.5", + "@esbuild/win32-arm64": "0.21.5", + "@esbuild/win32-ia32": "0.21.5", + "@esbuild/win32-x64": "0.21.5" + } + }, + "packages/xterm-zerolag-input/node_modules/pathe": { + "version": "1.1.2", + "dev": true, + "license": "MIT" + }, + "packages/xterm-zerolag-input/node_modules/tinyexec": { + "version": "0.3.2", + "dev": true, + "license": "MIT" + }, + "packages/xterm-zerolag-input/node_modules/tinyrainbow": { + "version": "1.2.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.0.0" + } + }, + "packages/xterm-zerolag-input/node_modules/vite": { + "version": "5.4.21", + "dev": true, + "license": "MIT", + "dependencies": { + "esbuild": "^0.21.3", + "postcss": "^8.4.43", + "rollup": "^4.20.0" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^18.0.0 || >=20.0.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^18.0.0 || >=20.0.0", + "less": "*", + "lightningcss": "^1.21.0", + "sass": "*", + "sass-embedded": "*", + "stylus": "*", + "sugarss": "*", + "terser": "^5.4.0" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "less": { + "optional": true + }, + "lightningcss": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + } + } + }, + "packages/xterm-zerolag-input/node_modules/vitest": { + "version": "2.1.9", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/expect": "2.1.9", + "@vitest/mocker": "2.1.9", + "@vitest/pretty-format": "^2.1.9", + "@vitest/runner": "2.1.9", + "@vitest/snapshot": "2.1.9", + "@vitest/spy": "2.1.9", + "@vitest/utils": "2.1.9", + "chai": "^5.1.2", + "debug": "^4.3.7", + "expect-type": "^1.1.0", + "magic-string": "^0.30.12", + "pathe": "^1.1.2", + "std-env": "^3.8.0", + "tinybench": "^2.9.0", + "tinyexec": "^0.3.1", + "tinypool": "^1.0.1", + "tinyrainbow": "^1.2.0", + "vite": "^5.0.0", + "vite-node": "2.1.9", + "why-is-node-running": "^2.3.0" + }, + "bin": { + "vitest": "vitest.mjs" + }, + "engines": { + "node": "^18.0.0 || >=20.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "@edge-runtime/vm": "*", + "@types/node": "^18.0.0 || >=20.0.0", + "@vitest/browser": "2.1.9", + "@vitest/ui": "2.1.9", + "happy-dom": "*", + "jsdom": "*" + }, + "peerDependenciesMeta": { + "@edge-runtime/vm": { + "optional": true + }, + "@types/node": { + "optional": true + }, + "@vitest/browser": { + "optional": true + }, + "@vitest/ui": { + "optional": true + }, + "happy-dom": { + "optional": true + }, + "jsdom": { + "optional": true + } + } } } } diff --git a/package.json b/package.json index 7c7fc587..f50838f1 100644 --- a/package.json +++ b/package.json @@ -10,20 +10,27 @@ }, "scripts": { "postinstall": "node scripts/postinstall.js", - "build": "tsc && chmod +x dist/index.js && mkdir -p dist/web dist/templates dist/web/public/vendor && cp -r src/web/public dist/web/ && cp src/templates/case-template.md dist/templates/ && cp node_modules/xterm/css/xterm.css dist/web/public/vendor/ && npx esbuild node_modules/xterm/lib/xterm.js --minify --outfile=dist/web/public/vendor/xterm.min.js && npx esbuild node_modules/xterm-addon-fit/lib/xterm-addon-fit.js --minify --outfile=dist/web/public/vendor/xterm-addon-fit.min.js && cp node_modules/xterm-addon-webgl/lib/xterm-addon-webgl.js dist/web/public/vendor/xterm-addon-webgl.min.js && npx esbuild node_modules/xterm-addon-unicode11/lib/xterm-addon-unicode11.js --minify --outfile=dist/web/public/vendor/xterm-addon-unicode11.min.js && npx esbuild dist/web/public/app.js --minify --drop:console --outfile=dist/web/public/app.js --allow-overwrite && npx esbuild dist/web/public/styles.css --minify --outfile=dist/web/public/styles.css --allow-overwrite && npx esbuild dist/web/public/mobile.css --minify --outfile=dist/web/public/mobile.css --allow-overwrite && for f in dist/web/public/*.js dist/web/public/*.css dist/web/public/*.html dist/web/public/vendor/*.js dist/web/public/vendor/*.css; do [ -f \"$f\" ] && gzip -9 -k -f \"$f\" && { brotli -9 -k -f \"$f\" 2>/dev/null || true; }; done", + "build": "node scripts/build.mjs", "start": "node dist/index.js", - "dev": "tsx src/index.ts", + "dev": "tsx src/index.ts web", "web": "node dist/index.js web", "clean": "rm -rf dist", "test": "vitest run", "test:watch": "vitest", "test:coverage": "vitest run --coverage", "typecheck": "tsc --noEmit", + "lint": "eslint 'src/**/*.ts'", + "lint:fix": "eslint 'src/**/*.ts' --fix", + "format": "prettier --write 'src/**/*.ts'", + "format:check": "prettier --check 'src/**/*.ts'", "capture:subagents": "node scripts/capture-subagent-screenshots.mjs", "changeset": "changeset", "version-packages": "changeset version", "release": "changeset publish" }, + "workspaces": [ + "packages/*" + ], "keywords": [ "claude", "claude-code", @@ -43,15 +50,12 @@ "@fastify/compress": "^8.3.1", "@fastify/cookie": "^11.0.2", "@fastify/static": "^8.0.0", - "@remotion/cli": "4.0.429", - "@remotion/transitions": "4.0.429", "chalk": "^5.3.0", "chokidar": "^3.6.0", "commander": "^12.1.0", "fastify": "^5.1.0", "node-pty": "^1.1.0", "qrcode": "^1.5.4", - "remotion": "4.0.429", "uuid": "^10.0.0", "web-push": "^3.6.7", "xterm": "^5.3.0", @@ -62,6 +66,9 @@ }, "devDependencies": { "@changesets/cli": "^2.29.8", + "@eslint/js": "^9.0.0", + "@remotion/cli": "4.0.429", + "@remotion/transitions": "4.0.429", "@types/node": "^20.19.33", "@types/pngjs": "^6.0.5", "@types/react": "^19.2.14", @@ -70,12 +77,16 @@ "@vitest/coverage-v8": "^4.0.18", "agent-browser": "^0.6.0", "esbuild": "^0.27.3", + "eslint": "^9.0.0", "pixelmatch": "^6.0.0", "playwright": "^1.58.0", "pngjs": "^7.0.0", + "prettier": "^3.4.0", "puppeteer": "^24.36.0", + "remotion": "4.0.429", "tsx": "^4.15.0", "typescript": "^5.9.3", + "typescript-eslint": "^8.0.0", "vitest": "^4.0.18" }, "engines": { diff --git a/scripts/build.mjs b/scripts/build.mjs new file mode 100644 index 00000000..2b21541b --- /dev/null +++ b/scripts/build.mjs @@ -0,0 +1,53 @@ +#!/usr/bin/env node +/** + * Build script for Codeman. + * Extracted from the package.json one-liner for readability and debuggability. + * + * Steps: + * 1. TypeScript compilation + * 2. Copy static assets (web/public, templates) + * 3. Build vendor xterm bundles + * 4. Minify frontend assets (app.js, styles.css, mobile.css) + * 5. Compress with gzip + brotli + */ + +import { execSync } from 'child_process'; +import { fileURLToPath } from 'url'; +import { join } from 'path'; + +const ROOT = join(fileURLToPath(import.meta.url), '..', '..'); + +function run(label, cmd) { + console.log(`\n[build] ${label}`); + execSync(cmd, { stdio: 'inherit', cwd: ROOT, shell: true }); +} + +// 1. TypeScript compilation +run('tsc', 'tsc'); +run('chmod dist/index.js', 'chmod +x dist/index.js'); + +// 2. Copy static assets +run('prepare dirs', 'mkdir -p dist/web dist/templates dist/web/public/vendor'); +run('copy web assets', 'cp -r src/web/public dist/web/'); +run('copy template', 'cp src/templates/case-template.md dist/templates/'); + +// 3. Vendor xterm bundles +run('xterm css', 'cp node_modules/xterm/css/xterm.css dist/web/public/vendor/'); +run('xterm js', 'npx esbuild node_modules/xterm/lib/xterm.js --minify --outfile=dist/web/public/vendor/xterm.min.js'); +run('xterm-addon-fit', 'npx esbuild node_modules/xterm-addon-fit/lib/xterm-addon-fit.js --minify --outfile=dist/web/public/vendor/xterm-addon-fit.min.js'); +run('xterm-addon-webgl', 'cp node_modules/xterm-addon-webgl/lib/xterm-addon-webgl.js dist/web/public/vendor/xterm-addon-webgl.min.js'); +run('xterm-addon-unicode11', 'npx esbuild node_modules/xterm-addon-unicode11/lib/xterm-addon-unicode11.js --minify --outfile=dist/web/public/vendor/xterm-addon-unicode11.min.js'); + +// 4. Minify frontend assets +run('minify app.js', 'npx esbuild dist/web/public/app.js --minify --drop:console --outfile=dist/web/public/app.js --allow-overwrite'); +run('minify styles.css', 'npx esbuild dist/web/public/styles.css --minify --outfile=dist/web/public/styles.css --allow-overwrite'); +run('minify mobile.css', 'npx esbuild dist/web/public/mobile.css --minify --outfile=dist/web/public/mobile.css --allow-overwrite'); + +// 5. Compress with gzip + brotli +run( + 'compress', + `for f in dist/web/public/*.js dist/web/public/*.css dist/web/public/*.html dist/web/public/vendor/*.js dist/web/public/vendor/*.css; do` + + ` [ -f "$f" ] && gzip -9 -k -f "$f" && { brotli -9 -k -f "$f" 2>/dev/null || true; }; done` +); + +console.log('\n✓ Build complete'); diff --git a/src/ai-checker-base.ts b/src/ai-checker-base.ts index dc9711c7..f5d1ef4e 100644 --- a/src/ai-checker-base.ts +++ b/src/ai-checker-base.ts @@ -115,7 +115,7 @@ export abstract class AiCheckerBase< V extends string, C extends AiCheckerConfigBase, R extends AiCheckerResultBase, - S extends AiCheckerStateBase + S extends AiCheckerStateBase, > extends EventEmitter { protected config: C; protected sessionId: string; @@ -205,9 +205,7 @@ export abstract class AiCheckerBase< super(); this.sessionId = sessionId; // Filter out undefined values to prevent overwriting defaults - const filteredConfig = Object.fromEntries( - Object.entries(config).filter(([, v]) => v !== undefined) - ) as Partial; + const filteredConfig = Object.fromEntries(Object.entries(config).filter(([, v]) => v !== undefined)) as Partial; this.config = { ...defaultConfig, ...filteredConfig }; } @@ -342,9 +340,7 @@ export abstract class AiCheckerBase< /** Update configuration at runtime */ updateConfig(config: Partial): void { // Filter out undefined values to prevent overwriting existing config - const filteredConfig = Object.fromEntries( - Object.entries(config).filter(([, v]) => v !== undefined) - ) as Partial; + const filteredConfig = Object.fromEntries(Object.entries(config).filter(([, v]) => v !== undefined)) as Partial; this.config = { ...this.config, ...filteredConfig }; if (config.enabled === false) { this.disable('Disabled by config'); @@ -369,9 +365,8 @@ export abstract class AiCheckerBase< // Prepare the terminal buffer (strip ANSI, trim to maxContextChars) const stripped = terminalBuffer.replace(ANSI_ESCAPE_PATTERN_SIMPLE, ''); - const trimmed = stripped.length > this.config.maxContextChars - ? stripped.slice(-this.config.maxContextChars) - : stripped; + const trimmed = + stripped.length > this.config.maxContextChars ? stripped.slice(-this.config.maxContextChars) : stripped; // Build the prompt const prompt = this.buildPrompt(trimmed); @@ -411,16 +406,15 @@ export abstract class AiCheckerBase< // No existing session, that's fine } - const muxProcess = childSpawn('tmux', [ - 'new-session', '-d', '-s', this.checkMuxName, - 'bash', '-c', fullCmd - ], { + const muxProcess = childSpawn('tmux', ['new-session', '-d', '-s', this.checkMuxName, 'bash', '-c', fullCmd], { detached: true, stdio: 'ignore', }); muxProcess.unref(); } catch (err) { - throw new Error(`Failed to spawn ${this.checkDescription} tmux session: ${err instanceof Error ? err.message : String(err)}`); + throw new Error( + `Failed to spawn ${this.checkDescription} tmux session: ${err instanceof Error ? err.message : String(err)}` + ); } // Poll the temp file for completion @@ -530,7 +524,9 @@ export abstract class AiCheckerBase< private handleError(errorMsg: string): void { this.consecutiveErrors++; - this.log(`${this.checkDescription} error (${this.consecutiveErrors}/${this.config.maxConsecutiveErrors}): ${errorMsg}`); + this.log( + `${this.checkDescription} error (${this.consecutiveErrors}/${this.config.maxConsecutiveErrors}): ${errorMsg}` + ); if (this.consecutiveErrors >= this.config.maxConsecutiveErrors) { this.disable(`${this.config.maxConsecutiveErrors} consecutive errors: ${errorMsg}`); diff --git a/src/ai-idle-checker.ts b/src/ai-idle-checker.ts index b5154602..6f1d311b 100644 --- a/src/ai-idle-checker.ts +++ b/src/ai-idle-checker.ts @@ -33,13 +33,13 @@ import { // ========== Types ========== -export interface AiIdleCheckConfig extends AiCheckerConfigBase {} +export type AiIdleCheckConfig = AiCheckerConfigBase; export type AiCheckVerdict = 'IDLE' | 'WORKING' | 'ERROR'; -export interface AiCheckResult extends AiCheckerResultBase {} +export type AiCheckResult = AiCheckerResultBase; -export interface AiCheckState extends AiCheckerStateBase {} +export type AiCheckState = AiCheckerStateBase; // ========== Constants ========== @@ -123,12 +123,7 @@ Remember: When uncertain, answer WORKING.`; * Manages AI-powered idle detection by spawning a fresh Claude CLI session * to analyze terminal output and provide a definitive IDLE/WORKING verdict. */ -export class AiIdleChecker extends AiCheckerBase< - AiCheckVerdict, - AiIdleCheckConfig, - AiCheckResult, - AiCheckState -> { +export class AiIdleChecker extends AiCheckerBase { protected readonly muxNamePrefix = 'codeman-aicheck-'; protected readonly doneMarker = '__AICHECK_DONE__'; protected readonly tempFilePrefix = 'codeman-aicheck'; diff --git a/src/ai-plan-checker.ts b/src/ai-plan-checker.ts index f302f88f..f73271b0 100644 --- a/src/ai-plan-checker.ts +++ b/src/ai-plan-checker.ts @@ -32,13 +32,13 @@ import { // ========== Types ========== -export interface AiPlanCheckConfig extends AiCheckerConfigBase {} +export type AiPlanCheckConfig = AiCheckerConfigBase; export type AiPlanCheckVerdict = 'PLAN_MODE' | 'NOT_PLAN_MODE' | 'ERROR'; -export interface AiPlanCheckResult extends AiCheckerResultBase {} +export type AiPlanCheckResult = AiCheckerResultBase; -export interface AiPlanCheckState extends AiCheckerStateBase {} +export type AiPlanCheckState = AiCheckerStateBase; // ========== Constants ========== diff --git a/src/bash-tool-parser.ts b/src/bash-tool-parser.ts index 6e6e92c5..eee92db0 100644 --- a/src/bash-tool-parser.ts +++ b/src/bash-tool-parser.ts @@ -73,25 +73,25 @@ const FOLLOW_MODE_PATTERN = /\s-[A-Za-z]*f[A-Za-z]*\s|\s--follow\s/; * Note: This is a simpler approach - we run it on each command string * rather than trying to match globally. */ -const FILE_PATH_PATTERN = /(?:^|\s|['"]|=)([\/~][^\s'"<>|;&\n]+)/g; +const FILE_PATH_PATTERN = /(?:^|\s|['"]|=)([/~][^\s'"<>|;&\n]+)/g; /** * Pattern to detect paths that are likely not real files (flags, etc.) */ -const INVALID_PATH_PATTERN = /^[\/~]-|\/dev\/null$/; +const INVALID_PATH_PATTERN = /^[/~]-|\/dev\/null$/; /** * Pattern to detect command suggestions in plain text output. * Matches lines like "tail -f /path/to/file" without the ● Bash() wrapper. * This catches commands Claude mentions but doesn't execute. */ -const TEXT_COMMAND_PATTERN = /^\s*(tail|cat|head|less|grep|watch|multitail)\s+(?:-[^\s]+\s+)*([\/~][^\s'"<>|;&\n]+)/; +const TEXT_COMMAND_PATTERN = /^\s*(tail|cat|head|less|grep|watch|multitail)\s+(?:-[^\s]+\s+)*([/~][^\s'"<>|;&\n]+)/; /** * Pattern to detect log file paths mentioned in text (even without commands). * Matches paths ending in .log, .txt, .out, or in common log directories. */ -const LOG_FILE_MENTION_PATTERN = /([\/~][^\s'"<>|;&\n]*(?:\.log|\.txt|\.out|\/log\/[^\s'"<>|;&\n]+))/g; +const LOG_FILE_MENTION_PATTERN = /([/~][^\s'"<>|;&\n]*(?:\.log|\.txt|\.out|\/log\/[^\s'"<>|;&\n]+))/g; // ========== Event Interfaces ========== @@ -245,7 +245,7 @@ export class BashToolParser extends EventEmitter { */ private isShallowRootPath(path: string): boolean { if (!path.startsWith('/')) return false; - const parts = path.split('/').filter(p => p !== ''); + const parts = path.split('/').filter((p) => p !== ''); return parts.length === 1; } @@ -354,10 +354,10 @@ export class BashToolParser extends EventEmitter { isFilePathTracked(filePath: string): boolean { const normalizedNew = this.normalizePath(filePath); - return Array.from(this._activeTools.values()).some(t => { + return Array.from(this._activeTools.values()).some((t) => { if (t.status !== 'running') return false; - return t.filePaths.some(existingPath => { + return t.filePaths.some((existingPath) => { const normalizedExisting = this.normalizePath(existingPath); return normalizedExisting === normalizedNew; }); @@ -418,9 +418,8 @@ export class BashToolParser extends EventEmitter { // Prevent unbounded growth if (this._lineBuffer.length > MAX_LINE_BUFFER_SIZE) { const trimPoint = this._lineBuffer.lastIndexOf('\n', MAX_LINE_BUFFER_SIZE / 2); - this._lineBuffer = trimPoint > 0 - ? this._lineBuffer.slice(trimPoint + 1) - : this._lineBuffer.slice(-MAX_LINE_BUFFER_SIZE / 2); + this._lineBuffer = + trimPoint > 0 ? this._lineBuffer.slice(trimPoint + 1) : this._lineBuffer.slice(-MAX_LINE_BUFFER_SIZE / 2); } // Process complete lines @@ -445,9 +444,8 @@ export class BashToolParser extends EventEmitter { if (this._lineBuffer.length > MAX_LINE_BUFFER_SIZE) { const trimPoint = this._lineBuffer.lastIndexOf('\n', MAX_LINE_BUFFER_SIZE / 2); - this._lineBuffer = trimPoint > 0 - ? this._lineBuffer.slice(trimPoint + 1) - : this._lineBuffer.slice(-MAX_LINE_BUFFER_SIZE / 2); + this._lineBuffer = + trimPoint > 0 ? this._lineBuffer.slice(trimPoint + 1) : this._lineBuffer.slice(-MAX_LINE_BUFFER_SIZE / 2); } const lines = this._lineBuffer.split('\n'); @@ -472,7 +470,6 @@ export class BashToolParser extends EventEmitter { * Process a single pre-stripped line of terminal output. */ private processCleanLine(cleanLine: string): void { - // Check for tool start const startMatch = cleanLine.match(BASH_TOOL_START_PATTERN); if (startMatch) { @@ -484,7 +481,7 @@ export class BashToolParser extends EventEmitter { const filePaths = this.extractFilePaths(command); // Skip if any file path is already tracked (cross-pattern dedup) - if (filePaths.some(fp => this.isFilePathTracked(fp))) { + if (filePaths.some((fp) => this.isFilePathTracked(fp))) { return; } @@ -502,8 +499,7 @@ export class BashToolParser extends EventEmitter { // Enforce max tools limit if (this._activeTools.size >= MAX_ACTIVE_TOOLS) { // Remove oldest tool - const oldest = Array.from(this._activeTools.entries()) - .sort((a, b) => a[1].startedAt - b[1].startedAt)[0]; + const oldest = Array.from(this._activeTools.entries()).sort((a, b) => a[1].startedAt - b[1].startedAt)[0]; if (oldest) { this._activeTools.delete(oldest[0]); } @@ -671,6 +667,7 @@ export class BashToolParser extends EventEmitter { */ private stripAnsi(str: string): string { // Comprehensive ANSI pattern + // eslint-disable-next-line no-control-regex return str.replace(/\x1b(?:\[[0-9;?]*[A-Za-z]|\][^\x07\x1b]*(?:\x07|\x1b\\)|[=>])/g, ''); } diff --git a/src/cli.ts b/src/cli.ts index 425d6c03..b4461043 100644 --- a/src/cli.ts +++ b/src/cli.ts @@ -21,17 +21,11 @@ const pkg = require('../package.json') as { version: string }; const program = new Command(); -program - .name('codeman') - .description('Claude Code session manager with autonomous Ralph Loop') - .version(pkg.version); +program.name('codeman').description('Claude Code session manager with autonomous Ralph Loop').version(pkg.version); // ============ Session Commands ============ -const sessionCmd = program - .command('session') - .alias('s') - .description('Manage Claude sessions'); +const sessionCmd = program.command('session').alias('s').description('Manage Claude sessions'); sessionCmd .command('start') @@ -83,11 +77,12 @@ sessionCmd console.log(' (none)'); } else { for (const session of sessions) { - const status = session.status === 'idle' - ? chalk.green('idle') - : session.status === 'busy' - ? chalk.yellow('busy') - : chalk.red(session.status); + const status = + session.status === 'idle' + ? chalk.green('idle') + : session.status === 'busy' + ? chalk.yellow('busy') + : chalk.red(session.status); console.log(` ${chalk.cyan(session.id.slice(0, 8))} ${status} ${session.workingDir}`); } } @@ -106,11 +101,12 @@ sessionCmd if (sessions.length === 0 && activeSessions.length > 0) { console.log(chalk.bold('\nActive Sessions (from web server):')); for (const session of activeSessions) { - const status = session.status === 'idle' - ? chalk.green('idle') - : session.status === 'busy' - ? chalk.yellow('busy') - : chalk.red(session.status); + const status = + session.status === 'idle' + ? chalk.green('idle') + : session.status === 'busy' + ? chalk.yellow('busy') + : chalk.red(session.status); const name = session.name ? ` (${session.name})` : ''; const mode = session.mode === 'shell' ? chalk.gray(' [shell]') : ''; const cost = session.totalCost ? chalk.gray(` $${session.totalCost.toFixed(4)}`) : ''; @@ -126,9 +122,7 @@ sessionCmd .option('-e, --errors', 'Show stderr instead of stdout') .action((id, options) => { const manager = getSessionManager(); - const output = options.errors - ? manager.getSessionError(id) - : manager.getSessionOutput(id); + const output = options.errors ? manager.getSessionError(id) : manager.getSessionOutput(id); if (output === null) { console.log(chalk.yellow(`Session ${id} not found or not active`)); @@ -145,10 +139,7 @@ sessionCmd // ============ Task Commands ============ -const taskCmd = program - .command('task') - .alias('t') - .description('Manage tasks'); +const taskCmd = program.command('task').alias('t').description('Manage tasks'); taskCmd .command('add ') @@ -205,7 +196,9 @@ taskCmd const counts = queue.getCount(); console.log(chalk.bold('\nSummary:')); - console.log(` Pending: ${counts.pending}, Running: ${counts.running}, Completed: ${counts.completed}, Failed: ${counts.failed}`); + console.log( + ` Pending: ${counts.pending}, Running: ${counts.running}, Completed: ${counts.completed}, Failed: ${counts.failed}` + ); console.log(''); }); @@ -276,10 +269,7 @@ taskCmd // ============ Ralph Loop Commands ============ -const ralphCmd = program - .command('ralph') - .alias('r') - .description('Control the Ralph autonomous loop'); +const ralphCmd = program.command('ralph').alias('r').description('Control the Ralph autonomous loop'); ralphCmd .command('start') @@ -355,17 +345,16 @@ ralphCmd }); function printStats(stats: ReturnType['getStats']>) { - const statusColor = - stats.status === 'running' ? chalk.green : - stats.status === 'paused' ? chalk.yellow : - chalk.gray; + const statusColor = stats.status === 'running' ? chalk.green : stats.status === 'paused' ? chalk.yellow : chalk.gray; console.log(chalk.bold('\nRalph Loop Status:')); console.log(` Status: ${statusColor(stats.status)}`); console.log(` Elapsed: ${stats.elapsedHours.toFixed(2)} hours`); if (stats.minDurationMs) { const minHours = stats.minDurationMs / (1000 * 60 * 60); - console.log(` Min Duration: ${minHours.toFixed(2)} hours (${stats.minDurationReached ? 'reached' : 'not reached'})`); + console.log( + ` Min Duration: ${minHours.toFixed(2)} hours (${stats.minDurationReached ? 'reached' : 'not reached'})` + ); } console.log(chalk.bold('\nTasks:')); @@ -422,10 +411,7 @@ program console.log(` Completed: ${taskCounts.completed}`); console.log(` Failed: ${taskCounts.failed}`); - const statusColor = - loopStatus === 'running' ? chalk.green : - loopStatus === 'paused' ? chalk.yellow : - chalk.gray; + const statusColor = loopStatus === 'running' ? chalk.green : loopStatus === 'paused' ? chalk.yellow : chalk.gray; console.log(chalk.bold('\nRalph Loop:')); console.log(` Status: ${statusColor(loopStatus)}`); console.log(''); @@ -481,11 +467,12 @@ program console.log(' (none)'); } else { for (const session of sessions) { - const status = session.status === 'idle' - ? chalk.green('idle') - : session.status === 'busy' - ? chalk.yellow('busy') - : chalk.red(session.status); + const status = + session.status === 'idle' + ? chalk.green('idle') + : session.status === 'busy' + ? chalk.yellow('busy') + : chalk.red(session.status); console.log(` ${chalk.cyan(session.id.slice(0, 8))} ${status} ${session.workingDir}`); } } diff --git a/src/file-stream-manager.ts b/src/file-stream-manager.ts index 55baea4c..fa187894 100644 --- a/src/file-stream-manager.ts +++ b/src/file-stream-manager.ts @@ -171,7 +171,10 @@ export class FileStreamManager extends EventEmitter { } } catch (err) { const errorCode = err instanceof Error && 'code' in err ? (err as NodeJS.ErrnoException).code : 'UNKNOWN'; - console.warn(`[FileStreamManager] Failed to stat file "${absolutePath}" (${errorCode}):`, err instanceof Error ? err.message : String(err)); + console.warn( + `[FileStreamManager] Failed to stat file "${absolutePath}" (${errorCode}):`, + err instanceof Error ? err.message : String(err) + ); return { success: false, error: 'File not found or not accessible' }; } @@ -379,9 +382,7 @@ export class FileStreamManager extends EventEmitter { } // Resolve to absolute path - let absolutePath = isAbsolute(expandedPath) - ? resolve(expandedPath) - : resolve(workingDir, expandedPath); + let absolutePath = isAbsolute(expandedPath) ? resolve(expandedPath) : resolve(workingDir, expandedPath); // Resolve symlinks to prevent symlink attacks — validate the real target, // not the symlink itself. Fall back to resolved path if file doesn't exist yet. diff --git a/src/image-watcher.ts b/src/image-watcher.ts index 87c43dc1..84812df8 100644 --- a/src/image-watcher.ts +++ b/src/image-watcher.ts @@ -24,15 +24,7 @@ export interface ImageWatcherEvents { // ========== Constants ========== /** Supported image file extensions (lowercase) */ -const IMAGE_EXTENSIONS = new Set([ - '.png', - '.jpg', - '.jpeg', - '.gif', - '.webp', - '.bmp', - '.svg', -]); +const IMAGE_EXTENSIONS = new Set(['.png', '.jpg', '.jpeg', '.gif', '.webp', '.bmp', '.svg']); /** Time to wait for file writes to stabilize (ms) */ const STABILITY_THRESHOLD_MS = 500; @@ -171,7 +163,12 @@ export class ImageWatcher extends EventEmitter { // Ignore common heavy directories for performance ignored: (path: string) => { // Skip node_modules, .git, and other heavy directories - if (path.includes('/node_modules/') || path.includes('/.git/') || path.includes('/dist/') || path.includes('/.next/')) { + if ( + path.includes('/node_modules/') || + path.includes('/.git/') || + path.includes('/dist/') || + path.includes('/.next/') + ) { return true; } const ext = extname(path).toLowerCase(); diff --git a/src/index.ts b/src/index.ts index ea502157..9dde2a9f 100644 --- a/src/index.ts +++ b/src/index.ts @@ -23,7 +23,9 @@ let errorResetTimer: ReturnType | null = null; function trackError(): void { consecutiveErrors++; if (errorResetTimer) clearTimeout(errorResetTimer); - errorResetTimer = setTimeout(() => { consecutiveErrors = 0; }, ERROR_RESET_MS); + errorResetTimer = setTimeout(() => { + consecutiveErrors = 0; + }, ERROR_RESET_MS); if (consecutiveErrors >= MAX_CONSECUTIVE_ERRORS) { console.error(`[FATAL] ${MAX_CONSECUTIVE_ERRORS} consecutive unhandled errors — exiting for systemd restart`); diff --git a/src/mux-interface.ts b/src/mux-interface.ts index e3a91ecc..6007e472 100644 --- a/src/mux-interface.ts +++ b/src/mux-interface.ts @@ -7,7 +7,14 @@ */ import type { EventEmitter } from 'node:events'; -import type { ProcessStats, PersistedRespawnConfig, NiceConfig, ClaudeMode, SessionMode, OpenCodeConfig } from './types.js'; +import type { + ProcessStats, + PersistedRespawnConfig, + NiceConfig, + ClaudeMode, + SessionMode, + OpenCodeConfig, +} from './types.js'; /** * Multiplexer session metadata. diff --git a/src/plan-orchestrator.ts b/src/plan-orchestrator.ts index 98bf9141..8d61482d 100644 --- a/src/plan-orchestrator.ts +++ b/src/plan-orchestrator.ts @@ -19,10 +19,7 @@ import { Session } from './session.js'; import type { TerminalMultiplexer } from './mux-interface.js'; import { existsSync, mkdirSync, writeFileSync } from 'node:fs'; import { join } from 'node:path'; -import { - RESEARCH_AGENT_PROMPT, - PLANNER_PROMPT, -} from './prompts/index.js'; +import { RESEARCH_AGENT_PROMPT, PLANNER_PROMPT } from './prompts/index.js'; import { PlanTaskStatus, TddPhase } from './types.js'; // ============================================================================ @@ -170,7 +167,7 @@ export class PlanOrchestrator { mux: TerminalMultiplexer, workingDir: string = process.cwd(), outputDir?: string, - modelConfig?: { defaultModel?: string; agentTypeOverrides?: Record }, + modelConfig?: { defaultModel?: string; agentTypeOverrides?: Record } ) { this.mux = mux; this.workingDir = workingDir; @@ -193,7 +190,11 @@ export class PlanOrchestrator { } const promptPath = join(agentDir, 'prompt.md'); - writeFileSync(promptPath, `# ${agentType} Agent Prompt\n\nGenerated: ${new Date().toISOString()}\nDuration: ${(durationMs / 1000).toFixed(1)}s\n\n## Task\n${this.taskDescription}\n\n## Prompt\n${prompt}\n`, 'utf-8'); + writeFileSync( + promptPath, + `# ${agentType} Agent Prompt\n\nGenerated: ${new Date().toISOString()}\nDuration: ${(durationMs / 1000).toFixed(1)}s\n\n## Task\n${this.taskDescription}\n\n## Prompt\n${prompt}\n`, + 'utf-8' + ); const resultPath = join(agentDir, 'result.json'); writeFileSync(resultPath, JSON.stringify(result, null, 2), 'utf-8'); @@ -227,9 +228,9 @@ export class PlanOrchestrator { private generateSummary(result: DetailedPlanResult): string { const items = result.items || []; - const p0 = items.filter(i => i.priority === 'P0'); - const p1 = items.filter(i => i.priority === 'P1'); - const p2 = items.filter(i => i.priority === 'P2'); + const p0 = items.filter((i) => i.priority === 'P0'); + const p1 = items.filter((i) => i.priority === 'P1'); + const p2 = items.filter((i) => i.priority === 'P2'); let md = `# Plan Summary\n\n`; md += `Generated: ${new Date().toISOString()}\n`; @@ -392,10 +393,29 @@ export class PlanOrchestrator { const startTime = Date.now(); if (this.cancelled) { - return { success: false, findings: { externalResources: [], codebasePatterns: [], technicalRecommendations: [], potentialChallenges: [], recommendedTools: [] }, enrichedTaskDescription: taskDescription, error: 'Cancelled', durationMs: 0 }; + return { + success: false, + findings: { + externalResources: [], + codebasePatterns: [], + technicalRecommendations: [], + potentialChallenges: [], + recommendedTools: [], + }, + enrichedTaskDescription: taskDescription, + error: 'Cancelled', + durationMs: 0, + }; } - onSubagent?.({ type: 'started', agentId, agentType: 'research', model: this.researchModel, status: 'running', detail: 'Researching...' }); + onSubagent?.({ + type: 'started', + agentId, + agentType: 'research', + model: this.researchModel, + status: 'running', + detail: 'Researching...', + }); const session = new Session({ workingDir: this.workingDir, @@ -411,7 +431,14 @@ export class PlanOrchestrator { // Start progress interval before try block to ensure cleanup in finally const progressInterval = setInterval(() => { const elapsed = Math.floor((Date.now() - startTime) / 1000); - onSubagent?.({ type: 'progress', agentId, agentType: 'research', model: this.researchModel, status: 'running', detail: `${elapsed}s elapsed` }); + onSubagent?.({ + type: 'progress', + agentId, + agentType: 'research', + model: this.researchModel, + status: 'running', + detail: `${elapsed}s elapsed`, + }); }, 30000); try { @@ -424,14 +451,54 @@ export class PlanOrchestrator { // Extract JSON from response const jsonMatch = response.match(/\{[\s\S]*\}/); if (!jsonMatch) { - onSubagent?.({ type: 'failed', agentId, agentType: 'research', model: this.researchModel, status: 'failed', error: 'No JSON found', durationMs }); - return { success: false, findings: { externalResources: [], codebasePatterns: [], technicalRecommendations: [], potentialChallenges: [], recommendedTools: [] }, enrichedTaskDescription: taskDescription, error: 'No JSON in response', durationMs }; + onSubagent?.({ + type: 'failed', + agentId, + agentType: 'research', + model: this.researchModel, + status: 'failed', + error: 'No JSON found', + durationMs, + }); + return { + success: false, + findings: { + externalResources: [], + codebasePatterns: [], + technicalRecommendations: [], + potentialChallenges: [], + recommendedTools: [], + }, + enrichedTaskDescription: taskDescription, + error: 'No JSON in response', + durationMs, + }; } const parsed = tryParseJSON(jsonMatch[0]); if (!parsed.success) { - onSubagent?.({ type: 'failed', agentId, agentType: 'research', model: this.researchModel, status: 'failed', error: parsed.error, durationMs }); - return { success: false, findings: { externalResources: [], codebasePatterns: [], technicalRecommendations: [], potentialChallenges: [], recommendedTools: [] }, enrichedTaskDescription: taskDescription, error: parsed.error, durationMs }; + onSubagent?.({ + type: 'failed', + agentId, + agentType: 'research', + model: this.researchModel, + status: 'failed', + error: parsed.error, + durationMs, + }); + return { + success: false, + findings: { + externalResources: [], + codebasePatterns: [], + technicalRecommendations: [], + potentialChallenges: [], + recommendedTools: [], + }, + enrichedTaskDescription: taskDescription, + error: parsed.error, + durationMs, + }; } const data = parsed.data as Record; @@ -444,20 +511,48 @@ export class PlanOrchestrator { potentialChallenges: Array.isArray(data.potentialChallenges) ? data.potentialChallenges : [], recommendedTools: Array.isArray(data.recommendedTools) ? data.recommendedTools : [], }, - enrichedTaskDescription: typeof data.enrichedTaskDescription === 'string' ? data.enrichedTaskDescription : taskDescription, + enrichedTaskDescription: + typeof data.enrichedTaskDescription === 'string' ? data.enrichedTaskDescription : taskDescription, durationMs, }; this.saveAgentOutput('research', prompt, result, durationMs); - onSubagent?.({ type: 'completed', agentId, agentType: 'research', model: this.researchModel, status: 'completed', durationMs }); + onSubagent?.({ + type: 'completed', + agentId, + agentType: 'research', + model: this.researchModel, + status: 'completed', + durationMs, + }); return result; } catch (err) { this.runningSessions.delete(session); const durationMs = Date.now() - startTime; const error = err instanceof Error ? err.message : String(err); - onSubagent?.({ type: 'failed', agentId, agentType: 'research', model: this.researchModel, status: 'failed', error, durationMs }); - return { success: false, findings: { externalResources: [], codebasePatterns: [], technicalRecommendations: [], potentialChallenges: [], recommendedTools: [] }, enrichedTaskDescription: taskDescription, error, durationMs }; + onSubagent?.({ + type: 'failed', + agentId, + agentType: 'research', + model: this.researchModel, + status: 'failed', + error, + durationMs, + }); + return { + success: false, + findings: { + externalResources: [], + codebasePatterns: [], + technicalRecommendations: [], + potentialChallenges: [], + recommendedTools: [], + }, + enrichedTaskDescription: taskDescription, + error, + durationMs, + }; } finally { // Always clear the progress interval to prevent memory leaks clearInterval(progressInterval); @@ -469,7 +564,13 @@ export class PlanOrchestrator { researchContext: string, onProgress?: ProgressCallback, onSubagent?: SubagentCallback - ): Promise<{ success: boolean; items?: PlanItem[]; gaps?: string[]; warnings?: string[]; error?: string }> { + ): Promise<{ + success: boolean; + items?: PlanItem[]; + gaps?: string[]; + warnings?: string[]; + error?: string; + }> { const agentId = `planner-${Date.now()}`; const startTime = Date.now(); @@ -477,7 +578,14 @@ export class PlanOrchestrator { return { success: false, error: 'Cancelled' }; } - onSubagent?.({ type: 'started', agentId, agentType: 'planner', model: this.plannerModel, status: 'running', detail: 'Generating plan...' }); + onSubagent?.({ + type: 'started', + agentId, + agentType: 'planner', + model: this.plannerModel, + status: 'running', + detail: 'Generating plan...', + }); const session = new Session({ workingDir: this.workingDir, @@ -488,14 +596,22 @@ export class PlanOrchestrator { this.runningSessions.add(session); - const prompt = PLANNER_PROMPT - .replace('{TASK}', taskDescription) - .replace('{RESEARCH_CONTEXT}', researchContext || ''); + const prompt = PLANNER_PROMPT.replace('{TASK}', taskDescription).replace( + '{RESEARCH_CONTEXT}', + researchContext || '' + ); // Start progress interval before try block to ensure cleanup in finally const progressInterval = setInterval(() => { const elapsed = Math.floor((Date.now() - startTime) / 1000); - onSubagent?.({ type: 'progress', agentId, agentType: 'planner', model: this.plannerModel, status: 'running', detail: `${elapsed}s elapsed` }); + onSubagent?.({ + type: 'progress', + agentId, + agentType: 'planner', + model: this.plannerModel, + status: 'running', + detail: `${elapsed}s elapsed`, + }); }, 30000); try { @@ -508,13 +624,29 @@ export class PlanOrchestrator { // Extract JSON from response const jsonMatch = response.match(/\{[\s\S]*\}/); if (!jsonMatch) { - onSubagent?.({ type: 'failed', agentId, agentType: 'planner', model: this.plannerModel, status: 'failed', error: 'No JSON found', durationMs }); + onSubagent?.({ + type: 'failed', + agentId, + agentType: 'planner', + model: this.plannerModel, + status: 'failed', + error: 'No JSON found', + durationMs, + }); return { success: false, error: 'No JSON in response' }; } const parsed = tryParseJSON(jsonMatch[0]); if (!parsed.success) { - onSubagent?.({ type: 'failed', agentId, agentType: 'planner', model: this.plannerModel, status: 'failed', error: parsed.error, durationMs }); + onSubagent?.({ + type: 'failed', + agentId, + agentType: 'planner', + model: this.plannerModel, + status: 'failed', + error: parsed.error, + durationMs, + }); return { success: false, error: parsed.error }; } @@ -524,7 +656,15 @@ export class PlanOrchestrator { const warnings: string[] = Array.isArray(data.warnings) ? data.warnings : []; this.saveAgentOutput('planner', prompt, { items, gaps, warnings }, durationMs); - onSubagent?.({ type: 'completed', agentId, agentType: 'planner', model: this.plannerModel, status: 'completed', itemCount: items.length, durationMs }); + onSubagent?.({ + type: 'completed', + agentId, + agentType: 'planner', + model: this.plannerModel, + status: 'completed', + itemCount: items.length, + durationMs, + }); onProgress?.('planning', `Generated ${items.length} tasks`); @@ -533,7 +673,15 @@ export class PlanOrchestrator { this.runningSessions.delete(session); const durationMs = Date.now() - startTime; const error = err instanceof Error ? err.message : String(err); - onSubagent?.({ type: 'failed', agentId, agentType: 'planner', model: this.plannerModel, status: 'failed', error, durationMs }); + onSubagent?.({ + type: 'failed', + agentId, + agentType: 'planner', + model: this.plannerModel, + status: 'failed', + error, + durationMs, + }); return { success: false, error }; } finally { // Always clear the progress interval to prevent memory leaks diff --git a/src/ralph-loop.ts b/src/ralph-loop.ts index cf3980dd..f561a756 100644 --- a/src/ralph-loop.ts +++ b/src/ralph-loop.ts @@ -282,10 +282,7 @@ export class RalphLoop extends EventEmitter { this.store.setRalphLoopState({ lastCheckAt: Date.now() }); // Run independent checks in parallel for better performance - await Promise.all([ - this.checkTimeouts(), - this.assignTasks(), - ]); + await Promise.all([this.checkTimeouts(), this.assignTasks()]); // Check if we should auto-generate tasks (depends on assignment results) if (this.autoGenerateTasks && this.shouldGenerateTasks()) { @@ -409,11 +406,7 @@ export class RalphLoop extends EventEmitter { // 2. Min duration not reached // 3. We have idle sessions const counts = this.taskQueue.getCount(); - return ( - counts.pending === 0 && - !this.isMinDurationReached() && - this.sessionManager.getIdleSessions().length > 0 - ); + return counts.pending === 0 && !this.isMinDurationReached() && this.sessionManager.getIdleSessions().length > 0; } private async generateFollowUpTasks(): Promise { diff --git a/src/ralph-tracker.ts b/src/ralph-tracker.ts index 868a2e11..46e5e9a6 100644 --- a/src/ralph-tracker.ts +++ b/src/ralph-tracker.ts @@ -34,12 +34,7 @@ import { PlanTaskStatus, TddPhase, } from './types.js'; -import { - ANSI_ESCAPE_PATTERN_SIMPLE, - fuzzyPhraseMatch, - todoContentHash, - stringSimilarity, -} from './utils/index.js'; +import { ANSI_ESCAPE_PATTERN_SIMPLE, fuzzyPhraseMatch, todoContentHash, stringSimilarity } from './utils/index.js'; import { MAX_LINE_BUFFER_SIZE } from './config/buffer-limits.js'; import { MAX_TODOS_PER_SESSION } from './config/map-limits.js'; @@ -151,8 +146,19 @@ const MAX_PLAN_HISTORY = 10; * P1-002: Configurable false positive prevention */ const COMMON_COMPLETION_PHRASES = new Set([ - 'DONE', 'COMPLETE', 'FINISHED', 'OK', 'YES', 'TRUE', 'SUCCESS', - 'READY', 'COMPLETED', 'PASSED', 'END', 'STOP', 'EXIT', + 'DONE', + 'COMPLETE', + 'FINISHED', + 'OK', + 'YES', + 'TRUE', + 'SUCCESS', + 'READY', + 'COMPLETED', + 'PASSED', + 'END', + 'STOP', + 'EXIT', ]); /** @@ -249,9 +255,9 @@ const TODO_PLAIN_CHECKMARK_PATTERN = /✔\s+(.+)/g; * Prevents false positives from tool invocations and Claude commentary */ const TODO_EXCLUDE_PATTERNS = [ - /^(?:Bash|Search|Read|Write|Glob|Grep|Edit|Task)\s*\(/i, // Tool invocations - /^(?:I'll |Let me |Now I|First,|Task \d+:|Result:|Error:)/i, // Claude commentary - /^\S+\([^)]+\)$/, // Generic function call pattern + /^(?:Bash|Search|Read|Write|Glob|Grep|Edit|Task)\s*\(/i, // Tool invocations + /^(?:I'll |Let me |Now I|First,|Task \d+:|Result:|Error:)/i, // Claude commentary + /^\S+\([^)]+\)$/, // Generic function call pattern ]; // ---------- Loop Status Patterns ---------- @@ -313,7 +319,8 @@ const TODOWRITE_PATTERN = /TodoWrite|todo(?:s)?\s*(?:updated|written|saved)|Todo * Examples: "All 8 files have been created", "All tasks completed", "Everything is done" * Used to mark all tracked todos as complete at once */ -const ALL_COMPLETE_PATTERN = /all\s+(?:\d+\s+)?(?:tasks?|files?|items?)\s+(?:have\s+been\s+|are\s+)?(?:completed?|done|finished|created)|completed?\s+all\s+(?:\d+\s+)?tasks?|all\s+done|everything\s+(?:is\s+)?(?:completed?|done)|finished\s+all\s+tasks?/i; +const ALL_COMPLETE_PATTERN = + /all\s+(?:\d+\s+)?(?:tasks?|files?|items?)\s+(?:have\s+been\s+|are\s+)?(?:completed?|done|finished|created)|completed?\s+all\s+(?:\d+\s+)?tasks?|all\s+done|everything\s+(?:is\s+)?(?:completed?|done)|finished\s+all\s+tasks?/i; /** * Extracts count from "all N items" messages @@ -327,7 +334,8 @@ const ALL_COUNT_PATTERN = /all\s+(\d+)\s+(?:tasks?|files?|items?)/i; * Examples: "Task #5 is done", "marked as completed", "todo 3 finished" * Used to update specific todo items by number */ -const TASK_DONE_PATTERN = /(?:task|item|todo)\s*(?:#?\d+|"\s*[^"]+\s*")?\s*(?:is\s+)?(?:done|completed?|finished)|(?:completed?|done|finished)\s+(?:task|item)\s*(?:#?\d+)?|marking\s+(?:.*?\s+)?(?:as\s+)?completed?|marked\s+(?:.*?\s+)?(?:as\s+)?completed?/i; +const TASK_DONE_PATTERN = + /(?:task|item|todo)\s*(?:#?\d+|"\s*[^"]+\s*")?\s*(?:is\s+)?(?:done|completed?|finished)|(?:completed?|done|finished)\s+(?:task|item)\s*(?:#?\d+)?|marking\s+(?:.*?\s+)?(?:as\s+)?completed?|marked\s+(?:.*?\s+)?(?:as\s+)?completed?/i; // ---------- Utility Patterns ---------- @@ -411,48 +419,48 @@ const COMPLETION_INDICATOR_PATTERNS = [ /** P0 (Critical) priority patterns - highest severity issues */ const P0_PRIORITY_PATTERNS = [ - /\bP0\b|\(P0\)|:?\s*P0\s*:/, // Explicit P0 - /\bCRITICAL\b/, // Critical keyword - /\bBLOCKER\b/, // Blocker - /\bURGENT\b/, // Urgent - /\bSECURITY\b/, // Security issues - /\bCRASH(?:ES|ING)?\b/, // Crash, crashes, crashing - /\bBROKEN\b/, // Broken - /\bDATA\s*LOSS\b/, // Data loss - /\bPRODUCTION\s*(?:DOWN|ISSUE|BUG)\b/, // Production issues - /\bHOTFIX\b/, // Hotfix - /\bSEVERITY\s*1\b/, // Severity 1 + /\bP0\b|\(P0\)|:?\s*P0\s*:/, // Explicit P0 + /\bCRITICAL\b/, // Critical keyword + /\bBLOCKER\b/, // Blocker + /\bURGENT\b/, // Urgent + /\bSECURITY\b/, // Security issues + /\bCRASH(?:ES|ING)?\b/, // Crash, crashes, crashing + /\bBROKEN\b/, // Broken + /\bDATA\s*LOSS\b/, // Data loss + /\bPRODUCTION\s*(?:DOWN|ISSUE|BUG)\b/, // Production issues + /\bHOTFIX\b/, // Hotfix + /\bSEVERITY\s*1\b/, // Severity 1 ]; /** P1 (High) priority patterns - important issues requiring attention */ const P1_PRIORITY_PATTERNS = [ - /\bP1\b|\(P1\)|:?\s*P1\s*:/, // Explicit P1 - /\bHIGH\s*PRIORITY\b/, // High priority - /\bIMPORTANT\b/, // Important - /\bBUG\b/, // Bug - /\bFIX\b/, // Fix (as task type) - /\bERROR\b/, // Error - /\bFAIL(?:S|ED|ING|URE)?\b/, // Fail variants - /\bREGRESSION\b/, // Regression - /\bMUST\s*(?:HAVE|FIX|DO)\b/, // Must have/fix/do - /\bSEVERITY\s*2\b/, // Severity 2 - /\bREQUIRED\b/, // Required + /\bP1\b|\(P1\)|:?\s*P1\s*:/, // Explicit P1 + /\bHIGH\s*PRIORITY\b/, // High priority + /\bIMPORTANT\b/, // Important + /\bBUG\b/, // Bug + /\bFIX\b/, // Fix (as task type) + /\bERROR\b/, // Error + /\bFAIL(?:S|ED|ING|URE)?\b/, // Fail variants + /\bREGRESSION\b/, // Regression + /\bMUST\s*(?:HAVE|FIX|DO)\b/, // Must have/fix/do + /\bSEVERITY\s*2\b/, // Severity 2 + /\bREQUIRED\b/, // Required ]; /** P2 (Medium) priority patterns - lower priority improvements */ const P2_PRIORITY_PATTERNS = [ - /\bP2\b|\(P2\)|:?\s*P2\s*:/, // Explicit P2 - /\bNICE\s*TO\s*HAVE\b/, // Nice to have - /\bLOW\s*PRIORITY\b/, // Low priority - /\bREFACTOR\b/, // Refactor - /\bCLEANUP\b/, // Cleanup - /\bIMPROVE(?:MENT)?\b/, // Improve/Improvement - /\bOPTIMIZ(?:E|ATION)\b/, // Optimize/Optimization - /\bCONSIDER\b/, // Consider - /\bWOULD\s*BE\s*NICE\b/, // Would be nice - /\bENHANCE(?:MENT)?\b/, // Enhance/Enhancement - /\bTECH(?:NICAL)?\s*DEBT\b/, // Tech debt - /\bDOCUMENT(?:ATION)?\b/, // Documentation + /\bP2\b|\(P2\)|:?\s*P2\s*:/, // Explicit P2 + /\bNICE\s*TO\s*HAVE\b/, // Nice to have + /\bLOW\s*PRIORITY\b/, // Low priority + /\bREFACTOR\b/, // Refactor + /\bCLEANUP\b/, // Cleanup + /\bIMPROVE(?:MENT)?\b/, // Improve/Improvement + /\bOPTIMIZ(?:E|ATION)\b/, // Optimize/Optimization + /\bCONSIDER\b/, // Consider + /\bWOULD\s*BE\s*NICE\b/, // Would be nice + /\bENHANCE(?:MENT)?\b/, // Enhance/Enhancement + /\bTECH(?:NICAL)?\s*DEBT\b/, // Tech debt + /\bDOCUMENT(?:ATION)?\b/, // Documentation ]; // ========== Event Types ========== @@ -950,7 +958,7 @@ export class RalphTracker extends EventEmitter { const wasEnabled = this._loopState.enabled; this._loopState = createInitialRalphTrackerState(); - this._loopState.enabled = wasEnabled; // Keep enabled status + this._loopState.enabled = wasEnabled; // Keep enabled status this._todos.clear(); this._completionPhraseCount.clear(); this._taskNumberToContent.clear(); @@ -1241,7 +1249,7 @@ export class RalphTracker extends EventEmitter { // Check if all todos are complete (adds 20 points) const todoArray = Array.from(this._todos.values()); - if (todoArray.length > 0 && todoArray.every(t => t.status === 'completed')) { + if (todoArray.length > 0 && todoArray.every((t) => t.status === 'completed')) { signals.allTodosComplete = true; score += 20; } @@ -1262,10 +1270,12 @@ export class RalphTracker extends EventEmitter { if (context) { const lowerContext = context.toLowerCase(); // Deduct points if phrase appears in prompt-like context - if (lowerContext.includes('output:') || - lowerContext.includes('completion phrase') || - lowerContext.includes('output exactly') || - lowerContext.includes('when done')) { + if ( + lowerContext.includes('output:') || + lowerContext.includes('completion phrase') || + lowerContext.includes('output exactly') || + lowerContext.includes('when done') + ) { signals.contextAppropriate = false; score -= 20; } else { @@ -1335,7 +1345,6 @@ export class RalphTracker extends EventEmitter { * Use this when the caller has already stripped ANSI to avoid redundant regex work. */ processCleanData(cleanData: string): void { - // If tracker is disabled, only check for patterns that should auto-enable it if (!this._loopState.enabled) { // Don't auto-enable if explicitly disabled by user setting @@ -1396,14 +1405,21 @@ export class RalphTracker extends EventEmitter { // substrings that any pattern could match are present in the data. // This avoids 12 regex tests on every PTY chunk (the common case). if ( - !data.includes('<') && // , TodoWrite - !data.includes('ralph') && !data.includes('Ralph') && - !data.includes('Todo') && !data.includes('todo') && - !data.includes('Iteration') && !data.includes('[') && - !data.includes('\u2610') && !data.includes('\u2612') && // ☐ ☒ + !data.includes('<') && // , TodoWrite + !data.includes('ralph') && + !data.includes('Ralph') && + !data.includes('Todo') && + !data.includes('todo') && + !data.includes('Iteration') && + !data.includes('[') && + !data.includes('\u2610') && + !data.includes('\u2612') && // ☐ ☒ !data.includes('\u2714') && // ✔ - !data.includes('Loop') && !data.includes('complete') && - !data.includes('COMPLETE') && !data.includes('Done') && !data.includes('DONE') + !data.includes('Loop') && + !data.includes('complete') && + !data.includes('COMPLETE') && + !data.includes('Done') && + !data.includes('DONE') ) { return false; } @@ -1677,8 +1693,8 @@ export class RalphTracker extends EventEmitter { // Avoid false positives: don't trigger on prompt context const isNotInPromptContext = !line.includes('') && !line.includes('output:'); // Also avoid triggering on "completion phrase is X" explanatory text - const isNotExplanation = !line.toLowerCase().includes('completion phrase') && - !line.toLowerCase().includes('output exactly'); + const isNotExplanation = + !line.toLowerCase().includes('completion phrase') && !line.toLowerCase().includes('output exactly'); if (isNotInPromptContext && isNotExplanation) { this.handleBareCompletionPhrase(expectedPhrase); @@ -1786,7 +1802,7 @@ export class RalphTracker extends EventEmitter { if (matchedPhrase) { // Use the matched phrase (canonical) for tracking - const canonicalCount = (this._completionPhraseCount.get(matchedPhrase) || 0); + const canonicalCount = this._completionPhraseCount.get(matchedPhrase) || 0; // Require 2nd+ occurrence of canonical phrase OR explicitly active loop. // First occurrence (count=1) is the prompt echo — not actual completion. if (canonicalCount >= 2 || this._loopState.active) { @@ -1862,7 +1878,7 @@ export class RalphTracker extends EventEmitter { * @fires phraseValidationWarning - When a risky phrase is detected */ private validateCompletionPhrase(phrase: string): void { - const normalized = phrase.toUpperCase().replace(/[\s_\-\.]+/g, ''); + const normalized = phrase.toUpperCase().replace(/[\s_\-.]+/g, ''); // Generate a suggested unique phrase const uniqueSuffix = Date.now().toString(36).slice(-4).toUpperCase(); @@ -1870,7 +1886,9 @@ export class RalphTracker extends EventEmitter { // Check for common phrases if (COMMON_COMPLETION_PHRASES.has(normalized)) { - console.warn(`[RalphTracker] Warning: Completion phrase "${phrase}" is very common and may cause false positives. Consider using: "${suggestedPhrase}"`); + console.warn( + `[RalphTracker] Warning: Completion phrase "${phrase}" is very common and may cause false positives. Consider using: "${suggestedPhrase}"` + ); this.emit('phraseValidationWarning', { phrase, reason: 'common', @@ -1881,7 +1899,9 @@ export class RalphTracker extends EventEmitter { // Check for short phrases if (normalized.length < MIN_RECOMMENDED_PHRASE_LENGTH) { - console.warn(`[RalphTracker] Warning: Completion phrase "${phrase}" is too short (${normalized.length} chars). Consider using: "${suggestedPhrase}"`); + console.warn( + `[RalphTracker] Warning: Completion phrase "${phrase}" is too short (${normalized.length} chars). Consider using: "${suggestedPhrase}"` + ); this.emit('phraseValidationWarning', { phrase, reason: 'short', @@ -1892,7 +1912,9 @@ export class RalphTracker extends EventEmitter { // Check for numeric-only phrases if (/^\d+$/.test(normalized)) { - console.warn(`[RalphTracker] Warning: Completion phrase "${phrase}" is numeric-only and may cause false positives. Consider using: "${suggestedPhrase}"`); + console.warn( + `[RalphTracker] Warning: Completion phrase "${phrase}" is numeric-only and may cause false positives. Consider using: "${suggestedPhrase}"` + ); this.emit('phraseValidationWarning', { phrase, reason: 'numeric', @@ -1971,14 +1993,16 @@ export class RalphTracker extends EventEmitter { if (currentIter !== this._lastObservedIteration) { this._lastIterationChangeTime = Date.now(); this._lastObservedIteration = currentIter; - this._iterationStallWarned = false; // Reset warning on iteration change + this._iterationStallWarned = false; // Reset warning on iteration change // P1-004: Reset circuit breaker on successful iteration progress // If we're making progress, the loop is healthy - if (this._circuitBreaker.state === 'HALF_OPEN' || - this._circuitBreaker.consecutiveNoProgress > 0 || - this._circuitBreaker.consecutiveSameError > 0 || - this._circuitBreaker.consecutiveTestsFailure > 0) { + if ( + this._circuitBreaker.state === 'HALF_OPEN' || + this._circuitBreaker.consecutiveNoProgress > 0 || + this._circuitBreaker.consecutiveSameError > 0 || + this._circuitBreaker.consecutiveTestsFailure > 0 + ) { this._circuitBreaker.consecutiveNoProgress = 0; this._circuitBreaker.consecutiveSameError = 0; this._circuitBreaker.lastProgressIteration = currentIter; @@ -2106,7 +2130,7 @@ export class RalphTracker extends EventEmitter { const content = match[2].trim(); // Skip if content matches exclude patterns (tool invocations, commentary) - const shouldExclude = TODO_EXCLUDE_PATTERNS.some(pattern => pattern.test(content)); + const shouldExclude = TODO_EXCLUDE_PATTERNS.some((pattern) => pattern.test(content)); if (shouldExclude) continue; // Skip if content is too short or looks like partial garbage @@ -2155,9 +2179,8 @@ export class RalphTracker extends EventEmitter { while ((match = TODO_TASK_STATUS_PATTERN.exec(line)) !== null) { const taskNum = parseInt(match[1], 10); const statusStr = match[2].trim(); - const status: RalphTodoStatus = statusStr === 'completed' ? 'completed' - : statusStr === 'in progress' ? 'in_progress' - : 'pending'; + const status: RalphTodoStatus = + statusStr === 'completed' ? 'completed' : statusStr === 'in progress' ? 'in_progress' : 'pending'; const content = this._taskNumberToContent.get(taskNum); if (content) { this.upsertTodo(content, status); @@ -2172,7 +2195,7 @@ export class RalphTracker extends EventEmitter { while ((match = TODO_PLAIN_CHECKMARK_PATTERN.exec(line)) !== null) { const content = match[1].trim(); // Skip if content matches exclude patterns - const shouldExclude = TODO_EXCLUDE_PATTERNS.some(pattern => pattern.test(content)); + const shouldExclude = TODO_EXCLUDE_PATTERNS.some((pattern) => pattern.test(content)); if (shouldExclude) continue; if (content.length < 5) continue; // Skip status/created/updated prefixed content (already handled above) @@ -2204,17 +2227,17 @@ export class RalphTracker extends EventEmitter { switch (icon) { case '✓': case '✅': - case '☒': // Claude Code checked checkbox - case '◉': // Filled circle (completed) - case '●': // Solid circle (completed) + case '☒': // Claude Code checked checkbox + case '◉': // Filled circle (completed) + case '●': // Solid circle (completed) return 'completed'; - case '◐': // Half-filled circle (in progress) + case '◐': // Half-filled circle (in progress) case '⏳': case '⌛': case '🔄': return 'in_progress'; - case '☐': // Claude Code empty checkbox - case '○': // Empty circle + case '☐': // Claude Code empty checkbox + case '○': // Empty circle default: return 'pending'; } @@ -2280,10 +2303,10 @@ export class RalphTracker extends EventEmitter { // Clean content: remove ANSI codes, collapse whitespace, trim const cleanContent = content - .replace(ANSI_ESCAPE_PATTERN_SIMPLE, '') // Remove ANSI escape codes - .replace(/\s+/g, ' ') // Collapse whitespace + .replace(ANSI_ESCAPE_PATTERN_SIMPLE, '') // Remove ANSI escape codes + .replace(/\s+/g, ' ') // Collapse whitespace .trim(); - if (cleanContent.length < 5) return; // Skip very short content + if (cleanContent.length < 5) return; // Skip very short content // Parse priority from content const priority = this.parsePriority(cleanContent); @@ -2402,8 +2425,8 @@ export class RalphTracker extends EventEmitter { private normalizeTodoContent(content: string): string { if (!content) return ''; return content - .replace(/\s+/g, ' ') // Collapse whitespace - .replace(/[^a-zA-Z0-9\s.,!?'"-]/g, '') // Remove special chars (keep punctuation) + .replace(/\s+/g, ' ') // Collapse whitespace + .replace(/[^a-zA-Z0-9\s.,!?'"-]/g, '') // Remove special chars (keep punctuation) .trim() .toLowerCase(); } @@ -2507,7 +2530,7 @@ export class RalphTracker extends EventEmitter { if (normalized.length < 30) { threshold = 0.95; // Very strict for short strings } else if (normalized.length < 60) { - threshold = 0.90; // Strict for medium strings + threshold = 0.9; // Strict for medium strings } else { threshold = TODO_SIMILARITY_THRESHOLD; // 0.85 for longer strings } @@ -2563,14 +2586,7 @@ export class RalphTracker extends EventEmitter { ]; // Moderate: Bugs, features, enhancements - const moderatePatterns = [ - /\bbug\b/, - /\bfeature\b/, - /\benhance(?:ment)?\b/, - /\bimplement\b/, - /\badd\b/, - /\bfix\b/, - ]; + const moderatePatterns = [/\bbug\b/, /\bfeature\b/, /\benhance(?:ment)?\b/, /\bimplement\b/, /\badd\b/, /\bfix\b/]; for (const pattern of complexPatterns) { if (pattern.test(lower)) return 'complex'; @@ -2609,10 +2625,10 @@ export class RalphTracker extends EventEmitter { // Default estimates (in ms) based on typical task durations const defaults = { - trivial: 1 * 60 * 1000, // 1 minute - simple: 3 * 60 * 1000, // 3 minutes - moderate: 10 * 60 * 1000, // 10 minutes - complex: 30 * 60 * 1000, // 30 minutes + trivial: 1 * 60 * 1000, // 1 minute + simple: 3 * 60 * 1000, // 3 minutes + moderate: 10 * 60 * 1000, // 10 minutes + complex: 30 * 60 * 1000, // 30 minutes }; return defaults[complexity]; } @@ -2671,9 +2687,9 @@ export class RalphTracker extends EventEmitter { public getTodoProgress(): RalphTodoProgress { const todos = Array.from(this._todos.values()); const total = todos.length; - const completed = todos.filter(t => t.status === 'completed').length; - const inProgress = todos.filter(t => t.status === 'in_progress').length; - const pending = todos.filter(t => t.status === 'pending').length; + const completed = todos.filter((t) => t.status === 'completed').length; + const inProgress = todos.filter((t) => t.status === 'in_progress').length; + const pending = todos.filter((t) => t.status === 'pending').length; const percentComplete = total > 0 ? Math.round((completed / total) * 100) : 0; @@ -2983,7 +2999,7 @@ export class RalphTracker extends EventEmitter { // Ensure enabled flag exists (backwards compatibility) this._loopState = { ...loopState, - enabled: loopState.enabled ?? false, // Override after spread for backwards compat + enabled: loopState.enabled ?? false, // Override after spread for backwards compat }; this._todos.clear(); for (const todo of todos) { @@ -3068,7 +3084,9 @@ export class RalphTracker extends EventEmitter { if (!Number.isNaN(value) && value >= 0) { block.tasksCompletedThisLoop = value; } else { - parseErrors.push(`Invalid TASKS_COMPLETED_THIS_LOOP value: "${tasksMatch[1]}". Expected: non-negative integer`); + parseErrors.push( + `Invalid TASKS_COMPLETED_THIS_LOOP value: "${tasksMatch[1]}". Expected: non-negative integer` + ); } matched = true; } @@ -3104,7 +3122,9 @@ export class RalphTracker extends EventEmitter { if (['IMPLEMENTATION', 'TESTING', 'DOCUMENTATION', 'REFACTORING'].includes(value)) { block.workType = value as RalphWorkType; } else { - parseErrors.push(`Invalid WORK_TYPE value: "${value}". Expected: IMPLEMENTATION, TESTING, DOCUMENTATION, or REFACTORING`); + parseErrors.push( + `Invalid WORK_TYPE value: "${value}". Expected: IMPLEMENTATION, TESTING, DOCUMENTATION, or REFACTORING` + ); } matched = true; } @@ -3126,7 +3146,7 @@ export class RalphTracker extends EventEmitter { // Track unknown fields for debugging (only if looks like a field) if (!matched && trimmedLine.includes(':')) { const fieldName = trimmedLine.split(':')[0].trim().toUpperCase(); - if (fieldName && !['#', '//'].some(c => fieldName.startsWith(c))) { + if (fieldName && !['#', '//'].some((c) => fieldName.startsWith(c))) { unknownFields.push(fieldName); } } @@ -3221,11 +3241,7 @@ export class RalphTracker extends EventEmitter { * @param status - Overall status from RALPH_STATUS * @fires circuitBreakerUpdate - If state changes */ - private updateCircuitBreaker( - hasProgress: boolean, - testsStatus: RalphTestsStatus, - status: RalphStatusValue - ): void { + private updateCircuitBreaker(hasProgress: boolean, testsStatus: RalphTestsStatus, status: RalphStatusValue): void { const prevState = this._circuitBreaker.state; if (hasProgress) { @@ -3319,7 +3335,11 @@ export class RalphTracker extends EventEmitter { /** * Get cumulative stats from status blocks. */ - get cumulativeStats(): { filesModified: number; tasksCompleted: number; completionIndicators: number } { + get cumulativeStats(): { + filesModified: number; + tasksCompleted: number; + completionIndicators: number; + } { return { filesModified: this._totalFilesModified, tasksCompleted: this._totalTasksCompleted, @@ -3456,7 +3476,7 @@ export class RalphTracker extends EventEmitter { const tasksHeaderPattern = /^##\s*Tasks/i; // Pattern for todo items - const todoPattern = /^-\s*\[([ x\-])\]\s*(.+)$/; + const todoPattern = /^-\s*\[([ x-])\]\s*(.+)$/; let inCompletedSection = false; @@ -3504,7 +3524,7 @@ export class RalphTracker extends EventEmitter { } // Parse priority from content if not in a priority section - const parsedPriority = inCompletedSection ? null : (currentPriority || this.parsePriority(content)); + const parsedPriority = inCompletedSection ? null : currentPriority || this.parsePriority(content); const id = this.generateTodoId(content); newTodos.push({ @@ -3535,17 +3555,19 @@ export class RalphTracker extends EventEmitter { * Initialize plan tasks from generated plan items. * Called when wizard generates a new plan. */ - initializePlanTasks(items: Array<{ - id?: string; - content: string; - priority?: 'P0' | 'P1' | 'P2' | null; - verificationCriteria?: string; - testCommand?: string; - dependencies?: string[]; - tddPhase?: TddPhase; - pairedWith?: string; - complexity?: 'low' | 'medium' | 'high'; - }>): void { + initializePlanTasks( + items: Array<{ + id?: string; + content: string; + priority?: 'P0' | 'P1' | 'P2' | null; + verificationCriteria?: string; + testCommand?: string; + dependencies?: string[]; + tddPhase?: TddPhase; + pairedWith?: string; + complexity?: 'low' | 'medium' | 'high'; + }> + ): void { // Save current plan to history before replacing if (this._planTasks.size > 0) { this._savePlanToHistory('Plan replaced with new generation'); @@ -3580,11 +3602,14 @@ export class RalphTracker extends EventEmitter { /** * Update a specific plan task's status, attempts, or error. */ - updatePlanTask(taskId: string, update: { - status?: PlanTaskStatus; - error?: string; - incrementAttempts?: boolean; - }): { success: boolean; task?: EnhancedPlanTask; error?: string } { + updatePlanTask( + taskId: string, + update: { + status?: PlanTaskStatus; + error?: string; + incrementAttempts?: boolean; + } + ): { success: boolean; task?: EnhancedPlanTask; error?: string } { const task = this._planTasks.get(taskId); if (!task) { return { success: false, error: 'Task not found' }; @@ -3635,7 +3660,7 @@ export class RalphTracker extends EventEmitter { for (const [_, task] of this._planTasks) { if (task.dependencies.includes(completedTaskId)) { // Check if all dependencies are now complete - const allDepsComplete = task.dependencies.every(depId => { + const allDepsComplete = task.dependencies.every((depId) => { const dep = this._planTasks.get(depId); return dep && dep.status === 'completed'; }); @@ -3653,8 +3678,7 @@ export class RalphTracker extends EventEmitter { */ private _checkForCheckpoint(): void { const currentIteration = this._loopState.cycleCount; - if (this._checkpointIterations.includes(currentIteration) && - currentIteration > this._lastCheckpointIteration) { + if (this._checkpointIterations.includes(currentIteration) && currentIteration > this._lastCheckpointIteration) { this._lastCheckpointIteration = currentIteration; const checkpoint = this.generateCheckpointReview(); this.emit('planCheckpoint', checkpoint); @@ -3669,17 +3693,17 @@ export class RalphTracker extends EventEmitter { const summary = { total: tasks.length, - completed: tasks.filter(t => t.status === 'completed').length, - failed: tasks.filter(t => t.status === 'failed').length, - blocked: tasks.filter(t => t.status === 'blocked').length, - pending: tasks.filter(t => t.status === 'pending').length, - inProgress: tasks.filter(t => t.status === 'in_progress').length, + completed: tasks.filter((t) => t.status === 'completed').length, + failed: tasks.filter((t) => t.status === 'failed').length, + blocked: tasks.filter((t) => t.status === 'blocked').length, + pending: tasks.filter((t) => t.status === 'pending').length, + inProgress: tasks.filter((t) => t.status === 'in_progress').length, }; // Find stuck tasks (3+ attempts or blocked) const stuckTasks = tasks - .filter(t => t.attempts >= 3 || t.status === 'blocked') - .map(t => ({ + .filter((t) => t.attempts >= 3 || t.status === 'blocked') + .map((t) => ({ id: t.id, content: t.content, attempts: t.attempts, @@ -3697,9 +3721,7 @@ export class RalphTracker extends EventEmitter { recommendations.push('More tasks have failed than completed. Review approach and consider plan adjustment.'); } - const progressPercent = summary.total > 0 - ? Math.round((summary.completed / summary.total) * 100) - : 0; + const progressPercent = summary.total > 0 ? Math.round((summary.completed / summary.total) * 100) : 0; if (progressPercent < 20 && this._loopState.cycleCount > 10) { recommendations.push('Progress is slow. Consider simplifying tasks or reviewing dependencies.'); } @@ -3749,7 +3771,7 @@ export class RalphTracker extends EventEmitter { summary: string; stats: { total: number; completed: number; failed: number }; }> { - return this._planHistory.map(h => { + return this._planHistory.map((h) => { const tasks = Array.from(h.tasks.values()); return { version: h.version, @@ -3757,8 +3779,8 @@ export class RalphTracker extends EventEmitter { summary: h.summary, stats: { total: tasks.length, - completed: tasks.filter(t => t.status === 'completed').length, - failed: tasks.filter(t => t.status === 'failed').length, + completed: tasks.filter((t) => t.status === 'completed').length, + failed: tasks.filter((t) => t.status === 'failed').length, }, }; }); @@ -3767,8 +3789,12 @@ export class RalphTracker extends EventEmitter { /** * Rollback to a previous plan version. */ - rollbackToVersion(version: number): { success: boolean; plan?: EnhancedPlanTask[]; error?: string } { - const historyEntry = this._planHistory.find(h => h.version === version); + rollbackToVersion(version: number): { + success: boolean; + plan?: EnhancedPlanTask[]; + error?: string; + } { + const historyEntry = this._planHistory.find((h) => h.version === version); if (!historyEntry) { return { success: false, error: `Version ${version} not found in history` }; } @@ -3807,7 +3833,7 @@ export class RalphTracker extends EventEmitter { // Generate unique ID const existingIds = Array.from(this._planTasks.keys()); const prefix = task.priority || 'P1'; - let counter = existingIds.filter(id => id.startsWith(prefix)).length + 1; + let counter = existingIds.filter((id) => id.startsWith(prefix)).length + 1; let id = `${prefix}-${String(counter).padStart(3, '0')}`; while (this._planTasks.has(id)) { counter++; @@ -3850,8 +3876,7 @@ export class RalphTracker extends EventEmitter { */ isCheckpointDue(): boolean { const currentIteration = this._loopState.cycleCount; - return this._checkpointIterations.includes(currentIteration) && - currentIteration > this._lastCheckpointIteration; + return this._checkpointIterations.includes(currentIteration) && currentIteration > this._lastCheckpointIteration; } /** diff --git a/src/respawn-controller.ts b/src/respawn-controller.ts index da3113f7..5322ff9b 100644 --- a/src/respawn-controller.ts +++ b/src/respawn-controller.ts @@ -41,15 +41,8 @@ import { AiIdleChecker, type AiCheckResult, type AiCheckState } from './ai-idle- import { AiPlanChecker, type AiPlanCheckResult } from './ai-plan-checker.js'; import type { TeamWatcher } from './team-watcher.js'; import { BufferAccumulator } from './utils/buffer-accumulator.js'; -import { - ANSI_ESCAPE_PATTERN_SIMPLE, - TOKEN_PATTERN, - assertNever, -} from './utils/index.js'; -import { - MAX_RESPAWN_BUFFER_SIZE, - TRIM_RESPAWN_BUFFER_TO as RESPAWN_BUFFER_TRIM_SIZE, -} from './config/buffer-limits.js'; +import { ANSI_ESCAPE_PATTERN_SIMPLE, TOKEN_PATTERN, assertNever } from './utils/index.js'; +import { MAX_RESPAWN_BUFFER_SIZE, TRIM_RESPAWN_BUFFER_TO as RESPAWN_BUFFER_TRIM_SIZE } from './config/buffer-limits.js'; import type { RespawnCycleMetrics, RespawnAggregateMetrics, @@ -542,45 +535,45 @@ export interface RespawnEvents { /** Default configuration values */ const DEFAULT_CONFIG: RespawnConfig = { - idleTimeoutMs: 10000, // 10 seconds of no activity after prompt (legacy, still used as fallback) + idleTimeoutMs: 10000, // 10 seconds of no activity after prompt (legacy, still used as fallback) updatePrompt: 'write a brief progress summary to CLAUDE.md noting what you accomplished, then continue working.', - interStepDelayMs: 1000, // 1 second between steps + interStepDelayMs: 1000, // 1 second between steps enabled: true, - sendClear: true, // send /clear after update prompt - sendInit: true, // send /init after /clear - completionConfirmMs: 10000, // 10 seconds of silence after completion message - noOutputTimeoutMs: 30000, // 30 seconds fallback if no output at all - autoAcceptPrompts: true, // auto-accept plan mode prompts (not questions) - autoAcceptDelayMs: 8000, // 8 seconds before auto-accepting - aiIdleCheckEnabled: true, // use AI to confirm idle state + sendClear: true, // send /clear after update prompt + sendInit: true, // send /init after /clear + completionConfirmMs: 10000, // 10 seconds of silence after completion message + noOutputTimeoutMs: 30000, // 30 seconds fallback if no output at all + autoAcceptPrompts: true, // auto-accept plan mode prompts (not questions) + autoAcceptDelayMs: 8000, // 8 seconds before auto-accepting + aiIdleCheckEnabled: true, // use AI to confirm idle state aiIdleCheckModel: 'claude-opus-4-5-20251101', - aiIdleCheckMaxContext: 16000, // ~4k tokens - aiIdleCheckTimeoutMs: 90000, // 90 seconds (thinking can be slow) + aiIdleCheckMaxContext: 16000, // ~4k tokens + aiIdleCheckTimeoutMs: 90000, // 90 seconds (thinking can be slow) aiIdleCheckCooldownMs: 180000, // 3 minutes after WORKING verdict - aiPlanCheckEnabled: true, // use AI to confirm plan mode before auto-accept + aiPlanCheckEnabled: true, // use AI to confirm plan mode before auto-accept aiPlanCheckModel: 'claude-opus-4-5-20251101', - aiPlanCheckMaxContext: 8000, // ~2k tokens (plan mode UI is compact) - aiPlanCheckTimeoutMs: 60000, // 60 seconds (thinking can be slow) - aiPlanCheckCooldownMs: 30000, // 30 seconds after NOT_PLAN_MODE - stuckStateDetectionEnabled: true, // detect stuck states - stuckStateWarningMs: 300000, // 5 minutes warning threshold - stuckStateRecoveryMs: 600000, // 10 minutes recovery threshold - maxStuckRecoveries: 3, // max recovery attempts + aiPlanCheckMaxContext: 8000, // ~2k tokens (plan mode UI is compact) + aiPlanCheckTimeoutMs: 60000, // 60 seconds (thinking can be slow) + aiPlanCheckCooldownMs: 30000, // 30 seconds after NOT_PLAN_MODE + stuckStateDetectionEnabled: true, // detect stuck states + stuckStateWarningMs: 300000, // 5 minutes warning threshold + stuckStateRecoveryMs: 600000, // 10 minutes recovery threshold + maxStuckRecoveries: 3, // max recovery attempts // P2-001: Adaptive timing - adaptiveTimingEnabled: true, // Use adaptive timing based on historical patterns - adaptiveMinConfirmMs: 5000, // Minimum 5 seconds - adaptiveMaxConfirmMs: 30000, // Maximum 30 seconds + adaptiveTimingEnabled: true, // Use adaptive timing based on historical patterns + adaptiveMinConfirmMs: 5000, // Minimum 5 seconds + adaptiveMaxConfirmMs: 30000, // Maximum 30 seconds // P2-002: Skip-clear optimization - skipClearWhenLowContext: true, // Skip /clear when token count is low - skipClearThresholdPercent: 30, // Skip if below 30% of max context + skipClearWhenLowContext: true, // Skip /clear when token count is low + skipClearThresholdPercent: 30, // Skip if below 30% of max context // P2-004: Cycle metrics - trackCycleMetrics: true, // Track and persist cycle metrics + trackCycleMetrics: true, // Track and persist cycle metrics // P2-001: Confidence scoring - minIdleConfidence: 65, // Minimum confidence to trigger idle (0-100) - confidenceWeightCompletion: 40, // Weight for completion message - confidenceWeightSilence: 25, // Weight for output silence - confidenceWeightTokens: 20, // Weight for token stability - confidenceWeightNoWorking: 15, // Weight for working pattern absence + minIdleConfidence: 65, // Minimum confidence to trigger idle (0-100) + confidenceWeightCompletion: 40, // Weight for completion message + confidenceWeightSilence: 25, // Weight for output silence + confidenceWeightTokens: 20, // Weight for token stability + confidenceWeightNoWorking: 15, // Weight for working pattern absence }; /** @@ -737,7 +730,8 @@ export class RespawnController extends EventEmitter { // ========== Timer Tracking for UI Countdown Display ========== /** Active timers being tracked for UI display */ - private activeTimers: Map = new Map(); + private activeTimers: Map = + new Map(); /** Recent action log entries (for UI display, max 20) */ private recentActions: ActionLogEntry[] = []; @@ -818,9 +812,9 @@ export class RespawnController extends EventEmitter { * Used as secondary signals, not primary detection. */ private readonly PROMPT_PATTERNS = [ - '❯', // Standard prompt - '\u276f', // Unicode variant - '⏵', // Claude Code prompt variant + '❯', // Standard prompt + '\u276f', // Unicode variant + '⏵', // Claude Code prompt variant ]; /** @@ -829,15 +823,55 @@ export class RespawnController extends EventEmitter { * Note: ✻ and ✽ removed - they appear in completion messages too. */ private readonly WORKING_PATTERNS = [ - 'Thinking', 'Writing', 'Reading', 'Running', 'Searching', - 'Editing', 'Creating', 'Deleting', 'Analyzing', 'Executing', - 'Synthesizing', 'Brewing', // Claude's processing indicators - 'Compiling', 'Building', 'Installing', 'Fetching', 'Downloading', - 'Processing', 'Generating', 'Loading', 'Starting', 'Updating', - 'Checking', 'Validating', 'Testing', 'Formatting', 'Linting', - '⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏', // Spinner chars - '◐', '◓', '◑', '◒', // Alternative spinners - '⣾', '⣽', '⣻', '⢿', '⡿', '⣟', '⣯', '⣷', // Braille spinners + 'Thinking', + 'Writing', + 'Reading', + 'Running', + 'Searching', + 'Editing', + 'Creating', + 'Deleting', + 'Analyzing', + 'Executing', + 'Synthesizing', + 'Brewing', // Claude's processing indicators + 'Compiling', + 'Building', + 'Installing', + 'Fetching', + 'Downloading', + 'Processing', + 'Generating', + 'Loading', + 'Starting', + 'Updating', + 'Checking', + 'Validating', + 'Testing', + 'Formatting', + 'Linting', + '⠋', + '⠙', + '⠹', + '⠸', + '⠼', + '⠴', + '⠦', + '⠧', + '⠇', + '⠏', // Spinner chars + '◐', + '◓', + '◑', + '◒', // Alternative spinners + '⣾', + '⣽', + '⣻', + '⢿', + '⡿', + '⣟', + '⣯', + '⣷', // Braille spinners ]; /** @@ -1200,7 +1234,7 @@ export class RespawnController extends EventEmitter { const prevState = this._state; this._state = newState; this.stateEnteredAt = Date.now(); - this.stuckStateWarned = false; // Reset warning for new state + this.stuckStateWarned = false; // Reset warning for new state this.log(`State: ${prevState} → ${newState}`); this.logAction('state', `${prevState} → ${newState}`); this.emit('stateChanged', newState, prevState); @@ -1518,7 +1552,9 @@ export class RespawnController extends EventEmitter { this.setState('watching'); } else { // Real content (not just escape codes or single chars) - cancel confirmation - this.log(`Substantial output during confirmation ("${stripped.substring(0, 40)}..."), cancelling idle detection`); + this.log( + `Substantial output during confirmation ("${stripped.substring(0, 40)}..."), cancelling idle detection` + ); this.cancelCompletionConfirm(); } return; @@ -1526,7 +1562,7 @@ export class RespawnController extends EventEmitter { } // Legacy fallback: detect prompt characters (still useful for waiting_* states) - const hasPrompt = this.PROMPT_PATTERNS.some(pattern => data.includes(pattern)); + const hasPrompt = this.PROMPT_PATTERNS.some((pattern) => data.includes(pattern)); if (hasPrompt) { this.promptDetected = true; this.workingDetected = false; @@ -1706,7 +1742,7 @@ export class RespawnController extends EventEmitter { if (this._state === 'stopped') return; const prompt = this.config.kickstartPrompt!; this.logAction('command', `Sending kickstart: "${prompt.substring(0, 40)}..."`); - await this.session.writeViaMux(prompt + '\r'); // \r triggers key.return in Ink/Claude CLI + await this.session.writeViaMux(prompt + '\r'); // \r triggers key.return in Ink/Claude CLI this.emit('stepSent', 'kickstart', prompt); this.setState('waiting_kickstart'); this.promptDetected = false; @@ -1831,11 +1867,16 @@ export class RespawnController extends EventEmitter { if (this.stuckRecoveryCount < this.config.maxStuckRecoveries) { this.stuckRecoveryCount++; this.logAction('stuck', `Recovery attempt ${this.stuckRecoveryCount}/${this.config.maxStuckRecoveries}`); - this.log(`Stuck-state recovery triggered (state: ${this._state}, duration: ${Math.round(durationMs / 1000)}s, attempt: ${this.stuckRecoveryCount})`); + this.log( + `Stuck-state recovery triggered (state: ${this._state}, duration: ${Math.round(durationMs / 1000)}s, attempt: ${this.stuckRecoveryCount})` + ); this.emit('stuckStateRecovery', this._state, durationMs, this.stuckRecoveryCount); this.handleStuckStateRecovery(); } else { - this.logAction('stuck', `Max recoveries (${this.config.maxStuckRecoveries}) reached - manual intervention needed`); + this.logAction( + 'stuck', + `Max recoveries (${this.config.maxStuckRecoveries}) reached - manual intervention needed` + ); this.log(`Stuck-state: max recoveries reached, manual intervention needed`); } return; @@ -1950,12 +1991,7 @@ export class RespawnController extends EventEmitter { * Start a tracked timer with UI countdown support. * Emits timerStarted event and tracks the timer for UI display. */ - private startTrackedTimer( - name: string, - durationMs: number, - callback: () => void, - reason?: string - ): NodeJS.Timeout { + private startTrackedTimer(name: string, durationMs: number, callback: () => void, reason?: string): NodeJS.Timeout { const now = Date.now(); const endsAt = now + durationMs; @@ -1989,7 +2025,7 @@ export class RespawnController extends EventEmitter { */ getActiveTimers(): ActiveTimerInfo[] { const now = Date.now(); - return Array.from(this.activeTimers.values()).map(t => ({ + return Array.from(this.activeTimers.values()).map((t) => ({ name: t.name, remainingMs: Math.max(0, t.endsAt - now), totalMs: t.durationMs, @@ -2038,7 +2074,7 @@ export class RespawnController extends EventEmitter { } // Check the rolling window (includes current data, catches both complete and split patterns) - return this.WORKING_PATTERNS.some(pattern => this.workingPatternWindow.includes(pattern)); + return this.WORKING_PATTERNS.some((pattern) => this.workingPatternWindow.includes(pattern)); } /** @@ -2175,7 +2211,9 @@ export class RespawnController extends EventEmitter { // If on cooldown, don't start check - wait for cooldown to expire if (this.aiChecker.isOnCooldown()) { - this.log(`AI check on cooldown (${Math.ceil(this.aiChecker.getCooldownRemainingMs() / 1000)}s remaining), waiting...`); + this.log( + `AI check on cooldown (${Math.ceil(this.aiChecker.getCooldownRemainingMs() / 1000)}s remaining), waiting...` + ); return; } @@ -2207,67 +2245,70 @@ export class RespawnController extends EventEmitter { // Get the terminal buffer for analysis const buffer = this.terminalBuffer.value; - this.aiChecker.check(buffer).then((result) => { - // If state changed while checking (e.g., cancelled), ignore result - if (this._state !== 'ai_checking') { - this.log(`AI check result ignored (state is now ${this._state})`); - return; - } - - // Validate this is the result for the current check (not a stale one) - if (this._currentAiCheckId !== checkId) { - this.log(`AI check result ignored (stale check ID: ${checkId.substring(0, 8)})`); - return; - } - - if (result.verdict === 'IDLE') { - // Cancel any pending confirmation timers - AI has spoken - this.cancelTrackedTimer('completion-confirm', this.completionConfirmTimer, 'AI verdict: IDLE'); - this.completionConfirmTimer = null; - this.cancelTrackedTimer('pre-filter', this.preFilterTimer, 'AI verdict: IDLE'); - this.preFilterTimer = null; + this.aiChecker + .check(buffer) + .then((result) => { + // If state changed while checking (e.g., cancelled), ignore result + if (this._state !== 'ai_checking') { + this.log(`AI check result ignored (state is now ${this._state})`); + return; + } - this.logAction('ai-check', `Verdict: IDLE - ${result.reasoning}`); - this.emit('aiCheckCompleted', result); - this.onIdleConfirmed(`ai-check: idle (${result.reasoning})`); - } else if (result.verdict === 'WORKING') { - // Cancel timers and go to cooldown - this.cancelTrackedTimer('completion-confirm', this.completionConfirmTimer, 'AI verdict: WORKING'); - this.completionConfirmTimer = null; + // Validate this is the result for the current check (not a stale one) + if (this._currentAiCheckId !== checkId) { + this.log(`AI check result ignored (stale check ID: ${checkId.substring(0, 8)})`); + return; + } - this.logAction('ai-check', `Verdict: WORKING - ${result.reasoning}`); - this.emit('aiCheckCompleted', result); - this.setState('watching'); - this.log(`AI check says WORKING, returning to watching with ${this.config.aiIdleCheckCooldownMs}ms cooldown`); - // Restart timers so the controller retries after cooldown expires - this.startNoOutputTimer(); - this.startPreFilterTimer(); - } else { - // ERROR verdict - this.logAction('ai-check', `Error: ${result.reasoning}`); - this.emit('aiCheckFailed', result.reasoning); - this.setState('watching'); - // Restart timers to allow retry - this.startNoOutputTimer(); - this.startPreFilterTimer(); - } - }).catch((err) => { - // Validate this is the error for the current check - if (this._currentAiCheckId !== checkId) { - return; // Stale check, ignore error - } - if (this._state === 'stopped') return; // Guard against stopped state - if (this._state === 'ai_checking') { - const errorMsg = err instanceof Error ? err.message : String(err); - this.logAction('ai-check', `Failed: ${errorMsg.substring(0, 50)}`); - this.emit('aiCheckFailed', errorMsg); - this.setState('watching'); - this.log(`AI check error: ${errorMsg}`); - // Restart timers to allow retry - this.startNoOutputTimer(); - this.startPreFilterTimer(); - } - }); + if (result.verdict === 'IDLE') { + // Cancel any pending confirmation timers - AI has spoken + this.cancelTrackedTimer('completion-confirm', this.completionConfirmTimer, 'AI verdict: IDLE'); + this.completionConfirmTimer = null; + this.cancelTrackedTimer('pre-filter', this.preFilterTimer, 'AI verdict: IDLE'); + this.preFilterTimer = null; + + this.logAction('ai-check', `Verdict: IDLE - ${result.reasoning}`); + this.emit('aiCheckCompleted', result); + this.onIdleConfirmed(`ai-check: idle (${result.reasoning})`); + } else if (result.verdict === 'WORKING') { + // Cancel timers and go to cooldown + this.cancelTrackedTimer('completion-confirm', this.completionConfirmTimer, 'AI verdict: WORKING'); + this.completionConfirmTimer = null; + + this.logAction('ai-check', `Verdict: WORKING - ${result.reasoning}`); + this.emit('aiCheckCompleted', result); + this.setState('watching'); + this.log(`AI check says WORKING, returning to watching with ${this.config.aiIdleCheckCooldownMs}ms cooldown`); + // Restart timers so the controller retries after cooldown expires + this.startNoOutputTimer(); + this.startPreFilterTimer(); + } else { + // ERROR verdict + this.logAction('ai-check', `Error: ${result.reasoning}`); + this.emit('aiCheckFailed', result.reasoning); + this.setState('watching'); + // Restart timers to allow retry + this.startNoOutputTimer(); + this.startPreFilterTimer(); + } + }) + .catch((err) => { + // Validate this is the error for the current check + if (this._currentAiCheckId !== checkId) { + return; // Stale check, ignore error + } + if (this._state === 'stopped') return; // Guard against stopped state + if (this._state === 'ai_checking') { + const errorMsg = err instanceof Error ? err.message : String(err); + this.logAction('ai-check', `Failed: ${errorMsg.substring(0, 50)}`); + this.emit('aiCheckFailed', errorMsg); + this.setState('watching'); + this.log(`AI check error: ${errorMsg}`); + // Restart timers to allow retry + this.startNoOutputTimer(); + this.startPreFilterTimer(); + } + }); } // ========== Auto-Accept Prompt Methods ========== @@ -2351,7 +2392,9 @@ export class RespawnController extends EventEmitter { // Stage 2: AI confirmation (if enabled and available) if (this.config.aiPlanCheckEnabled && this.planChecker.status !== 'disabled') { if (this.planChecker.isOnCooldown()) { - this.log(`Skipping auto-accept: plan checker on cooldown (${Math.ceil(this.planChecker.getCooldownRemainingMs() / 1000)}s remaining)`); + this.log( + `Skipping auto-accept: plan checker on cooldown (${Math.ceil(this.planChecker.getCooldownRemainingMs() / 1000)}s remaining)` + ); return; } if (this.planChecker.status === 'checking') { @@ -2396,7 +2439,7 @@ export class RespawnController extends EventEmitter { // Working patterns before the selector are from earlier work and don't matter. const selectorIndex = stripped.lastIndexOf(selectorMatch[0]); const afterSelector = stripped.slice(selectorIndex + selectorMatch[0].length); - const hasWorking = this.WORKING_PATTERNS.some(pattern => afterSelector.includes(pattern)); + const hasWorking = this.WORKING_PATTERNS.some((pattern) => afterSelector.includes(pattern)); if (hasWorking) return false; return true; @@ -2416,36 +2459,39 @@ export class RespawnController extends EventEmitter { this.logAction('plan-check', 'Spawning AI plan checker'); this.emit('planCheckStarted'); - this.planChecker.check(buffer).then((result) => { - // Discard stale result if new output arrived during check - if (this.lastOutputTime > this.planCheckStartTime) { - this.logAction('plan-check', 'Result discarded (output arrived during check)'); - return; - } - - if (result.verdict === 'PLAN_MODE') { - // Don't send Enter if state changed (e.g., AI idle check started or respawn cycle began) - if (this._state !== 'watching') { - this.logAction('plan-check', `Verdict: PLAN_MODE but state is ${this._state}, not sending Enter`); + this.planChecker + .check(buffer) + .then((result) => { + // Discard stale result if new output arrived during check + if (this.lastOutputTime > this.planCheckStartTime) { + this.logAction('plan-check', 'Result discarded (output arrived during check)'); return; } - this.emit('planCheckCompleted', result); - this.logAction('plan-check', 'Verdict: PLAN_MODE - sending Enter immediately'); - this.sendAutoAcceptEnter(); - // No cooldown needed - we're taking action - } else if (result.verdict === 'NOT_PLAN_MODE') { - this.emit('planCheckCompleted', result); - this.logAction('plan-check', `Verdict: NOT_PLAN_MODE - ${result.reasoning}`); - } else { - // ERROR verdict - this.emit('planCheckFailed', result.reasoning); - this.logAction('plan-check', `Error: ${result.reasoning}`); - } - }).catch((err) => { - const errorMsg = err instanceof Error ? err.message : String(err); - this.emit('planCheckFailed', errorMsg); - this.logAction('plan-check', `Failed: ${errorMsg.substring(0, 50)}`); - }); + + if (result.verdict === 'PLAN_MODE') { + // Don't send Enter if state changed (e.g., AI idle check started or respawn cycle began) + if (this._state !== 'watching') { + this.logAction('plan-check', `Verdict: PLAN_MODE but state is ${this._state}, not sending Enter`); + return; + } + this.emit('planCheckCompleted', result); + this.logAction('plan-check', 'Verdict: PLAN_MODE - sending Enter immediately'); + this.sendAutoAcceptEnter(); + // No cooldown needed - we're taking action + } else if (result.verdict === 'NOT_PLAN_MODE') { + this.emit('planCheckCompleted', result); + this.logAction('plan-check', `Verdict: NOT_PLAN_MODE - ${result.reasoning}`); + } else { + // ERROR verdict + this.emit('planCheckFailed', result.reasoning); + this.logAction('plan-check', `Error: ${result.reasoning}`); + } + }) + .catch((err) => { + const errorMsg = err instanceof Error ? err.message : String(err); + this.emit('planCheckFailed', errorMsg); + this.logAction('plan-check', `Failed: ${errorMsg.substring(0, 50)}`); + }); } /** @@ -2765,11 +2811,13 @@ export class RespawnController extends EventEmitter { this.log(`Idle confirmed via: ${reason}`); const status = this.getDetectionStatus(); - this.log(`Detection status: confidence=${status.confidenceLevel}%, ` + - `completion=${status.completionMessageDetected}, ` + - `silent=${status.outputSilent}, ` + - `tokensStable=${status.tokensStable}, ` + - `noWorking=${status.workingPatternsAbsent}`); + this.log( + `Detection status: confidence=${status.confidenceLevel}%, ` + + `completion=${status.completionMessageDetected}, ` + + `silent=${status.outputSilent}, ` + + `tokensStable=${status.tokensStable}, ` + + `noWorking=${status.workingPatternsAbsent}` + ); // ========== Agent Teams Integration ========== // Check if session has active teammates — don't respawn while team is working @@ -2777,7 +2825,10 @@ export class RespawnController extends EventEmitter { const count = this.teamWatcher.getActiveTeammateCount(this.session.id); this.log(`Respawn blocked - ${count} active teammate(s) working`); this.logAction('team', `Active teammates: ${count}`); - this.emit('respawnBlocked', { reason: 'active_teammates', details: `${count} teammate(s) still working` }); + this.emit('respawnBlocked', { + reason: 'active_teammates', + details: `${count} teammate(s) still working`, + }); this.setState('watching'); this.startNoOutputTimer(); this.startPreFilterTimer(); @@ -2792,7 +2843,10 @@ export class RespawnController extends EventEmitter { if (circuitBreaker.state === 'OPEN') { this.log(`Respawn blocked - Circuit breaker OPEN: ${circuitBreaker.reason}`); this.logAction('ralph', `Circuit breaker OPEN: ${circuitBreaker.reason}`); - this.emit('respawnBlocked', { reason: 'circuit_breaker_open', details: circuitBreaker.reason }); + this.emit('respawnBlocked', { + reason: 'circuit_breaker_open', + details: circuitBreaker.reason, + }); this.setState('watching'); // Don't restart timers - wait for manual reset or circuit breaker resolution return; @@ -2804,7 +2858,10 @@ export class RespawnController extends EventEmitter { if (statusBlock?.exitSignal) { this.log(`Respawn paused - RALPH_STATUS EXIT_SIGNAL=true`); this.logAction('ralph', `Exit signal detected: ${statusBlock.recommendation || 'Task complete'}`); - this.emit('respawnBlocked', { reason: 'exit_signal', details: statusBlock.recommendation || 'Task complete' }); + this.emit('respawnBlocked', { + reason: 'exit_signal', + details: statusBlock.recommendation || 'Task complete', + }); this.setState('watching'); // Don't restart timers - loop is complete return; @@ -2814,7 +2871,10 @@ export class RespawnController extends EventEmitter { if (statusBlock?.status === 'BLOCKED') { this.log(`Respawn blocked - RALPH_STATUS reports BLOCKED`); this.logAction('ralph', `Claude reported BLOCKED: ${statusBlock.recommendation || 'Needs human intervention'}`); - this.emit('respawnBlocked', { reason: 'status_blocked', details: statusBlock.recommendation || 'Needs human intervention' }); + this.emit('respawnBlocked', { + reason: 'status_blocked', + details: statusBlock.recommendation || 'Needs human intervention', + }); this.setState('watching'); return; } @@ -2846,7 +2906,10 @@ export class RespawnController extends EventEmitter { if (this.session.status === 'error') { this.log('Skipping respawn cycle - session is in error state'); this.logAction('health', 'Respawn skipped: Session error state'); - this.emit('respawnBlocked', { reason: 'session_error', details: 'Session is in error state' }); + this.emit('respawnBlocked', { + reason: 'session_error', + details: 'Session is in error state', + }); this.setState('watching'); return; } @@ -2907,7 +2970,7 @@ export class RespawnController extends EventEmitter { this.logAction('ralph', `Using RECOMMENDATION: ${rec.substring(0, 50)}...`); } - const input = updatePrompt + '\r'; // \r triggers Enter in Ink/Claude CLI + const input = updatePrompt + '\r'; // \r triggers Enter in Ink/Claude CLI this.logAction('command', `Sending: "${updatePrompt.substring(0, 50)}..."`); await this.session.writeViaMux(input); this.emit('stepSent', 'update', updatePrompt); @@ -2937,7 +3000,7 @@ export class RespawnController extends EventEmitter { this.stepTimer = null; if (this._state === 'stopped') return; this.logAction('command', 'Sending: /clear'); - await this.session.writeViaMux('/clear\r'); // \r triggers Enter in Ink/Claude CLI + await this.session.writeViaMux('/clear\r'); // \r triggers Enter in Ink/Claude CLI this.emit('stepSent', 'clear', '/clear'); this.setState('waiting_clear'); this.promptDetected = false; @@ -2981,7 +3044,7 @@ export class RespawnController extends EventEmitter { this.stepTimer = null; if (this._state === 'stopped') return; this.logAction('command', 'Sending: /init'); - await this.session.writeViaMux('/init\r'); // \r triggers Enter in Ink/Claude CLI + await this.session.writeViaMux('/init\r'); // \r triggers Enter in Ink/Claude CLI this.emit('stepSent', 'init', '/init'); this.setState('waiting_init'); this.promptDetected = false; @@ -3052,9 +3115,13 @@ export class RespawnController extends EventEmitter { this.config = { ...this.config, ...filteredConfig }; // Sync AI checker config if relevant fields changed - if (config.aiIdleCheckEnabled !== undefined || config.aiIdleCheckModel !== undefined || - config.aiIdleCheckMaxContext !== undefined || config.aiIdleCheckTimeoutMs !== undefined || - config.aiIdleCheckCooldownMs !== undefined) { + if ( + config.aiIdleCheckEnabled !== undefined || + config.aiIdleCheckModel !== undefined || + config.aiIdleCheckMaxContext !== undefined || + config.aiIdleCheckTimeoutMs !== undefined || + config.aiIdleCheckCooldownMs !== undefined + ) { this.aiChecker.updateConfig({ enabled: this.config.aiIdleCheckEnabled, model: this.config.aiIdleCheckModel, @@ -3065,9 +3132,13 @@ export class RespawnController extends EventEmitter { } // Sync plan checker config if relevant fields changed - if (config.aiPlanCheckEnabled !== undefined || config.aiPlanCheckModel !== undefined || - config.aiPlanCheckMaxContext !== undefined || config.aiPlanCheckTimeoutMs !== undefined || - config.aiPlanCheckCooldownMs !== undefined) { + if ( + config.aiPlanCheckEnabled !== undefined || + config.aiPlanCheckModel !== undefined || + config.aiPlanCheckMaxContext !== undefined || + config.aiPlanCheckTimeoutMs !== undefined || + config.aiPlanCheckCooldownMs !== undefined + ) { this.planChecker.updateConfig({ enabled: this.config.aiPlanCheckEnabled, model: this.config.aiPlanCheckModel, @@ -3276,7 +3347,7 @@ export class RespawnController extends EventEmitter { const now = Date.now(); const metrics: RespawnCycleMetrics = { - ...this.currentCycleMetrics as RespawnCycleMetrics, + ...(this.currentCycleMetrics as RespawnCycleMetrics), completedAt: now, durationMs: now - (this.currentCycleMetrics.startedAt ?? now), outcome, @@ -3299,7 +3370,9 @@ export class RespawnController extends EventEmitter { // Clear current cycle this.currentCycleMetrics = null; - this.log(`Cycle #${metrics.cycleNumber} metrics: ${outcome}, duration=${metrics.durationMs}ms, idle_detection=${metrics.idleDetectionMs}ms`); + this.log( + `Cycle #${metrics.cycleNumber} metrics: ${outcome}, duration=${metrics.durationMs}ms, idle_detection=${metrics.idleDetectionMs}ms` + ); } /** @@ -3333,8 +3406,8 @@ export class RespawnController extends EventEmitter { } // Recalculate averages using all recent metrics - const durations = this.recentCycleMetrics.map(m => m.durationMs); - const idleTimes = this.recentCycleMetrics.map(m => m.idleDetectionMs); + const durations = this.recentCycleMetrics.map((m) => m.durationMs); + const idleTimes = this.recentCycleMetrics.map((m) => m.idleDetectionMs); if (durations.length > 0) { agg.avgCycleDurationMs = Math.round(durations.reduce((a, b) => a + b, 0) / durations.length); @@ -3347,9 +3420,7 @@ export class RespawnController extends EventEmitter { } // Calculate success rate - agg.successRate = agg.totalCycles > 0 - ? Math.round((agg.successfulCycles / agg.totalCycles) * 100) - : 100; + agg.successRate = agg.totalCycles > 0 ? Math.round((agg.successfulCycles / agg.totalCycles) * 100) : 100; agg.lastUpdatedAt = Date.now(); } @@ -3392,18 +3463,18 @@ export class RespawnController extends EventEmitter { // Weighted average (cycle success is most important) const weights = { cycleSuccess: 0.35, - circuitBreaker: 0.20, - iterationProgress: 0.20, + circuitBreaker: 0.2, + iterationProgress: 0.2, aiChecker: 0.15, - stuckRecovery: 0.10, + stuckRecovery: 0.1, }; const score = Math.round( components.cycleSuccess * weights.cycleSuccess + - components.circuitBreaker * weights.circuitBreaker + - components.iterationProgress * weights.iterationProgress + - components.aiChecker * weights.aiChecker + - components.stuckRecovery * weights.stuckRecovery + components.circuitBreaker * weights.circuitBreaker + + components.iterationProgress * weights.iterationProgress + + components.aiChecker * weights.aiChecker + + components.stuckRecovery * weights.stuckRecovery ); // Determine status @@ -3446,10 +3517,14 @@ export class RespawnController extends EventEmitter { const cb = tracker.circuitBreakerStatus; switch (cb.state) { - case 'CLOSED': return 100; - case 'HALF_OPEN': return 50; - case 'OPEN': return 0; - default: return 100; + case 'CLOSED': + return 100; + case 'HALF_OPEN': + return 50; + case 'OPEN': + return 0; + default: + return 100; } } @@ -3527,8 +3602,10 @@ export class RespawnController extends EventEmitter { status: HealthStatus, components: RalphLoopHealthScore['components'] ): string { - const lowest = Object.entries(components).reduce((min, [key, val]) => - val < min.val ? { key, val } : min, { key: '', val: 100 }); + const lowest = Object.entries(components).reduce((min, [key, val]) => (val < min.val ? { key, val } : min), { + key: '', + val: 100, + }); if (status === 'excellent') { return `Ralph Loop is operating excellently (${score}/100). All systems healthy.`; diff --git a/src/run-summary.ts b/src/run-summary.ts index 7a9c0fae..bf27842a 100644 --- a/src/run-summary.ts +++ b/src/run-summary.ts @@ -139,13 +139,10 @@ export class RunSummaryTracker { // Record state transition if (oldState && oldState !== newState) { this.stats.stateTransitions++; - this.addEvent( - 'respawn_state_change', - 'info', - `State: ${oldState} → ${newState}`, - details, - { from: oldState, to: newState } - ); + this.addEvent('respawn_state_change', 'info', `State: ${oldState} → ${newState}`, details, { + from: oldState, + to: newState, + }); } // Update state tracking @@ -214,7 +211,11 @@ export class RunSummaryTracker { 'info', `Token milestone: ${this.formatTokens(currentMilestone)}`, `Input: ${this.formatTokens(inputTokens)}, Output: ${this.formatTokens(outputTokens)}`, - { total, input: inputTokens, output: outputTokens } + { + total, + input: inputTokens, + output: outputTokens, + } ); } } @@ -264,13 +265,9 @@ export class RunSummaryTracker { * Record a Ralph completion detection. */ recordRalphCompletion(phrase: string): void { - this.addEvent( - 'ralph_completion', - 'success', - 'Ralph completion detected', - `Phrase: ${phrase}`, - { phrase } - ); + this.addEvent('ralph_completion', 'success', 'Ralph completion detected', `Phrase: ${phrase}`, { + phrase, + }); } /** @@ -278,9 +275,7 @@ export class RunSummaryTracker { */ recordHookEvent(eventType: string, data?: Record): void { const severity: RunSummaryEventSeverity = - eventType === 'stop' ? 'warning' : - eventType === 'permission_prompt' ? 'info' : - 'info'; + eventType === 'stop' ? 'warning' : eventType === 'permission_prompt' ? 'info' : 'info'; this.addEvent( 'hook_event', @@ -311,13 +306,10 @@ export class RunSummaryTracker { * Record session started. */ recordSessionStarted(mode: string, workingDir: string): void { - this.addEvent( - 'session_started', - 'success', - 'Session started', - `Mode: ${mode}, Dir: ${workingDir}`, - { mode, workingDir } - ); + this.addEvent('session_started', 'success', 'Session started', `Mode: ${mode}, Dir: ${workingDir}`, { + mode, + workingDir, + }); } /** diff --git a/src/session-lifecycle-log.ts b/src/session-lifecycle-log.ts index ddab9978..cd33ceb3 100644 --- a/src/session-lifecycle-log.ts +++ b/src/session-lifecycle-log.ts @@ -62,7 +62,7 @@ export class SessionLifecycleLog { } const lines = raw.trim().split('\n').filter(Boolean); - let entries: LifecycleEntry[] = []; + const entries: LifecycleEntry[] = []; // Parse in reverse (newest first) for efficiency with limit for (let i = lines.length - 1; i >= 0 && entries.length < limit; i--) { diff --git a/src/session-manager.ts b/src/session-manager.ts index 70420d89..387c9cbe 100644 --- a/src/session-manager.ts +++ b/src/session-manager.ts @@ -102,7 +102,7 @@ export class SessionManager extends EventEmitter { // Create a new lock promise that others will wait on // Define unlock first to ensure it's always in scope before promise assignment let unlock!: () => void; - const lockPromise = new Promise(resolve => { + const lockPromise = new Promise((resolve) => { unlock = resolve; }); this._sessionCreationLock = lockPromise; @@ -196,9 +196,7 @@ export class SessionManager extends EventEmitter { * Uses Promise.allSettled to ensure all sessions are stopped even if some fail. */ async stopAllSessions(): Promise { - const stopPromises = Array.from(this.sessions.keys()).map((id) => - this.stopSession(id) - ); + const stopPromises = Array.from(this.sessions.keys()).map((id) => this.stopSession(id)); const results = await Promise.allSettled(stopPromises); // Log any failures but don't throw - best effort cleanup for (const result of results) { @@ -292,4 +290,3 @@ export function getSessionManager(): SessionManager { } return managerInstance; } - diff --git a/src/session.ts b/src/session.ts index 8d64a404..4150aebe 100644 --- a/src/session.ts +++ b/src/session.ts @@ -18,19 +18,26 @@ import { EventEmitter } from 'node:events'; import { v4 as uuidv4 } from 'uuid'; import * as pty from 'node-pty'; -import { SessionState, SessionStatus, SessionConfig, RalphTrackerState, RalphTodoItem, ActiveBashTool, NiceConfig, DEFAULT_NICE_CONFIG, type ClaudeMode, type SessionMode, type OpenCodeConfig } from './types.js'; +import { + SessionState, + SessionStatus, + SessionConfig, + RalphTrackerState, + RalphTodoItem, + ActiveBashTool, + NiceConfig, + DEFAULT_NICE_CONFIG, + type ClaudeMode, + type SessionMode, + type OpenCodeConfig, +} from './types.js'; import type { TerminalMultiplexer, MuxSession } from './mux-interface.js'; import { TaskTracker, type BackgroundTask } from './task-tracker.js'; import { RalphTracker } from './ralph-tracker.js'; import { BashToolParser } from './bash-tool-parser.js'; import { BufferAccumulator } from './utils/buffer-accumulator.js'; import { LRUMap } from './utils/lru-map.js'; -import { - ANSI_ESCAPE_PATTERN_FULL, - TOKEN_PATTERN, - SPINNER_PATTERN, - MAX_SESSION_TOKENS, -} from './utils/index.js'; +import { ANSI_ESCAPE_PATTERN_FULL, TOKEN_PATTERN, SPINNER_PATTERN, MAX_SESSION_TOKENS } from './utils/index.js'; import { MAX_TERMINAL_BUFFER_SIZE, TRIM_TERMINAL_TO as TERMINAL_BUFFER_TRIM_SIZE, @@ -68,6 +75,7 @@ const GRACEFUL_SHUTDOWN_DELAY_MS = 100; // Filter out terminal focus escape sequences (focus in/out reports) // ^[[I (focus in), ^[[O (focus out), and the enable/disable sequences +// eslint-disable-next-line no-control-regex const FOCUS_ESCAPE_FILTER = /\x1b\[\?1004[hl]|\x1b\[[IO]/g; // Pattern to match Task tool invocations in terminal output @@ -78,8 +86,10 @@ const TASK_TOOL_PATTERN = /\b(Explore|Task|Bash|Plan|general-purpose)\(([^)]+)\) // Pre-compiled patterns for hot paths (avoid regex compilation per call) /** Pattern to strip leading ANSI escapes and whitespace from terminal buffer */ +// eslint-disable-next-line no-control-regex const LEADING_ANSI_WHITESPACE_PATTERN = /^(\x1b\[\??[\d;]*[A-Za-z]|[\s\r\n])+/; /** Pattern to match Ctrl+L (form feed) characters */ +// eslint-disable-next-line no-control-regex const CTRL_L_PATTERN = /\x0c/g; /** Pattern to split by newlines (CR or LF) */ const NEWLINE_SPLIT_PATTERN = /\r?\n/; @@ -96,11 +106,7 @@ import { getAugmentedPath } from './utils/claude-cli-resolver.js'; * @param operation - Description of the operation for error messages * @returns Promise that resolves/rejects with the original result or timeout error */ -function withTimeout( - promise: Promise, - timeoutMs: number, - operation: string -): Promise { +function withTimeout(promise: Promise, timeoutMs: number, operation: string): Promise { let timeoutId: NodeJS.Timeout; const timeoutPromise = new Promise((_, reject) => { @@ -193,7 +199,12 @@ export interface SessionEvents { /** Active Bash tools list updated */ bashToolsUpdate: (tools: ActiveBashTool[]) => void; /** CLI info (version, model, account) updated */ - cliInfoUpdated: (info: { version: string | null; model: string | null; accountType: string | null; latestVersion: string | null }) => void; + cliInfoUpdated: (info: { + version: string | null; + model: string | null; + accountType: string | null; + latestVersion: string | null; + }) => void; } // SessionMode is imported from types.ts (single source of truth) @@ -258,7 +269,7 @@ export class Session extends EventEmitter { private _lineBufferFlushTimer: NodeJS.Timeout | null = null; private resolvePromise: ((value: { result: string; cost: number }) => void) | null = null; private rejectPromise: ((reason: Error) => void) | null = null; - private _promptResolved: boolean = false; // Guard against race conditions in runPrompt + private _promptResolved: boolean = false; // Guard against race conditions in runPrompt private _isWorking: boolean = false; private _lastPromptTime: number = 0; private activityTimeout: NodeJS.Timeout | null = null; @@ -356,7 +367,9 @@ export class Session extends EventEmitter { // Task descriptions parsed from terminal output (e.g., "Explore(Description)") // Used to correlate with SubagentWatcher discoveries for better window titles // Uses LRUMap for automatic eviction at MAX_TASK_DESCRIPTIONS limit - private _recentTaskDescriptions: LRUMap = new LRUMap({ maxSize: Session.MAX_TASK_DESCRIPTIONS }); + private _recentTaskDescriptions: LRUMap = new LRUMap({ + maxSize: Session.MAX_TASK_DESCRIPTIONS, + }); // Throttle expensive PTY processing (Ralph, bash parser, task descriptions) // Accumulates clean data between processing windows to avoid running regex on every chunk @@ -365,26 +378,28 @@ export class Session extends EventEmitter { private _expensiveProcessTimer: NodeJS.Timeout | null = null; private static readonly EXPENSIVE_PROCESS_INTERVAL_MS = 150; // Process at most every 150ms - constructor(config: Partial & { - workingDir: string; - mode?: SessionMode; - name?: string; - /** Terminal multiplexer instance (tmux) */ - mux?: TerminalMultiplexer; - /** Whether to use multiplexer wrapping */ - useMux?: boolean; - /** Existing mux session for restored sessions */ - muxSession?: MuxSession; - niceConfig?: NiceConfig; // Nice prioritying configuration - /** Claude model override (e.g., 'opus', 'sonnet', 'haiku') */ - model?: string; - /** Claude CLI startup permission mode */ - claudeMode?: ClaudeMode; - /** Comma-separated allowed tools (for 'allowedTools' mode) */ - allowedTools?: string; - /** OpenCode configuration (only for mode === 'opencode') */ - openCodeConfig?: OpenCodeConfig; - }) { + constructor( + config: Partial & { + workingDir: string; + mode?: SessionMode; + name?: string; + /** Terminal multiplexer instance (tmux) */ + mux?: TerminalMultiplexer; + /** Whether to use multiplexer wrapping */ + useMux?: boolean; + /** Existing mux session for restored sessions */ + muxSession?: MuxSession; + niceConfig?: NiceConfig; // Nice prioritying configuration + /** Claude model override (e.g., 'opus', 'sonnet', 'haiku') */ + model?: string; + /** Claude CLI startup permission mode */ + claudeMode?: ClaudeMode; + /** Comma-separated allowed tools (for 'allowedTools' mode) */ + allowedTools?: string; + /** OpenCode configuration (only for mode === 'opencode') */ + openCodeConfig?: OpenCodeConfig; + } + ) { super(); this.setMaxListeners(25); @@ -472,7 +487,6 @@ export class Session extends EventEmitter { this._bashToolParser.on('toolStart', this._bashToolHandlers.toolStart); this._bashToolParser.on('toolEnd', this._bashToolHandlers.toolEnd); this._bashToolParser.on('toolsUpdate', this._bashToolHandlers.toolsUpdate); - } get status(): SessionStatus { @@ -673,17 +687,23 @@ export class Session extends EventEmitter { restoreTokens(inputTokens: number, outputTokens: number, totalCost: number): void { // Sanity check: reject absurdly large individual values if (inputTokens > MAX_SESSION_TOKENS || outputTokens > MAX_SESSION_TOKENS) { - console.warn(`[Session ${this.id}] Rejected absurd restored tokens: input=${inputTokens}, output=${outputTokens}`); + console.warn( + `[Session ${this.id}] Rejected absurd restored tokens: input=${inputTokens}, output=${outputTokens}` + ); return; } // Check token sum doesn't overflow MAX_SESSION_TOKENS if (inputTokens + outputTokens > MAX_SESSION_TOKENS) { - console.warn(`[Session ${this.id}] Rejected token sum overflow: input=${inputTokens} + output=${outputTokens} = ${inputTokens + outputTokens} > ${MAX_SESSION_TOKENS}`); + console.warn( + `[Session ${this.id}] Rejected token sum overflow: input=${inputTokens} + output=${outputTokens} = ${inputTokens + outputTokens} > ${MAX_SESSION_TOKENS}` + ); return; } // Reject negative values if (inputTokens < 0 || outputTokens < 0 || totalCost < 0) { - console.warn(`[Session ${this.id}] Rejected negative restored tokens: input=${inputTokens}, output=${outputTokens}, cost=${totalCost}`); + console.warn( + `[Session ${this.id}] Rejected negative restored tokens: input=${inputTokens}, output=${outputTokens}, cost=${totalCost}` + ); return; } @@ -722,7 +742,9 @@ export class Session extends EventEmitter { if (threshold !== undefined) { // Validate threshold bounds if (threshold < Session.MIN_AUTO_THRESHOLD || threshold > Session.MAX_AUTO_THRESHOLD) { - console.warn(`[Session ${this.id}] Invalid autoClear threshold ${threshold}, must be between ${Session.MIN_AUTO_THRESHOLD} and ${Session.MAX_AUTO_THRESHOLD}. Using default ${Session.DEFAULT_AUTO_CLEAR_THRESHOLD}.`); + console.warn( + `[Session ${this.id}] Invalid autoClear threshold ${threshold}, must be between ${Session.MIN_AUTO_THRESHOLD} and ${Session.MAX_AUTO_THRESHOLD}. Using default ${Session.DEFAULT_AUTO_CLEAR_THRESHOLD}.` + ); this._autoClearThreshold = Session.DEFAULT_AUTO_CLEAR_THRESHOLD; } else { this._autoClearThreshold = threshold; @@ -747,7 +769,9 @@ export class Session extends EventEmitter { if (threshold !== undefined) { // Validate threshold bounds if (threshold < Session.MIN_AUTO_THRESHOLD || threshold > Session.MAX_AUTO_THRESHOLD) { - console.warn(`[Session ${this.id}] Invalid autoCompact threshold ${threshold}, must be between ${Session.MIN_AUTO_THRESHOLD} and ${Session.MAX_AUTO_THRESHOLD}. Using default ${Session.DEFAULT_AUTO_COMPACT_THRESHOLD}.`); + console.warn( + `[Session ${this.id}] Invalid autoCompact threshold ${threshold}, must be between ${Session.MIN_AUTO_THRESHOLD} and ${Session.MAX_AUTO_THRESHOLD}. Using default ${Session.DEFAULT_AUTO_COMPACT_THRESHOLD}.` + ); this._autoCompactThreshold = Session.DEFAULT_AUTO_COMPACT_THRESHOLD; } else { this._autoCompactThreshold = threshold; @@ -911,7 +935,9 @@ export class Session extends EventEmitter { this._lastActivityAt = Date.now(); const modeLabel = this.mode === 'opencode' ? 'OpenCode' : 'Claude'; - console.log(`[Session] Starting interactive ${modeLabel} session` + (this._useMux ? ` (with ${this._mux!.backend})` : '')); + console.log( + `[Session] Starting interactive ${modeLabel} session` + (this._useMux ? ` (with ${this._mux!.backend})` : '') + ); // If mux wrapping is enabled, create or attach to a mux session if (this._useMux && this._mux) { @@ -928,16 +954,21 @@ export class Session extends EventEmitter { if (this._muxSession && this._mux.isPaneDead(this._muxSession.muxName)) { console.log('[Session] Dead pane detected, respawning:', this._muxSession.muxName); const newPid = await this._mux.respawnPane({ - sessionId: this.id, workingDir: this.workingDir, mode: this.mode, - niceConfig: this._niceConfig, model: this._model, claudeMode: this._claudeMode, - allowedTools: this._allowedTools, openCodeConfig: this._openCodeConfig, + sessionId: this.id, + workingDir: this.workingDir, + mode: this.mode, + niceConfig: this._niceConfig, + model: this._model, + claudeMode: this._claudeMode, + allowedTools: this._allowedTools, + openCodeConfig: this._openCodeConfig, }); if (!newPid) { console.error('[Session] Failed to respawn pane, will create new session'); needsNewSession = true; } else { // Wait a moment for the respawned process to fully start - await new Promise(resolve => setTimeout(resolve, MUX_STARTUP_DELAY_MS)); + await new Promise((resolve) => setTimeout(resolve, MUX_STARTUP_DELAY_MS)); } } @@ -948,9 +979,14 @@ export class Session extends EventEmitter { } else { // Create a new mux session this._muxSession = await this._mux.createSession({ - sessionId: this.id, workingDir: this.workingDir, mode: this.mode, - name: this._name, niceConfig: this._niceConfig, model: this._model, - claudeMode: this._claudeMode, allowedTools: this._allowedTools, + sessionId: this.id, + workingDir: this.workingDir, + mode: this.mode, + name: this._name, + niceConfig: this._niceConfig, + model: this._model, + claudeMode: this._claudeMode, + allowedTools: this._allowedTools, openCodeConfig: this._openCodeConfig, }); console.log('[Session] Created mux session:', this._muxSession.muxName); @@ -962,13 +998,21 @@ export class Session extends EventEmitter { this.ptyProcess = pty.spawn( this._mux.getAttachCommand(), this._mux.getAttachArgs(this._muxSession!.muxName), - { - name: 'xterm-256color', - cols: 120, - rows: 40, - cwd: this.workingDir, - env: { ...process.env, LANG: 'en_US.UTF-8', LC_ALL: 'en_US.UTF-8', TERM: 'xterm-256color', COLORTERM: undefined, CLAUDECODE: undefined }, - }); + { + name: 'xterm-256color', + cols: 120, + rows: 40, + cwd: this.workingDir, + env: { + ...process.env, + LANG: 'en_US.UTF-8', + LC_ALL: 'en_US.UTF-8', + TERM: 'xterm-256color', + COLORTERM: undefined, + CLAUDECODE: undefined, + }, + } + ); // Set claudeSessionId immediately since we passed --session-id to Claude // The mux manager passes --session-id ${sessionId} to Claude @@ -1010,9 +1054,7 @@ export class Session extends EventEmitter { // Clean the buffer - remove mux init junk before actual content // Strip: cursor movement (\x1b[nA/B/C/D), positioning (\x1b[n;nH), // clear screen (\x1b[2J), scroll region (\x1b[n;nr), and whitespace - this._terminalBuffer.set( - bufferValue.replace(LEADING_ANSI_WHITESPACE_PATTERN, '') - ); + this._terminalBuffer.set(bufferValue.replace(LEADING_ANSI_WHITESPACE_PATTERN, '')); // Signal client to refresh this.emit('clearTerminal'); } @@ -1081,9 +1123,7 @@ export class Session extends EventEmitter { this.ptyProcess.onData((rawData: string) => { // Filter out focus escape sequences and Ctrl+L (form feed) - const data = rawData - .replace(FOCUS_ESCAPE_FILTER, '') - .replace(CTRL_L_PATTERN, ''); // Remove Ctrl+L + const data = rawData.replace(FOCUS_ESCAPE_FILTER, '').replace(CTRL_L_PATTERN, ''); // Remove Ctrl+L if (!data) return; // Skip if only filtered sequences // BufferAccumulator handles auto-trimming when max size exceeded @@ -1252,8 +1292,12 @@ export class Session extends EventEmitter { // Only check if spinner didn't already trigger working state if (!this._isWorking) { const cleanData = getCleanData(); - if (cleanData.includes('Thinking') || cleanData.includes('Writing') || - cleanData.includes('Reading') || cleanData.includes('Running')) { + if ( + cleanData.includes('Thinking') || + cleanData.includes('Writing') || + cleanData.includes('Reading') || + cleanData.includes('Running') + ) { this._isWorking = true; this._status = 'busy'; this.emit('working'); @@ -1293,7 +1337,10 @@ export class Session extends EventEmitter { // Use user's default shell or bash const shell = process.env.SHELL || '/bin/bash'; - console.log('[Session] Starting shell session with:', shell + (this._useMux ? ` (with ${this._mux!.backend})` : '')); + console.log( + '[Session] Starting shell session with:', + shell + (this._useMux ? ` (with ${this._mux!.backend})` : '') + ); // If mux wrapping is enabled, create or attach to a mux session if (this._useMux && this._mux) { @@ -1308,12 +1355,17 @@ export class Session extends EventEmitter { let needsNewSession = false; if (this._muxSession && this._mux.isPaneDead(this._muxSession.muxName)) { console.log('[Session] Dead pane detected, respawning:', this._muxSession.muxName); - const newPid = await this._mux.respawnPane({ sessionId: this.id, workingDir: this.workingDir, mode: 'shell', niceConfig: this._niceConfig }); + const newPid = await this._mux.respawnPane({ + sessionId: this.id, + workingDir: this.workingDir, + mode: 'shell', + niceConfig: this._niceConfig, + }); if (!newPid) { console.error('[Session] Failed to respawn pane, will create new session'); needsNewSession = true; } else { - await new Promise(resolve => setTimeout(resolve, MUX_STARTUP_DELAY_MS)); + await new Promise((resolve) => setTimeout(resolve, MUX_STARTUP_DELAY_MS)); } } @@ -1323,7 +1375,13 @@ export class Session extends EventEmitter { console.log('[Session] Attaching to existing mux session:', this._muxSession!.muxName); } else { // Create a new mux session - this._muxSession = await this._mux.createSession({ sessionId: this.id, workingDir: this.workingDir, mode: 'shell', name: this._name, niceConfig: this._niceConfig }); + this._muxSession = await this._mux.createSession({ + sessionId: this.id, + workingDir: this.workingDir, + mode: 'shell', + name: this._name, + niceConfig: this._niceConfig, + }); console.log('[Session] Created mux session:', this._muxSession.muxName); // No extra sleep — createSession() already waits for tmux readiness } @@ -1333,13 +1391,21 @@ export class Session extends EventEmitter { this.ptyProcess = pty.spawn( this._mux.getAttachCommand(), this._mux.getAttachArgs(this._muxSession!.muxName), - { - name: 'xterm-256color', - cols: 120, - rows: 40, - cwd: this.workingDir, - env: { ...process.env, LANG: 'en_US.UTF-8', LC_ALL: 'en_US.UTF-8', TERM: 'xterm-256color', COLORTERM: undefined, CLAUDECODE: undefined }, - }); + { + name: 'xterm-256color', + cols: 120, + rows: 40, + cwd: this.workingDir, + env: { + ...process.env, + LANG: 'en_US.UTF-8', + LC_ALL: 'en_US.UTF-8', + TERM: 'xterm-256color', + COLORTERM: undefined, + CLAUDECODE: undefined, + }, + } + ); } catch (spawnErr) { console.error('[Session] Failed to spawn PTY for shell mux attachment:', spawnErr); this.emit('error', `Failed to attach to mux session: ${spawnErr}`); @@ -1474,7 +1540,7 @@ export class Session extends EventEmitter { this._messages = []; this._lineBuffer = ''; this._lastActivityAt = Date.now(); - this._promptResolved = false; // Reset race condition guard + this._promptResolved = false; // Reset race condition guard this.resolvePromise = resolve; this.rejectPromise = reject; @@ -1482,14 +1548,13 @@ export class Session extends EventEmitter { try { // Spawn claude in a real PTY const model = options?.model; - console.log('[Session] Spawning PTY for claude with prompt:', prompt.substring(0, 50), model ? `(model: ${model})` : ''); - - const args = [ - '-p', - '--verbose', - '--dangerously-skip-permissions', - '--output-format', 'stream-json', - ]; + console.log( + '[Session] Spawning PTY for claude with prompt:', + prompt.substring(0, 50), + model ? `(model: ${model})` : '' + ); + + const args = ['-p', '--verbose', '--dangerously-skip-permissions', '--output-format', 'stream-json']; if (model) { args.push('--model', model); } @@ -1517,7 +1582,10 @@ export class Session extends EventEmitter { }); } catch (spawnErr) { console.error('[Session] Failed to spawn Claude PTY for runPrompt:', spawnErr); - this.emit('error', `Failed to spawn Claude: ${spawnErr instanceof Error ? spawnErr.message : String(spawnErr)}`); + this.emit( + 'error', + `Failed to spawn Claude: ${spawnErr instanceof Error ? spawnErr.message : String(spawnErr)}` + ); throw spawnErr; } @@ -1561,7 +1629,7 @@ export class Session extends EventEmitter { this.rejectPromise = null; // Find result from parsed messages or use text output - const resultMsg = this._messages.find(m => m.type === 'result'); + const resultMsg = this._messages.find((m) => m.type === 'result'); if (resultMsg && !resultMsg.is_error) { this._status = 'idle'; @@ -1579,13 +1647,15 @@ export class Session extends EventEmitter { } else { this._status = 'idle'; if (resolve) { - resolve({ result: this._textOutput.value || this._terminalBuffer.value, cost: this._totalCost }); + resolve({ + result: this._textOutput.value || this._terminalBuffer.value, + cost: this._totalCost, + }); } } this.emit('exit', exitCode); }); - } catch (err) { this._status = 'error'; reject(err); @@ -1649,8 +1719,8 @@ export class Session extends EventEmitter { // Extract Claude session ID from messages (can be in any message type) // Support both sessionId (camelCase) and session_id (snake_case) - const msgSessionId = (msg as unknown as Record).sessionId as string | undefined - ?? msg.session_id; + const msgSessionId = + ((msg as unknown as Record).sessionId as string | undefined) ?? msg.session_id; if (msgSessionId && !this._claudeSessionId) { this._claudeSessionId = msgSessionId; } @@ -1689,7 +1759,10 @@ export class Session extends EventEmitter { } } catch (parseErr) { // Not JSON, just regular output - this is expected for non-JSON lines - console.debug('[Session] Line not JSON (expected for text output):', parseErr instanceof Error ? parseErr.message : parseErr); + console.debug( + '[Session] Line not JSON (expected for text output):', + parseErr instanceof Error ? parseErr.message : parseErr + ); this._textOutput.append(line + '\n'); } } else if (trimmed) { @@ -1829,7 +1902,9 @@ export class Session extends EventEmitter { // Safety: Reject M values that would result in > 500k tokens // Claude's context window is ~200k, so anything claiming millions is likely a false match if (tokenCount > 0.5) { - console.warn(`[Session ${this.id}] Rejected suspicious M token value: ${tokenMatch[0]} (would be ${tokenCount * 1000000} tokens)`); + console.warn( + `[Session ${this.id}] Rejected suspicious M token value: ${tokenMatch[0]} (would be ${tokenCount * 1000000} tokens)` + ); return; } tokenCount *= 1000000; @@ -1850,7 +1925,9 @@ export class Session extends EventEmitter { // Safety: Reject suspiciously large jumps (max 100k per update) const MAX_DELTA_PER_UPDATE = 100_000; if (delta > MAX_DELTA_PER_UPDATE) { - console.warn(`[Session ${this.id}] Rejected suspicious token jump: ${currentTotal} -> ${tokenCount} (delta: ${delta})`); + console.warn( + `[Session ${this.id}] Rejected suspicious token jump: ${currentTotal} -> ${tokenCount} (delta: ${delta})` + ); return; } @@ -1874,7 +1951,12 @@ export class Session extends EventEmitter { if (this._cliInfoParsed) return; // Quick pre-checks - if (!cleanData.includes('Claude') && !cleanData.includes('current:') && !cleanData.includes('Opus') && !cleanData.includes('Sonnet')) { + if ( + !cleanData.includes('Claude') && + !cleanData.includes('current:') && + !cleanData.includes('Opus') && + !cleanData.includes('Sonnet') + ) { return; } let changed = false; @@ -1960,14 +2042,12 @@ export class Session extends EventEmitter { if (this._isStopped) return; // Send /compact command with optional prompt - const compactCmd = this._autoCompactPrompt - ? `/compact ${this._autoCompactPrompt}\r` - : '/compact\r'; + const compactCmd = this._autoCompactPrompt ? `/compact ${this._autoCompactPrompt}\r` : '/compact\r'; await this.writeViaMux(compactCmd); this.emit('autoCompact', { tokens: totalTokens, threshold: this._autoCompactThreshold, - prompt: this._autoCompactPrompt || undefined + prompt: this._autoCompactPrompt || undefined, }); // Wait a moment then re-enable (longer than clear since compact takes time) @@ -2121,7 +2201,7 @@ export class Session extends EventEmitter { async sendInput(input: string): Promise { this._status = 'busy'; this._lastActivityAt = Date.now(); - this.runPrompt(input).catch(err => { + this.runPrompt(input).catch((err) => { const errorMsg = err instanceof Error ? err.message : String(err); this.emit('error', errorMsg); }); @@ -2260,7 +2340,7 @@ export class Session extends EventEmitter { } // Give it a moment to terminate gracefully - await new Promise(resolve => setTimeout(resolve, GRACEFUL_SHUTDOWN_DELAY_MS)); + await new Promise((resolve) => setTimeout(resolve, GRACEFUL_SHUTDOWN_DELAY_MS)); // Force kill with SIGKILL if still alive try { diff --git a/src/state-store.ts b/src/state-store.ts index cd872b90..106b196e 100644 --- a/src/state-store.ts +++ b/src/state-store.ts @@ -18,7 +18,16 @@ import { readFileSync, writeFileSync, existsSync, mkdirSync, renameSync, unlinkS import { writeFile, rename, unlink, copyFile, access } from 'node:fs/promises'; import { homedir } from 'node:os'; import { dirname, join } from 'node:path'; -import { AppState, createInitialState, RalphSessionState, createInitialRalphSessionState, GlobalStats, createInitialGlobalStats, TokenStats, TokenUsageEntry } from './types.js'; +import { + AppState, + createInitialState, + RalphSessionState, + createInitialRalphSessionState, + GlobalStats, + createInitialGlobalStats, + TokenStats, + TokenUsageEntry, +} from './types.js'; import { MAX_SESSION_TOKENS } from './utils/index.js'; /** Debounce delay for batching state writes (ms) */ @@ -299,7 +308,11 @@ export class StateStore { } catch (err) { console.error('[StateStore] Failed to write state file:', err); this.consecutiveSaveFailures++; - try { if (existsSync(tempPath)) unlinkSync(tempPath); } catch { /* ignore */ } + try { + if (existsSync(tempPath)) unlinkSync(tempPath); + } catch { + /* ignore */ + } if (this.consecutiveSaveFailures >= MAX_CONSECUTIVE_FAILURES) { console.error('[StateStore] Circuit breaker OPEN - writes failing repeatedly'); this.circuitBreakerOpen = true; @@ -384,7 +397,10 @@ export class StateStore { * @param activeSessionIds - Set of currently active session IDs * @returns Number of sessions cleaned up */ - cleanupStaleSessions(activeSessionIds: Set): { count: number; cleaned: Array<{ id: string; name?: string }> } { + cleanupStaleSessions(activeSessionIds: Set): { + count: number; + cleaned: Array<{ id: string; name?: string }>; + } { const allSessionIds = Object.keys(this.state.sessions); const cleaned: Array<{ id: string; name?: string }> = []; @@ -481,7 +497,9 @@ export class StateStore { } // Reject negative values if (inputTokens < 0 || outputTokens < 0 || cost < 0) { - console.warn(`[StateStore] Rejected negative global stats: input=${inputTokens}, output=${outputTokens}, cost=${cost}`); + console.warn( + `[StateStore] Rejected negative global stats: input=${inputTokens}, output=${outputTokens}, cost=${cost}` + ); return; } @@ -505,7 +523,9 @@ export class StateStore { * Returns aggregate stats combining global (deleted sessions) + active sessions. * @param activeSessions Map of active session states */ - getAggregateStats(activeSessions: Record): { + getAggregateStats( + activeSessions: Record + ): { totalInputTokens: number; totalOutputTokens: number; totalCost: number; @@ -602,7 +622,7 @@ export class StateStore { } // Find or create today's entry - let todayEntry = stats.daily.find(e => e.date === today); + let todayEntry = stats.daily.find((e) => e.date === today); if (!todayEntry) { todayEntry = { date: today, @@ -617,10 +637,7 @@ export class StateStore { // Accumulate tokens todayEntry.inputTokens += inputTokens; todayEntry.outputTokens += outputTokens; - todayEntry.estimatedCost = this.calculateEstimatedCost( - todayEntry.inputTokens, - todayEntry.outputTokens - ); + todayEntry.estimatedCost = this.calculateEstimatedCost(todayEntry.inputTokens, todayEntry.outputTokens); // Only increment session count for unique sessions if (sessionId && !this.dailySessionIds.has(sessionId)) { diff --git a/src/subagent-watcher.ts b/src/subagent-watcher.ts index e9008055..2443c710 100644 --- a/src/subagent-watcher.ts +++ b/src/subagent-watcher.ts @@ -77,16 +77,18 @@ export interface SubagentTranscriptEntry { input_tokens?: number; output_tokens?: number; }; - content: string | Array<{ - type: 'text' | 'tool_use' | 'tool_result'; - text?: string; - name?: string; - id?: string; // tool_use_id for tool_use blocks - tool_use_id?: string; // tool_use_id for tool_result blocks - input?: Record; - content?: string | Array<{ type: string; text?: string }>; // tool_result content - is_error?: boolean; // For tool_result errors - }>; + content: + | string + | Array<{ + type: 'text' | 'tool_use' | 'tool_result'; + text?: string; + name?: string; + id?: string; // tool_use_id for tool_use blocks + tool_use_id?: string; // tool_use_id for tool_result blocks + input?: Record; + content?: string | Array<{ type: string; text?: string }>; // tool_result content + is_error?: boolean; // For tool_result errors + }>; }; data?: { type: string; @@ -135,11 +137,11 @@ const MAX_TRACKED_AGENTS = 500; // Maximum agents to track (LRU eviction when ex // Internal Claude Code agent patterns to filter out (not real user-initiated subagents) const INTERNAL_AGENT_PATTERNS = [ - /^\[?SUGGESTION MODE/i, // Claude Code's internal suggestion mode - /^Suggest what user might/i, // Suggestion mode prompt variant - /aprompt/i, // Internal prompt agent (anywhere in string) - /^a\s?prompt/i, // Variants of internal prompt agent - /^prompt$/i, // Just "prompt" + /^\[?SUGGESTION MODE/i, // Claude Code's internal suggestion mode + /^Suggest what user might/i, // Suggestion mode prompt variant + /aprompt/i, // Internal prompt agent (anywhere in string) + /^a\s?prompt/i, // Variants of internal prompt agent + /^prompt$/i, // Just "prompt" ]; // Minimum description length - very short descriptions are likely internal or malformed @@ -194,7 +196,7 @@ export class SubagentWatcher extends EventEmitter { if (!description) return false; // Filter out very short descriptions (likely internal or malformed) if (description.length < MIN_DESCRIPTION_LENGTH) return true; - return INTERNAL_AGENT_PATTERNS.some(pattern => pattern.test(description)); + return INTERNAL_AGENT_PATTERNS.some((pattern) => pattern.test(description)); } /** @@ -263,7 +265,7 @@ export class SubagentWatcher extends EventEmitter { if (await this.checkSubagentFileAlive(info)) continue; // Tier 2: Cached PID check (~0.1ms per agent) - if (info.pid && await this.checkPidAlive(info.pid)) continue; + if (info.pid && (await this.checkPidAlive(info.pid))) continue; // Tiers 1+2 failed — need expensive scan for this agent needsFullScan.push(info); @@ -322,20 +324,35 @@ export class SubagentWatcher extends EventEmitter { resolve(stdout); }); }); - const pids = pgrepOutput.trim().split('\n').filter(Boolean).map(s => parseInt(s, 10)).filter(n => !Number.isNaN(n)); + const pids = pgrepOutput + .trim() + .split('\n') + .filter(Boolean) + .map((s) => parseInt(s, 10)) + .filter((n) => !Number.isNaN(n)); // Read /proc for all PIDs in parallel - await Promise.all(pids.map(async (pid) => { - let environ = ''; - let cmdline = ''; - try { environ = await readFile(`/proc/${pid}/environ`, 'utf8'); } catch { /* skip */ } - try { cmdline = await readFile(`/proc/${pid}/cmdline`, 'utf8'); } catch { /* skip */ } - // Skip main Codeman-managed Claude processes — only track subagents - if (environ.includes('CODEMAN_MUX=1')) return; - if (environ || cmdline) { - result.set(pid, { environ, cmdline }); - } - })); + await Promise.all( + pids.map(async (pid) => { + let environ = ''; + let cmdline = ''; + try { + environ = await readFile(`/proc/${pid}/environ`, 'utf8'); + } catch { + /* skip */ + } + try { + cmdline = await readFile(`/proc/${pid}/cmdline`, 'utf8'); + } catch { + /* skip */ + } + // Skip main Codeman-managed Claude processes — only track subagents + if (environ.includes('CODEMAN_MUX=1')) return; + if (environ || cmdline) { + result.set(pid, { environ, cmdline }); + } + }) + ); // Update cached PIDs on tracked agents for (const [pid, procInfo] of result) { @@ -567,9 +584,7 @@ export class SubagentWatcher extends EventEmitter { */ getSubagentsForSession(workingDir: string): SubagentInfo[] { const projectHash = this.getProjectHash(workingDir); - return Array.from(this.agentInfo.values()).filter( - (info) => info.projectHash === projectHash - ); + return Array.from(this.agentInfo.values()).filter((info) => info.projectHash === projectHash); } /** @@ -815,7 +830,8 @@ export class SubagentWatcher extends EventEmitter { } else if (content.type === 'text' && content.text) { const text = content.text.trim(); if (text.length > 0) { - const preview = text.length > TEXT_PREVIEW_LENGTH ? text.substring(0, TEXT_PREVIEW_LENGTH) + '...' : text; + const preview = + text.length > TEXT_PREVIEW_LENGTH ? text.substring(0, TEXT_PREVIEW_LENGTH) + '...' : text; lines.push(`${this.formatTime(entry.timestamp)} 💬 ${preview.replace(/\n/g, ' ')}`); } } @@ -860,7 +876,7 @@ export class SubagentWatcher extends EventEmitter { const MAX_LEN = SMART_TITLE_MAX_LENGTH; // Get first line/sentence - let title = text.split('\n')[0].trim(); + const title = text.split('\n')[0].trim(); // If already short enough, use it if (title.length <= MAX_LEN) { @@ -932,14 +948,18 @@ export class SubagentWatcher extends EventEmitter { // Check cache first (covers burst of simultaneous agent discoveries) const cached = this.parentDescriptionCache.get(cacheKey); - if (cached && (Date.now() - cached.timestamp) < CACHE_TTL_MS) { + if (cached && Date.now() - cached.timestamp < CACHE_TTL_MS) { return cached.descriptions.get(agentId); } try { // The parent session's transcript is at: ~/.claude/projects/{projectHash}/{sessionId}.jsonl const transcriptPath = join(CLAUDE_PROJECTS_DIR, projectHash, `${sessionId}.jsonl`); - try { await statAsync(transcriptPath); } catch { return undefined; } + try { + await statAsync(transcriptPath); + } catch { + return undefined; + } const content = await readFile(transcriptPath, 'utf8'); const lines = content.split('\n').filter((l) => l.trim()); @@ -949,11 +969,7 @@ export class SubagentWatcher extends EventEmitter { for (const line of lines) { try { const entry = JSON.parse(line); - if ( - entry.type === 'user' && - entry.toolUseResult?.agentId && - entry.toolUseResult?.description - ) { + if (entry.type === 'user' && entry.toolUseResult?.agentId && entry.toolUseResult?.description) { descriptions.set(entry.toolUseResult.agentId, entry.toolUseResult.description); } } catch { @@ -982,7 +998,11 @@ export class SubagentWatcher extends EventEmitter { let lineCount = 0; let resolved = false; rl.on('line', (line) => { - if (resolved || lineCount >= 5) { rl.close(); stream.destroy(); return; } + if (resolved || lineCount >= 5) { + rl.close(); + stream.destroy(); + return; + } lineCount++; if (!line.trim()) return; try { @@ -1008,8 +1028,12 @@ export class SubagentWatcher extends EventEmitter { // Skip malformed lines } }); - rl.on('close', () => { if (!resolved) resolve(undefined); }); - rl.on('error', () => { if (!resolved) resolve(undefined); }); + rl.on('close', () => { + if (!resolved) resolve(undefined); + }); + rl.on('error', () => { + if (!resolved) resolve(undefined); + }); }); } catch { // Failed to read file @@ -1021,7 +1045,11 @@ export class SubagentWatcher extends EventEmitter { * Scan for all subagent directories (async to avoid blocking event loop) */ private async scanForSubagents(): Promise { - try { await statAsync(CLAUDE_PROJECTS_DIR); } catch { return; } + try { + await statAsync(CLAUDE_PROJECTS_DIR); + } catch { + return; + } try { const projects = await readdir(CLAUDE_PROJECTS_DIR); @@ -1123,7 +1151,12 @@ export class SubagentWatcher extends EventEmitter { * @param sessionId Claude session ID * @param isInitialScan If true, skip files older than STARTUP_MAX_FILE_AGE_MS */ - private async watchAgentFile(filePath: string, projectHash: string, sessionId: string, isInitialScan: boolean = false): Promise { + private async watchAgentFile( + filePath: string, + projectHash: string, + sessionId: string, + isInitialScan: boolean = false + ): Promise { if (this.fileWatchers.has(filePath)) return; const agentId = basename(filePath).replace('agent-', '').replace('.jsonl', ''); @@ -1192,12 +1225,14 @@ export class SubagentWatcher extends EventEmitter { this.emit('subagent:discovered', info); // Read existing content - this.tailFile(filePath, agentId, sessionId, 0).then((position) => { - this.filePositions.set(filePath, position); - }).catch((err) => { - // Log but don't throw - non-critical background operation - console.warn(`[SubagentWatcher] Failed to read initial content for ${agentId}:`, err); - }); + this.tailFile(filePath, agentId, sessionId, 0) + .then((position) => { + this.filePositions.set(filePath, position); + }) + .catch((err) => { + // Log but don't throw - non-critical background operation + console.warn(`[SubagentWatcher] Failed to read initial content for ${agentId}:`, err); + }); // Watch for changes try { @@ -1269,12 +1304,7 @@ export class SubagentWatcher extends EventEmitter { /** * Tail a file from a specific position */ - private async tailFile( - filePath: string, - agentId: string, - sessionId: string, - fromPosition: number - ): Promise { + private async tailFile(filePath: string, agentId: string, sessionId: string, fromPosition: number): Promise { return new Promise((resolve) => { let position = fromPosition; @@ -1337,11 +1367,7 @@ export class SubagentWatcher extends EventEmitter { // Check if this is first user message and description is missing if (info && !info.description && entry.type === 'user' && entry.message?.content) { // First try parent transcript (most reliable) - let description = await this.extractDescriptionFromParentTranscript( - info.projectHash, - info.sessionId, - agentId - ); + let description = await this.extractDescriptionFromParentTranscript(info.projectHash, info.sessionId, agentId); // Fallback: extract smart title from the prompt content if (!description) { let text: string | undefined; @@ -1378,9 +1404,11 @@ export class SubagentWatcher extends EventEmitter { resultCount: entry.data.resultCount, // Extract hook event info if present hookEvent: entry.data.hookEvent, - hookName: entry.data.hookName || (entry.data.hookEvent && entry.data.tool_name - ? `${entry.data.hookEvent}:${entry.data.tool_name}` - : undefined), + hookName: + entry.data.hookName || + (entry.data.hookEvent && entry.data.tool_name + ? `${entry.data.hookEvent}:${entry.data.tool_name}` + : undefined), }; this.emit('subagent:progress', progress); } else if (entry.type === 'assistant' && entry.message?.content) { @@ -1531,8 +1559,8 @@ export class SubagentWatcher extends EventEmitter { if (typeof content === 'string') return content; if (Array.isArray(content)) { return content - .filter(c => c.type === 'text' && c.text) - .map(c => c.text) + .filter((c) => c.type === 'text' && c.text) + .map((c) => c.text) .join('\n'); } return ''; diff --git a/src/task-queue.ts b/src/task-queue.ts index 23850cad..bf668d0b 100644 --- a/src/task-queue.ts +++ b/src/task-queue.ts @@ -196,7 +196,9 @@ export class TaskQueue extends EventEmitter { private validateDependencies(taskId: string, dependencies: string[]): void { for (const depId of dependencies) { if (this.wouldCreateCycle(taskId, depId)) { - throw new Error(`Circular dependency detected: adding dependency ${depId} to task ${taskId} would create a cycle`); + throw new Error( + `Circular dependency detected: adding dependency ${depId} to task ${taskId} would create a cycle` + ); } } } @@ -208,14 +210,21 @@ export class TaskQueue extends EventEmitter { /** Gets the currently running task for a session, if any. */ getRunningTaskForSession(sessionId: string): Task | null { - return this.getAllTasks().find( - (t) => t.isRunning() && t.assignedSessionId === sessionId - ) || null; + return this.getAllTasks().find((t) => t.isRunning() && t.assignedSessionId === sessionId) || null; } /** Gets counts of tasks by status (single-pass). */ - getCount(): { total: number; pending: number; running: number; completed: number; failed: number } { - let pending = 0, running = 0, completed = 0, failed = 0; + getCount(): { + total: number; + pending: number; + running: number; + completed: number; + failed: number; + } { + let pending = 0, + running = 0, + completed = 0, + failed = 0; for (const task of this.tasks.values()) { if (task.isPending()) pending++; else if (task.isRunning()) running++; @@ -258,7 +267,6 @@ export class TaskQueue extends EventEmitter { this.tasks.clear(); return count; } - } // Singleton instance diff --git a/src/task-tracker.ts b/src/task-tracker.ts index 6006569e..5440e609 100644 --- a/src/task-tracker.ts +++ b/src/task-tracker.ts @@ -51,21 +51,13 @@ const MAX_PENDING_TOOL_USES = 100; * Used as fallback when JSON parsing doesn't capture the launch. * Capture group 1: Agent/task type name */ -const LAUNCH_PATTERNS = [ - /Launching\s+(\w+)\s+agent/i, - /Starting\s+(\w+)\s+task/i, - /Spawning\s+(\w+)\s+agent/i, -]; +const LAUNCH_PATTERNS = [/Launching\s+(\w+)\s+agent/i, /Starting\s+(\w+)\s+task/i, /Spawning\s+(\w+)\s+agent/i]; /** * Patterns that indicate a task has completed. * Used as fallback when JSON parsing doesn't capture the result. */ -const COMPLETE_PATTERNS = [ - /Task\s+completed/i, - /Agent\s+finished/i, - /Background\s+task\s+done/i, -]; +const COMPLETE_PATTERNS = [/Task\s+completed/i, /Agent\s+finished/i, /Background\s+task\s+done/i]; // ========== Type Definitions ========== @@ -218,7 +210,10 @@ export class TaskTracker extends EventEmitter { private taskStack: string[] = []; /** Pending tool_use blocks waiting for results (with timestamp for cleanup) */ - private pendingToolUses: Map = new Map(); + private pendingToolUses: Map< + string, + { description: string; subagentType: string; parentId: string | null; createdAt: number } + > = new Map(); /** * Creates a new TaskTracker instance. @@ -316,7 +311,12 @@ export class TaskTracker extends EventEmitter { const parentId = this.taskStack.length > 0 ? this.taskStack[this.taskStack.length - 1] : null; // Store pending tool use - task starts when we see activity - this.pendingToolUses.set(toolUseId, { description, subagentType, parentId, createdAt: Date.now() }); + this.pendingToolUses.set(toolUseId, { + description, + subagentType, + parentId, + createdAt: Date.now(), + }); // Clean up old pending entries to prevent unbounded growth this.cleanupOldPendingToolUses(); @@ -361,9 +361,7 @@ export class TaskTracker extends EventEmitter { if (task) { task.status = block.is_error ? 'failed' : 'completed'; task.endTime = Date.now(); - task.output = typeof block.content === 'string' - ? block.content - : JSON.stringify(block.content); + task.output = typeof block.content === 'string' ? block.content : JSON.stringify(block.content); // Remove from stack const stackIndex = this.taskStack.indexOf(toolUseId); @@ -610,13 +608,21 @@ export class TaskTracker extends EventEmitter { * - failed: Tasks that ended with errors */ getStats(): { total: number; running: number; completed: number; failed: number } { - let running = 0, completed = 0, failed = 0; + let running = 0, + completed = 0, + failed = 0; for (const task of this.tasks.values()) { switch (task.status) { - case 'running': running++; break; - case 'completed': completed++; break; - case 'failed': failed++; break; + case 'running': + running++; + break; + case 'completed': + completed++; + break; + case 'failed': + failed++; + break; default: assertNever(task.status, `Unhandled BackgroundTask status: ${task.status}`); } diff --git a/src/team-watcher.ts b/src/team-watcher.ts index 4087859e..4e2c5421 100644 --- a/src/team-watcher.ts +++ b/src/team-watcher.ts @@ -86,13 +86,13 @@ export class TeamWatcher extends EventEmitter { getTeamTasks(teamName: string): TeamTask[] { const tasks = this.teamTasks.get(teamName); if (!tasks) return []; - return tasks.filter(t => !t.metadata?._internal); + return tasks.filter((t) => !t.metadata?._internal); } /** Count active (non-completed) tasks for a team */ getActiveTaskCount(teamName: string): number { const tasks = this.getTeamTasks(teamName); - return tasks.filter(t => t.status !== 'completed').length; + return tasks.filter((t) => t.status !== 'completed').length; } /** Get inbox messages for a team member (or all members) */ @@ -108,9 +108,7 @@ export class TeamWatcher extends EventEmitter { messages.push(...msgs); } } - return messages.sort((a, b) => - new Date(a.timestamp).getTime() - new Date(b.timestamp).getTime() - ); + return messages.sort((a, b) => new Date(a.timestamp).getTime() - new Date(b.timestamp).getTime()); } /** Check if a session has active teammates (for idle detection) */ @@ -119,7 +117,7 @@ export class TeamWatcher extends EventEmitter { if (!team) return false; // Check if any non-lead members exist (they are active by definition while present) - const teammates = team.members.filter(m => m.agentType !== 'team-lead'); + const teammates = team.members.filter((m) => m.agentType !== 'team-lead'); if (teammates.length === 0) return false; // Check if team has active (non-completed) tasks @@ -132,19 +130,17 @@ export class TeamWatcher extends EventEmitter { const team = this.teams.get(teamName); if (!team) return []; - return team.members - .filter((m): m is TeamMember & { tmuxPaneId: string } => - m.agentType !== 'team-lead' && - !!m.tmuxPaneId && - m.tmuxPaneId !== 'in-process' - ); + return team.members.filter( + (m): m is TeamMember & { tmuxPaneId: string } => + m.agentType !== 'team-lead' && !!m.tmuxPaneId && m.tmuxPaneId !== 'in-process' + ); } /** Get count of active teammates for a session */ getActiveTeammateCount(sessionId: string): number { const team = this.getTeamForSession(sessionId); if (!team) return 0; - return team.members.filter(m => m.agentType !== 'team-lead').length; + return team.members.filter((m) => m.agentType !== 'team-lead').length; } // ========== Private Methods ========== @@ -257,7 +253,7 @@ export class TeamWatcher extends EventEmitter { let taskFiles: string[]; try { - taskFiles = (await readdir(teamTaskDir)).filter(f => f.endsWith('.json') && f !== '.lock'); + taskFiles = (await readdir(teamTaskDir)).filter((f) => f.endsWith('.json') && f !== '.lock'); } catch { continue; } @@ -285,7 +281,7 @@ export class TeamWatcher extends EventEmitter { let inboxFiles: string[]; try { - inboxFiles = (await readdir(inboxDir)).filter(f => f.endsWith('.json')); + inboxFiles = (await readdir(inboxDir)).filter((f) => f.endsWith('.json')); } catch { continue; } @@ -314,7 +310,7 @@ export class TeamWatcher extends EventEmitter { this.inboxCache.set(cacheKey, messages); // Emit new messages — compare by timestamp to handle deletions/reordering - const prevTimestamps = new Set(previous?.map(m => m.timestamp) || []); + const prevTimestamps = new Set(previous?.map((m) => m.timestamp) || []); for (const msg of messages) { if (!prevTimestamps.has(msg.timestamp)) { this.emit('inboxMessage', { teamName, member: memberName, message: msg }); diff --git a/src/tmux-manager.ts b/src/tmux-manager.ts index af62c836..44f01d3e 100644 --- a/src/tmux-manager.ts +++ b/src/tmux-manager.ts @@ -30,10 +30,25 @@ import { existsSync, readFileSync, mkdirSync } from 'node:fs'; import { writeFile, rename } from 'node:fs/promises'; import { dirname, join } from 'node:path'; import { homedir } from 'node:os'; -import { ProcessStats, PersistedRespawnConfig, getErrorMessage, DEFAULT_NICE_CONFIG, type PaneInfo, type ClaudeMode, type SessionMode, type OpenCodeConfig } from './types.js'; +import { + ProcessStats, + PersistedRespawnConfig, + getErrorMessage, + DEFAULT_NICE_CONFIG, + type PaneInfo, + type ClaudeMode, + type SessionMode, + type OpenCodeConfig, +} from './types.js'; import { wrapWithNice } from './utils/nice-wrapper.js'; import { SAFE_PATH_PATTERN } from './utils/regex-patterns.js'; -import type { TerminalMultiplexer, MuxSession, MuxSessionWithStats, CreateSessionOptions, RespawnPaneOptions } from './mux-interface.js'; +import type { + TerminalMultiplexer, + MuxSession, + MuxSessionWithStats, + CreateSessionOptions, + RespawnPaneOptions, +} from './mux-interface.js'; // Claude CLI PATH resolution — shared utility import { findClaudeDir } from './utils/claude-cli-resolver.js'; @@ -103,11 +118,23 @@ function isValidMuxName(name: string): boolean { * Prevents command injection via malformed paths. */ function isValidPath(path: string): boolean { - if (path.includes(';') || path.includes('&') || path.includes('|') || - path.includes('$') || path.includes('`') || path.includes('(') || - path.includes(')') || path.includes('{') || path.includes('}') || - path.includes('<') || path.includes('>') || path.includes("'") || - path.includes('"') || path.includes('\n') || path.includes('\r')) { + if ( + path.includes(';') || + path.includes('&') || + path.includes('|') || + path.includes('$') || + path.includes('`') || + path.includes('(') || + path.includes(')') || + path.includes('{') || + path.includes('}') || + path.includes('<') || + path.includes('>') || + path.includes("'") || + path.includes('"') || + path.includes('\n') || + path.includes('\r') + ) { return false; } if (path.includes('..')) { @@ -177,7 +204,7 @@ function buildSpawnCommand(options: { }): string { if (options.mode === 'claude') { // Validate model to prevent command injection - const safeModel = (options.model && /^[a-zA-Z0-9._-]+$/.test(options.model)) ? options.model : undefined; + const safeModel = options.model && /^[a-zA-Z0-9._-]+$/.test(options.model) ? options.model : undefined; const modelFlag = safeModel ? ` --model ${safeModel}` : ''; return `claude${buildClaudePermissionFlags(options.claudeMode, options.allowedTools)} --session-id "${options.sessionId}"${modelFlag}`; } @@ -204,7 +231,9 @@ function setOpenCodeEnvVars(muxName: string): void { timeout: EXEC_TIMEOUT_MS, stdio: ['pipe', 'pipe', 'pipe'], }); - } catch { /* Non-critical — key may not be needed */ } + } catch { + /* Non-critical — key may not be needed */ + } } } } @@ -225,7 +254,9 @@ function setOpenCodeConfigContent(muxName: string, config?: OpenCodeConfig): voi const existing = JSON.parse(config.configContent) as Record; Object.assign(permConfig, existing); permConfig.permission = { '*': 'allow' }; - } catch { /* invalid JSON, use default permConfig */ } + } catch { + /* invalid JSON, use default permConfig */ + } } jsonContent = JSON.stringify(permConfig); } else if (config.configContent) { @@ -247,7 +278,9 @@ function setOpenCodeConfigContent(muxName: string, config?: OpenCodeConfig): voi timeout: EXEC_TIMEOUT_MS, stdio: ['pipe', 'pipe', 'pipe'], }); - } catch { /* Non-critical */ } + } catch { + /* Non-critical */ + } } } @@ -394,7 +427,14 @@ export class TmuxManager extends EventEmitter implements TerminalMultiplexer { if (mode === 'claude') envExports.splice(2, 0, 'unset CLAUDECODE'); const envExportsStr = envExports.join(' && '); - const baseCmd = buildSpawnCommand({ mode, sessionId, model, claudeMode, allowedTools, openCodeConfig }); + const baseCmd = buildSpawnCommand({ + mode, + sessionId, + model, + claudeMode, + allowedTools, + openCodeConfig, + }); const config = niceConfig || DEFAULT_NICE_CONFIG; const cmd = wrapWithNice(baseCmd, config); @@ -412,15 +452,22 @@ export class TmuxManager extends EventEmitter implements TerminalMultiplexer { // (Production uses systemd which has a clean env, but dev/test may be nested.) const cleanEnv = { ...process.env }; delete cleanEnv.TMUX; - execSync( - `tmux new-session -ds "${muxName}" -c "${workingDir}" -x 120 -y 40`, - { cwd: workingDir, timeout: EXEC_TIMEOUT_MS, stdio: 'ignore', env: cleanEnv } - ); + execSync(`tmux new-session -ds "${muxName}" -c "${workingDir}" -x 120 -y 40`, { + cwd: workingDir, + timeout: EXEC_TIMEOUT_MS, + stdio: 'ignore', + env: cleanEnv, + }); // Set remain-on-exit now that the server is running — must be before respawn-pane try { - execSync(`tmux set-option -t "${muxName}" remain-on-exit on`, { timeout: EXEC_TIMEOUT_MS, stdio: 'ignore' }); - } catch { /* Non-critical */ } + execSync(`tmux set-option -t "${muxName}" remain-on-exit on`, { + timeout: EXEC_TIMEOUT_MS, + stdio: 'ignore', + }); + } catch { + /* Non-critical */ + } // For OpenCode: set sensitive env vars and config via tmux setenv // (not visible in ps output or tmux history, inherited by panes) @@ -430,13 +477,13 @@ export class TmuxManager extends EventEmitter implements TerminalMultiplexer { } // Replace the shell with the actual command (no echo in terminal) - execSync( - `tmux respawn-pane -k -t "${muxName}" bash -c ${JSON.stringify(fullCmd)}`, - { timeout: EXEC_TIMEOUT_MS, stdio: 'ignore' } - ); + execSync(`tmux respawn-pane -k -t "${muxName}" bash -c ${JSON.stringify(fullCmd)}`, { + timeout: EXEC_TIMEOUT_MS, + stdio: 'ignore', + }); // Wait for tmux session to be queryable - await new Promise(resolve => setTimeout(resolve, TMUX_CREATION_WAIT_MS)); + await new Promise((resolve) => setTimeout(resolve, TMUX_CREATION_WAIT_MS)); // Non-critical tmux config — run in parallel to avoid blocking event loop. // These configure UX niceties (no status bar, true color). @@ -445,18 +492,28 @@ export class TmuxManager extends EventEmitter implements TerminalMultiplexer { const configPromises: Promise[] = [ // Disable tmux status bar — Codeman's web UI provides session info execAsync(`tmux set-option -t "${muxName}" status off`, { timeout: EXEC_TIMEOUT_MS }) - .then(() => {}).catch(() => { /* Non-critical — session still works with status bar */ }), + .then(() => {}) + .catch(() => { + /* Non-critical — session still works with status bar */ + }), // Override global remain-on-exit with session-level setting execAsync(`tmux set-option -t "${muxName}" remain-on-exit on`, { timeout: EXEC_TIMEOUT_MS }) - .then(() => {}).catch(() => { /* Already set globally as fallback */ }), + .then(() => {}) + .catch(() => { + /* Already set globally as fallback */ + }), ]; // Enable 24-bit true color passthrough — server-wide, set once per lifetime if (!this.trueColorConfigured) { configPromises.push( execAsync(`tmux set-option -sa terminal-overrides ",*:Tc"`, { timeout: EXEC_TIMEOUT_MS }) - .then(() => { this.trueColorConfigured = true; }) - .catch(() => { /* Non-critical — colors limited to 256 */ }) + .then(() => { + this.trueColorConfigured = true; + }) + .catch(() => { + /* Non-critical — colors limited to 256 */ + }) ); } @@ -467,7 +524,7 @@ export class TmuxManager extends EventEmitter implements TerminalMultiplexer { // Get the PID of the pane process (retry for tmux server cold-start) let pid = this.getPanePid(muxName); for (let i = 0; !pid && i < GET_PID_MAX_RETRIES; i++) { - await new Promise(resolve => setTimeout(resolve, GET_PID_RETRY_MS)); + await new Promise((resolve) => setTimeout(resolve, GET_PID_RETRY_MS)); pid = this.getPanePid(muxName); } if (!pid) { @@ -507,10 +564,10 @@ export class TmuxManager extends EventEmitter implements TerminalMultiplexer { } try { - const output = execSync( - `tmux display-message -t "${muxName}" -p '#{pane_pid}'`, - { encoding: 'utf-8', timeout: EXEC_TIMEOUT_MS } - ).trim(); + const output = execSync(`tmux display-message -t "${muxName}" -p '#{pane_pid}'`, { + encoding: 'utf-8', + timeout: EXEC_TIMEOUT_MS, + }).trim(); const pid = parseInt(output, 10); return Number.isNaN(pid) ? null : pid; } catch { @@ -533,10 +590,10 @@ export class TmuxManager extends EventEmitter implements TerminalMultiplexer { if (IS_TEST_MODE) return false; if (!isValidMuxName(muxName)) return false; try { - const output = execSync( - `tmux display-message -t "${muxName}" -p '#{pane_dead}'`, - { encoding: 'utf-8', timeout: EXEC_TIMEOUT_MS } - ).trim(); + const output = execSync(`tmux display-message -t "${muxName}" -p '#{pane_dead}'`, { + encoding: 'utf-8', + timeout: EXEC_TIMEOUT_MS, + }).trim(); return output === '1'; } catch { return false; @@ -578,7 +635,14 @@ export class TmuxManager extends EventEmitter implements TerminalMultiplexer { if (mode === 'claude') envExports.splice(2, 0, 'unset CLAUDECODE'); const envExportsStr = envExports.join(' && '); - const baseCmd = buildSpawnCommand({ mode, sessionId, model, claudeMode, allowedTools, openCodeConfig }); + const baseCmd = buildSpawnCommand({ + mode, + sessionId, + model, + claudeMode, + allowedTools, + openCodeConfig, + }); const config = niceConfig || DEFAULT_NICE_CONFIG; const cmd = wrapWithNice(baseCmd, config); const fullCmd = `${pathExport}${envExportsStr} && ${cmd}`; @@ -590,12 +654,11 @@ export class TmuxManager extends EventEmitter implements TerminalMultiplexer { setOpenCodeConfigContent(muxName, openCodeConfig); } - await execAsync( - `tmux respawn-pane -k -t "${muxName}" bash -c ${JSON.stringify(fullCmd)}`, - { timeout: EXEC_TIMEOUT_MS } - ); + await execAsync(`tmux respawn-pane -k -t "${muxName}" bash -c ${JSON.stringify(fullCmd)}`, { + timeout: EXEC_TIMEOUT_MS, + }); // Wait for the respawned process to start - await new Promise(resolve => setTimeout(resolve, TMUX_CREATION_WAIT_MS)); + await new Promise((resolve) => setTimeout(resolve, TMUX_CREATION_WAIT_MS)); const pid = this.getPanePid(muxName); if (pid) session.pid = pid; return pid; @@ -628,7 +691,10 @@ export class TmuxManager extends EventEmitter implements TerminalMultiplexer { timeout: EXEC_TIMEOUT_MS, }).trim(); if (output) { - for (const childPid of output.split('\n').map(p => parseInt(p, 10)).filter(p => !Number.isNaN(p))) { + for (const childPid of output + .split('\n') + .map((p) => parseInt(p, 10)) + .filter((p) => !Number.isNaN(p))) { pids.push(childPid); pids.push(...this.getChildPids(childPid)); } @@ -655,14 +721,14 @@ export class TmuxManager extends EventEmitter implements TerminalMultiplexer { const checkInterval = 100; while (Date.now() - startTime < maxWaitMs) { - const aliveCount = pids.filter(pid => this.isProcessAlive(pid)).length; + const aliveCount = pids.filter((pid) => this.isProcessAlive(pid)).length; if (aliveCount === 0) { return true; } - await new Promise(resolve => setTimeout(resolve, checkInterval)); + await new Promise((resolve) => setTimeout(resolve, checkInterval)); } - const stillAlive = pids.filter(pid => this.isProcessAlive(pid)); + const stillAlive = pids.filter((pid) => this.isProcessAlive(pid)); if (stillAlive.length > 0) { console.warn(`[TmuxManager] ${stillAlive.length} processes still alive after kill: ${stillAlive.join(', ')}`); } @@ -717,7 +783,7 @@ export class TmuxManager extends EventEmitter implements TerminalMultiplexer { } } - await new Promise(resolve => setTimeout(resolve, TMUX_KILL_WAIT_MS)); + await new Promise((resolve) => setTimeout(resolve, TMUX_KILL_WAIT_MS)); childPids = this.getChildPids(currentPid); for (const childPid of childPids) { @@ -735,7 +801,7 @@ export class TmuxManager extends EventEmitter implements TerminalMultiplexer { if (this.isProcessAlive(currentPid)) { try { process.kill(-currentPid, 'SIGTERM'); - await new Promise(resolve => setTimeout(resolve, GRACEFUL_SHUTDOWN_WAIT_MS)); + await new Promise((resolve) => setTimeout(resolve, GRACEFUL_SHUTDOWN_WAIT_MS)); if (this.isProcessAlive(currentPid)) { process.kill(-currentPid, 'SIGKILL'); } @@ -829,10 +895,10 @@ export class TmuxManager extends EventEmitter implements TerminalMultiplexer { // Discover unknown codeman sessions try { - const output = execSync( - "tmux list-sessions -F '#{session_name}' 2>/dev/null || true", - { encoding: 'utf-8', timeout: EXEC_TIMEOUT_MS } - ).trim(); + const output = execSync("tmux list-sessions -F '#{session_name}' 2>/dev/null || true", { + encoding: 'utf-8', + timeout: EXEC_TIMEOUT_MS, + }).trim(); for (const line of output.split('\n')) { const sessionName = line.trim(); @@ -890,26 +956,26 @@ export class TmuxManager extends EventEmitter implements TerminalMultiplexer { } try { - const psOutput = execSync( - `ps -o rss=,pcpu= -p ${session.pid} 2>/dev/null || echo "0 0"`, - { encoding: 'utf-8', timeout: EXEC_TIMEOUT_MS } - ).trim(); + const psOutput = execSync(`ps -o rss=,pcpu= -p ${session.pid} 2>/dev/null || echo "0 0"`, { + encoding: 'utf-8', + timeout: EXEC_TIMEOUT_MS, + }).trim(); - const [rss, cpu] = psOutput.split(/\s+/).map(x => parseFloat(x) || 0); + const [rss, cpu] = psOutput.split(/\s+/).map((x) => parseFloat(x) || 0); let childCount = 0; try { - const childOutput = execSync( - `pgrep -P ${session.pid} | wc -l`, - { encoding: 'utf-8', timeout: EXEC_TIMEOUT_MS } - ).trim(); + const childOutput = execSync(`pgrep -P ${session.pid} | wc -l`, { + encoding: 'utf-8', + timeout: EXEC_TIMEOUT_MS, + }).trim(); childCount = parseInt(childOutput, 10) || 0; } catch { // No children or command failed } return { - memoryMB: Math.round(rss / 1024 * 10) / 10, + memoryMB: Math.round((rss / 1024) * 10) / 10, cpuPercent: Math.round(cpu * 10) / 10, childCount, updatedAt: Date.now(), @@ -921,7 +987,7 @@ export class TmuxManager extends EventEmitter implements TerminalMultiplexer { async getSessionsWithStats(): Promise { if (IS_TEST_MODE) { - return Array.from(this.sessions.values()).map(s => ({ + return Array.from(this.sessions.values()).map((s) => ({ ...s, stats: { memoryMB: 0, cpuPercent: 0, childCount: 0, updatedAt: Date.now() }, })); @@ -932,7 +998,7 @@ export class TmuxManager extends EventEmitter implements TerminalMultiplexer { return []; } - const sessionPids = sessions.map(s => s.pid); + const sessionPids = sessions.map((s) => s.pid); const statsMap = new Map(); try { @@ -941,7 +1007,10 @@ export class TmuxManager extends EventEmitter implements TerminalMultiplexer { const pgrepOutput = execSync( `for p in ${sessionPids.join(' ')}; do children=$(pgrep -P $p 2>/dev/null | tr '\\n' ','); echo "$p:$children"; done`, - { encoding: 'utf-8', timeout: EXEC_TIMEOUT_MS } + { + encoding: 'utf-8', + timeout: EXEC_TIMEOUT_MS, + } ).trim(); for (const line of pgrepOutput.split('\n')) { @@ -950,8 +1019,8 @@ export class TmuxManager extends EventEmitter implements TerminalMultiplexer { if (!Number.isNaN(sessionPid)) { const children = (childrenStr || '') .split(',') - .map(s => parseInt(s.trim(), 10)) - .filter(n => !Number.isNaN(n) && n > 0); + .map((s) => parseInt(s.trim(), 10)) + .filter((n) => !Number.isNaN(n) && n > 0); descendantMap.set(sessionPid, children); } } @@ -967,10 +1036,10 @@ export class TmuxManager extends EventEmitter implements TerminalMultiplexer { // Step 3: Single ps call const pidArray = Array.from(allPids); if (pidArray.length > 0) { - const psOutput = execSync( - `ps -o pid=,rss=,pcpu= -p ${pidArray.join(',')} 2>/dev/null || true`, - { encoding: 'utf-8', timeout: EXEC_TIMEOUT_MS } - ).trim(); + const psOutput = execSync(`ps -o pid=,rss=,pcpu= -p ${pidArray.join(',')} 2>/dev/null || true`, { + encoding: 'utf-8', + timeout: EXEC_TIMEOUT_MS, + }).trim(); const processStats = new Map(); for (const line of psOutput.split('\n')) { @@ -1002,7 +1071,7 @@ export class TmuxManager extends EventEmitter implements TerminalMultiplexer { } statsMap.set(sessionPid, { - memoryMB: Math.round(totalRss / 1024 * 10) / 10, + memoryMB: Math.round((totalRss / 1024) * 10) / 10, cpuPercent: Math.round(totalCpu * 10) / 10, childCount: children.length, updatedAt: Date.now(), @@ -1011,7 +1080,7 @@ export class TmuxManager extends EventEmitter implements TerminalMultiplexer { } } catch { // Fall back to individual queries - const statsPromises = sessions.map(session => this.getProcessStats(session.sessionId)); + const statsPromises = sessions.map((session) => this.getProcessStats(session.sessionId)); const results = await Promise.allSettled(statsPromises); return sessions.map((session, i) => ({ ...session, @@ -1019,7 +1088,7 @@ export class TmuxManager extends EventEmitter implements TerminalMultiplexer { })); } - return sessions.map(session => ({ + return sessions.map((session) => ({ ...session, stats: statsMap.get(session.pid) || undefined, })); @@ -1145,7 +1214,9 @@ export class TmuxManager extends EventEmitter implements TerminalMultiplexer { async sendInput(sessionId: string, input: string): Promise { const session = this.sessions.get(sessionId); if (!session) { - console.error(`[TmuxManager] sendInput failed: no session found for ${sessionId}. Known: ${Array.from(this.sessions.keys()).join(', ')}`); + console.error( + `[TmuxManager] sendInput failed: no session found for ${sessionId}. Known: ${Array.from(this.sessions.keys()).join(', ')}` + ); return false; } @@ -1154,7 +1225,9 @@ export class TmuxManager extends EventEmitter implements TerminalMultiplexer { return true; } - console.log(`[TmuxManager] sendInput to ${session.muxName}, input length: ${input.length}, hasCarriageReturn: ${input.includes('\r')}`); + console.log( + `[TmuxManager] sendInput to ${session.muxName}, input length: ${input.length}, hasCarriageReturn: ${input.includes('\r')}` + ); if (!isValidMuxName(session.muxName)) { console.error('[TmuxManager] Invalid session name in sendInput:', session.muxName); @@ -1170,27 +1243,23 @@ export class TmuxManager extends EventEmitter implements TerminalMultiplexer { // Ink (Claude CLI's terminal framework) needs them split — sending both in a // single tmux invocation (via \;) causes Ink to interpret Enter as a newline // character in the input buffer rather than as form submission. - await execAsync( - `tmux send-keys -t "${session.muxName}" -l ${shellescape(textPart)}`, - { timeout: EXEC_TIMEOUT_MS } - ); - await new Promise(resolve => setTimeout(resolve, 50)); - await execAsync( - `tmux send-keys -t "${session.muxName}" Enter`, - { timeout: EXEC_TIMEOUT_MS } - ); + await execAsync(`tmux send-keys -t "${session.muxName}" -l ${shellescape(textPart)}`, { + timeout: EXEC_TIMEOUT_MS, + }); + await new Promise((resolve) => setTimeout(resolve, 50)); + await execAsync(`tmux send-keys -t "${session.muxName}" Enter`, { + timeout: EXEC_TIMEOUT_MS, + }); } else if (textPart) { // Text only, no Enter - await execAsync( - `tmux send-keys -t "${session.muxName}" -l ${shellescape(textPart)}`, - { timeout: EXEC_TIMEOUT_MS } - ); + await execAsync(`tmux send-keys -t "${session.muxName}" -l ${shellescape(textPart)}`, { + timeout: EXEC_TIMEOUT_MS, + }); } else if (hasCarriageReturn) { // Enter only - await execAsync( - `tmux send-keys -t "${session.muxName}" Enter`, - { timeout: EXEC_TIMEOUT_MS } - ); + await execAsync(`tmux send-keys -t "${session.muxName}" Enter`, { + timeout: EXEC_TIMEOUT_MS, + }); } return true; @@ -1215,10 +1284,10 @@ export class TmuxManager extends EventEmitter implements TerminalMultiplexer { } try { - execSync( - `tmux set-option -t "${muxName}" mouse on`, - { encoding: 'utf-8', timeout: EXEC_TIMEOUT_MS } - ); + execSync(`tmux set-option -t "${muxName}" mouse on`, { + encoding: 'utf-8', + timeout: EXEC_TIMEOUT_MS, + }); console.log(`[TmuxManager] Mouse mode ON for ${muxName}`); return true; } catch (err) { @@ -1239,10 +1308,10 @@ export class TmuxManager extends EventEmitter implements TerminalMultiplexer { } try { - execSync( - `tmux set-option -t "${muxName}" mouse off`, - { encoding: 'utf-8', timeout: EXEC_TIMEOUT_MS } - ); + execSync(`tmux set-option -t "${muxName}" mouse off`, { + encoding: 'utf-8', + timeout: EXEC_TIMEOUT_MS, + }); console.log(`[TmuxManager] Mouse mode OFF for ${muxName}`); return true; } catch (err) { @@ -1283,16 +1352,19 @@ export class TmuxManager extends EventEmitter implements TerminalMultiplexer { { encoding: 'utf-8', timeout: EXEC_TIMEOUT_MS } ).trim(); - return output.split('\n').map(line => { - const [paneId, indexStr, pidStr, widthStr, heightStr] = line.split(':'); - return { - paneId, - paneIndex: parseInt(indexStr, 10), - panePid: parseInt(pidStr, 10), - width: parseInt(widthStr, 10), - height: parseInt(heightStr, 10), - }; - }).filter(p => !Number.isNaN(p.paneIndex)); + return output + .split('\n') + .map((line) => { + const [paneId, indexStr, pidStr, widthStr, heightStr] = line.split(':'); + return { + paneId, + paneIndex: parseInt(indexStr, 10), + panePid: parseInt(pidStr, 10), + width: parseInt(widthStr, 10), + height: parseInt(heightStr, 10), + }; + }) + .filter((p) => !Number.isNaN(p.paneIndex)); } catch { return []; } @@ -1314,33 +1386,31 @@ export class TmuxManager extends EventEmitter implements TerminalMultiplexer { } // Build target: sessionName.paneId (e.g., "codeman-abc12345.%1") - const target = paneTarget.startsWith('%') - ? `${muxName}.${paneTarget}` - : `${muxName}.%${paneTarget}`; + const target = paneTarget.startsWith('%') ? `${muxName}.${paneTarget}` : `${muxName}.%${paneTarget}`; try { const hasCarriageReturn = input.includes('\r'); const textPart = input.replace(/\r/g, '').replace(/\n/g, '').trimEnd(); if (textPart && hasCarriageReturn) { - execSync( - `tmux send-keys -t ${shellescape(target)} -l ${shellescape(textPart)}`, - { encoding: 'utf-8', timeout: EXEC_TIMEOUT_MS } - ); - execSync( - `tmux send-keys -t ${shellescape(target)} Enter`, - { encoding: 'utf-8', timeout: EXEC_TIMEOUT_MS } - ); + execSync(`tmux send-keys -t ${shellescape(target)} -l ${shellescape(textPart)}`, { + encoding: 'utf-8', + timeout: EXEC_TIMEOUT_MS, + }); + execSync(`tmux send-keys -t ${shellescape(target)} Enter`, { + encoding: 'utf-8', + timeout: EXEC_TIMEOUT_MS, + }); } else if (textPart) { - execSync( - `tmux send-keys -t ${shellescape(target)} -l ${shellescape(textPart)}`, - { encoding: 'utf-8', timeout: EXEC_TIMEOUT_MS } - ); + execSync(`tmux send-keys -t ${shellescape(target)} -l ${shellescape(textPart)}`, { + encoding: 'utf-8', + timeout: EXEC_TIMEOUT_MS, + }); } else if (hasCarriageReturn) { - execSync( - `tmux send-keys -t ${shellescape(target)} Enter`, - { encoding: 'utf-8', timeout: EXEC_TIMEOUT_MS } - ); + execSync(`tmux send-keys -t ${shellescape(target)} Enter`, { + encoding: 'utf-8', + timeout: EXEC_TIMEOUT_MS, + }); } return true; @@ -1365,15 +1435,13 @@ export class TmuxManager extends EventEmitter implements TerminalMultiplexer { return null; } - const target = paneTarget.startsWith('%') - ? `${muxName}.${paneTarget}` - : `${muxName}.%${paneTarget}`; + const target = paneTarget.startsWith('%') ? `${muxName}.${paneTarget}` : `${muxName}.%${paneTarget}`; try { - return execSync( - `tmux capture-pane -p -e -t ${shellescape(target)} -S -5000`, - { encoding: 'utf-8', timeout: EXEC_TIMEOUT_MS } - ); + return execSync(`tmux capture-pane -p -e -t ${shellescape(target)} -S -5000`, { + encoding: 'utf-8', + timeout: EXEC_TIMEOUT_MS, + }); } catch (err) { console.error('[TmuxManager] Failed to capture pane buffer:', err); return null; @@ -1399,15 +1467,13 @@ export class TmuxManager extends EventEmitter implements TerminalMultiplexer { return false; } - const target = paneTarget.startsWith('%') - ? `${muxName}.${paneTarget}` - : `${muxName}.%${paneTarget}`; + const target = paneTarget.startsWith('%') ? `${muxName}.${paneTarget}` : `${muxName}.%${paneTarget}`; try { - execSync( - `tmux pipe-pane -O -t ${shellescape(target)} ${shellescape('cat >> ' + outputFile)}`, - { encoding: 'utf-8', timeout: EXEC_TIMEOUT_MS } - ); + execSync(`tmux pipe-pane -O -t ${shellescape(target)} ${shellescape('cat >> ' + outputFile)}`, { + encoding: 'utf-8', + timeout: EXEC_TIMEOUT_MS, + }); return true; } catch (err) { console.error('[TmuxManager] Failed to start pipe-pane:', err); @@ -1429,15 +1495,13 @@ export class TmuxManager extends EventEmitter implements TerminalMultiplexer { return false; } - const target = paneTarget.startsWith('%') - ? `${muxName}.${paneTarget}` - : `${muxName}.%${paneTarget}`; + const target = paneTarget.startsWith('%') ? `${muxName}.${paneTarget}` : `${muxName}.%${paneTarget}`; try { - execSync( - `tmux pipe-pane -t ${shellescape(target)}`, - { encoding: 'utf-8', timeout: EXEC_TIMEOUT_MS } - ); + execSync(`tmux pipe-pane -t ${shellescape(target)}`, { + encoding: 'utf-8', + timeout: EXEC_TIMEOUT_MS, + }); return true; } catch (err) { console.error('[TmuxManager] Failed to stop pipe-pane:', err); diff --git a/src/transcript-watcher.ts b/src/transcript-watcher.ts index 42f68699..356e0397 100644 --- a/src/transcript-watcher.ts +++ b/src/transcript-watcher.ts @@ -86,12 +86,7 @@ const POLL_INTERVAL_MS = 1000; const MAX_MESSAGE_LENGTH = 500; /** Patterns that indicate plan mode / approval prompt */ -const PLAN_MODE_PATTERNS = [ - /ExitPlanMode/i, - /AskUserQuestion/i, - /Ready for user approval/i, - /approve.*plan/i, -]; +const PLAN_MODE_PATTERNS = [/ExitPlanMode/i, /AskUserQuestion/i, /Ready for user approval/i, /approve.*plan/i]; // ========== TranscriptWatcher Class ========== @@ -410,12 +405,13 @@ export class TranscriptWatcher extends EventEmitter { if (entry.type !== 'assistant' || !entry.message?.content) return; const content = entry.message.content; - const textToCheck = typeof content === 'string' - ? content - : content - .filter((b): b is { type: 'text'; text: string } => b.type === 'text' && !!b.text) - .map(b => b.text) - .join(' '); + const textToCheck = + typeof content === 'string' + ? content + : content + .filter((b): b is { type: 'text'; text: string } => b.type === 'text' && !!b.text) + .map((b) => b.text) + .join(' '); // Also check for tool_use with ExitPlanMode or AskUserQuestion if (Array.isArray(content)) { diff --git a/src/tunnel-manager.ts b/src/tunnel-manager.ts index 62a9f03c..4d1e6a99 100644 --- a/src/tunnel-manager.ts +++ b/src/tunnel-manager.ts @@ -112,7 +112,10 @@ export class TunnelManager extends EventEmitter { const binary = this.resolveCloudflared(); if (!binary) { - this.emit('error', 'cloudflared not found. Install from https://developers.cloudflare.com/cloudflare-one/connections/connect-networks/downloads/'); + this.emit( + 'error', + 'cloudflared not found. Install from https://developers.cloudflare.com/cloudflare-one/connections/connect-networks/downloads/' + ); return; } diff --git a/src/types.ts b/src/types.ts index d0841727..1ff36b6c 100644 --- a/src/types.ts +++ b/src/types.ts @@ -80,16 +80,16 @@ export type TddPhase = 'setup' | 'test' | 'impl' | 'verify' | 'review'; /** Types of session lifecycle events recorded to the audit log */ export type LifecycleEventType = - | 'created' // Session object created - | 'started' // PTY process launched (interactive/shell/prompt) - | 'exit' // PTY process exited (with exit code) - | 'deleted' // cleanupSession() called — session removed - | 'detached' // Server shutdown — PTY left alive in tmux for recovery - | 'recovered' // Session restored from tmux on server restart - | 'stale_cleaned' // Removed from state.json by cleanupStaleSessions() - | 'mux_died' // tmux session died (detected by reconciliation) - | 'server_started' // Server started (marker for restart detection) - | 'server_stopped'; // Server shutting down + | 'created' // Session object created + | 'started' // PTY process launched (interactive/shell/prompt) + | 'exit' // PTY process exited (with exit code) + | 'deleted' // cleanupSession() called — session removed + | 'detached' // Server shutdown — PTY left alive in tmux for recovery + | 'recovered' // Session restored from tmux on server restart + | 'stale_cleaned' // Removed from state.json by cleanupStaleSessions() + | 'mux_died' // tmux session died (detected by reconciliation) + | 'server_started' // Server started (marker for restart detection) + | 'server_stopped'; // Server shutting down /** A single entry in the session lifecycle audit log */ export interface LifecycleEntry { @@ -145,15 +145,7 @@ export interface SessionConfig { /** * Available session colors for visual differentiation */ -export type SessionColor = - | 'default' - | 'red' - | 'orange' - | 'yellow' - | 'green' - | 'blue' - | 'purple' - | 'pink'; +export type SessionColor = 'default' | 'red' | 'orange' | 'yellow' | 'green' | 'blue' | 'purple' | 'pink'; /** * Current state of a session @@ -472,11 +464,11 @@ export interface RespawnConfig { * Outcome of a respawn cycle */ export type CycleOutcome = - | 'success' // Cycle completed normally - | 'stuck_recovery' // Stuck-state recovery triggered - | 'blocked' // Blocked by circuit breaker or exit signal - | 'error' // Error during cycle - | 'cancelled'; // Cancelled (e.g., controller stopped) + | 'success' // Cycle completed normally + | 'stuck_recovery' // Stuck-state recovery triggered + | 'blocked' // Blocked by circuit breaker or exit signal + | 'error' // Error during cycle + | 'cancelled'; // Cancelled (e.g., controller stopped) /** * Metrics for a single respawn cycle. @@ -687,7 +679,13 @@ export const ErrorMessages: Record = { /** * Hook event types triggered by Claude Code's hooks system */ -export type HookEventType = 'idle_prompt' | 'permission_prompt' | 'elicitation_dialog' | 'stop' | 'teammate_idle' | 'task_completed'; +export type HookEventType = + | 'idle_prompt' + | 'permission_prompt' + | 'elicitation_dialog' + | 'stop' + | 'teammate_idle' + | 'task_completed'; // ========== API Response Types ========== @@ -842,12 +840,12 @@ export const DEFAULT_CONFIG: AppConfig = { maxConcurrentSessions: 5, stateFilePath: '', respawn: { - idleTimeoutMs: 5000, // 5 seconds of no activity after prompt + idleTimeoutMs: 5000, // 5 seconds of no activity after prompt updatePrompt: 'update all the docs and CLAUDE.md', - interStepDelayMs: 1000, // 1 second between steps - enabled: false, // disabled by default - sendClear: true, // send /clear after update prompt - sendInit: true, // send /init after /clear + interStepDelayMs: 1000, // 1 second between steps + enabled: false, // disabled by default + sendClear: true, // send /clear after update prompt + sendInit: true, // send /init after /clear }, lastUsedCase: null, ralphEnabled: false, @@ -1117,7 +1115,7 @@ export function createInitialCircuitBreakerStatus(): CircuitBreakerStatus { */ export function createInitialRalphTrackerState(): RalphTrackerState { return { - enabled: false, // Disabled by default, auto-enables when Ralph patterns detected + enabled: false, // Disabled by default, auto-enables when Ralph patterns detected active: false, completionPhrase: null, startedAt: null, diff --git a/src/utils/buffer-accumulator.ts b/src/utils/buffer-accumulator.ts index d61b949b..7e1eeccc 100644 --- a/src/utils/buffer-accumulator.ts +++ b/src/utils/buffer-accumulator.ts @@ -149,7 +149,7 @@ export class BufferAccumulator { * @returns True if buffer ends with the suffix */ endsWith(suffix: string): boolean { - if (!suffix) return true; // All strings end with empty string + if (!suffix) return true; // All strings end with empty string if (suffix.length > this.totalLength) return false; return this.tail(suffix.length) === suffix; } diff --git a/src/utils/claude-cli-resolver.ts b/src/utils/claude-cli-resolver.ts index 5999267b..82cbe5f2 100644 --- a/src/utils/claude-cli-resolver.ts +++ b/src/utils/claude-cli-resolver.ts @@ -57,7 +57,7 @@ export function findClaudeDir(): string | null { } } - _claudeDir = ''; // mark as searched, not found + _claudeDir = ''; // mark as searched, not found return null; } diff --git a/src/utils/cleanup-manager.ts b/src/utils/cleanup-manager.ts index 67a4a0f1..8f1ea99d 100644 --- a/src/utils/cleanup-manager.ts +++ b/src/utils/cleanup-manager.ts @@ -115,11 +115,7 @@ export class CleanupManager implements Disposable { * @param options - Optional configuration * @returns Timer ID for manual clearing if needed */ - setTimeout( - callback: () => void, - delay: number, - options?: TimerOptions - ): string { + setTimeout(callback: () => void, delay: number, options?: TimerOptions): string { const id = uuidv4(); const timeoutId = setTimeout(() => { // Remove registration when timer fires naturally @@ -148,11 +144,7 @@ export class CleanupManager implements Disposable { * @param options - Optional configuration * @returns Interval ID for manual clearing if needed */ - setInterval( - callback: () => void, - delay: number, - options?: TimerOptions - ): string { + setInterval(callback: () => void, delay: number, options?: TimerOptions): string { const id = uuidv4(); const intervalId = setInterval(() => { // Don't execute if stopped @@ -179,11 +171,7 @@ export class CleanupManager implements Disposable { * @param description - Human-readable description * @returns Registration ID for manual removal if needed */ - registerCleanup( - type: CleanupResourceType, - cleanup: () => void, - description: string - ): string { + registerCleanup(type: CleanupResourceType, cleanup: () => void, description: string): string { const id = uuidv4(); this.register({ id, @@ -202,10 +190,7 @@ export class CleanupManager implements Disposable { * @param description - Human-readable description * @returns Registration ID */ - registerWatcher( - watcher: { close: () => void }, - description: string - ): string { + registerWatcher(watcher: { close: () => void }, description: string): string { return this.registerCleanup('watcher', () => watcher.close(), description); } @@ -218,19 +203,23 @@ export class CleanupManager implements Disposable { * @param description - Human-readable description * @returns Registration ID */ - registerListener void) => void; off?: (event: string, listener: () => void) => void }>( - emitter: T, - event: string, - listener: () => void, - description: string - ): string { - return this.registerCleanup('listener', () => { - if (emitter.removeListener) { - emitter.removeListener(event, listener); - } else if (emitter.off) { - emitter.off(event, listener); - } - }, description); + registerListener< + T extends { + removeListener?: (event: string, listener: () => void) => void; + off?: (event: string, listener: () => void) => void; + }, + >(emitter: T, event: string, listener: () => void, description: string): string { + return this.registerCleanup( + 'listener', + () => { + if (emitter.removeListener) { + emitter.removeListener(event, listener); + } else if (emitter.off) { + emitter.off(event, listener); + } + }, + description + ); } /** @@ -240,17 +229,18 @@ export class CleanupManager implements Disposable { * @param description - Human-readable description * @returns Registration ID */ - registerStream( - stream: { destroy?: () => void; close?: () => void }, - description: string - ): string { - return this.registerCleanup('stream', () => { - if (stream.destroy) { - stream.destroy(); - } else if (stream.close) { - stream.close(); - } - }, description); + registerStream(stream: { destroy?: () => void; close?: () => void }, description: string): string { + return this.registerCleanup( + 'stream', + () => { + if (stream.destroy) { + stream.destroy(); + } else if (stream.close) { + stream.close(); + } + }, + description + ); } /** @@ -297,8 +287,10 @@ export class CleanupManager implements Disposable { this.registrations.clear(); if (errors.length > 0) { - console.error(`[CleanupManager] ${errors.length} errors during disposal:`, - errors.map(e => e.description).join(', ')); + console.error( + `[CleanupManager] ${errors.length} errors during disposal:`, + errors.map((e) => e.description).join(', ') + ); } } diff --git a/src/utils/index.ts b/src/utils/index.ts index aaf790c0..8f1cac54 100644 --- a/src/utils/index.ts +++ b/src/utils/index.ts @@ -19,17 +19,8 @@ export { createAnsiPatternSimple, stripAnsi, } from './regex-patterns.js'; -export { - MAX_SESSION_TOKENS, - validateTokenCounts, - validateTokensAndCost, -} from './token-validation.js'; -export { - stringSimilarity, - normalizePhrase, - fuzzyPhraseMatch, - todoContentHash, -} from './string-similarity.js'; +export { MAX_SESSION_TOKENS, validateTokenCounts, validateTokensAndCost } from './token-validation.js'; +export { stringSimilarity, normalizePhrase, fuzzyPhraseMatch, todoContentHash } from './string-similarity.js'; export { assertNever } from './type-safety.js'; export { wrapWithNice } from './nice-wrapper.js'; export { findClaudeDir, getAugmentedPath } from './claude-cli-resolver.js'; diff --git a/src/utils/opencode-cli-resolver.ts b/src/utils/opencode-cli-resolver.ts index 4a223d58..4600d7a5 100644 --- a/src/utils/opencode-cli-resolver.ts +++ b/src/utils/opencode-cli-resolver.ts @@ -17,13 +17,13 @@ const EXEC_TIMEOUT_MS = 5000; /** Common directories where the OpenCode CLI binary may be installed */ const OPENCODE_SEARCH_DIRS = [ - join(homedir(), '.opencode', 'bin'), // Default install location - join(homedir(), '.local', 'bin'), // Alternative install location - '/usr/local/bin', // Homebrew / system - join(homedir(), 'go', 'bin'), // Go install - join(homedir(), '.bun', 'bin'), // Bun global - join(homedir(), '.npm-global', 'bin'), // npm global - join(homedir(), 'bin'), // User bin + join(homedir(), '.opencode', 'bin'), // Default install location + join(homedir(), '.local', 'bin'), // Alternative install location + '/usr/local/bin', // Homebrew / system + join(homedir(), 'go', 'bin'), // Go install + join(homedir(), '.bun', 'bin'), // Bun global + join(homedir(), '.npm-global', 'bin'), // npm global + join(homedir(), 'bin'), // User bin ]; /** Cached directory containing the opencode binary (empty string = searched but not found) */ @@ -41,7 +41,10 @@ export function resolveOpenCodeDir(): string | null { // Try `which` first (respects current PATH) try { - const result = execSync('which opencode', { encoding: 'utf-8', timeout: EXEC_TIMEOUT_MS }).trim(); + const result = execSync('which opencode', { + encoding: 'utf-8', + timeout: EXEC_TIMEOUT_MS, + }).trim(); if (result && existsSync(result)) { _openCodeDir = dirname(result); return _openCodeDir; @@ -58,7 +61,7 @@ export function resolveOpenCodeDir(): string | null { } } - _openCodeDir = ''; // mark as searched, not found + _openCodeDir = ''; // mark as searched, not found return null; } diff --git a/src/utils/regex-patterns.ts b/src/utils/regex-patterns.ts index 14ec9894..590043b1 100644 --- a/src/utils/regex-patterns.ts +++ b/src/utils/regex-patterns.ts @@ -17,6 +17,7 @@ * Use this when you need complete ANSI stripping including OSC sequences. * Note: Has global flag - reset lastIndex before exec() if reusing. */ +// eslint-disable-next-line no-control-regex export const ANSI_ESCAPE_PATTERN_FULL = /\x1b(?:\[[0-9;?]*[A-Za-z]|\][^\x07\x1b]*(?:\x07|\x1b\\)|[=>])/g; /** @@ -26,6 +27,7 @@ export const ANSI_ESCAPE_PATTERN_FULL = /\x1b(?:\[[0-9;?]*[A-Za-z]|\][^\x07\x1b] * Use this for faster stripping when OSC sequences aren't a concern. * Note: Has global flag - reset lastIndex before exec() if reusing. */ +// eslint-disable-next-line no-control-regex export const ANSI_ESCAPE_PATTERN_SIMPLE = /\x1b\[[0-9;]*[A-Za-z]/g; /** @@ -43,6 +45,7 @@ export const TOKEN_PATTERN = /(\d+(?:\.\d+)?)\s*([kKmM])?\s*tokens/; * Use when you need a pattern without shared lastIndex state. */ export function createAnsiPatternFull(): RegExp { + // eslint-disable-next-line no-control-regex return /\x1b(?:\[[0-9;?]*[A-Za-z]|\][^\x07\x1b]*(?:\x07|\x1b\\)|[=>])/g; } @@ -51,6 +54,7 @@ export function createAnsiPatternFull(): RegExp { * Use when you need a pattern without shared lastIndex state. */ export function createAnsiPatternSimple(): RegExp { + // eslint-disable-next-line no-control-regex return /\x1b\[[0-9;]*[A-Za-z]/g; } @@ -74,5 +78,4 @@ export function stripAnsi(text: string): string { */ export const SPINNER_PATTERN = /[⠋⠙⠹⠸⠼⠴⠦⠧]/; -export const SAFE_PATH_PATTERN = /^[a-zA-Z0-9_\/\-. ~]+$/; - +export const SAFE_PATH_PATTERN = /^[a-zA-Z0-9_/\-. ~]+$/; diff --git a/src/utils/stale-expiration-map.ts b/src/utils/stale-expiration-map.ts index 1862d120..f5e35925 100644 --- a/src/utils/stale-expiration-map.ts +++ b/src/utils/stale-expiration-map.ts @@ -245,29 +245,23 @@ export class StaleExpirationMap implements Disposable { /** * Get all keys (non-expired). */ - keys(): IterableIterator { - const self = this; - return (function* () { - for (const [key, entry] of self.entries) { - if (!self.isExpired(entry)) { - yield key; - } + *keys(): IterableIterator { + for (const [key, entry] of this.entries) { + if (!this.isExpired(entry)) { + yield key; } - })(); + } } /** * Get all values (non-expired). */ - values(): IterableIterator { - const self = this; - return (function* () { - for (const [, entry] of self.entries) { - if (!self.isExpired(entry)) { - yield entry.value; - } + *values(): IterableIterator { + for (const [, entry] of this.entries) { + if (!this.isExpired(entry)) { + yield entry.value; } - })(); + } } /** diff --git a/src/utils/string-similarity.ts b/src/utils/string-similarity.ts index 869949df..27ea785d 100644 --- a/src/utils/string-similarity.ts +++ b/src/utils/string-similarity.ts @@ -55,8 +55,8 @@ export function levenshteinDistance(a: string, b: string): number { for (let i = 1; i <= m; i++) { const cost = a[i - 1] === b[j - 1] ? 0 : 1; curr[i] = Math.min( - prev[i] + 1, // deletion - curr[i - 1] + 1, // insertion + prev[i] + 1, // deletion + curr[i - 1] + 1, // insertion prev[i - 1] + cost // substitution ); } @@ -139,7 +139,7 @@ export function isSimilarByDistance(a: string, b: string, maxDistance = 2): bool export function normalizePhrase(phrase: string): string { return phrase .toUpperCase() - .replace(/[\s_\-\.]+/g, '') // Remove whitespace, underscores, hyphens, dots + .replace(/[\s_\-.]+/g, '') // Remove whitespace, underscores, hyphens, dots .trim(); } @@ -161,11 +161,7 @@ export function normalizePhrase(phrase: string): string { * fuzzyPhraseMatch('TASK_DONE', 'TASKDONE') // true (separator) * fuzzyPhraseMatch('COMPLETE', 'FINISHED') // false (different word) */ -export function fuzzyPhraseMatch( - phrase1: string, - phrase2: string, - maxDistance = 2 -): boolean { +export function fuzzyPhraseMatch(phrase1: string, phrase2: string, maxDistance = 2): boolean { const norm1 = normalizePhrase(phrase1); const norm2 = normalizePhrase(phrase2); @@ -201,7 +197,7 @@ export function todoContentHash(content: string): string { let hash = 0; for (let i = 0; i < normalized.length; i++) { const char = normalized.charCodeAt(i); - hash = ((hash << 5) - hash) + char; + hash = (hash << 5) - hash + char; hash = hash & hash; // Convert to 32-bit integer } return hash.toString(36); diff --git a/src/utils/token-validation.ts b/src/utils/token-validation.ts index 5900d793..bb554318 100644 --- a/src/utils/token-validation.ts +++ b/src/utils/token-validation.ts @@ -21,10 +21,7 @@ export const MAX_SESSION_TOKENS = 500_000; * @param outputTokens - Output token count to validate * @returns Object with isValid flag and optional error reason */ -export function validateTokenCounts( - inputTokens: number, - outputTokens: number -): { isValid: boolean; reason?: string } { +export function validateTokenCounts(inputTokens: number, outputTokens: number): { isValid: boolean; reason?: string } { if (inputTokens < 0 || outputTokens < 0) { return { isValid: false, diff --git a/src/web/schemas.ts b/src/web/schemas.ts index 3c6fdadc..0b96f671 100644 --- a/src/web/schemas.ts +++ b/src/web/schemas.ts @@ -15,11 +15,23 @@ import { SAFE_PATH_PATTERN } from '../utils/regex-patterns.js'; /** Validate a path string: no shell metacharacters, no traversal, must be absolute */ export function isValidWorkingDir(p: string): boolean { if (!p || !p.startsWith('/')) return false; - if (p.includes(';') || p.includes('&') || p.includes('|') || - p.includes('$') || p.includes('`') || p.includes('(') || - p.includes(')') || p.includes('{') || p.includes('}') || - p.includes('<') || p.includes('>') || p.includes("'") || - p.includes('"') || p.includes('\n') || p.includes('\r')) { + if ( + p.includes(';') || + p.includes('&') || + p.includes('|') || + p.includes('$') || + p.includes('`') || + p.includes('(') || + p.includes(')') || + p.includes('{') || + p.includes('}') || + p.includes('<') || + p.includes('>') || + p.includes("'") || + p.includes('"') || + p.includes('\n') || + p.includes('\r') + ) { return false; } if (p.includes('..')) return false; @@ -38,25 +50,35 @@ const ALLOWED_ENV_PREFIXES = ['CLAUDE_CODE_', 'OPENCODE_']; /** Env var keys that are always blocked (security-sensitive) */ const BLOCKED_ENV_KEYS = new Set([ - 'PATH', 'LD_PRELOAD', 'LD_LIBRARY_PATH', 'NODE_OPTIONS', - 'CODEMAN_MUX_NAME', 'CODEMAN_TMUX', - 'OPENCODE_SERVER_PASSWORD', // Security-sensitive: server auth password + 'PATH', + 'LD_PRELOAD', + 'LD_LIBRARY_PATH', + 'NODE_OPTIONS', + 'CODEMAN_MUX_NAME', + 'CODEMAN_TMUX', + 'OPENCODE_SERVER_PASSWORD', // Security-sensitive: server auth password ]); /** Validate that an env var key is allowed */ function isAllowedEnvKey(key: string): boolean { if (BLOCKED_ENV_KEYS.has(key)) return false; - return ALLOWED_ENV_PREFIXES.some(prefix => key.startsWith(prefix)); + return ALLOWED_ENV_PREFIXES.some((prefix) => key.startsWith(prefix)); } /** Zod schema for env overrides with allowlist enforcement */ -const safeEnvOverridesSchema = z.record(z.string(), z.string()).optional().refine( - (val) => { - if (!val) return true; - return Object.keys(val).every(isAllowedEnvKey); - }, - { message: 'envOverrides contains blocked or disallowed env var keys. Only CLAUDE_CODE_* and OPENCODE_* keys are allowed.' }, -); +const safeEnvOverridesSchema = z + .record(z.string(), z.string()) + .optional() + .refine( + (val) => { + if (!val) return true; + return Object.keys(val).every(isAllowedEnvKey); + }, + { + message: + 'envOverrides contains blocked or disallowed env var keys. Only CLAUDE_CODE_* and OPENCODE_* keys are allowed.', + } + ); // ========== Session Routes ========== @@ -65,16 +87,37 @@ const safeEnvOverridesSchema = z.record(z.string(), z.string()).optional().refin * Creates a new session with optional working directory, mode, and name. */ /** Schema for OpenCode-specific configuration */ -const OpenCodeConfigSchema = z.object({ - model: z.string().max(100).regex(/^[a-zA-Z0-9._\-/]+$/).optional(), - autoAllowTools: z.boolean().optional(), - continueSession: z.string().max(100).regex(/^[a-zA-Z0-9_-]+$/).optional(), - forkSession: z.boolean().optional(), - configContent: z.string().max(10000).refine( - (val) => { try { JSON.parse(val); return true; } catch { return false; } }, - { message: 'configContent must be valid JSON' }, - ).optional(), -}).optional(); +const OpenCodeConfigSchema = z + .object({ + model: z + .string() + .max(100) + .regex(/^[a-zA-Z0-9._\-/]+$/) + .optional(), + autoAllowTools: z.boolean().optional(), + continueSession: z + .string() + .max(100) + .regex(/^[a-zA-Z0-9_-]+$/) + .optional(), + forkSession: z.boolean().optional(), + configContent: z + .string() + .max(10000) + .refine( + (val) => { + try { + JSON.parse(val); + return true; + } catch { + return false; + } + }, + { message: 'configContent must be valid JSON' } + ) + .optional(), + }) + .optional(); export const CreateSessionSchema = z.object({ workingDir: safePathSchema.optional(), @@ -108,7 +151,9 @@ export const ResizeSchema = z.object({ * Creates a new case folder. */ export const CreateCaseSchema = z.object({ - name: z.string().regex(/^[a-zA-Z0-9_-]+$/, 'Invalid case name format. Use only letters, numbers, hyphens, underscores.'), + name: z + .string() + .regex(/^[a-zA-Z0-9_-]+$/, 'Invalid case name format. Use only letters, numbers, hyphens, underscores.'), description: z.string().max(1000).optional(), }); @@ -119,7 +164,10 @@ export const CreateCaseSchema = z.object({ * Creates case (if needed) and starts interactive session. */ export const QuickStartSchema = z.object({ - caseName: z.string().regex(/^[a-zA-Z0-9_-]+$/, 'Invalid case name format. Use only letters, numbers, hyphens, underscores.').optional(), + caseName: z + .string() + .regex(/^[a-zA-Z0-9_-]+$/, 'Invalid case name format. Use only letters, numbers, hyphens, underscores.') + .optional(), mode: z.enum(['claude', 'shell', 'opencode']).optional(), openCodeConfig: OpenCodeConfigSchema, }); @@ -175,86 +223,100 @@ export const RespawnConfigSchema = z.object({ * Schema for PUT /api/config * Updates application configuration with whitelist of allowed fields. */ -export const ConfigUpdateSchema = z.object({ - pollIntervalMs: z.number().int().min(100).max(60000).optional(), - defaultTimeoutMs: z.number().int().min(1000).max(3600000).optional(), - maxConcurrentSessions: z.number().int().min(1).max(50).optional(), - respawn: RespawnConfigSchema.optional(), -}).strict(); +export const ConfigUpdateSchema = z + .object({ + pollIntervalMs: z.number().int().min(100).max(60000).optional(), + defaultTimeoutMs: z.number().int().min(1000).max(3600000).optional(), + maxConcurrentSessions: z.number().int().min(1).max(50).optional(), + respawn: RespawnConfigSchema.optional(), + }) + .strict(); /** * Schema for PUT /api/settings * Explicit allowlist of known settings fields — prevents arbitrary key persistence. */ -const NotificationEventSchema = z.object({ - enabled: z.boolean().optional(), - browser: z.boolean().optional(), - audio: z.boolean().optional(), - push: z.boolean().optional(), -}).optional(); - -export const SettingsUpdateSchema = z.object({ - // Paths - defaultClaudeMdPath: z.string().max(500).optional(), - defaultWorkingDir: z.string().max(500).optional(), - lastUsedCase: z.string().max(200).optional(), - // Feature toggles - ralphTrackerEnabled: z.boolean().optional(), - subagentTrackingEnabled: z.boolean().optional(), - subagentActiveTabOnly: z.boolean().optional(), - imageWatcherEnabled: z.boolean().optional(), - tunnelEnabled: z.boolean().optional(), - tabTwoRows: z.boolean().optional(), - agentTeamsEnabled: z.boolean().optional(), - // UI visibility - showFontControls: z.boolean().optional(), - showSystemStats: z.boolean().optional(), - showTokenCount: z.boolean().optional(), - showCost: z.boolean().optional(), - showLifecycleLog: z.boolean().optional(), - showMonitor: z.boolean().optional(), - showProjectInsights: z.boolean().optional(), - showFileBrowser: z.boolean().optional(), - showSubagents: z.boolean().optional(), - // Claude CLI settings - claudeMode: z.string().max(50).optional(), - allowedTools: z.string().max(2000).optional(), - // CPU priority - nice: z.object({ - enabled: z.boolean().optional(), - niceValue: z.number().int().min(-20).max(19).optional(), - }).optional(), - // Notification preferences (cross-device sync) - notificationPreferences: z.object({ +const NotificationEventSchema = z + .object({ enabled: z.boolean().optional(), - browserNotifications: z.boolean().optional(), - audioAlerts: z.boolean().optional(), - stuckThresholdMs: z.number().optional(), - muteCritical: z.boolean().optional(), - muteWarning: z.boolean().optional(), - muteInfo: z.boolean().optional(), - eventTypes: z.object({ - permission_prompt: NotificationEventSchema, - elicitation_dialog: NotificationEventSchema, - idle_prompt: NotificationEventSchema, - stop: NotificationEventSchema, - session_error: NotificationEventSchema, - respawn_cycle: NotificationEventSchema, - token_milestone: NotificationEventSchema, - ralph_complete: NotificationEventSchema, - subagent_spawn: NotificationEventSchema, - subagent_complete: NotificationEventSchema, - }).optional(), - _version: z.number().optional(), - }).optional(), - // Voice settings (cross-device sync) - voiceSettings: z.object({ - apiKey: z.string().max(200).optional(), - language: z.string().max(20).optional(), - keyterms: z.string().max(500).optional(), - insertMode: z.string().max(20).optional(), - }).optional(), -}).strict(); + browser: z.boolean().optional(), + audio: z.boolean().optional(), + push: z.boolean().optional(), + }) + .optional(); + +export const SettingsUpdateSchema = z + .object({ + // Paths + defaultClaudeMdPath: z.string().max(500).optional(), + defaultWorkingDir: z.string().max(500).optional(), + lastUsedCase: z.string().max(200).optional(), + // Feature toggles + ralphTrackerEnabled: z.boolean().optional(), + subagentTrackingEnabled: z.boolean().optional(), + subagentActiveTabOnly: z.boolean().optional(), + imageWatcherEnabled: z.boolean().optional(), + tunnelEnabled: z.boolean().optional(), + tabTwoRows: z.boolean().optional(), + agentTeamsEnabled: z.boolean().optional(), + // UI visibility + showFontControls: z.boolean().optional(), + showSystemStats: z.boolean().optional(), + showTokenCount: z.boolean().optional(), + showCost: z.boolean().optional(), + showLifecycleLog: z.boolean().optional(), + showMonitor: z.boolean().optional(), + showProjectInsights: z.boolean().optional(), + showFileBrowser: z.boolean().optional(), + showSubagents: z.boolean().optional(), + // Claude CLI settings + claudeMode: z.string().max(50).optional(), + allowedTools: z.string().max(2000).optional(), + // CPU priority + nice: z + .object({ + enabled: z.boolean().optional(), + niceValue: z.number().int().min(-20).max(19).optional(), + }) + .optional(), + // Notification preferences (cross-device sync) + notificationPreferences: z + .object({ + enabled: z.boolean().optional(), + browserNotifications: z.boolean().optional(), + audioAlerts: z.boolean().optional(), + stuckThresholdMs: z.number().optional(), + muteCritical: z.boolean().optional(), + muteWarning: z.boolean().optional(), + muteInfo: z.boolean().optional(), + eventTypes: z + .object({ + permission_prompt: NotificationEventSchema, + elicitation_dialog: NotificationEventSchema, + idle_prompt: NotificationEventSchema, + stop: NotificationEventSchema, + session_error: NotificationEventSchema, + respawn_cycle: NotificationEventSchema, + token_milestone: NotificationEventSchema, + ralph_complete: NotificationEventSchema, + subagent_spawn: NotificationEventSchema, + subagent_complete: NotificationEventSchema, + }) + .optional(), + _version: z.number().optional(), + }) + .optional(), + // Voice settings (cross-device sync) + voiceSettings: z + .object({ + apiKey: z.string().max(200).optional(), + language: z.string().max(20).optional(), + keyterms: z.string().max(500).optional(), + insertMode: z.string().max(20).optional(), + }) + .optional(), + }) + .strict(); /** * Schema for POST /api/sessions/:id/input with length limit @@ -381,10 +443,12 @@ export const CpuLimitSchema = z.object({ export const ModelConfigUpdateSchema = z.record(z.string(), z.unknown()); /** PUT /api/subagent-window-states */ -export const SubagentWindowStatesSchema = z.object({ - minimized: z.record(z.string(), z.boolean()).optional(), - open: z.array(z.string()).optional(), -}).passthrough(); +export const SubagentWindowStatesSchema = z + .object({ + minimized: z.record(z.string(), z.boolean()).optional(), + open: z.array(z.string()).optional(), + }) + .passthrough(); /** PUT /api/subagent-parents */ export const SubagentParentMapSchema = z.record(z.string(), z.string()); @@ -423,14 +487,22 @@ export const PushPreferencesUpdateSchema = z.object({ /** POST /api/ralph-loop/start */ export const RalphLoopStartSchema = z.object({ - caseName: z.string().regex(/^[a-zA-Z0-9_-]+$/, 'Invalid case name format').optional().default('testcase'), + caseName: z + .string() + .regex(/^[a-zA-Z0-9_-]+$/, 'Invalid case name format') + .optional() + .default('testcase'), taskDescription: z.string().min(1).max(100000), completionPhrase: z.string().max(100).default('COMPLETE'), maxIterations: z.number().int().min(0).max(1000).nullable().default(10), enableRespawn: z.boolean().default(false), - planItems: z.array(z.object({ - content: z.string(), - priority: z.string().optional(), - enabled: z.boolean().default(true), - })).optional(), + planItems: z + .array( + z.object({ + content: z.string(), + priority: z.string().optional(), + enabled: z.boolean().default(true), + }) + ) + .optional(), }); diff --git a/src/web/server.ts b/src/web/server.ts index c8db4adf..27924992 100644 --- a/src/web/server.ts +++ b/src/web/server.ts @@ -22,7 +22,14 @@ import { execSync } from 'node:child_process'; import { randomBytes, timingSafeEqual } from 'node:crypto'; import { homedir, totalmem, freemem, loadavg, cpus } from 'node:os'; import { EventEmitter } from 'node:events'; -import { Session, ClaudeMessage, type BackgroundTask, type RalphTrackerState, type RalphTodoItem, type ActiveBashTool } from '../session.js'; +import { + Session, + ClaudeMessage, + type BackgroundTask, + type RalphTrackerState, + type RalphTodoItem, + type ActiveBashTool, +} from '../session.js'; import type { ClaudeMode } from '../types.js'; import { fileStreamManager } from '../file-stream-manager.js'; import { RespawnController, RespawnConfig, RespawnState } from '../respawn-controller.js'; @@ -32,7 +39,14 @@ import { getStore } from '../state-store.js'; import { generateClaudeMd } from '../templates/claude-md.js'; import { parseRalphLoopConfig, extractCompletionPhrase } from '../ralph-config.js'; import { writeHooksConfig, updateCaseEnvVars } from '../hooks-config.js'; -import { subagentWatcher, type SubagentInfo, type SubagentToolCall, type SubagentProgress, type SubagentMessage, type SubagentToolResult } from '../subagent-watcher.js'; +import { + subagentWatcher, + type SubagentInfo, + type SubagentToolCall, + type SubagentProgress, + type SubagentMessage, + type SubagentToolResult, +} from '../subagent-watcher.js'; import { imageWatcher } from '../image-watcher.js'; import { TranscriptWatcher } from '../transcript-watcher.js'; import { TeamWatcher } from '../team-watcher.js'; @@ -127,8 +141,8 @@ const TASK_UPDATE_BATCH_INTERVAL = 100; // When terminal supports this, it buffers all output between start/end markers // and renders atomically, eliminating partial-frame flicker from Ink redraws. // Supported by: WezTerm, Kitty, Ghostty, iTerm2 3.5+, Windows Terminal, VSCode terminal -const DEC_SYNC_START = '\x1b[?2026h'; // Begin synchronized update -const DEC_SYNC_END = '\x1b[?2026l'; // End synchronized update (flush to screen) +const DEC_SYNC_START = '\x1b[?2026h'; // Begin synchronized update +const DEC_SYNC_END = '\x1b[?2026l'; // End synchronized update (flush to screen) // State update debounce interval (batch expensive toDetailedState() calls) const STATE_UPDATE_DEBOUNCE_INTERVAL = 500; // Cache TTL for getLightSessionsState() — avoids re-serializing all sessions on every SSE init / /api/sessions call @@ -172,7 +186,9 @@ const ITERATION_PAUSE_MS = 2000; // Set high (32KB) to allow effective batching; avg Ink events are ~14KB const BATCH_FLUSH_THRESHOLD = 32 * 1024; // Pre-compiled regex for terminal buffer cleaning (avoids per-request compilation) +// eslint-disable-next-line no-control-regex const CLAUDE_BANNER_PATTERN = /\x1b\[1mClaud/; +// eslint-disable-next-line no-control-regex const CTRL_L_PATTERN = /\x0c/g; const LEADING_WHITESPACE_PATTERN = /^[\s\r\n]+/; @@ -205,8 +221,14 @@ function sanitizeHookData(data: Record | null | undefined): Rec // Only forward known safe fields from Claude Code hook stdin const safeFields: Record = {}; const allowedKeys = [ - 'hook_event_name', 'tool_name', 'tool_input', 'session_id', - 'cwd', 'permission_mode', 'stop_hook_active', 'transcript_path', + 'hook_event_name', + 'tool_name', + 'tool_input', + 'session_id', + 'cwd', + 'permission_mode', + 'stop_hook_active', + 'transcript_path', ]; for (const key of allowedKeys) { @@ -248,16 +270,17 @@ function sanitizeHookData(data: Record | null | undefined): Rec * The ralph-loop.local.md file has priority because it contains * the exact configuration from an active Ralph loop session. */ -function autoConfigureRalph(session: Session, workingDir: string, broadcast: (event: string, data: unknown) => void): void { +function autoConfigureRalph( + session: Session, + workingDir: string, + broadcast: (event: string, data: unknown) => void +): void { // First, try to read the official Ralph Wiggum plugin state file const ralphConfig = parseRalphLoopConfig(workingDir); if (ralphConfig && ralphConfig.completionPromise) { session.ralphTracker.enable(); - session.ralphTracker.startLoop( - ralphConfig.completionPromise, - ralphConfig.maxIterations ?? undefined - ); + session.ralphTracker.startLoop(ralphConfig.completionPromise, ralphConfig.maxIterations ?? undefined); // Restore iteration count if available if (ralphConfig.iteration > 0) { @@ -266,7 +289,9 @@ function autoConfigureRalph(session: Session, workingDir: string, broadcast: (ev console.log(`[auto-detect] Ralph loop at iteration ${ralphConfig.iteration}/${ralphConfig.maxIterations ?? '∞'}`); } - console.log(`[auto-detect] Configured Ralph loop for session ${session.id} from ralph-loop.local.md: ${ralphConfig.completionPromise}`); + console.log( + `[auto-detect] Configured Ralph loop for session ${session.id} from ralph-loop.local.md: ${ralphConfig.completionPromise}` + ); broadcast('session:ralphLoopUpdate', { sessionId: session.id, state: session.ralphTracker.loopState, @@ -310,9 +335,9 @@ function getOrCreateSelfSignedCert(): { key: string; cert: string } { // Generate self-signed cert valid for 365 days, covering localhost and common LAN access patterns execSync( `openssl req -x509 -newkey rsa:2048 -nodes ` + - `-keyout "${keyPath}" -out "${certPath}" ` + - `-days 365 -subj "/CN=codeman" ` + - `-addext "subjectAltName=DNS:localhost,IP:127.0.0.1,IP:0.0.0.0"`, + `-keyout "${keyPath}" -out "${certPath}" ` + + `-days 365 -subj "/CN=codeman" ` + + `-addext "subjectAltName=DNS:localhost,IP:127.0.0.1,IP:0.0.0.0"`, { stdio: 'pipe' } ); @@ -377,13 +402,13 @@ export class WebServer extends EventEmitter { private mux: TerminalMultiplexer; // Terminal batching for performance private terminalBatches: Map = new Map(); - private terminalBatchSizes: Map = new Map(); // Running total avoids O(n) reduce per push - private terminalBatchTimers: Map = new Map(); // Per-session timers (staggered flushes) + private terminalBatchSizes: Map = new Map(); // Running total avoids O(n) reduce per push + private terminalBatchTimers: Map = new Map(); // Per-session timers (staggered flushes) // Adaptive batching: track rapid events to extend batch window (per-session) // StaleExpirationMap auto-cleans entries for sessions that stop generating output private lastTerminalEventTime: StaleExpirationMap = new StaleExpirationMap({ ttlMs: 5 * 60 * 1000, // 5 minutes - auto-expire stale session timing data - refreshOnGet: false, // Don't refresh on reads, only on explicit sets + refreshOnGet: false, // Don't refresh on reads, only on explicit sets }); // Scheduled runs cleanup timer private scheduledCleanupTimer: NodeJS.Timeout | null = null; @@ -398,7 +423,6 @@ export class WebServer extends EventEmitter { // Flag to prevent new timers during shutdown private _isStopping: boolean = false; // Cached light state for SSE init (avoids rebuilding on every reconnect) - // eslint-disable-next-line @typescript-eslint/no-explicit-any private cachedLightState: { data: Record; timestamp: number } | null = null; private static readonly LIGHT_STATE_CACHE_TTL_MS = 1000; // Cached sessions list for getLightSessionsState() (avoids re-serializing all sessions on every call) @@ -715,7 +739,10 @@ export class WebServer extends EventEmitter { this.app.addHook('onRequest', (req, reply, done) => { reply.header('X-Content-Type-Options', 'nosniff'); reply.header('X-Frame-Options', 'SAMEORIGIN'); - reply.header('Content-Security-Policy', "default-src 'self'; script-src 'self' 'unsafe-inline' https://cdn.jsdelivr.net; style-src 'self' 'unsafe-inline' https://cdn.jsdelivr.net; img-src 'self' data: blob:; connect-src 'self' wss://api.deepgram.com; font-src 'self' https://cdn.jsdelivr.net; frame-ancestors 'self'"); + reply.header( + 'Content-Security-Policy', + "default-src 'self'; script-src 'self' 'unsafe-inline' https://cdn.jsdelivr.net; style-src 'self' 'unsafe-inline' https://cdn.jsdelivr.net; img-src 'self' data: blob:; connect-src 'self' wss://api.deepgram.com; font-src 'self' https://cdn.jsdelivr.net; frame-ancestors 'self'" + ); if (this.https) { reply.header('Strict-Transport-Security', 'max-age=31536000; includeSubDomains'); } @@ -776,7 +803,7 @@ export class WebServer extends EventEmitter { reply.raw.writeHead(200, { 'Content-Type': 'text/event-stream', 'Cache-Control': 'no-cache', - 'Connection': 'keep-alive', + Connection: 'keep-alive', 'X-Accel-Buffering': 'no', // Disable nginx buffering }); @@ -841,7 +868,12 @@ export class WebServer extends EventEmitter { // Session lifecycle audit log this.app.get('/api/session-lifecycle', async (req) => { - const query = req.query as { sessionId?: string; event?: string; since?: string; limit?: string }; + const query = req.query as { + sessionId?: string; + event?: string; + since?: string; + limit?: string; + }; const lifecycleLog = getLifecycleLog(); const entries = await lifecycleLog.query({ sessionId: query.sessionId, @@ -854,7 +886,8 @@ export class WebServer extends EventEmitter { // Global stats endpoint this.app.get('/api/stats', async () => { - const activeSessionTokens: Record = {}; + const activeSessionTokens: Record = + {}; for (const [sessionId, session] of this.sessions) { activeSessionTokens[sessionId] = { inputTokens: session.inputTokens, @@ -872,7 +905,8 @@ export class WebServer extends EventEmitter { // Token stats with daily history this.app.get('/api/token-stats', async () => { // Get aggregate totals (global + active sessions) - const activeSessionTokens: Record = {}; + const activeSessionTokens: Record = + {}; for (const [sessionId, session] of this.sessions) { activeSessionTokens[sessionId] = { inputTokens: session.inputTokens, @@ -931,15 +965,15 @@ export class WebServer extends EventEmitter { return { memory: { rss: mem.rss, - rssMB: Math.round(mem.rss / 1024 / 1024 * 10) / 10, + rssMB: Math.round((mem.rss / 1024 / 1024) * 10) / 10, heapUsed: mem.heapUsed, - heapUsedMB: Math.round(mem.heapUsed / 1024 / 1024 * 10) / 10, + heapUsedMB: Math.round((mem.heapUsed / 1024 / 1024) * 10) / 10, heapTotal: mem.heapTotal, - heapTotalMB: Math.round(mem.heapTotal / 1024 / 1024 * 10) / 10, + heapTotalMB: Math.round((mem.heapTotal / 1024 / 1024) * 10) / 10, external: mem.external, - externalMB: Math.round(mem.external / 1024 / 1024 * 10) / 10, + externalMB: Math.round((mem.external / 1024 / 1024) * 10) / 10, arrayBuffers: mem.arrayBuffers, - arrayBuffersMB: Math.round(mem.arrayBuffers / 1024 / 1024 * 10) / 10, + arrayBuffersMB: Math.round((mem.arrayBuffers / 1024 / 1024) * 10) / 10, }, mapSizes: { server: serverMapSizes, @@ -976,7 +1010,10 @@ export class WebServer extends EventEmitter { this.app.post('/api/sessions', async (req) => { // Prevent unbounded session creation if (this.sessions.size >= MAX_CONCURRENT_SESSIONS) { - return createErrorResponse(ApiErrorCode.OPERATION_FAILED, `Maximum concurrent sessions (${MAX_CONCURRENT_SESSIONS}) reached. Delete some sessions first.`); + return createErrorResponse( + ApiErrorCode.OPERATION_FAILED, + `Maximum concurrent sessions (${MAX_CONCURRENT_SESSIONS}) reached. Delete some sessions first.` + ); } const result = CreateSessionSchema.safeParse(req.body); @@ -1007,16 +1044,18 @@ export class WebServer extends EventEmitter { if (body.mode === 'opencode') { const { isOpenCodeAvailable } = await import('../utils/opencode-cli-resolver.js'); if (!isOpenCodeAvailable()) { - return createErrorResponse(ApiErrorCode.OPERATION_FAILED, 'OpenCode CLI not found. Install with: curl -fsSL https://opencode.ai/install | bash'); + return createErrorResponse( + ApiErrorCode.OPERATION_FAILED, + 'OpenCode CLI not found. Install with: curl -fsSL https://opencode.ai/install | bash' + ); } } const globalNice = await this.getGlobalNiceConfig(); const modelConfig = await this.getModelConfig(); const mode = body.mode || 'claude'; - const model = mode === 'opencode' - ? body.openCodeConfig?.model - : (mode !== 'shell' ? modelConfig?.defaultModel : undefined); + const model = + mode === 'opencode' ? body.openCodeConfig?.model : mode !== 'shell' ? modelConfig?.defaultModel : undefined; const claudeModeConfig = await this.getClaudeModeConfig(); const session = new Session({ workingDir, @@ -1147,7 +1186,7 @@ export class WebServer extends EventEmitter { textOutput: session.textOutput, messages: session.messages, errorBuffer: session.errorBuffer, - } + }, }; }); @@ -1166,7 +1205,7 @@ export class WebServer extends EventEmitter { loop: session.ralphLoopState, todos: session.ralphTodos, todoStats: session.ralphTodoStats, - } + }, }; }); @@ -1206,7 +1245,7 @@ export class WebServer extends EventEmitter { success: true, data: { tools: session.activeTools, - } + }, }; }); @@ -1225,7 +1264,22 @@ export class WebServer extends EventEmitter { const workingDir = session.workingDir; // Default excludes - large/generated directories - const excludeDirs = new Set(['.git', 'node_modules', 'dist', 'build', '__pycache__', '.cache', '.next', '.nuxt', 'coverage', '.venv', 'venv', '.tox', 'target', 'vendor']); + const excludeDirs = new Set([ + '.git', + 'node_modules', + 'dist', + 'build', + '__pycache__', + '.cache', + '.next', + '.nuxt', + 'coverage', + '.venv', + 'venv', + '.tox', + 'target', + 'vendor', + ]); interface FileTreeNode { name: string; @@ -1319,7 +1373,7 @@ export class WebServer extends EventEmitter { totalFiles, totalDirectories, truncated, - } + }, }; }); @@ -1349,7 +1403,34 @@ export class WebServer extends EventEmitter { // Check if it's a binary/media file const ext = filePath.split('.').pop()?.toLowerCase() || ''; - const binaryExts = new Set(['png', 'jpg', 'jpeg', 'gif', 'webp', 'ico', 'svg', 'bmp', 'mp4', 'webm', 'mov', 'avi', 'mp3', 'wav', 'ogg', 'pdf', 'zip', 'tar', 'gz', 'exe', 'dll', 'so', 'woff', 'woff2', 'ttf', 'eot']); + const binaryExts = new Set([ + 'png', + 'jpg', + 'jpeg', + 'gif', + 'webp', + 'ico', + 'svg', + 'bmp', + 'mp4', + 'webm', + 'mov', + 'avi', + 'mp3', + 'wav', + 'ogg', + 'pdf', + 'zip', + 'tar', + 'gz', + 'exe', + 'dll', + 'so', + 'woff', + 'woff2', + 'ttf', + 'eot', + ]); const imageExts = new Set(['png', 'jpg', 'jpeg', 'gif', 'webp', 'svg', 'bmp', 'ico']); const videoExts = new Set(['mp4', 'webm', 'mov', 'avi']); @@ -1363,14 +1444,17 @@ export class WebServer extends EventEmitter { type: imageExts.has(ext) ? 'image' : videoExts.has(ext) ? 'video' : 'binary', extension: ext, url: `/api/sessions/${id}/file-raw?path=${encodeURIComponent(filePath)}`, - } + }, }; } // Validate file size before reading (DoS protection - prevent memory exhaustion) const MAX_TEXT_FILE_SIZE = 10 * 1024 * 1024; // 10MB if (stat.size > MAX_TEXT_FILE_SIZE) { - return createErrorResponse(ApiErrorCode.INVALID_INPUT, `File too large (${Math.round(stat.size / 1024 / 1024)}MB > ${MAX_TEXT_FILE_SIZE / 1024 / 1024}MB limit)`); + return createErrorResponse( + ApiErrorCode.INVALID_INPUT, + `File too large (${Math.round(stat.size / 1024 / 1024)}MB > ${MAX_TEXT_FILE_SIZE / 1024 / 1024}MB limit)` + ); } // Read text file with line limit (bounded to prevent DoS) @@ -1390,7 +1474,7 @@ export class WebServer extends EventEmitter { totalLines: allLines.length, truncated: truncatedContent, extension: ext, - } + }, }; } catch (err) { return createErrorResponse(ApiErrorCode.OPERATION_FAILED, `Failed to read file: ${getErrorMessage(err)}`); @@ -1426,24 +1510,44 @@ export class WebServer extends EventEmitter { const MAX_RAW_FILE_SIZE = 50 * 1024 * 1024; // 50MB for raw files const stat = await fs.stat(fullPath); if (stat.size > MAX_RAW_FILE_SIZE) { - reply.code(400).send(createErrorResponse(ApiErrorCode.INVALID_INPUT, `File too large (${Math.round(stat.size / 1024 / 1024)}MB > ${MAX_RAW_FILE_SIZE / 1024 / 1024}MB limit)`)); + reply + .code(400) + .send( + createErrorResponse( + ApiErrorCode.INVALID_INPUT, + `File too large (${Math.round(stat.size / 1024 / 1024)}MB > ${MAX_RAW_FILE_SIZE / 1024 / 1024}MB limit)` + ) + ); return; } const ext = filePath.split('.').pop()?.toLowerCase() || ''; const mimeTypes: Record = { - 'png': 'image/png', 'jpg': 'image/jpeg', 'jpeg': 'image/jpeg', 'gif': 'image/gif', - 'webp': 'image/webp', 'svg': 'image/svg+xml', 'ico': 'image/x-icon', 'bmp': 'image/bmp', - 'mp4': 'video/mp4', 'webm': 'video/webm', 'mov': 'video/quicktime', - 'mp3': 'audio/mpeg', 'wav': 'audio/wav', 'ogg': 'audio/ogg', - 'pdf': 'application/pdf', 'json': 'application/json', + png: 'image/png', + jpg: 'image/jpeg', + jpeg: 'image/jpeg', + gif: 'image/gif', + webp: 'image/webp', + svg: 'image/svg+xml', + ico: 'image/x-icon', + bmp: 'image/bmp', + mp4: 'video/mp4', + webm: 'video/webm', + mov: 'video/quicktime', + mp3: 'audio/mpeg', + wav: 'audio/wav', + ogg: 'audio/ogg', + pdf: 'application/pdf', + json: 'application/json', }; const content = await fs.readFile(fullPath); reply.header('Content-Type', mimeTypes[ext] || 'application/octet-stream'); reply.send(content); } catch (err) { - reply.code(500).send(createErrorResponse(ApiErrorCode.OPERATION_FAILED, `Failed to read file: ${getErrorMessage(err)}`)); + reply + .code(500) + .send(createErrorResponse(ApiErrorCode.OPERATION_FAILED, `Failed to read file: ${getErrorMessage(err)}`)); } }); @@ -1467,7 +1571,7 @@ export class WebServer extends EventEmitter { reply.raw.writeHead(200, { 'Content-Type': 'text/event-stream', 'Cache-Control': 'no-cache', - 'Connection': 'keep-alive', + Connection: 'keep-alive', 'X-Accel-Buffering': 'no', }); @@ -1599,7 +1703,7 @@ export class WebServer extends EventEmitter { this.persistSessionState(session); this.broadcast('session:ralphLoopUpdate', { sessionId: id, - state: session.ralphLoopState + state: session.ralphLoopState, }); return { success: true }; @@ -1634,7 +1738,7 @@ export class WebServer extends EventEmitter { circuitBreaker: session.ralphTracker.circuitBreakerStatus, cumulativeStats: session.ralphTracker.cumulativeStats, exitGateMet: session.ralphTracker.exitGateMet, - } + }, }; }); @@ -1653,7 +1757,7 @@ export class WebServer extends EventEmitter { data: { content, todoCount: session.ralphTracker.todos.length, - } + }, }; }); @@ -1679,7 +1783,7 @@ export class WebServer extends EventEmitter { data: { importedCount, todos: session.ralphTracker.todos, - } + }, }; }); @@ -1707,7 +1811,7 @@ export class WebServer extends EventEmitter { data: { filePath, todoCount: session.ralphTracker.todos.length, - } + }, }; } catch (error) { return createErrorResponse(ApiErrorCode.OPERATION_FAILED, `Failed to write file: ${error}`); @@ -1741,7 +1845,7 @@ export class WebServer extends EventEmitter { filePath, importedCount, todos: session.ralphTracker.todos, - } + }, }; } catch (error) { if ((error as NodeJS.ErrnoException).code === 'ENOENT') { @@ -1780,7 +1884,7 @@ export class WebServer extends EventEmitter { data: { filePath, contentLength: content.length, - } + }, }; } catch (error) { return createErrorResponse(ApiErrorCode.OPERATION_FAILED, `Failed to write file: ${error}`); @@ -1806,7 +1910,7 @@ export class WebServer extends EventEmitter { } // Run async, don't wait - session.runPrompt(prompt).catch(err => { + session.runPrompt(prompt).catch((err) => { this.broadcast('session:error', { id, error: err.message }); }); @@ -1830,7 +1934,11 @@ export class WebServer extends EventEmitter { try { // Auto-detect completion phrase from CLAUDE.md BEFORE starting (only if globally enabled and not explicitly disabled by user) // Ralph tracker is not supported for opencode sessions - if (session.mode !== 'opencode' && this.store.getConfig().ralphEnabled && !session.ralphTracker.autoEnableDisabled) { + if ( + session.mode !== 'opencode' && + this.store.getConfig().ralphEnabled && + !session.ralphTracker.autoEnableDisabled + ) { autoConfigureRalph(session, session.workingDir, () => {}); if (!session.ralphTracker.enabled) { session.ralphTracker.enable(); @@ -1838,7 +1946,12 @@ export class WebServer extends EventEmitter { } await session.startInteractive(); - getLifecycleLog().log({ event: 'started', sessionId: id, name: session.name, mode: session.mode }); + getLifecycleLog().log({ + event: 'started', + sessionId: id, + name: session.name, + mode: session.mode, + }); this.broadcast('session:interactive', { id }); this.broadcast('session:updated', { session: this.getSessionStateWithRespawn(session) }); @@ -1863,7 +1976,12 @@ export class WebServer extends EventEmitter { try { await session.startShell(); - getLifecycleLog().log({ event: 'started', sessionId: id, name: session.name, mode: 'shell' }); + getLifecycleLog().log({ + event: 'started', + sessionId: id, + name: session.name, + mode: 'shell', + }); this.broadcast('session:interactive', { id, mode: 'shell' }); this.broadcast('session:updated', { session: this.getSessionStateWithRespawn(session) }); return { success: true }; @@ -1889,7 +2007,10 @@ export class WebServer extends EventEmitter { const inputStr = String(input); if (inputStr.length > MAX_INPUT_LENGTH) { - return createErrorResponse(ApiErrorCode.INVALID_INPUT, `Input exceeds maximum length (${MAX_INPUT_LENGTH} bytes)`); + return createErrorResponse( + ApiErrorCode.INVALID_INPUT, + `Input exceeds maximum length (${MAX_INPUT_LENGTH} bytes)` + ); } // Write input to PTY. Direct write is synchronous; writeViaMux @@ -1897,14 +2018,17 @@ export class WebServer extends EventEmitter { if (useMux) { // Fire-and-forget: don't block HTTP response on tmux child process. // Fallback to direct write on failure. - session.writeViaMux(inputStr).then(ok => { - if (!ok) { - console.warn(`[Server] writeViaMux failed for session ${id}, falling back to direct write`); + session + .writeViaMux(inputStr) + .then((ok) => { + if (!ok) { + console.warn(`[Server] writeViaMux failed for session ${id}, falling back to direct write`); + session.write(inputStr); + } + }) + .catch(() => { session.write(inputStr); - } - }).catch(() => { - session.write(inputStr); - }); + }); } else { session.write(inputStr); } @@ -1927,7 +2051,10 @@ export class WebServer extends EventEmitter { // Note: Zod already validates that cols and rows are positive integers within bounds if (cols > MAX_TERMINAL_COLS || rows > MAX_TERMINAL_ROWS) { - return createErrorResponse(ApiErrorCode.INVALID_INPUT, `Terminal dimensions exceed maximum (${MAX_TERMINAL_COLS}x${MAX_TERMINAL_ROWS})`); + return createErrorResponse( + ApiErrorCode.INVALID_INPUT, + `Terminal dimensions exceed maximum (${MAX_TERMINAL_COLS}x${MAX_TERMINAL_ROWS})` + ); } session.resize(cols, rows); @@ -1979,9 +2106,7 @@ export class WebServer extends EventEmitter { } // Remove Ctrl+L and leading whitespace (cheap on tailed subset) - cleanBuffer = cleanBuffer - .replace(CTRL_L_PATTERN, '') - .replace(LEADING_WHITESPACE_PATTERN, ''); + cleanBuffer = cleanBuffer.replace(CTRL_L_PATTERN, '').replace(LEADING_WHITESPACE_PATTERN, ''); return { terminalBuffer: cleanBuffer, @@ -2171,7 +2296,10 @@ export class WebServer extends EventEmitter { if (!irResult.success) { return createErrorResponse(ApiErrorCode.INVALID_INPUT, 'Invalid request body'); } - const body = irResult.data as { respawnConfig?: Partial; durationMinutes?: number }; + const body = irResult.data as { + respawnConfig?: Partial; + durationMinutes?: number; + }; const session = this.sessions.get(id); if (!session) { @@ -2198,7 +2326,13 @@ export class WebServer extends EventEmitter { // Start interactive session await session.startInteractive(); - getLifecycleLog().log({ event: 'started', sessionId: id, name: session.name, mode: session.mode, reason: 'interactive_respawn' }); + getLifecycleLog().log({ + event: 'started', + sessionId: id, + name: session.name, + mode: session.mode, + reason: 'interactive_respawn', + }); this.broadcast('session:interactive', { id }); this.broadcast('session:updated', { session: this.getSessionStateWithRespawn(session) }); @@ -2407,7 +2541,10 @@ export class WebServer extends EventEmitter { this.app.post('/api/run', async (req) => { // Prevent unbounded session creation if (this.sessions.size >= MAX_CONCURRENT_SESSIONS) { - return createErrorResponse(ApiErrorCode.SESSION_BUSY, `Maximum concurrent sessions (${MAX_CONCURRENT_SESSIONS}) reached`); + return createErrorResponse( + ApiErrorCode.SESSION_BUSY, + `Maximum concurrent sessions (${MAX_CONCURRENT_SESSIONS}) reached` + ); } const qrResult = QuickRunSchema.safeParse(req.body); @@ -2438,7 +2575,12 @@ export class WebServer extends EventEmitter { this.store.incrementSessionsCreated(); this.persistSessionState(session); await this.setupSessionListeners(session); - getLifecycleLog().log({ event: 'created', sessionId: session.id, name: session.name, reason: 'run_prompt' }); + getLifecycleLog().log({ + event: 'created', + sessionId: session.id, + name: session.name, + reason: 'run_prompt', + }); this.broadcast('session:created', this.getSessionStateWithRespawn(session)); @@ -2459,28 +2601,31 @@ export class WebServer extends EventEmitter { return Array.from(this.scheduledRuns.values()); }); - this.app.post('/api/scheduled', async (req): Promise<{ success: boolean; run: ScheduledRun } | ApiResponse> => { - const srResult = ScheduledRunSchema.safeParse(req.body); - if (!srResult.success) { - return createErrorResponse(ApiErrorCode.INVALID_INPUT, 'Invalid request body'); - } - const { prompt, workingDir, durationMinutes } = srResult.data; + this.app.post( + '/api/scheduled', + async (req): Promise<{ success: boolean; run: ScheduledRun } | ApiResponse> => { + const srResult = ScheduledRunSchema.safeParse(req.body); + if (!srResult.success) { + return createErrorResponse(ApiErrorCode.INVALID_INPUT, 'Invalid request body'); + } + const { prompt, workingDir, durationMinutes } = srResult.data; - // Validate workingDir exists and is a directory - if (workingDir) { - try { - const stat = statSync(workingDir); - if (!stat.isDirectory()) { - return createErrorResponse(ApiErrorCode.INVALID_INPUT, 'workingDir is not a directory'); + // Validate workingDir exists and is a directory + if (workingDir) { + try { + const stat = statSync(workingDir); + if (!stat.isDirectory()) { + return createErrorResponse(ApiErrorCode.INVALID_INPUT, 'workingDir is not a directory'); + } + } catch { + return createErrorResponse(ApiErrorCode.INVALID_INPUT, 'workingDir does not exist'); } - } catch { - return createErrorResponse(ApiErrorCode.INVALID_INPUT, 'workingDir does not exist'); } - } - const run = await this.startScheduledRun(prompt, workingDir || process.cwd(), durationMinutes ?? 60); - return { success: true, run }; - }); + const run = await this.startScheduledRun(prompt, workingDir || process.cwd(), durationMinutes ?? 60); + return { success: true, run }; + } + ); this.app.delete('/api/scheduled/:id', async (req) => { const { id } = req.params as { id: string }; @@ -2533,7 +2678,7 @@ export class WebServer extends EventEmitter { const linkedCases: Record = JSON.parse(await fs.readFile(linkedCasesFile, 'utf-8')); for (const [name, path] of Object.entries(linkedCases)) { // Only add if not already in cases (avoid duplicates) and path exists - if (!cases.some(c => c.name === name) && existsSync(path)) { + if (!cases.some((c) => c.name === name) && existsSync(path)) { cases.push({ name, path, @@ -2600,9 +2745,7 @@ export class WebServer extends EventEmitter { const { name, path: folderPath } = lcResult.data; // Expand ~ to home directory - const expandedPath = folderPath.startsWith('~') - ? join(homedir(), folderPath.slice(1)) - : folderPath; + const expandedPath = folderPath.startsWith('~') ? join(homedir(), folderPath.slice(1)) : folderPath; // Validate the folder exists if (!existsSync(expandedPath)) { @@ -2612,7 +2755,10 @@ export class WebServer extends EventEmitter { // Check if case name already exists in casesDir const casePath = join(casesDir, name); if (existsSync(casePath)) { - return createErrorResponse(ApiErrorCode.ALREADY_EXISTS, 'A case with this name already exists in codeman-cases.'); + return createErrorResponse( + ApiErrorCode.ALREADY_EXISTS, + 'A case with this name already exists in codeman-cases.' + ); } // Load existing linked cases @@ -2628,7 +2774,10 @@ export class WebServer extends EventEmitter { // Check if name is already linked if (linkedCases[name]) { - return createErrorResponse(ApiErrorCode.ALREADY_EXISTS, `Case "${name}" is already linked to ${linkedCases[name]}`); + return createErrorResponse( + ApiErrorCode.ALREADY_EXISTS, + `Case "${name}" is already linked to ${linkedCases[name]}` + ); } // Save the linked case @@ -2711,8 +2860,12 @@ export class WebServer extends EventEmitter { const content = await fs.readFile(fixPlanPath, 'utf-8'); // Parse todos from the content (similar to ralph-tracker's importFixPlanMarkdown) - const todos: Array<{ content: string; status: 'pending' | 'in_progress' | 'completed'; priority: string | null }> = []; - const todoPattern = /^-\s*\[([ xX\-])\]\s*(.+)$/; + const todos: Array<{ + content: string; + status: 'pending' | 'in_progress' | 'completed'; + priority: string | null; + }> = []; + const todoPattern = /^-\s*\[([ xX-])\]\s*(.+)$/; const p0HeaderPattern = /^##\s*(High Priority|Critical|P0|Critical Path)/i; const p1HeaderPattern = /^##\s*(Standard|P1|Medium Priority)/i; const p2HeaderPattern = /^##\s*(Nice to Have|P2|Low Priority)/i; @@ -2766,7 +2919,9 @@ export class WebServer extends EventEmitter { } // Calculate stats in a single pass for better performance - let pending = 0, inProgress = 0, completed = 0; + let pending = 0, + inProgress = 0, + completed = 0; for (const t of todos) { if (t.status === 'pending') pending++; else if (t.status === 'in_progress') inProgress++; @@ -2790,7 +2945,10 @@ export class WebServer extends EventEmitter { this.app.post('/api/quick-start', async (req): Promise => { // Prevent unbounded session creation if (this.sessions.size >= MAX_CONCURRENT_SESSIONS) { - return createErrorResponse(ApiErrorCode.SESSION_BUSY, `Maximum concurrent sessions (${MAX_CONCURRENT_SESSIONS}) reached.`); + return createErrorResponse( + ApiErrorCode.SESSION_BUSY, + `Maximum concurrent sessions (${MAX_CONCURRENT_SESSIONS}) reached.` + ); } const result = QuickStartSchema.safeParse(req.body); @@ -2803,7 +2961,10 @@ export class WebServer extends EventEmitter { if (mode === 'opencode') { const { isOpenCodeAvailable } = await import('../utils/opencode-cli-resolver.js'); if (!isOpenCodeAvailable()) { - return createErrorResponse(ApiErrorCode.OPERATION_FAILED, 'OpenCode CLI not found. Install with: curl -fsSL https://opencode.ai/install | bash'); + return createErrorResponse( + ApiErrorCode.OPERATION_FAILED, + 'OpenCode CLI not found. Install with: curl -fsSL https://opencode.ai/install | bash' + ); } } @@ -2844,9 +3005,8 @@ export class WebServer extends EventEmitter { // Apply global Nice priority config and model config from settings const niceConfig = await this.getGlobalNiceConfig(); const qsModelConfig = await this.getModelConfig(); - const qsModel = mode === 'opencode' - ? openCodeConfig?.model - : (mode !== 'shell' ? qsModelConfig?.defaultModel : undefined); + const qsModel = + mode === 'opencode' ? openCodeConfig?.model : mode !== 'shell' ? qsModelConfig?.defaultModel : undefined; const qsClaudeModeConfig = await this.getClaudeModeConfig(); const session = new Session({ workingDir: casePath, @@ -2874,19 +3034,34 @@ export class WebServer extends EventEmitter { this.store.incrementSessionsCreated(); this.persistSessionState(session); await this.setupSessionListeners(session); - getLifecycleLog().log({ event: 'created', sessionId: session.id, name: session.name, reason: 'quick_start' }); + getLifecycleLog().log({ + event: 'created', + sessionId: session.id, + name: session.name, + reason: 'quick_start', + }); this.broadcast('session:created', this.getSessionStateWithRespawn(session)); // Start in the appropriate mode try { if (mode === 'shell') { await session.startShell(); - getLifecycleLog().log({ event: 'started', sessionId: session.id, name: session.name, mode: 'shell' }); + getLifecycleLog().log({ + event: 'started', + sessionId: session.id, + name: session.name, + mode: 'shell', + }); this.broadcast('session:interactive', { id: session.id, mode: 'shell' }); } else { // Both 'claude' and 'opencode' modes use startInteractive() await session.startInteractive(); - getLifecycleLog().log({ event: 'started', sessionId: session.id, name: session.name, mode }); + getLifecycleLog().log({ + event: 'started', + sessionId: session.id, + name: session.name, + mode, + }); this.broadcast('session:interactive', { id: session.id, mode }); } this.broadcast('session:updated', { session: this.getSessionStateWithRespawn(session) }); @@ -2933,12 +3108,18 @@ export class WebServer extends EventEmitter { this.app.post('/api/ralph-loop/start', async (req): Promise => { // Prevent unbounded session creation if (this.sessions.size >= MAX_CONCURRENT_SESSIONS) { - return createErrorResponse(ApiErrorCode.SESSION_BUSY, `Maximum concurrent sessions (${MAX_CONCURRENT_SESSIONS}) reached.`); + return createErrorResponse( + ApiErrorCode.SESSION_BUSY, + `Maximum concurrent sessions (${MAX_CONCURRENT_SESSIONS}) reached.` + ); } const rlResult = RalphLoopStartSchema.safeParse(req.body); if (!rlResult.success) { - return createErrorResponse(ApiErrorCode.INVALID_INPUT, rlResult.error.issues[0]?.message ?? 'Validation failed'); + return createErrorResponse( + ApiErrorCode.INVALID_INPUT, + rlResult.error.issues[0]?.message ?? 'Validation failed' + ); } const { caseName, taskDescription, completionPhrase, maxIterations, enableRespawn, planItems } = rlResult.data; @@ -2991,19 +3172,43 @@ export class WebServer extends EventEmitter { session.ralphTracker.startLoop(completionPhrase, maxIterations ?? undefined); // Build fix_plan markdown from plan items if provided - const enabledItems = planItems?.filter(i => i.enabled) ?? []; + const enabledItems = planItems?.filter((i) => i.enabled) ?? []; let planContent = ''; if (enabledItems.length > 0) { - const p0 = enabledItems.filter(i => i.priority === 'P0'); - const p1 = enabledItems.filter(i => i.priority === 'P1'); - const p2 = enabledItems.filter(i => i.priority === 'P2'); - const noPri = enabledItems.filter(i => !i.priority); + const p0 = enabledItems.filter((i) => i.priority === 'P0'); + const p1 = enabledItems.filter((i) => i.priority === 'P1'); + const p2 = enabledItems.filter((i) => i.priority === 'P2'); + const noPri = enabledItems.filter((i) => !i.priority); planContent = '# Implementation Plan\n\n'; planContent += `Generated: ${new Date().toISOString().slice(0, 10)}\n\n`; - if (p0.length > 0) { planContent += '## Critical Path (P0)\n\n'; p0.forEach(i => { planContent += `- [ ] ${i.content}\n`; }); planContent += '\n'; } - if (p1.length > 0) { planContent += '## Standard (P1)\n\n'; p1.forEach(i => { planContent += `- [ ] ${i.content}\n`; }); planContent += '\n'; } - if (p2.length > 0) { planContent += '## Nice-to-Have (P2)\n\n'; p2.forEach(i => { planContent += `- [ ] ${i.content}\n`; }); planContent += '\n'; } - if (noPri.length > 0) { planContent += '## Tasks\n\n'; noPri.forEach(i => { planContent += `- [ ] ${i.content}\n`; }); planContent += '\n'; } + if (p0.length > 0) { + planContent += '## Critical Path (P0)\n\n'; + p0.forEach((i) => { + planContent += `- [ ] ${i.content}\n`; + }); + planContent += '\n'; + } + if (p1.length > 0) { + planContent += '## Standard (P1)\n\n'; + p1.forEach((i) => { + planContent += `- [ ] ${i.content}\n`; + }); + planContent += '\n'; + } + if (p2.length > 0) { + planContent += '## Nice-to-Have (P2)\n\n'; + p2.forEach((i) => { + planContent += `- [ ] ${i.content}\n`; + }); + planContent += '\n'; + } + if (noPri.length > 0) { + planContent += '## Tasks\n\n'; + noPri.forEach((i) => { + planContent += `- [ ] ${i.content}\n`; + }); + planContent += '\n'; + } // Import into tracker and write to disk session.ralphTracker.importFixPlanMarkdown(planContent); @@ -3038,7 +3243,7 @@ export class WebServer extends EventEmitter { fullPrompt += '- Changes are committed\n\n'; fullPrompt += '## If Stuck\n\n'; fullPrompt += 'If you encounter the same error for 3+ iterations:\n'; - fullPrompt += '1. Document what you\'ve tried\n'; + fullPrompt += "1. Document what you've tried\n"; fullPrompt += '2. Identify the specific blocker\n'; fullPrompt += '3. Try an alternative approach\n'; fullPrompt += '4. If truly blocked, output `BLOCKED` with an explanation\n'; @@ -3052,13 +3257,23 @@ export class WebServer extends EventEmitter { this.store.incrementSessionsCreated(); this.persistSessionState(session); await this.setupSessionListeners(session); - getLifecycleLog().log({ event: 'created', sessionId: session.id, name: session.name, reason: 'ralph_loop_start' }); + getLifecycleLog().log({ + event: 'created', + sessionId: session.id, + name: session.name, + reason: 'ralph_loop_start', + }); this.broadcast('session:created', this.getSessionStateWithRespawn(session)); // Start interactive mode try { await session.startInteractive(); - getLifecycleLog().log({ event: 'started', sessionId: session.id, name: session.name, mode: 'claude' }); + getLifecycleLog().log({ + event: 'started', + sessionId: session.id, + name: session.name, + mode: 'claude', + }); this.broadcast('session:interactive', { id: session.id, mode: 'claude' }); this.broadcast('session:updated', { session: this.getSessionStateWithRespawn(session) }); } catch (err) { @@ -3068,7 +3283,8 @@ export class WebServer extends EventEmitter { // Enable respawn if requested if (enableRespawn) { - const ralphUpdatePrompt = 'Before /clear: Update CLAUDE.md with discoveries and notes, mark completed tasks in @fix_plan.md, write a brief progress summary to a file so the next iteration can continue seamlessly.'; + const ralphUpdatePrompt = + 'Before /clear: Update CLAUDE.md with discoveries and notes, mark completed tasks in @fix_plan.md, write a brief progress summary to a file so the next iteration can continue seamlessly.'; const ralphKickstartPrompt = `You are in a Ralph Wiggum loop. Read @fix_plan.md for task status, continue on the next uncompleted task, output ${completionPhrase} when ALL tasks are complete.`; const controller = new RespawnController(session, { updatePrompt: ralphUpdatePrompt, @@ -3081,19 +3297,28 @@ export class WebServer extends EventEmitter { controller.start(); this.saveRespawnConfig(session.id, controller.getConfig()); this.persistSessionState(session); - this.broadcast('respawn:started', { sessionId: session.id, status: controller.getStatus() }); + this.broadcast('respawn:started', { + sessionId: session.id, + status: controller.getStatus(), + }); } // Save lastUsedCase try { const settingsFilePath = join(homedir(), '.codeman', 'settings.json'); let settings: Record = {}; - try { settings = JSON.parse(await fs.readFile(settingsFilePath, 'utf-8')); } catch { /* ignore */ } + try { + settings = JSON.parse(await fs.readFile(settingsFilePath, 'utf-8')); + } catch { + /* ignore */ + } settings.lastUsedCase = caseName; const dir = dirname(settingsFilePath); if (!existsSync(dir)) mkdirSync(dir, { recursive: true }); fs.writeFile(settingsFilePath, JSON.stringify(settings, null, 2)).catch(() => {}); - } catch { /* non-critical */ } + } catch { + /* non-critical */ + } const sessionId = session.id; @@ -3101,7 +3326,7 @@ export class WebServer extends EventEmitter { setImmediate(() => { const pollReady = async () => { for (let attempt = 0; attempt < 60; attempt++) { - await new Promise(r => setTimeout(r, 500)); + await new Promise((r) => setTimeout(r, 500)); const s = this.sessions.get(sessionId); if (!s) return; // session was deleted // Check terminal output for prompt indicator @@ -3111,7 +3336,7 @@ export class WebServer extends EventEmitter { } } // Small extra delay for CLI to settle - await new Promise(r => setTimeout(r, 2000)); + await new Promise((r) => setTimeout(r, 2000)); const s = this.sessions.get(sessionId); if (!s) return; try { @@ -3120,7 +3345,7 @@ export class WebServer extends EventEmitter { console.warn(`[RalphLoop] Failed to send prompt to session ${sessionId}:`, getErrorMessage(err)); } }; - pollReady().catch(err => console.error('[RalphLoop] pollReady error:', err)); + pollReady().catch((err) => console.error('[RalphLoop] pollReady error:', err)); }); return { @@ -3137,16 +3362,16 @@ export class WebServer extends EventEmitter { if (!gpResult.success) { return createErrorResponse(ApiErrorCode.INVALID_INPUT, 'Invalid request body'); } - const { - taskDescription, - detailLevel = 'standard' - } = gpResult.data; + const { taskDescription, detailLevel = 'standard' } = gpResult.data; // Build sophisticated prompt based on Ralph Wiggum methodology const detailConfig = { brief: { style: 'high-level milestones', testDepth: 'basic' }, standard: { style: 'balanced implementation steps', testDepth: 'thorough' }, - detailed: { style: 'granular sub-tasks with full TDD coverage', testDepth: 'comprehensive' }, + detailed: { + style: 'granular sub-tasks with full TDD coverage', + testDepth: 'comprehensive', + }, }; const levelConfig = detailConfig[detailLevel] || detailConfig.standard; @@ -3278,7 +3503,12 @@ NOW: Generate the implementation plan for the task above. Think step by step.`; // Parse tddPhase let tddPhase: 'setup' | 'test' | 'impl' | 'verify' | undefined; - if (obj.tddPhase === 'setup' || obj.tddPhase === 'test' || obj.tddPhase === 'impl' || obj.tddPhase === 'verify') { + if ( + obj.tddPhase === 'setup' || + obj.tddPhase === 'test' || + obj.tddPhase === 'impl' || + obj.tddPhase === 'verify' + ) { tddPhase = obj.tddPhase; } @@ -3286,9 +3516,8 @@ NOW: Generate the implementation plan for the task above. Think step by step.`; id: obj.id ? String(obj.id) : `task-${idx}`, content, priority, - verificationCriteria: typeof obj.verificationCriteria === 'string' - ? obj.verificationCriteria - : 'Task completed successfully', + verificationCriteria: + typeof obj.verificationCriteria === 'string' ? obj.verificationCriteria : 'Task completed successfully', tddPhase, dependencies: Array.isArray(obj.dependencies) ? obj.dependencies.map(String) : [], status: 'pending' as const, @@ -3297,16 +3526,17 @@ NOW: Generate the implementation plan for the task above. Think step by step.`; }; }); // No artificial limit - let Claude generate what's needed - } catch (parseErr) { - return createErrorResponse(ApiErrorCode.OPERATION_FAILED, 'Failed to parse plan JSON: ' + getErrorMessage(parseErr)); + return createErrorResponse( + ApiErrorCode.OPERATION_FAILED, + 'Failed to parse plan JSON: ' + getErrorMessage(parseErr) + ); } return { success: true, data: { items, costUsd: cost }, }; - } catch (err) { return createErrorResponse(ApiErrorCode.OPERATION_FAILED, 'Plan generation failed: ' + getErrorMessage(err)); } finally { @@ -3416,8 +3646,15 @@ NOW: Generate the implementation plan for the task above. Think step by step.`; } catch (err) { // Clean up on error too this.activePlanOrchestrators.delete(orchestratorId); - this.broadcast('plan:completed', { orchestratorId, success: false, error: getErrorMessage(err) }); - return createErrorResponse(ApiErrorCode.OPERATION_FAILED, 'Detailed plan generation failed: ' + getErrorMessage(err)); + this.broadcast('plan:completed', { + orchestratorId, + success: false, + error: getErrorMessage(err), + }); + return createErrorResponse( + ApiErrorCode.OPERATION_FAILED, + 'Detailed plan generation failed: ' + getErrorMessage(err) + ); } }); @@ -3589,8 +3826,11 @@ NOW: Generate the implementation plan for the task above. Think step by step.`; .replace(/\n/g, '\\n') .replace(/\r/g, '\\r') .replace(/\t/g, '\\t') - // eslint-disable-next-line no-control-regex - .replace(/[\x00-\x1f]/g, (c) => `\\u${c.charCodeAt(0).toString(16).padStart(4, '0')}`); + .replace( + // eslint-disable-next-line no-control-regex + /[\x00-\x1f]/g, + (c) => `\\u${c.charCodeAt(0).toString(16).padStart(4, '0')}` + ); }); parsed = JSON.parse(repaired); } catch { @@ -3753,7 +3993,11 @@ NOW: Generate the implementation plan for the task above. Think step by step.`; mkdirSync(dir, { recursive: true }); } let existing: Record = {}; - try { existing = JSON.parse(await fs.readFile(settingsPath, 'utf-8')); } catch { /* ignore */ } + try { + existing = JSON.parse(await fs.readFile(settingsPath, 'utf-8')); + } catch { + /* ignore */ + } const merged = { ...existing, ...settings }; await fs.writeFile(settingsPath, JSON.stringify(merged, null, 2)); @@ -3963,7 +4207,7 @@ NOW: Generate the implementation plan for the task above. Think step by step.`; const sessions = await this.mux.getSessionsWithStats(); return { sessions, - muxAvailable: this.mux.isAvailable() + muxAvailable: this.mux.isAvailable(), }; }); @@ -4071,7 +4315,6 @@ NOW: Generate the implementation plan for the task above. Think step by step.`; return { success: true, data: { cleared } }; }); - // ========== Agent Teams ========== // List all discovered teams @@ -4085,7 +4328,6 @@ NOW: Generate the implementation plan for the task above. Think step by step.`; return { success: true, data: this.teamWatcher.getTeamTasks(name) }; }); - // ========== Hook Events ========== this.app.post('/api/hook-event', async (req) => { @@ -4237,7 +4479,7 @@ NOW: Generate the implementation plan for the task above. Think step by step.`; pos = nextBoundary === -1 ? body.length : nextBoundary; } - const filePart = parts.find(p => p.headers.includes('name="file"')); + const filePart = parts.find((p) => p.headers.includes('name="file"')); if (!filePart || filePart.data.length === 0) { return createErrorResponse(ApiErrorCode.INVALID_INPUT, 'No file uploaded'); } @@ -4251,7 +4493,12 @@ NOW: Generate the implementation plan for the task above. Think step by step.`; } const ctMatch = filePart.headers.match(/Content-Type:\s*image\/(png|jpeg|webp|gif)/i); if (ctMatch) { - const map: Record = { png: '.png', jpeg: '.jpg', webp: '.webp', gif: '.gif' }; + const map: Record = { + png: '.png', + jpeg: '.jpg', + webp: '.webp', + gif: '.gif', + }; ext = map[ctMatch[1].toLowerCase()] ?? ext; } @@ -4273,11 +4520,11 @@ NOW: Generate the implementation plan for the task above. Think step by step.`; return { files: [] }; } const files = readdirSync(SCREENSHOTS_DIR) - .filter(f => /\.(png|jpg|jpeg|webp|gif)$/i.test(f)) + .filter((f) => /\.(png|jpg|jpeg|webp|gif)$/i.test(f)) .sort() .reverse() .slice(0, 50) - .map(name => ({ name, path: join(SCREENSHOTS_DIR, name) })); + .map((name) => ({ name, path: join(SCREENSHOTS_DIR, name) })); return { files }; }); @@ -4295,7 +4542,13 @@ NOW: Generate the implementation plan for the task above. Think step by step.`; return createErrorResponse(ApiErrorCode.NOT_FOUND, 'Screenshot not found'); } const ext = name.match(/\.(png|jpg|jpeg|webp|gif)$/i)?.[1]?.toLowerCase() ?? 'png'; - const mimeMap: Record = { png: 'image/png', jpg: 'image/jpeg', jpeg: 'image/jpeg', webp: 'image/webp', gif: 'image/gif' }; + const mimeMap: Record = { + png: 'image/png', + jpg: 'image/jpeg', + jpeg: 'image/jpeg', + webp: 'image/webp', + gif: 'image/gif', + }; reply.type(mimeMap[ext] ?? 'image/png'); return fs.readFile(filepath); }); @@ -4333,7 +4586,12 @@ NOW: Generate the implementation plan for the task above. Think step by step.`; }); watcher.on('transcript:tool_end', (toolName: string, isError: boolean) => { - this.broadcast('transcript:tool_end', { sessionId, toolName, isError, timestamp: Date.now() }); + this.broadcast('transcript:tool_end', { + sessionId, + toolName, + isError, + timestamp: Date.now(), + }); }); watcher.on('transcript:error', (error: Error) => { @@ -4353,7 +4611,7 @@ NOW: Generate the implementation plan for the task above. Think step by step.`; private stopTranscriptWatcher(sessionId: string): void { const watcher = this.transcriptWatchers.get(sessionId); if (watcher) { - watcher.removeAllListeners(); // Prevent memory leaks from attached listeners + watcher.removeAllListeners(); // Prevent memory leaks from attached listeners watcher.stop(); this.transcriptWatchers.delete(sessionId); } @@ -4363,13 +4621,16 @@ NOW: Generate the implementation plan for the task above. Think step by step.`; private persistSessionState(session: Session): void { const existing = this.persistDebounceTimers.get(session.id); if (existing) clearTimeout(existing); - this.persistDebounceTimers.set(session.id, setTimeout(() => { - this.persistDebounceTimers.delete(session.id); - // Session may have been removed during debounce - if (this.sessions.has(session.id)) { - this._persistSessionStateNow(session); - } - }, 100)); + this.persistDebounceTimers.set( + session.id, + setTimeout(() => { + this.persistDebounceTimers.delete(session.id); + // Session may have been removed during debounce + if (this.sessions.has(session.id)) { + this._persistSessionStateNow(session); + } + }, 100) + ); } /** Persists full session state including respawn config to state.json */ @@ -4379,9 +4640,7 @@ NOW: Generate the implementation plan for the task above. Think step by step.`; if (controller) { const config = controller.getConfig(); const timerInfo = this.respawnTimers.get(session.id); - const durationMinutes = timerInfo - ? Math.round((timerInfo.endAt - timerInfo.startedAt) / 60000) - : undefined; + const durationMinutes = timerInfo ? Math.round((timerInfo.endAt - timerInfo.startedAt) / 60000) : undefined; state.respawnConfig = { ...config, durationMinutes }; // Use config.enabled instead of controller.state - this way the respawn // will be restored on server restart even if it was temporarily stopped @@ -4430,7 +4689,10 @@ NOW: Generate the implementation plan for the task above. Think step by step.`; } // Get system CPU and memory usage - private getSystemStats(): { cpu: number; memory: { usedMB: number; totalMB: number; percent: number } } { + private getSystemStats(): { + cpu: number; + memory: { usedMB: number; totalMB: number; percent: number }; + } { try { const totalMem = totalmem(); @@ -4462,13 +4724,13 @@ NOW: Generate the implementation plan for the task above. Think step by step.`; memory: { usedMB: Math.round(usedMem / (1024 * 1024)), totalMB: Math.round(totalMem / (1024 * 1024)), - percent: Math.round((usedMem / totalMem) * 100) - } + percent: Math.round((usedMem / totalMem) * 100), + }, }; } catch { return { cpu: 0, - memory: { usedMB: 0, totalMB: 0, percent: 0 } + memory: { usedMB: 0, totalMB: 0, percent: 0 }, }; } } @@ -4520,9 +4782,7 @@ NOW: Generate the implementation plan for the task above. Think step by step.`; // Save the config BEFORE removing controller, so it can be restored on restart const config = controller.getConfig(); const timerInfo = this.respawnTimers.get(sessionId); - const durationMinutes = timerInfo - ? Math.round((timerInfo.endAt - timerInfo.startedAt) / 60000) - : undefined; + const durationMinutes = timerInfo ? Math.round((timerInfo.endAt - timerInfo.startedAt) / 60000) : undefined; this.saveRespawnConfig(sessionId, config, durationMinutes); controller.stop(); @@ -4580,12 +4840,21 @@ NOW: Generate the implementation plan for the task above. Think step by step.`; // Broadcast Ralph cleared to update UI this.broadcast('session:ralphLoopUpdate', { sessionId, - state: { enabled: false, active: false, completionPhrase: null, startedAt: null, cycleCount: 0, maxIterations: null, lastActivity: Date.now(), elapsedHours: null } + state: { + enabled: false, + active: false, + completionPhrase: null, + startedAt: null, + cycleCount: 0, + maxIterations: null, + lastActivity: Date.now(), + elapsedHours: null, + }, }); this.broadcast('session:ralphTodoUpdate', { sessionId, todos: [], - stats: { total: 0, pending: 0, inProgress: 0, completed: 0 } + stats: { total: 0, pending: 0, inProgress: 0, completed: 0 }, }); // Stop session and remove listeners @@ -4602,7 +4871,9 @@ NOW: Generate the implementation plan for the task above. Think step by step.`; this.store.recordDailyUsage(deltaInput, deltaOutput, sessionId); } this.lastRecordedTokens.delete(sessionId); - console.log(`[Server] Added to global stats: ${session.inputTokens + session.outputTokens} tokens, $${session.totalCost.toFixed(4)} from session ${sessionId}`); + console.log( + `[Server] Added to global stats: ${session.inputTokens + session.outputTokens} tokens, $${session.totalCost.toFixed(4)} from session ${sessionId}` + ); } // Explicitly remove stored listeners to break closure references (prevents memory leak) @@ -4665,7 +4936,7 @@ NOW: Generate the implementation plan for the task above. Think step by step.`; } // Start watching for new images in this session's working directory (if enabled globally and per-session) - if (await this.isImageWatcherEnabled() && session.imageWatcherEnabled) { + if ((await this.isImageWatcherEnabled()) && session.imageWatcherEnabled) { imageWatcher.watchSession(session.id, session.workingDir); } @@ -4693,7 +4964,11 @@ NOW: Generate the implementation plan for the task above. Think step by step.`; error: (error) => { this.broadcast('session:error', { id: session.id, error }); - this.sendPushNotifications('session:error', { sessionId: session.id, sessionName: session.name, error: String(error) }); + this.sendPushNotifications('session:error', { + sessionId: session.id, + sessionName: session.name, + error: String(error), + }); // Track in run summary const tracker = this.runSummaryTrackers.get(session.id); if (tracker) tracker.recordError('Session error', String(error)); @@ -4709,7 +4984,12 @@ NOW: Generate the implementation plan for the task above. Think step by step.`; }, exit: (code) => { - getLifecycleLog().log({ event: 'exit', sessionId: session.id, name: session.name, exitCode: code }); + getLifecycleLog().log({ + event: 'exit', + sessionId: session.id, + name: session.name, + exitCode: code, + }); // Wrap in try/catch to ensure cleanup always happens try { this.broadcast('session:exit', { id: session.id, code }); @@ -4818,7 +5098,11 @@ NOW: Generate the implementation plan for the task above. Think step by step.`; ralphCompletionDetected: (phrase: string) => { this.broadcast('session:ralphCompletionDetected', { sessionId: session.id, phrase }); - this.sendPushNotifications('session:ralphCompletionDetected', { sessionId: session.id, sessionName: session.name, phrase }); + this.sendPushNotifications('session:ralphCompletionDetected', { + sessionId: session.id, + sessionName: session.name, + phrase, + }); // Track in run summary const tracker = this.runSummaryTrackers.get(session.id); if (tracker) tracker.recordRalphCompletion(phrase); @@ -4844,12 +5128,7 @@ NOW: Generate the implementation plan for the task above. Think step by step.`; // Track state changes in run summary const tracker = this.runSummaryTrackers.get(session.id); if (tracker && status.state === 'OPEN') { - tracker.addEvent( - 'warning', - 'warning', - 'Circuit Breaker Opened', - status.reason - ); + tracker.addEvent('warning', 'warning', 'Circuit Breaker Opened', status.reason); } }, @@ -4937,7 +5216,11 @@ NOW: Generate the implementation plan for the task above. Think step by step.`; controller.on('respawnBlocked', (data: { reason: string; details: string }) => { this.broadcast('respawn:blocked', { sessionId, reason: data.reason, details: data.details }); const sessionForPush = this.sessions.get(sessionId); - this.sendPushNotifications('respawn:blocked', { sessionId, sessionName: sessionForPush?.name ?? sessionId.slice(0, 8), reason: data.reason }); + this.sendPushNotifications('respawn:blocked', { + sessionId, + sessionName: sessionForPush?.name ?? sessionId.slice(0, 8), + reason: data.reason, + }); // Track in run summary (lazy lookup) const tracker = getTracker(); if (tracker) tracker.recordWarning(`Respawn blocked: ${data.reason}`, data.details); @@ -4964,7 +5247,12 @@ NOW: Generate the implementation plan for the task above. Think step by step.`; }); controller.on('aiCheckCompleted', (result: { verdict: string; reasoning: string; durationMs: number }) => { - this.broadcast('respawn:aiCheckCompleted', { sessionId, verdict: result.verdict, reasoning: result.reasoning, durationMs: result.durationMs }); + this.broadcast('respawn:aiCheckCompleted', { + sessionId, + verdict: result.verdict, + reasoning: result.reasoning, + durationMs: result.durationMs, + }); // Track in run summary (lazy lookup) const tracker = getTracker(); if (tracker) tracker.recordAiCheckResult(result.verdict); @@ -4986,7 +5274,12 @@ NOW: Generate the implementation plan for the task above. Think step by step.`; }); controller.on('planCheckCompleted', (result: { verdict: string; reasoning: string; durationMs: number }) => { - this.broadcast('respawn:planCheckCompleted', { sessionId, verdict: result.verdict, reasoning: result.reasoning, durationMs: result.durationMs }); + this.broadcast('respawn:planCheckCompleted', { + sessionId, + verdict: result.verdict, + reasoning: result.reasoning, + durationMs: result.durationMs, + }); }); controller.on('planCheckFailed', (error: string) => { @@ -5032,28 +5325,30 @@ NOW: Generate the implementation plan for the task above. Think step by step.`; const now = Date.now(); const endAt = now + durationMinutes * 60 * 1000; - const timer = setTimeout(() => { - // Stop respawn when time is up - const controller = this.respawnControllers.get(sessionId); - if (controller) { - controller.stop(); - controller.removeAllListeners(); - this.respawnControllers.delete(sessionId); - this.broadcast('respawn:stopped', { sessionId, reason: 'duration_expired' }); - } - this.respawnTimers.delete(sessionId); - // Update persisted state (respawn no longer active) - const session = this.sessions.get(sessionId); - if (session) { - this.persistSessionState(session); - } - }, durationMinutes * 60 * 1000); + const timer = setTimeout( + () => { + // Stop respawn when time is up + const controller = this.respawnControllers.get(sessionId); + if (controller) { + controller.stop(); + controller.removeAllListeners(); + this.respawnControllers.delete(sessionId); + this.broadcast('respawn:stopped', { sessionId, reason: 'duration_expired' }); + } + this.respawnTimers.delete(sessionId); + // Update persisted state (respawn no longer active) + const session = this.sessions.get(sessionId); + if (session) { + this.persistSessionState(session); + } + }, + durationMinutes * 60 * 1000 + ); this.respawnTimers.set(sessionId, { timer, endAt, startedAt: now }); this.broadcast('respawn:timerStarted', { sessionId, durationMinutes, endAt, startedAt: now }); } - /** * Restore a RespawnController from persisted configuration. * Creates the controller, sets up listeners, but does NOT start it. @@ -5062,11 +5357,7 @@ NOW: Generate the implementation plan for the task above. Think step by step.`; * @param config - The persisted respawn configuration * @param source - Source of the config for logging (e.g., 'state.json' or 'mux-sessions.json') */ - private restoreRespawnController( - session: Session, - config: PersistedRespawnConfig, - source: string - ): void { + private restoreRespawnController(session: Session, config: PersistedRespawnConfig, source: string): void { const controller = new RespawnController(session, { idleTimeoutMs: config.idleTimeoutMs, updatePrompt: config.updatePrompt, @@ -5100,7 +5391,9 @@ NOW: Generate the implementation plan for the task above. Think step by step.`; const delayMs = Math.max(0, WebServer.RESPAWN_RESTORE_GRACE_PERIOD_MS - timeSinceStart); if (delayMs > 0) { - console.log(`[Server] Restored respawn controller for session ${session.id} from ${source} (will start in ${Math.ceil(delayMs / 1000)}s)`); + console.log( + `[Server] Restored respawn controller for session ${session.id} from ${source} (will start in ${Math.ceil(delayMs / 1000)}s)` + ); const timer = setTimeout(() => { this.pendingRespawnStarts.delete(session.id); // Verify session still exists (may have been deleted during grace period) @@ -5120,7 +5413,9 @@ NOW: Generate the implementation plan for the task above. Think step by step.`; } else { // Grace period has passed, start immediately controller.start(); - console.log(`[Server] Restored respawn controller for session ${session.id} from ${source} (started immediately)`); + console.log( + `[Server] Restored respawn controller for session ${session.id} from ${source} (started immediately)` + ); } if (config.durationMinutes && config.durationMinutes > 0) { @@ -5191,9 +5486,17 @@ NOW: Generate the implementation plan for the task above. Think step by step.`; } // Helper to get model configuration from settings - private async getModelConfig(): Promise<{ defaultModel?: string; agentTypeOverrides?: Record } | null> { + private async getModelConfig(): Promise<{ + defaultModel?: string; + agentTypeOverrides?: Record; + } | null> { const settings = await this.readSettings(); - return (settings.modelConfig as { defaultModel?: string; agentTypeOverrides?: Record }) || null; + return ( + (settings.modelConfig as { + defaultModel?: string; + agentTypeOverrides?: Record; + }) || null + ); } private async startScheduledRun(prompt: string, workingDir: string, durationMinutes: number): Promise { @@ -5244,7 +5547,7 @@ NOW: Generate the implementation plan for the task above. Think step by step.`; // Check session limit before creating new session if (this.sessions.size >= MAX_CONCURRENT_SESSIONS) { addLog(`Waiting: maximum concurrent sessions (${MAX_CONCURRENT_SESSIONS}) reached`); - await new Promise(r => setTimeout(r, SESSION_LIMIT_WAIT_MS)); + await new Promise((r) => setTimeout(r, SESSION_LIMIT_WAIT_MS)); continue; } @@ -5277,7 +5580,7 @@ NOW: Generate the implementation plan for the task above. Think step by step.`; run.sessionId = null; // Small pause between iterations - await new Promise(r => setTimeout(r, ITERATION_PAUSE_MS)); + await new Promise((r) => setTimeout(r, ITERATION_PAUSE_MS)); } catch (err) { addLog(`Error: ${getErrorMessage(err)}`); this.broadcast('scheduled:updated', run); @@ -5293,7 +5596,7 @@ NOW: Generate the implementation plan for the task above. Think step by step.`; } // Continue despite errors - await new Promise(r => setTimeout(r, SESSION_LIMIT_WAIT_MS)); + await new Promise((r) => setTimeout(r, SESSION_LIMIT_WAIT_MS)); } } @@ -5342,12 +5645,12 @@ NOW: Generate the implementation plan for the task above. Think step by step.`; */ private getLightSessionsState() { const now = Date.now(); - if (this.cachedSessionsList && (now - this.cachedSessionsList.timestamp) < SESSIONS_LIST_CACHE_TTL) { + if (this.cachedSessionsList && now - this.cachedSessionsList.timestamp < SESSIONS_LIST_CACHE_TTL) { return this.cachedSessionsList.data; } // getSessionStateWithRespawn already uses toLightDetailedState() which // excludes terminalBuffer and textOutput — no extra stripping needed - const data = Array.from(this.sessions.values()).map(s => this.getSessionStateWithRespawn(s)); + const data = Array.from(this.sessions.values()).map((s) => this.getSessionStateWithRespawn(s)); this.cachedSessionsList = { data, timestamp: now }; return data; } @@ -5456,7 +5759,9 @@ NOW: Generate the implementation plan for the task above. Think step by step.`; // Tell it to reload the active session's buffer to recover. try { reply.raw.write(`event: session:needsRefresh\ndata: {}\n\n`); - } catch { /* client gone */ } + } catch { + /* client gone */ + } }); } } catch { @@ -5542,10 +5847,13 @@ NOW: Generate the implementation plan for the task above. Think step by step.`; // Each session flushes independently — prevents one busy session from // forcing all sessions to flush at its rate (thundering herd) if (!this.terminalBatchTimers.has(sessionId)) { - this.terminalBatchTimers.set(sessionId, setTimeout(() => { - this.terminalBatchTimers.delete(sessionId); - this.flushSessionTerminalBatch(sessionId); - }, sessionInterval)); + this.terminalBatchTimers.set( + sessionId, + setTimeout(() => { + this.terminalBatchTimers.delete(sessionId); + this.flushSessionTerminalBatch(sessionId); + }, sessionInterval) + ); } } @@ -5645,8 +5953,18 @@ NOW: Generate the implementation plan for the task above. Think step by step.`; // ========== Web Push ========== /** Map SSE event names to push notification payloads */ - private static readonly PUSH_EVENT_MAP: Record }> = { - 'hook:permission_prompt': { title: 'Permission Required', urgency: 'critical', actions: [{ action: 'approve', title: 'Approve' }, { action: 'deny', title: 'Deny' }] }, + private static readonly PUSH_EVENT_MAP: Record< + string, + { title: string; urgency: string; actions?: Array<{ action: string; title: string }> } + > = { + 'hook:permission_prompt': { + title: 'Permission Required', + urgency: 'critical', + actions: [ + { action: 'approve', title: 'Approve' }, + { action: 'deny', title: 'Deny' }, + ], + }, 'hook:elicitation_dialog': { title: 'Question Asked', urgency: 'critical' }, 'hook:idle_prompt': { title: 'Waiting for Input', urgency: 'warning' }, 'hook:stop': { title: 'Response Complete', urgency: 'info' }, @@ -5813,9 +6131,12 @@ NOW: Generate the implementation plan for the task above. Think step by step.`; }, SSE_HEALTH_CHECK_INTERVAL); // Start token recording timer (every 5 minutes for long-running sessions) - this.tokenRecordingTimer = setInterval(() => { - this.recordPeriodicTokenUsage(); - }, 5 * 60 * 1000); + this.tokenRecordingTimer = setInterval( + () => { + this.recordPeriodicTokenUsage(); + }, + 5 * 60 * 1000 + ); // Start subagent watcher for Claude Code background agent visibility (if enabled) if (await this.isSubagentTrackingEnabled()) { @@ -5842,7 +6163,6 @@ NOW: Generate the implementation plan for the task above. Think step by step.`; // Start team watcher for agent team awareness (always on — lightweight polling) this.teamWatcher.start(); console.log('Team watcher started - monitoring ~/.claude/teams/ for agent team activity'); - } /** @@ -5924,13 +6244,13 @@ NOW: Generate the implementation plan for the task above. Think step by step.`; // Create a session object for this mux session const recoveryClaudeMode = await this.getClaudeModeConfig(); const session = new Session({ - id: muxSession.sessionId, // Preserve the original session ID + id: muxSession.sessionId, // Preserve the original session ID workingDir: muxSession.workingDir, mode: muxSession.mode, name: sessionName, mux: this.mux, useMux: true, - muxSession: muxSession, // Pass the existing session so startInteractive() can attach to it + muxSession: muxSession, // Pass the existing session so startInteractive() can attach to it claudeMode: recoveryClaudeMode.claudeMode, allowedTools: recoveryClaudeMode.allowedTools, }); @@ -5950,13 +6270,14 @@ NOW: Generate the implementation plan for the task above. Think step by step.`; } // Auto-clear if (savedState.autoClearEnabled !== undefined || savedState.autoClearThreshold !== undefined) { - session.setAutoClear( - savedState.autoClearEnabled ?? false, - savedState.autoClearThreshold - ); + session.setAutoClear(savedState.autoClearEnabled ?? false, savedState.autoClearThreshold); } // Token tracking - if (savedState.inputTokens !== undefined || savedState.outputTokens !== undefined || savedState.totalCost !== undefined) { + if ( + savedState.inputTokens !== undefined || + savedState.outputTokens !== undefined || + savedState.totalCost !== undefined + ) { session.restoreTokens( savedState.inputTokens ?? 0, savedState.outputTokens ?? 0, @@ -5969,7 +6290,9 @@ NOW: Generate the implementation plan for the task above. Think step by step.`; }); const totalTokens = (savedState.inputTokens ?? 0) + (savedState.outputTokens ?? 0); if (totalTokens > 0) { - console.log(`[Server] Restored tokens for session ${session.id}: ${totalTokens} tokens, $${(savedState.totalCost ?? 0).toFixed(4)}`); + console.log( + `[Server] Restored tokens for session ${session.id}: ${totalTokens} tokens, $${(savedState.totalCost ?? 0).toFixed(4)}` + ); } } // Ralph / Todo tracker (not supported for opencode sessions) @@ -5986,7 +6309,9 @@ NOW: Generate the implementation plan for the task above. Think step by step.`; if (savedState.ralphCompletionPhrase) { session.ralphTracker.startLoop(savedState.ralphCompletionPhrase); } - console.log(`[Server] Restored Ralph tracker for session ${session.id} (phrase: ${savedState.ralphCompletionPhrase || 'none'})`); + console.log( + `[Server] Restored Ralph tracker for session ${session.id} (phrase: ${savedState.ralphCompletionPhrase || 'none'})` + ); } } // Nice priority config @@ -6011,17 +6336,28 @@ NOW: Generate the implementation plan for the task above. Think step by step.`; } // Fallback: restore respawn from mux-sessions.json if state.json didn't have it (not supported for opencode) - if (session.mode !== 'opencode' && !this.respawnControllers.has(session.id) && muxSession.respawnConfig?.enabled) { + if ( + session.mode !== 'opencode' && + !this.respawnControllers.has(session.id) && + muxSession.respawnConfig?.enabled + ) { try { this.restoreRespawnController(session, muxSession.respawnConfig, 'mux-sessions.json'); } catch (err) { - console.error(`[Server] Failed to restore respawn from mux-sessions.json for session ${session.id}:`, err); + console.error( + `[Server] Failed to restore respawn from mux-sessions.json for session ${session.id}:`, + err + ); } } // Fallback: restore Ralph state from state-inner.json if not already set and not explicitly disabled // Ralph tracker is not supported for opencode sessions - if (session.mode !== 'opencode' && !session.ralphTracker.enabled && !session.ralphTracker.autoEnableDisabled) { + if ( + session.mode !== 'opencode' && + !session.ralphTracker.enabled && + !session.ralphTracker.autoEnableDisabled + ) { const ralphState = this.store.getRalphState(muxSession.sessionId); if (ralphState?.loop?.enabled) { session.ralphTracker.restoreState(ralphState.loop, ralphState.todos); @@ -6030,7 +6366,11 @@ NOW: Generate the implementation plan for the task above. Think step by step.`; } // Fallback: auto-detect completion phrase from CLAUDE.md (not supported for opencode) - if (session.mode !== 'opencode' && session.ralphTracker.enabled && !session.ralphTracker.loopState.completionPhrase) { + if ( + session.mode !== 'opencode' && + session.ralphTracker.enabled && + !session.ralphTracker.loopState.completionPhrase + ) { const claudeMdPath = join(session.workingDir, 'CLAUDE.md'); const completionPhrase = extractCompletionPhrase(claudeMdPath); if (completionPhrase) { @@ -6044,7 +6384,11 @@ NOW: Generate the implementation plan for the task above. Think step by step.`; this.persistSessionState(session); // Mark it as restored (not started yet - user needs to attach) - getLifecycleLog().log({ event: 'recovered', sessionId: session.id, name: session.name }); + getLifecycleLog().log({ + event: 'recovered', + sessionId: session.id, + name: session.name, + }); console.log(`[Server] Restored session ${session.id} from mux ${muxSession.muxName}`); } } @@ -6156,9 +6500,7 @@ NOW: Generate the implementation plan for the task above. Think step by step.`; this.respawnControllers.clear(); // Stop all scheduled runs first (they have their own session cleanup) - await Promise.allSettled( - Array.from(this.scheduledRuns.keys()).map(id => this.stopScheduledRun(id)) - ); + await Promise.allSettled(Array.from(this.scheduledRuns.keys()).map((id) => this.stopScheduledRun(id))); // On server shutdown, DO NOT call cleanupSession — it tears down session state, // removes listeners, kills PTY processes, and broadcasts session:deleted. @@ -6266,7 +6608,11 @@ NOW: Generate the implementation plan for the task above. Think step by step.`; } } -export async function startWebServer(port: number = 3000, https: boolean = false, testMode: boolean = false): Promise { +export async function startWebServer( + port: number = 3000, + https: boolean = false, + testMode: boolean = false +): Promise { const server = new WebServer(port, https, testMode); await server.start(); return server; diff --git a/remotion/Root.tsx b/tools/remotion/Root.tsx similarity index 100% rename from remotion/Root.tsx rename to tools/remotion/Root.tsx diff --git a/remotion/components/ClickCursor.tsx b/tools/remotion/components/ClickCursor.tsx similarity index 100% rename from remotion/components/ClickCursor.tsx rename to tools/remotion/components/ClickCursor.tsx diff --git a/remotion/components/PhoneFrame.tsx b/tools/remotion/components/PhoneFrame.tsx similarity index 100% rename from remotion/components/PhoneFrame.tsx rename to tools/remotion/components/PhoneFrame.tsx diff --git a/remotion/components/TitleCard.tsx b/tools/remotion/components/TitleCard.tsx similarity index 100% rename from remotion/components/TitleCard.tsx rename to tools/remotion/components/TitleCard.tsx diff --git a/remotion/compositions/CodemanDemo.tsx b/tools/remotion/compositions/CodemanDemo.tsx similarity index 100% rename from remotion/compositions/CodemanDemo.tsx rename to tools/remotion/compositions/CodemanDemo.tsx diff --git a/remotion/index.ts b/tools/remotion/index.ts similarity index 100% rename from remotion/index.ts rename to tools/remotion/index.ts diff --git a/remotion/lib/theme.ts b/tools/remotion/lib/theme.ts similarity index 100% rename from remotion/lib/theme.ts rename to tools/remotion/lib/theme.ts diff --git a/remotion/public/desktop-both-claude.png b/tools/remotion/public/desktop-both-claude.png similarity index 100% rename from remotion/public/desktop-both-claude.png rename to tools/remotion/public/desktop-both-claude.png diff --git a/remotion/public/desktop-both-opencode.png b/tools/remotion/public/desktop-both-opencode.png similarity index 100% rename from remotion/public/desktop-both-opencode.png rename to tools/remotion/public/desktop-both-opencode.png diff --git a/remotion/public/desktop-claude.png b/tools/remotion/public/desktop-claude.png similarity index 100% rename from remotion/public/desktop-claude.png rename to tools/remotion/public/desktop-claude.png diff --git a/remotion/public/desktop-welcome.png b/tools/remotion/public/desktop-welcome.png similarity index 100% rename from remotion/public/desktop-welcome.png rename to tools/remotion/public/desktop-welcome.png diff --git a/remotion/public/mobile-claude.png b/tools/remotion/public/mobile-claude.png similarity index 100% rename from remotion/public/mobile-claude.png rename to tools/remotion/public/mobile-claude.png diff --git a/remotion/public/mobile-opencode.png b/tools/remotion/public/mobile-opencode.png similarity index 100% rename from remotion/public/mobile-opencode.png rename to tools/remotion/public/mobile-opencode.png