diff --git a/docs/code-health/dependency-repair.md b/docs/code-health/dependency-repair.md new file mode 100644 index 0000000..219b0e3 --- /dev/null +++ b/docs/code-health/dependency-repair.md @@ -0,0 +1,48 @@ +# Development-tool dependency repair + +Tracked by [Motion #26](https://github.com/Significant-Hobbies/motion/issues/26). + +The 8 October 2026 audit found critical shell-quote and high source-map-js +advisories in existing development tooling. The critical/high gate correctly +failed; an older green CI run did not cover the newer advisory database. + +Vitest and its coverage provider now use 4.1.11, and the web build uses Vite +7.3.7. Scoped overrides resolve existing transitive dependencies to patched +versions without adding a production dependency: + +| Parent | Dependency | Patched version | +| --- | --- | --- | +| concurrently | shell-quote | 1.11.0 | +| magicast, postcss | source-map-js | 1.2.2 | +| vite | postcss | 8.5.23 | +| knip | smol-toml | 1.9.0 | + +Review these overrides when their parents change and remove them when the +parent's declared minimum excludes the affected versions. Keep the frozen +lockfile and the real resolved-dependency regression checks. + +`scripts/development-command-quoting.test.mjs` exercises concurrently's actual +shell-quote dependency. It rejects four line terminators after a comment token +and preserves quoting of ordinary arguments. It never executes the generated +shell text. These cases failed before the update and pass afterward. + +Local verification: 16 focused tests and all 42 tests pass; `pnpm check` and +`pnpm quality:swift-format` pass. The audit reports zero critical/high findings +and one moderate finding. PartyKit 0.0.115, its runtime patch, Miniflare and +resolved Undici 6.29.0 are unchanged. The patched executable/source-map hashes +match the baseline and the network-disabled runtime inspection passes. These +checks do not establish a new real-relay, login, camera or physical-device run. + +The remaining moderate esbuild advisory is in PartyKit's 0.21.5 dependency. +An override across its declared minor range requires separate real-relay +compatibility qualification. No new exception or relaxed threshold hides it. +Coverage remains 6.43% lines, with three complexity violations, five duplication +groups and 4,553 Swift-format diagnostics. An iOS test target/coverage and the +remaining unused-code debt are still part of the open umbrella issue. + +Primary advisories: [shell-quote](https://github.com/advisories/GHSA-pqg4-j6r4-53mv), +[source-map-js](https://github.com/advisories/GHSA-68fv-2mgg-jv7q), +[Vitest](https://github.com/advisories/GHSA-82fw-gwwq-j7x9), +[PostCSS](https://github.com/advisories/GHSA-fxqj-rqcc-2cmp), +[smol-toml](https://github.com/advisories/GHSA-r4xh-jqrq-34v2), +[remaining esbuild finding](https://github.com/advisories/GHSA-67mh-4wv8-2f99). diff --git a/package.json b/package.json index 9a24098..3eab2b0 100644 --- a/package.json +++ b/package.json @@ -32,12 +32,12 @@ }, "devDependencies": { "@biomejs/biome": "2.5.8", - "@vitest/coverage-v8": "4.1.10", + "@vitest/coverage-v8": "4.1.11", "concurrently": "^9.1.0", "jscpd": "5.0.14", "knip": "6.32.2", "ultracite": "7.10.2", - "vitest": "4.1.10" + "vitest": "4.1.11" }, "packageManager": "pnpm@10.33.2", "engines": { @@ -47,7 +47,12 @@ "overrides": { "brace-expansion@>=5.0.0 <6.0.0": "5.0.12", "nanoid@>=3.0.0 <4.0.0": "3.3.18", - "miniflare>undici": "6.29.0" + "miniflare>undici": "6.29.0", + "concurrently>shell-quote": "1.11.0", + "magicast>source-map-js": "1.2.2", + "postcss>source-map-js": "1.2.2", + "vite>postcss": "8.5.23", + "knip>smol-toml": "1.9.0" }, "patchedDependencies": { "partykit@0.0.115": "patches/partykit@0.0.115.patch" diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 27c0080..242e121 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -8,6 +8,11 @@ overrides: brace-expansion@>=5.0.0 <6.0.0: 5.0.12 nanoid@>=3.0.0 <4.0.0: 3.3.18 miniflare>undici: 6.29.0 + concurrently>shell-quote: 1.11.0 + magicast>source-map-js: 1.2.2 + postcss>source-map-js: 1.2.2 + vite>postcss: 8.5.23 + knip>smol-toml: 1.9.0 patchedDependencies: partykit@0.0.115: @@ -22,8 +27,8 @@ importers: specifier: 2.5.8 version: 2.5.8 '@vitest/coverage-v8': - specifier: 4.1.10 - version: 4.1.10(vitest@4.1.10) + specifier: 4.1.11 + version: 4.1.11(vitest@4.1.11) concurrently: specifier: ^9.1.0 version: 9.2.4 @@ -37,8 +42,8 @@ importers: specifier: 7.10.2 version: 7.10.2 vitest: - specifier: 4.1.10 - version: 4.1.10(@vitest/coverage-v8@4.1.10)(vite@7.3.6(jiti@2.7.0)(yaml@2.9.0)) + specifier: 4.1.11 + version: 4.1.11(@vitest/coverage-v8@4.1.11)(vite@7.3.7(jiti@2.7.0)(yaml@2.9.0)) server: devDependencies: @@ -59,8 +64,8 @@ importers: specifier: ^5.6.0 version: 5.9.3 vite: - specifier: ^7.3.6 - version: 7.3.6(jiti@2.7.0)(yaml@2.9.0) + specifier: ^7.3.7 + version: 7.3.7(jiti@2.7.0)(yaml@2.9.0) packages: @@ -891,20 +896,20 @@ packages: '@types/estree@1.0.9': resolution: {integrity: sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg==} - '@vitest/coverage-v8@4.1.10': - resolution: {integrity: sha512-IM49HmthevbgAO4anp1hwtoT9wYe59w0LR00gr+eagHE+ZJ5lK4sLPeO0ubgoJcwLk6dehU3R24N+FbEEKDc8g==} + '@vitest/coverage-v8@4.1.11': + resolution: {integrity: sha512-8MVGEFnJIcdGjcbfKmeq8z0pZHH0JlVtoVZH9Q/qwUp6wyFnEJUBMrw9DCaj+ra3vShGmhavjalMIhPNxZAUcw==} peerDependencies: - '@vitest/browser': 4.1.10 - vitest: 4.1.10 + '@vitest/browser': 4.1.11 + vitest: 4.1.11 peerDependenciesMeta: '@vitest/browser': optional: true - '@vitest/expect@4.1.10': - resolution: {integrity: sha512-YsCn+qAk1GWjQOWFEsEcL2gNQ0zmVmQu3T03qP6UyjhtmdtwtbuI+DASn/7iQB3HGTXkdBwGddzxPlmiql5vlA==} + '@vitest/expect@4.1.11': + resolution: {integrity: sha512-VX2x5vNJXET47KAFzwERI+KRMtTTCSWTfSMKsW7JsUsXV4psq++e3DvZpuTDOpHcxytiDs6p2nhVb2tVDiiUYw==} - '@vitest/mocker@4.1.10': - resolution: {integrity: sha512-v0xaezt+DKEmKfaxg133ldzADrwLGd7Ze1MfQQTYfvs8OqZIwbxyxaYURivwV7sWy5fqn3rH5uOrSp07bp44Ow==} + '@vitest/mocker@4.1.11': + resolution: {integrity: sha512-2XJVD55d1o5AZous5CCGKS74g/riOj9odEt2bQpCVZeblHyHdnMeFl4jl0XjU21stf4mbjUkew2eXQZt65g5CQ==} peerDependencies: msw: ^2.4.9 vite: ^6.0.0 || ^7.0.0 || ^8.0.0 @@ -914,20 +919,20 @@ packages: vite: optional: true - '@vitest/pretty-format@4.1.10': - resolution: {integrity: sha512-W1HsjSH4MXQ9YfmmhLAoIYf1HRfekQCGngeIgcei6MP5QQGWUe0gkopdZQaVCFO+JDJMrAJGwa5pRpNpvy4P8Q==} + '@vitest/pretty-format@4.1.11': + resolution: {integrity: sha512-yiZzPbGTS9Sr/JpFl8zHrcIkAofNbFV6k21vIgQN/cY/oxZeXhJv5sc/MBJ5jFKWmWs+oJHw0UXLZjmf931+Vw==} - '@vitest/runner@4.1.10': - resolution: {integrity: sha512-IKI6kpIH+LmpROplyLwBBaCfMgOZOMsygVa6BARD6ahA04VRuJSa6OaVG7kRvSEMD870Vd91rSSw0eegtWyLGg==} + '@vitest/runner@4.1.11': + resolution: {integrity: sha512-LztvUgdwMNJMIkj3hQnnxiC2Xy1zNxq928W/xhjCLaNCzqTZOudjwbQf6v9IntZGPw132i2Lq2rgTRZHD3JHNw==} - '@vitest/snapshot@4.1.10': - resolution: {integrity: sha512-xRkfOT1qpTAi/Ti4Y1LtfRc3kEuqxGw59eN2jN9pRWMtS/XDevekhcFSqvQqjUNGksfjMJu3Y+oJ+4Ypn2OaJw==} + '@vitest/snapshot@4.1.11': + resolution: {integrity: sha512-pN7ikn1ON7h8ee4gIAp4AzyK+zBtJPzVbqOgu5LCEh4VaJVbPQcgYQYJIMGQPXVeJJq1fnfazis7a5pFNPahog==} - '@vitest/spy@4.1.10': - resolution: {integrity: sha512-PLf/Ugvoq5wO/b4rwYCR1h2PSIdXz7wnkQFMiUpLdtM7l6pqVFcQIBEHyT1+l+cj7mNwAfZHzqXqDyjvOuwbDw==} + '@vitest/spy@4.1.11': + resolution: {integrity: sha512-apNa/prQy2qCeywhnixOHPRCgGNhvg7T4Dapfl1GahLp/R+uhBm5cPyFoNVyqsNd2h1nJxL6BqqdIjiABL60YA==} - '@vitest/utils@4.1.10': - resolution: {integrity: sha512-fy9am/HWxbaGt/Sawrp90vt6Y6jQwf1RX77cz3uwoJwJVMli/e1IEwRPnMNJ7vKfPTwo0diXifkpPvwH9v7nGA==} + '@vitest/utils@4.1.11': + resolution: {integrity: sha512-zTCVGpyFsGWBhllOyKlTw/vnr6D9qxsfSDyfbyZmTyjHw5N/VuvzHpHoQjm2ZJzn4RJgx5w4r7V0er69CmLgPQ==} acorn-walk@8.3.5: resolution: {integrity: sha512-HEHNfbars9v4pgpW6SO1KSPkfoS0xVOM/9UzkJltjlsHZmJasxg8aXkuZa7SMf8vKGIBhpUsPluQSqhJFCqebw==} @@ -1346,8 +1351,8 @@ packages: pkg-types@1.3.1: resolution: {integrity: sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ==} - postcss@8.5.19: - resolution: {integrity: sha512-Mz8SaolMd8nB+G13WkORcxQKHZ/NE4xXevtkJHVuG+guo9/wYKlIMTKAqGdEmYOXR2ijPjTYNHssizdaVSUNdQ==} + postcss@8.5.23: + resolution: {integrity: sha512-g50586zr4bZmwFiTlflMu8E0bDTb5I5gertgwAKmsdUlTQIhZtunzUlD1WSzwcVWPoAVpsrA6vlfCD7oXvRwgg==} engines: {node: ^10 || ^12 || >=14} printable-characters@1.0.42: @@ -1381,8 +1386,8 @@ packages: resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} engines: {node: '>=8'} - shell-quote@1.9.0: - resolution: {integrity: sha512-Iov+JwFv/2HcTpcwNMKd8+IWNb8tboQJNQTkAY/LLVK7gGH9jy+LGkVqPxfekHl+yMmiqXszdGWXgkfml7hjqA==} + shell-quote@1.11.0: + resolution: {integrity: sha512-JdxDPD0DBTyu08pq0kPC0xSNet/qsU07qT6IsX1AS8oO2ICNRY4ldNa8OAI6PuwAH8tG3lxEhbqmyp4Dw4036g==} engines: {node: '>= 0.4'} siginfo@2.0.0: @@ -1395,12 +1400,12 @@ packages: sisteransi@1.0.5: resolution: {integrity: sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==} - smol-toml@1.8.0: - resolution: {integrity: sha512-kCZr2V3ch9i00x8zXRhjUNVcjG9ijES5dDudkXvUVCT5QlJNQWElSJdZqyPemffHoLNUYwOcou0Fy+ojN0uHSQ==} + smol-toml@1.9.0: + resolution: {integrity: sha512-hpd+HLON7HdZXqYchMM/+LaTTbdK0AU3NngIJ4KVyWbY9bfQqdL9cD+4yf6dUoU2Ap4VsU0JkQi6FxAI1B2mXQ==} engines: {node: '>= 18'} - source-map-js@1.2.1: - resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} + source-map-js@1.2.2: + resolution: {integrity: sha512-KGj/8Y43x35aZVDtt+J4mK1hoLGHULMYfSkODJNQjNDC3oW1PqPoxMwo0pLUsWM/UEGzON/NxeHywEfNXNP3Vw==} engines: {node: '>=0.10.0'} source-map@0.6.1: @@ -1505,8 +1510,8 @@ packages: unenv@2.0.0-rc.0: resolution: {integrity: sha512-H0kl2w8jFL/FAk0xvjVing4bS3jd//mbg1QChDnn58l9Sc5RtduaKmLAL8n+eBw5jJo8ZjYV7CrEGage5LAOZQ==} - vite@7.3.6: - resolution: {integrity: sha512-4XP60spRGjSZFf1qYH+dJIkK2znL3zQfl9KkOV9MkkRR/3Dls0dxaBsQPTloEc5BLXWPL9vsOxopxyKoMmDueg==} + vite@7.3.7: + resolution: {integrity: sha512-AHEzTORMbi7/7aXp7w7KZ5+DCUdSeLsJz0grY8xHpc9DHdYb0vQu6DqJfm2tOw3gDExNgPgnJTXxM6syYFHaCA==} engines: {node: ^20.19.0 || >=22.12.0} hasBin: true peerDependencies: @@ -1545,20 +1550,20 @@ packages: yaml: optional: true - vitest@4.1.10: - resolution: {integrity: sha512-R9jUTe5S4Qb0HCd4TNqpC7oGcrMssMRGXLW80ubjWsW9VH5GF8y1Y0SFLY9AbqSk6nt0PnOx4H4WNJYZ13GUPw==} + vitest@4.1.11: + resolution: {integrity: sha512-fhACrNXUidIbGSBr5FlbuBkO7VWC1ZyLl0DO4CU2DrQoAPxX84Ysxs+HeGQpii5lZWV1Q4gBZTTu49mF+A6Edw==} engines: {node: ^20.0.0 || ^22.0.0 || >=24.0.0} hasBin: true peerDependencies: '@edge-runtime/vm': '*' '@opentelemetry/api': ^1.9.0 '@types/node': ^20.0.0 || ^22.0.0 || >=24.0.0 - '@vitest/browser-playwright': 4.1.10 - '@vitest/browser-preview': 4.1.10 - '@vitest/browser-webdriverio': 4.1.10 - '@vitest/coverage-istanbul': 4.1.10 - '@vitest/coverage-v8': 4.1.10 - '@vitest/ui': 4.1.10 + '@vitest/browser-playwright': 4.1.11 + '@vitest/browser-preview': 4.1.11 + '@vitest/browser-webdriverio': 4.1.11 + '@vitest/coverage-istanbul': 4.1.11 + '@vitest/coverage-v8': 4.1.11 + '@vitest/ui': 4.1.11 happy-dom: '*' jsdom: '*' vite: ^6.0.0 || ^7.0.0 || ^8.0.0 @@ -2130,10 +2135,10 @@ snapshots: '@types/estree@1.0.9': {} - '@vitest/coverage-v8@4.1.10(vitest@4.1.10)': + '@vitest/coverage-v8@4.1.11(vitest@4.1.11)': dependencies: '@bcoe/v8-coverage': 1.0.2 - '@vitest/utils': 4.1.10 + '@vitest/utils': 4.1.11 ast-v8-to-istanbul: 1.0.5 istanbul-lib-coverage: 3.2.2 istanbul-lib-report: 3.0.1 @@ -2142,46 +2147,46 @@ snapshots: obug: 2.1.4 std-env: 4.2.0 tinyrainbow: 3.1.1 - vitest: 4.1.10(@vitest/coverage-v8@4.1.10)(vite@7.3.6(jiti@2.7.0)(yaml@2.9.0)) + vitest: 4.1.11(@vitest/coverage-v8@4.1.11)(vite@7.3.7(jiti@2.7.0)(yaml@2.9.0)) - '@vitest/expect@4.1.10': + '@vitest/expect@4.1.11': dependencies: '@standard-schema/spec': 1.1.0 '@types/chai': 5.2.3 - '@vitest/spy': 4.1.10 - '@vitest/utils': 4.1.10 + '@vitest/spy': 4.1.11 + '@vitest/utils': 4.1.11 chai: 6.2.2 tinyrainbow: 3.1.1 - '@vitest/mocker@4.1.10(vite@7.3.6(jiti@2.7.0)(yaml@2.9.0))': + '@vitest/mocker@4.1.11(vite@7.3.7(jiti@2.7.0)(yaml@2.9.0))': dependencies: - '@vitest/spy': 4.1.10 + '@vitest/spy': 4.1.11 estree-walker: 3.0.3 magic-string: 0.30.21 optionalDependencies: - vite: 7.3.6(jiti@2.7.0)(yaml@2.9.0) + vite: 7.3.7(jiti@2.7.0)(yaml@2.9.0) - '@vitest/pretty-format@4.1.10': + '@vitest/pretty-format@4.1.11': dependencies: tinyrainbow: 3.1.1 - '@vitest/runner@4.1.10': + '@vitest/runner@4.1.11': dependencies: - '@vitest/utils': 4.1.10 + '@vitest/utils': 4.1.11 pathe: 2.0.3 - '@vitest/snapshot@4.1.10': + '@vitest/snapshot@4.1.11': dependencies: - '@vitest/pretty-format': 4.1.10 - '@vitest/utils': 4.1.10 + '@vitest/pretty-format': 4.1.11 + '@vitest/utils': 4.1.11 magic-string: 0.30.21 pathe: 2.0.3 - '@vitest/spy@4.1.10': {} + '@vitest/spy@4.1.11': {} - '@vitest/utils@4.1.10': + '@vitest/utils@4.1.11': dependencies: - '@vitest/pretty-format': 4.1.10 + '@vitest/pretty-format': 4.1.11 convert-source-map: 2.0.0 tinyrainbow: 3.1.1 @@ -2255,7 +2260,7 @@ snapshots: dependencies: chalk: 4.1.2 rxjs: 7.8.2 - shell-quote: 1.9.0 + shell-quote: 1.11.0 supports-color: 8.1.1 tree-kill: 1.2.2 yargs: 17.7.2 @@ -2492,7 +2497,7 @@ snapshots: oxc-parser: 0.143.0 oxc-resolver: 11.24.2 picomatch: 4.0.5 - smol-toml: 1.8.0 + smol-toml: 1.9.0 strip-json-comments: 5.0.3 tinyglobby: 0.2.17 unbash: 4.0.10 @@ -2509,7 +2514,7 @@ snapshots: dependencies: '@babel/parser': 7.29.8 '@babel/types': 7.29.8 - source-map-js: 1.2.1 + source-map-js: 1.2.2 make-dir@4.0.0: dependencies: @@ -2664,11 +2669,11 @@ snapshots: mlly: 1.8.2 pathe: 2.0.3 - postcss@8.5.19: + postcss@8.5.23: dependencies: nanoid: 3.3.18 picocolors: 1.1.1 - source-map-js: 1.2.1 + source-map-js: 1.2.2 printable-characters@1.0.42: {} @@ -2719,7 +2724,7 @@ snapshots: shebang-regex@3.0.0: {} - shell-quote@1.9.0: {} + shell-quote@1.11.0: {} siginfo@2.0.0: {} @@ -2727,9 +2732,9 @@ snapshots: sisteransi@1.0.5: {} - smol-toml@1.8.0: {} + smol-toml@1.9.0: {} - source-map-js@1.2.1: {} + source-map-js@1.2.2: {} source-map@0.6.1: {} @@ -2813,12 +2818,12 @@ snapshots: pathe: 1.1.2 ufo: 1.6.4 - vite@7.3.6(jiti@2.7.0)(yaml@2.9.0): + vite@7.3.7(jiti@2.7.0)(yaml@2.9.0): dependencies: esbuild: 0.28.1 fdir: 6.5.0(picomatch@4.0.5) picomatch: 4.0.5 - postcss: 8.5.19 + postcss: 8.5.23 rollup: 4.62.2 tinyglobby: 0.2.17 optionalDependencies: @@ -2826,15 +2831,15 @@ snapshots: jiti: 2.7.0 yaml: 2.9.0 - vitest@4.1.10(@vitest/coverage-v8@4.1.10)(vite@7.3.6(jiti@2.7.0)(yaml@2.9.0)): + vitest@4.1.11(@vitest/coverage-v8@4.1.11)(vite@7.3.7(jiti@2.7.0)(yaml@2.9.0)): dependencies: - '@vitest/expect': 4.1.10 - '@vitest/mocker': 4.1.10(vite@7.3.6(jiti@2.7.0)(yaml@2.9.0)) - '@vitest/pretty-format': 4.1.10 - '@vitest/runner': 4.1.10 - '@vitest/snapshot': 4.1.10 - '@vitest/spy': 4.1.10 - '@vitest/utils': 4.1.10 + '@vitest/expect': 4.1.11 + '@vitest/mocker': 4.1.11(vite@7.3.7(jiti@2.7.0)(yaml@2.9.0)) + '@vitest/pretty-format': 4.1.11 + '@vitest/runner': 4.1.11 + '@vitest/snapshot': 4.1.11 + '@vitest/spy': 4.1.11 + '@vitest/utils': 4.1.11 es-module-lexer: 2.3.1 expect-type: 1.4.0 magic-string: 0.30.21 @@ -2846,10 +2851,10 @@ snapshots: tinyexec: 1.3.0 tinyglobby: 0.2.17 tinyrainbow: 3.1.1 - vite: 7.3.6(jiti@2.7.0)(yaml@2.9.0) + vite: 7.3.7(jiti@2.7.0)(yaml@2.9.0) why-is-node-running: 2.3.0 optionalDependencies: - '@vitest/coverage-v8': 4.1.10(vitest@4.1.10) + '@vitest/coverage-v8': 4.1.11(vitest@4.1.11) transitivePeerDependencies: - msw diff --git a/scripts/development-command-quoting.test.mjs b/scripts/development-command-quoting.test.mjs new file mode 100644 index 0000000..da51d26 --- /dev/null +++ b/scripts/development-command-quoting.test.mjs @@ -0,0 +1,24 @@ +// The live dependency gate found GHSA-pqg4-j6r4-53mv in concurrently's +// shell-quote dependency. Exercise that resolved dependency without executing +// a shell command: a comment must not let a later token introduce a new line. +import { createRequire } from "node:module"; +import { describe, expect, it } from "vitest"; + +const require = createRequire(import.meta.url); +const toolRequire = createRequire(require.resolve("concurrently")); +const { quote } = toolRequire("shell-quote"); + +describe("development command quoting", () => { + it.each(["\n", "\r", "\u2028", "\u2029"])( + "rejects a line terminator after a comment token: %j", + (terminator) => { + expect(() => + quote(["echo", "ok", { comment: "fixture" }, `a${terminator}echo x;#`]) + ).toThrow(TypeError); + } + ); + + it("keeps ordinary arguments with spaces quoted", () => { + expect(quote(["node", "a file.js"])).toBe("node 'a file.js'"); + }); +}); diff --git a/web/package.json b/web/package.json index 8916e12..547f206 100644 --- a/web/package.json +++ b/web/package.json @@ -13,6 +13,6 @@ }, "devDependencies": { "typescript": "^5.6.0", - "vite": "^7.3.6" + "vite": "^7.3.7" } }