From f1758c34f92374f43ac4f29bf1e3f1a509b2ff78 Mon Sep 17 00:00:00 2001 From: Jeffrey Tseng Date: Thu, 1 Oct 2026 01:46:00 -0700 Subject: [PATCH 1/3] chore(deps): patch runtime transport dependencies Update exact Undici, Vitest and coverage versions to the reviewed security patches and preserve the corresponding generated distribution locks. Keep the dependency-only review separate from hosted model behavior while maintaining one consistent source, installation and shipped CLI graph. --- package-lock.json | 144 +++++++++--------- packages/agent/package.json | 4 +- packages/ai/package.json | 2 +- packages/client/package.json | 2 +- packages/coding-agent-server/package.json | 2 +- .../install-lock/package-lock.json | 14 +- packages/coding-agent/npm-shrinkwrap.json | 14 +- packages/coding-agent/package.json | 4 +- packages/evals/package.json | 2 +- packages/evolution/package.json | 2 +- packages/harness-state/package.json | 2 +- packages/harness-trace/package.json | 2 +- packages/protocol/package.json | 2 +- packages/server/package.json | 2 +- .../session-backends/sqlite-node/package.json | 4 +- packages/telemetry/package.json | 2 +- 16 files changed, 102 insertions(+), 102 deletions(-) diff --git a/package-lock.json b/package-lock.json index 246380bb5..cc35871d5 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2497,14 +2497,14 @@ } }, "node_modules/@vitest/coverage-v8": { - "version": "4.1.9", - "resolved": "https://registry.npmjs.org/@vitest/coverage-v8/-/coverage-v8-4.1.9.tgz", - "integrity": "sha512-G9/lgqibheLVBDRuya45EbsEXTYcWoSG+TLg7i2axuzx0Eq62eXn+aWXyaVdV5vKvFSWd6ywcX8hA7la9Pvu8g==", + "version": "4.1.11", + "resolved": "https://registry.npmjs.org/@vitest/coverage-v8/-/coverage-v8-4.1.11.tgz", + "integrity": "sha512-8MVGEFnJIcdGjcbfKmeq8z0pZHH0JlVtoVZH9Q/qwUp6wyFnEJUBMrw9DCaj+ra3vShGmhavjalMIhPNxZAUcw==", "dev": true, "license": "MIT", "dependencies": { "@bcoe/v8-coverage": "^1.0.2", - "@vitest/utils": "4.1.9", + "@vitest/utils": "4.1.11", "ast-v8-to-istanbul": "^1.0.0", "istanbul-lib-coverage": "^3.2.2", "istanbul-lib-report": "^3.0.1", @@ -2518,8 +2518,8 @@ "url": "https://opencollective.com/vitest" }, "peerDependencies": { - "@vitest/browser": "4.1.9", - "vitest": "4.1.9" + "@vitest/browser": "4.1.11", + "vitest": "4.1.11" }, "peerDependenciesMeta": { "@vitest/browser": { @@ -2528,16 +2528,16 @@ } }, "node_modules/@vitest/expect": { - "version": "4.1.9", - "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-4.1.9.tgz", - "integrity": "sha512-vl/rYsUKcBr3SnQn166+XR5ZQcgMx3DQhFWdfli/cWpLnLUmbxZvyrJZotLFUryib+LtArYMSTJ5RbQ57ZqrlA==", + "version": "4.1.11", + "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-4.1.11.tgz", + "integrity": "sha512-VX2x5vNJXET47KAFzwERI+KRMtTTCSWTfSMKsW7JsUsXV4psq++e3DvZpuTDOpHcxytiDs6p2nhVb2tVDiiUYw==", "dev": true, "license": "MIT", "dependencies": { "@standard-schema/spec": "^1.1.0", "@types/chai": "^5.2.2", - "@vitest/spy": "4.1.9", - "@vitest/utils": "4.1.9", + "@vitest/spy": "4.1.11", + "@vitest/utils": "4.1.11", "chai": "^6.2.2", "tinyrainbow": "^3.1.0" }, @@ -2546,13 +2546,13 @@ } }, "node_modules/@vitest/mocker": { - "version": "4.1.9", - "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-4.1.9.tgz", - "integrity": "sha512-EVkXzBjrPGM+cK8/ANWgBrkUCfJfb38/EfTSO8h7pWvKkyPkpWxvR7BkD2MyItMF62C97zAEoqdpUixwR/e+Rw==", + "version": "4.1.11", + "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-4.1.11.tgz", + "integrity": "sha512-2XJVD55d1o5AZous5CCGKS74g/riOj9odEt2bQpCVZeblHyHdnMeFl4jl0XjU21stf4mbjUkew2eXQZt65g5CQ==", "dev": true, "license": "MIT", "dependencies": { - "@vitest/spy": "4.1.9", + "@vitest/spy": "4.1.11", "estree-walker": "^3.0.3", "magic-string": "^0.30.21" }, @@ -2573,9 +2573,9 @@ } }, "node_modules/@vitest/pretty-format": { - "version": "4.1.9", - "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-4.1.9.tgz", - "integrity": "sha512-s0iufns3iIFitdgm+YR7g1whCAaGtXz459VS9/PqyKDEEFgYIhsHOQmXgIgDuYCt7DeQmiZT0Qe2OA2p4ZPu5A==", + "version": "4.1.11", + "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-4.1.11.tgz", + "integrity": "sha512-yiZzPbGTS9Sr/JpFl8zHrcIkAofNbFV6k21vIgQN/cY/oxZeXhJv5sc/MBJ5jFKWmWs+oJHw0UXLZjmf931+Vw==", "dev": true, "license": "MIT", "dependencies": { @@ -2586,13 +2586,13 @@ } }, "node_modules/@vitest/runner": { - "version": "4.1.9", - "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-4.1.9.tgz", - "integrity": "sha512-KXLMDtc7oe70+3mJfGrPUWPesswH+3sTxAMAMl8DG7I8IUQT4XW718dY5ID3vPUcmlu27CcKfY4P3h3I29SLJg==", + "version": "4.1.11", + "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-4.1.11.tgz", + "integrity": "sha512-LztvUgdwMNJMIkj3hQnnxiC2Xy1zNxq928W/xhjCLaNCzqTZOudjwbQf6v9IntZGPw132i2Lq2rgTRZHD3JHNw==", "dev": true, "license": "MIT", "dependencies": { - "@vitest/utils": "4.1.9", + "@vitest/utils": "4.1.11", "pathe": "^2.0.3" }, "funding": { @@ -2600,14 +2600,14 @@ } }, "node_modules/@vitest/snapshot": { - "version": "4.1.9", - "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-4.1.9.tgz", - "integrity": "sha512-Jc7RKGNBo8Z28WYIm0Niej4xdSPByRf6mU58VpHQkd6Zh05rlnA+twjbK5HyeIGHxrzsc3mJgS43uM0CZKzaIA==", + "version": "4.1.11", + "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-4.1.11.tgz", + "integrity": "sha512-pN7ikn1ON7h8ee4gIAp4AzyK+zBtJPzVbqOgu5LCEh4VaJVbPQcgYQYJIMGQPXVeJJq1fnfazis7a5pFNPahog==", "dev": true, "license": "MIT", "dependencies": { - "@vitest/pretty-format": "4.1.9", - "@vitest/utils": "4.1.9", + "@vitest/pretty-format": "4.1.11", + "@vitest/utils": "4.1.11", "magic-string": "^0.30.21", "pathe": "^2.0.3" }, @@ -2616,9 +2616,9 @@ } }, "node_modules/@vitest/spy": { - "version": "4.1.9", - "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-4.1.9.tgz", - "integrity": "sha512-fHpsS6mIi+PiEW+vcRVOMkX1oSaPKne3VOclSFICPcGOmfKgXPU5iAah+wcNcj2xPrCCmfq99IDGf+EojhhvhA==", + "version": "4.1.11", + "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-4.1.11.tgz", + "integrity": "sha512-apNa/prQy2qCeywhnixOHPRCgGNhvg7T4Dapfl1GahLp/R+uhBm5cPyFoNVyqsNd2h1nJxL6BqqdIjiABL60YA==", "dev": true, "license": "MIT", "funding": { @@ -2626,13 +2626,13 @@ } }, "node_modules/@vitest/utils": { - "version": "4.1.9", - "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-4.1.9.tgz", - "integrity": "sha512-A51o8ymO5PpqlWNnBP9ZHPXDIpuMtTLlGSjN7la4US+LJzoUMyhwjA5QXlm39JexgwHKW4Xjs8Z2d3dLCXOeuA==", + "version": "4.1.11", + "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-4.1.11.tgz", + "integrity": "sha512-zTCVGpyFsGWBhllOyKlTw/vnr6D9qxsfSDyfbyZmTyjHw5N/VuvzHpHoQjm2ZJzn4RJgx5w4r7V0er69CmLgPQ==", "dev": true, "license": "MIT", "dependencies": { - "@vitest/pretty-format": "4.1.9", + "@vitest/pretty-format": "4.1.11", "convert-source-map": "^2.0.0", "tinyrainbow": "^3.1.0" }, @@ -2735,9 +2735,9 @@ "license": "MIT" }, "node_modules/brace-expansion": { - "version": "5.0.9", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.9.tgz", - "integrity": "sha512-ScQ4IuvIEF1TMlP7Zt+vjJ//9zlPb2SDcxWxM3bk8s6t6GGdJ7KO1dCcTidOPJKePW30LE/2cT7wCyPho9/Wxg==", + "version": "5.0.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.12.tgz", + "integrity": "sha512-YovQ3rzhaLMIrDjNDMkNS01tea93qhEhG5xy8f6+R0l+dw3Ki+5sCoIoI942iuLZTHWogWktgwVDhU09iNEimQ==", "license": "MIT", "dependencies": { "balanced-match": "^4.0.2" @@ -5137,9 +5137,9 @@ } }, "node_modules/undici": { - "version": "8.9.0", - "resolved": "https://registry.npmjs.org/undici/-/undici-8.9.0.tgz", - "integrity": "sha512-aWZpUj7XoGonMClx4gdDRfgBjqeA+F473aDmROQQbM9n6PRfK/u1q/a0X4wMTgcHfT8H6fpbt98PFuDUwFg2YA==", + "version": "8.10.2", + "resolved": "https://registry.npmjs.org/undici/-/undici-8.10.2.tgz", + "integrity": "sha512-/y4/bH9YNU5hi9NIrpOuvGXFcxrj3CMrV+/AYpowAYTpHn8gX/XPFjNy766FPoYY0miQhdW977JFWKGNhBdwyQ==", "license": "MIT", "engines": { "node": ">=22.19.0" @@ -5250,19 +5250,19 @@ } }, "node_modules/vitest": { - "version": "4.1.9", - "resolved": "https://registry.npmjs.org/vitest/-/vitest-4.1.9.tgz", - "integrity": "sha512-nE3/LEyc0z87uHYLZebqCUOaJr2hdtuPp7BQ4BosVFnfltxgAvMG08NyrSGlPpOUWvR27c5flSmYFTNr78L9GQ==", + "version": "4.1.11", + "resolved": "https://registry.npmjs.org/vitest/-/vitest-4.1.11.tgz", + "integrity": "sha512-fhACrNXUidIbGSBr5FlbuBkO7VWC1ZyLl0DO4CU2DrQoAPxX84Ysxs+HeGQpii5lZWV1Q4gBZTTu49mF+A6Edw==", "dev": true, "license": "MIT", "dependencies": { - "@vitest/expect": "4.1.9", - "@vitest/mocker": "4.1.9", - "@vitest/pretty-format": "4.1.9", - "@vitest/runner": "4.1.9", - "@vitest/snapshot": "4.1.9", - "@vitest/spy": "4.1.9", - "@vitest/utils": "4.1.9", + "@vitest/expect": "4.1.11", + "@vitest/mocker": "4.1.11", + "@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.0.0", "expect-type": "^1.3.0", "magic-string": "^0.30.21", @@ -5290,12 +5290,12 @@ "@edge-runtime/vm": "*", "@opentelemetry/api": "^1.9.0", "@types/node": "^20.0.0 || ^22.0.0 || >=24.0.0", - "@vitest/browser-playwright": "4.1.9", - "@vitest/browser-preview": "4.1.9", - "@vitest/browser-webdriverio": "4.1.9", - "@vitest/coverage-istanbul": "4.1.9", - "@vitest/coverage-v8": "4.1.9", - "@vitest/ui": "4.1.9", + "@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" @@ -5511,9 +5511,9 @@ }, "devDependencies": { "@types/node": "24.12.4", - "@vitest/coverage-v8": "4.1.9", + "@vitest/coverage-v8": "4.1.11", "typescript": "5.9.3", - "vitest": "4.1.9" + "vitest": "4.1.11" }, "engines": { "node": ">=22.19.0" @@ -5560,7 +5560,7 @@ "devDependencies": { "@types/node": "24.12.4", "canvas": "3.2.3", - "vitest": "4.1.9" + "vitest": "4.1.11" }, "engines": { "node": ">=22.19.0" @@ -5592,7 +5592,7 @@ }, "devDependencies": { "shx": "0.4.0", - "vitest": "4.1.9" + "vitest": "4.1.11" }, "engines": { "node": ">=22.19.0" @@ -5624,7 +5624,7 @@ "proper-lockfile": "4.1.2", "semver": "7.8.0", "typebox": "1.3.7", - "undici": "8.9.0", + "undici": "8.10.2", "yaml": "2.9.0" }, "bin": { @@ -5640,7 +5640,7 @@ "@types/semver": "7.7.1", "shx": "0.4.0", "typescript": "5.9.3", - "vitest": "4.1.9" + "vitest": "4.1.11" }, "engines": { "node": ">=22.19.0" @@ -5664,7 +5664,7 @@ "devDependencies": { "@diffexai/diffex-client": "^0.3.2", "shx": "0.4.0", - "vitest": "4.1.9", + "vitest": "4.1.11", "ws": "8.21.0" }, "engines": { @@ -5734,7 +5734,7 @@ "@types/node": "24.12.4", "shx": "0.4.0", "typescript": "5.9.3", - "vitest": "4.1.9", + "vitest": "4.1.11", "vitest-evals": "0.15.0" } }, @@ -5769,7 +5769,7 @@ "@types/proper-lockfile": "4.1.4", "shx": "0.4.0", "typebox": "1.3.7", - "vitest": "4.1.9" + "vitest": "4.1.11" }, "engines": { "node": ">=22.19.0" @@ -5804,7 +5804,7 @@ "devDependencies": { "@types/proper-lockfile": "4.1.4", "shx": "0.4.0", - "vitest": "4.1.9" + "vitest": "4.1.11" }, "engines": { "node": ">=22.19.0" @@ -5820,7 +5820,7 @@ "devDependencies": { "@types/node": "24.12.4", "shx": "0.4.0", - "vitest": "4.1.9" + "vitest": "4.1.11" }, "engines": { "node": ">=22.19.0" @@ -5852,7 +5852,7 @@ }, "devDependencies": { "shx": "0.4.0", - "vitest": "4.1.9" + "vitest": "4.1.11" }, "engines": { "node": ">=22.19.0" @@ -5870,7 +5870,7 @@ "devDependencies": { "@types/ws": "8.18.1", "shx": "0.4.0", - "vitest": "4.1.9" + "vitest": "4.1.11" }, "engines": { "node": ">=22.19.0" @@ -5885,8 +5885,8 @@ "@diffexai/diffex-ai": "^0.3.2" }, "devDependencies": { - "@vitest/coverage-v8": "4.1.9", - "vitest": "4.1.9" + "@vitest/coverage-v8": "4.1.11", + "vitest": "4.1.11" }, "engines": { "node": ">=22.19.0" @@ -5898,7 +5898,7 @@ "license": "Apache-2.0", "devDependencies": { "@types/node": "24.12.4", - "vitest": "4.1.9" + "vitest": "4.1.11" }, "engines": { "node": ">=22.19.0" diff --git a/packages/agent/package.json b/packages/agent/package.json index b01023c35..75b2ea540 100644 --- a/packages/agent/package.json +++ b/packages/agent/package.json @@ -67,9 +67,9 @@ }, "devDependencies": { "@types/node": "24.12.4", - "@vitest/coverage-v8": "4.1.9", + "@vitest/coverage-v8": "4.1.11", "typescript": "5.9.3", - "vitest": "4.1.9" + "vitest": "4.1.11" }, "private": true } diff --git a/packages/ai/package.json b/packages/ai/package.json index 824b02078..428430928 100644 --- a/packages/ai/package.json +++ b/packages/ai/package.json @@ -102,7 +102,7 @@ "devDependencies": { "@types/node": "24.12.4", "canvas": "3.2.3", - "vitest": "4.1.9" + "vitest": "4.1.11" }, "private": true } diff --git a/packages/client/package.json b/packages/client/package.json index 204ff74e5..db72c3d04 100644 --- a/packages/client/package.json +++ b/packages/client/package.json @@ -65,7 +65,7 @@ }, "devDependencies": { "shx": "0.4.0", - "vitest": "4.1.9" + "vitest": "4.1.11" }, "private": true } diff --git a/packages/coding-agent-server/package.json b/packages/coding-agent-server/package.json index bcb880ea7..737ff2747 100644 --- a/packages/coding-agent-server/package.json +++ b/packages/coding-agent-server/package.json @@ -48,7 +48,7 @@ "devDependencies": { "@diffexai/diffex-client": "^0.3.2", "shx": "0.4.0", - "vitest": "4.1.9", + "vitest": "4.1.11", "ws": "8.21.0" }, "private": true diff --git a/packages/coding-agent/install-lock/package-lock.json b/packages/coding-agent/install-lock/package-lock.json index e98550e74..6f2ad1b45 100644 --- a/packages/coding-agent/install-lock/package-lock.json +++ b/packages/coding-agent/install-lock/package-lock.json @@ -481,7 +481,7 @@ "proper-lockfile": "4.1.2", "semver": "7.8.0", "typebox": "1.3.7", - "undici": "8.9.0", + "undici": "8.10.2", "yaml": "2.9.0" }, "optionalDependencies": { @@ -1212,9 +1212,9 @@ "license": "MIT" }, "node_modules/brace-expansion": { - "version": "5.0.9", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.9.tgz", - "integrity": "sha512-ScQ4IuvIEF1TMlP7Zt+vjJ//9zlPb2SDcxWxM3bk8s6t6GGdJ7KO1dCcTidOPJKePW30LE/2cT7wCyPho9/Wxg==", + "version": "5.0.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.12.tgz", + "integrity": "sha512-YovQ3rzhaLMIrDjNDMkNS01tea93qhEhG5xy8f6+R0l+dw3Ki+5sCoIoI942iuLZTHWogWktgwVDhU09iNEimQ==", "license": "MIT", "dependencies": { "balanced-match": "^4.0.2" @@ -1912,9 +1912,9 @@ "license": "MIT" }, "node_modules/undici": { - "version": "8.9.0", - "resolved": "https://registry.npmjs.org/undici/-/undici-8.9.0.tgz", - "integrity": "sha512-aWZpUj7XoGonMClx4gdDRfgBjqeA+F473aDmROQQbM9n6PRfK/u1q/a0X4wMTgcHfT8H6fpbt98PFuDUwFg2YA==", + "version": "8.10.2", + "resolved": "https://registry.npmjs.org/undici/-/undici-8.10.2.tgz", + "integrity": "sha512-/y4/bH9YNU5hi9NIrpOuvGXFcxrj3CMrV+/AYpowAYTpHn8gX/XPFjNy766FPoYY0miQhdW977JFWKGNhBdwyQ==", "license": "MIT", "engines": { "node": ">=22.19.0" diff --git a/packages/coding-agent/npm-shrinkwrap.json b/packages/coding-agent/npm-shrinkwrap.json index f5563800b..514fbb17e 100644 --- a/packages/coding-agent/npm-shrinkwrap.json +++ b/packages/coding-agent/npm-shrinkwrap.json @@ -36,7 +36,7 @@ "proper-lockfile": "4.1.2", "semver": "7.8.0", "typebox": "1.3.7", - "undici": "8.9.0", + "undici": "8.10.2", "yaml": "2.9.0" }, "optionalDependencies": { @@ -1202,9 +1202,9 @@ "license": "MIT" }, "node_modules/brace-expansion": { - "version": "5.0.9", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.9.tgz", - "integrity": "sha512-ScQ4IuvIEF1TMlP7Zt+vjJ//9zlPb2SDcxWxM3bk8s6t6GGdJ7KO1dCcTidOPJKePW30LE/2cT7wCyPho9/Wxg==", + "version": "5.0.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.12.tgz", + "integrity": "sha512-YovQ3rzhaLMIrDjNDMkNS01tea93qhEhG5xy8f6+R0l+dw3Ki+5sCoIoI942iuLZTHWogWktgwVDhU09iNEimQ==", "license": "MIT", "dependencies": { "balanced-match": "^4.0.2" @@ -1902,9 +1902,9 @@ "license": "MIT" }, "node_modules/undici": { - "version": "8.9.0", - "resolved": "https://registry.npmjs.org/undici/-/undici-8.9.0.tgz", - "integrity": "sha512-aWZpUj7XoGonMClx4gdDRfgBjqeA+F473aDmROQQbM9n6PRfK/u1q/a0X4wMTgcHfT8H6fpbt98PFuDUwFg2YA==", + "version": "8.10.2", + "resolved": "https://registry.npmjs.org/undici/-/undici-8.10.2.tgz", + "integrity": "sha512-/y4/bH9YNU5hi9NIrpOuvGXFcxrj3CMrV+/AYpowAYTpHn8gX/XPFjNy766FPoYY0miQhdW977JFWKGNhBdwyQ==", "license": "MIT", "engines": { "node": ">=22.19.0" diff --git a/packages/coding-agent/package.json b/packages/coding-agent/package.json index 0725d1283..89f8a5337 100644 --- a/packages/coding-agent/package.json +++ b/packages/coding-agent/package.json @@ -71,7 +71,7 @@ "proper-lockfile": "4.1.2", "semver": "7.8.0", "typebox": "1.3.7", - "undici": "8.9.0", + "undici": "8.10.2", "yaml": "2.9.0" }, "overrides": { @@ -94,7 +94,7 @@ "@types/semver": "7.7.1", "shx": "0.4.0", "typescript": "5.9.3", - "vitest": "4.1.9" + "vitest": "4.1.11" }, "keywords": [ "coding-agent", diff --git a/packages/evals/package.json b/packages/evals/package.json index 4bd297b17..72e1939d9 100644 --- a/packages/evals/package.json +++ b/packages/evals/package.json @@ -15,6 +15,6 @@ "shx": "0.4.0", "typescript": "5.9.3", "vitest-evals": "0.15.0", - "vitest": "4.1.9" + "vitest": "4.1.11" } } diff --git a/packages/evolution/package.json b/packages/evolution/package.json index ef94a9f80..d9b6d9c70 100644 --- a/packages/evolution/package.json +++ b/packages/evolution/package.json @@ -45,6 +45,6 @@ "@types/proper-lockfile": "4.1.4", "shx": "0.4.0", "typebox": "1.3.7", - "vitest": "4.1.9" + "vitest": "4.1.11" } } diff --git a/packages/harness-state/package.json b/packages/harness-state/package.json index 7b43b476e..fd5141a24 100644 --- a/packages/harness-state/package.json +++ b/packages/harness-state/package.json @@ -50,7 +50,7 @@ "devDependencies": { "@types/proper-lockfile": "4.1.4", "shx": "0.4.0", - "vitest": "4.1.9" + "vitest": "4.1.11" }, "private": true } diff --git a/packages/harness-trace/package.json b/packages/harness-trace/package.json index e1c7998ab..c29bad8c1 100644 --- a/packages/harness-trace/package.json +++ b/packages/harness-trace/package.json @@ -41,6 +41,6 @@ "devDependencies": { "@types/node": "24.12.4", "shx": "0.4.0", - "vitest": "4.1.9" + "vitest": "4.1.11" } } diff --git a/packages/protocol/package.json b/packages/protocol/package.json index d5e3937a5..ae93d8073 100644 --- a/packages/protocol/package.json +++ b/packages/protocol/package.json @@ -49,7 +49,7 @@ }, "devDependencies": { "shx": "0.4.0", - "vitest": "4.1.9" + "vitest": "4.1.11" }, "private": true } diff --git a/packages/server/package.json b/packages/server/package.json index 78ac968a1..c58d66fa6 100644 --- a/packages/server/package.json +++ b/packages/server/package.json @@ -64,7 +64,7 @@ "devDependencies": { "@types/ws": "8.18.1", "shx": "0.4.0", - "vitest": "4.1.9" + "vitest": "4.1.11" }, "private": true } diff --git a/packages/session-backends/sqlite-node/package.json b/packages/session-backends/sqlite-node/package.json index 7e9e41261..2dff3ca97 100644 --- a/packages/session-backends/sqlite-node/package.json +++ b/packages/session-backends/sqlite-node/package.json @@ -44,8 +44,8 @@ "@diffexai/diffex-agent-core": "^0.3.2" }, "devDependencies": { - "@vitest/coverage-v8": "4.1.9", - "vitest": "4.1.9" + "@vitest/coverage-v8": "4.1.11", + "vitest": "4.1.11" }, "private": true } diff --git a/packages/telemetry/package.json b/packages/telemetry/package.json index dfa16b497..23116e8ed 100644 --- a/packages/telemetry/package.json +++ b/packages/telemetry/package.json @@ -48,7 +48,7 @@ }, "devDependencies": { "@types/node": "24.12.4", - "vitest": "4.1.9" + "vitest": "4.1.11" }, "private": true } From 9c8854ff67ed3923d9bd7062b5fc37b3bcc90a6f Mon Sep 17 00:00:00 2001 From: Jeffrey Tseng Date: Fri, 2 Oct 2026 21:22:29 -0700 Subject: [PATCH 2/3] fix(coding-agent): bound build-tool brace nesting The shx dependency chain still uses braces 3.0.3, which can exhaust recursive AST walkers on deeply nested patterns and has no upstream patched release. Vendor the reviewed MIT source with fixed depth and AST-value guards under a transparent private version, scope its override to shx, copy it before Docker installation, and verify the real installed glob and CLI paths while preserving existing transport and test dependency patches. --- Dockerfile.runtime | 1 + package-lock.json | 23 +- package.json | 4 + scripts/vendored-braces-security.test.mjs | 162 +++++++++++ vendor/braces/LICENSE | 21 ++ vendor/braces/README.md | 47 +++ vendor/braces/index.js | 170 +++++++++++ vendor/braces/lib/compile.js | 61 ++++ vendor/braces/lib/constants.js | 57 ++++ vendor/braces/lib/expand.js | 120 ++++++++ vendor/braces/lib/parse.js | 334 ++++++++++++++++++++++ vendor/braces/lib/stringify.js | 32 +++ vendor/braces/lib/utils.js | 136 +++++++++ vendor/braces/package.json | 18 ++ 14 files changed, 1175 insertions(+), 11 deletions(-) create mode 100644 scripts/vendored-braces-security.test.mjs create mode 100644 vendor/braces/LICENSE create mode 100644 vendor/braces/README.md create mode 100644 vendor/braces/index.js create mode 100644 vendor/braces/lib/compile.js create mode 100644 vendor/braces/lib/constants.js create mode 100644 vendor/braces/lib/expand.js create mode 100644 vendor/braces/lib/parse.js create mode 100644 vendor/braces/lib/stringify.js create mode 100644 vendor/braces/lib/utils.js create mode 100644 vendor/braces/package.json diff --git a/Dockerfile.runtime b/Dockerfile.runtime index 95819e284..bf2275985 100644 --- a/Dockerfile.runtime +++ b/Dockerfile.runtime @@ -11,6 +11,7 @@ COPY legal ./legal COPY docs/release/distribution-policy.json ./docs/release/distribution-policy.json COPY packages ./packages COPY scripts ./scripts +COPY vendor ./vendor RUN npm ci --ignore-scripts RUN npm run hydrate:model-data && npm run build:offline diff --git a/package-lock.json b/package-lock.json index cc35871d5..f4a1e1f79 100644 --- a/package-lock.json +++ b/package-lock.json @@ -20,6 +20,7 @@ "@biomejs/biome": "2.3.5", "@types/node": "22.19.19", "@typescript/native-preview": "7.0.0-dev.20260120.1", + "braces": "file:vendor/braces", "esbuild": "0.28.1", "husky": "9.1.7", "jiti": "2.7.0", @@ -2747,17 +2748,8 @@ } }, "node_modules/braces": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", - "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", - "dev": true, - "license": "MIT", - "dependencies": { - "fill-range": "^7.1.1" - }, - "engines": { - "node": ">=8" - } + "resolved": "vendor/braces", + "link": true }, "node_modules/buffer": { "version": "5.7.1", @@ -5936,6 +5928,15 @@ "engines": { "node": ">=22.19.0" } + }, + "vendor/braces": { + "name": "@diffex-cloud/braces", + "version": "3.0.3-diffex.1", + "dev": true, + "license": "MIT", + "dependencies": { + "fill-range": "7.1.1" + } } } } diff --git a/package.json b/package.json index 70956bcd2..c7350cabc 100644 --- a/package.json +++ b/package.json @@ -55,6 +55,7 @@ "@biomejs/biome": "2.3.5", "@types/node": "22.19.19", "@typescript/native-preview": "7.0.0-dev.20260120.1", + "braces": "file:vendor/braces", "esbuild": "0.28.1", "husky": "9.1.7", "jiti": "2.7.0", @@ -67,6 +68,9 @@ }, "version": "0.0.3", "overrides": { + "shx": { + "braces": "$braces" + }, "nanoid": "3.3.18", "protobufjs": "7.6.5", "rimraf": "6.1.2", diff --git a/scripts/vendored-braces-security.test.mjs b/scripts/vendored-braces-security.test.mjs new file mode 100644 index 000000000..7986e0f5e --- /dev/null +++ b/scripts/vendored-braces-security.test.mjs @@ -0,0 +1,162 @@ +import assert from "node:assert/strict"; +import { spawnSync } from "node:child_process"; +import { mkdirSync, mkdtempSync, readdirSync, rmSync, writeFileSync } from "node:fs"; +import { createRequire } from "node:module"; +import { tmpdir } from "node:os"; +import { join } from "node:path"; +import test from "node:test"; + +const require = createRequire(import.meta.url); +const shxRequire = createRequire(require.resolve("shx/package.json")); +const shellRequire = createRequire(shxRequire.resolve("shelljs")); +const globRequire = createRequire(shellRequire.resolve("fast-glob")); +const matchRequire = createRequire(globRequire.resolve("micromatch")); +const braces = matchRequire("braces"); +const glob = shellRequire("fast-glob"); +const match = globRequire("micromatch"); +const nested = (depth, open = "{", close = "}") => open.repeat(depth) + "x" + close.repeat(depth); + +function directAst(depth) { + let node = { type: "text", value: "x" }; + for (let i = 0; i < depth; i++) { + const parent = { type: "paren", nodes: [node] }; + node.parent = parent; + node = parent; + } + const root = { type: "root", nodes: [node] }; + node.parent = root; + return root; +} + +test("actual shx dependency resolves the transparent private patch", () => { + const manifest = matchRequire("braces/package.json"); + assert.equal(manifest.name, "@diffex-cloud/braces"); + assert.equal(manifest.version, "3.0.3-diffex.1"); +}); + +for (const [open, close] of [ + ["{", "}"], + ["(", ")"], + ["{(", ")}"], +]) { + test(`bounds combined nesting for ${open}`, () => { + const boundary = open.length === 2 ? 50 : 100; + for (const method of ["parse", "compile", "expand", "stringify"]) { + assert.doesNotThrow(() => braces[method](nested(boundary, open, close))); + assert.throws(() => braces[method](nested(boundary + 1, open, close)), /maximum depth/u); + } + assert.throws(() => braces(nested(4000), { maxDepth: Infinity }), /maximum depth/u); + }); +} + +for (const method of ["compile", "expand", "stringify"]) { + test(`protects caller-supplied ASTs in ${method}`, () => { + assert.doesNotThrow(() => braces[method](directAst(100))); + assert.throws(() => braces[method](directAst(4000)), /maximum depth/u); + const cycle = { type: "root", nodes: [] }; + cycle.nodes.push(cycle); + assert.throws(() => braces[method](cycle), /maximum depth/u); + const array = []; + array.push(array); + assert.throws( + () => braces[method]({ type: "root", nodes: [{ type: "text", value: array }] }), + /AST values must be strings/u, + ); + }); +} + +test("bounds cyclic parent traversal and recursive helper arrays", () => { + const parent = { type: "paren", nodes: [] }; + parent.parent = parent; + assert.throws(() => braces.expand(parent), /maximum depth/u); + const utils = createRequire(matchRequire.resolve("braces"))("./lib/utils.js"); + let deep = ["x"]; + for (let i = 0; i < 4000; i++) deep = [deep]; + assert.throws(() => utils.flatten(deep), /maximum depth/u); + const cycle = []; + cycle.push(cycle); + assert.throws(() => utils.flatten(cycle), /maximum depth/u); +}); + +test("validates range AST values before numeric coercion", () => { + let step = ["1"]; + for (let i = 0; i < 4000; i++) step = [step]; + for (const method of ["compile", "expand", "stringify"]) { + const range = { + type: "root", + nodes: [ + { + type: "brace", + nodes: ["1", "2", step].map((value) => ({ type: "text", value })), + open: true, + close: true, + commas: 0, + ranges: 1, + }, + ], + }; + assert.throws(() => braces[method](range), /AST values must be strings/u); + } +}); + +test("preserves alternatives, ranges, escaping, and options", () => { + assert.deepEqual(braces.expand("a/{b,{c,d}}/{01..03..2}"), [ + "a/b/01", + "a/b/03", + "a/c/01", + "a/c/03", + "a/d/01", + "a/d/03", + ]); + assert.deepEqual(braces.expand("{a..e..2}"), ["a", "c", "e"]); + assert.deepEqual(braces.expand("{-2..2}"), ["-2", "-1", "0", "1", "2"]); + assert.deepEqual(braces.expand("{a,b}{c,d}"), ["ac", "ad", "bc", "bd"]); + assert.deepEqual(braces("{a,b}"), ["(a|b)"]); + assert.deepEqual(braces(["{a,a}", "{a,b}"], { expand: true, nodupes: true }), ["a", "b"]); + assert.deepEqual(braces.expand("{,a}", { noempty: true }), ["a"]); + for (const literal of [ + '"' + nested(150) + '"', + "[" + nested(150) + "]", + "\\{".repeat(150) + "x" + "\\}".repeat(150), + ]) + assert.doesNotThrow(() => braces(literal)); + assert.equal(braces.stringify(braces.parse("a/{b,c}/d")), "a/{b,c}/d"); + assert.throws(() => braces.expand("{1..2000}"), /range limit/u); +}); + +test("preserves installed glob consumers and actual build-tool CLI behavior", () => { + assert.deepEqual(match(["a.ts", "b.js", "c.md"], ["*.{ts,js}"]), ["a.ts", "b.js"]); + const directory = mkdtempSync(join(tmpdir(), "diffex-braces-")); + try { + for (const file of ["a.txt", "b.txt", ".hidden.txt", "skip.md"]) writeFileSync(join(directory, file), "fixture"); + assert.deepEqual(glob.sync(["*.{txt,md}"], { cwd: directory, dot: true }).sort(), [ + ".hidden.txt", + "a.txt", + "b.txt", + "skip.md", + ]); + const output = join(directory, "out"); + mkdirSync(output); + const copied = spawnSync(process.execPath, [require.resolve("shx/lib/cli.js"), "cp", "*.{txt,md}", output], { + cwd: directory, + encoding: "utf8", + timeout: 10_000, + }); + assert.ifError(copied.error); + assert.equal(copied.status, 0, copied.stderr); + assert.deepEqual(readdirSync(output).sort(), ["a.txt", "b.txt", "skip.md"]); + assert.throws(() => glob.sync([nested(4000)], { cwd: directory, dot: true }), /maximum depth/u); + assert.deepEqual(match(["x"], [nested(4000)]), []); + const rejected = spawnSync(process.execPath, [require.resolve("shx/lib/cli.js"), "ls", nested(4000)], { + cwd: directory, + encoding: "utf8", + timeout: 10_000, + }); + assert.ifError(rejected.error); + assert.equal(rejected.signal, null); + assert.equal(rejected.status, 2); + assert.doesNotMatch(rejected.stderr, /Maximum call stack|RangeError/u); + } finally { + rmSync(directory, { recursive: true, force: true }); + } +}); diff --git a/vendor/braces/LICENSE b/vendor/braces/LICENSE new file mode 100644 index 000000000..9af4a67d2 --- /dev/null +++ b/vendor/braces/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2014-present, Jon Schlinkert. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/vendor/braces/README.md b/vendor/braces/README.md new file mode 100644 index 000000000..0244bbbd1 --- /dev/null +++ b/vendor/braces/README.md @@ -0,0 +1,47 @@ +# Local braces security patch + +This private package preserves the upstream `braces` 3.0.3 API and MIT license while bounding nesting to address [GHSA-vfj7-8cjw-p6xm](https://github.com/advisories/GHSA-vfj7-8cjw-p6xm). +It is named `@diffex-cloud/braces` at version `3.0.3-diffex.1` because this is our reviewed patch, not an upstream fixed release. +Each consuming repository scopes its npm override to the affected dependency chain and tests the installed consumer rather than changing its functionality. + +## Provenance + +The source is copied from the immutable [npm braces 3.0.3 tarball](https://registry.npmjs.org/braces/-/braces-3.0.3.tgz). +Its npm integrity is `sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==` and SHA-1 is `490332f40919452272d55a8480adc0c441358789`. +The library files are source, not generated code. +They retain upstream formatting to make the patch easy to compare. +The unchanged upstream MIT license is in `LICENSE`. +The private manifest pins the existing `fill-range` dependency to the reviewed version `7.1.1`. + +The original SHA-256 fingerprints are: + +| File | Original SHA-256 | +| ------------------ | ------------------------------------------------------------------ | +| `index.js` | `332ea07c7b006361aad12aa994ca75dc1db8e8382b884909e2f38f10b85c88a4` | +| `lib/compile.js` | `dc98f22eee3d511785d92a00758d5f0d48efed5f5813bdecc2de430c529b5c9f` | +| `lib/constants.js` | `c18ac5adb57308f1ce42a28552da3a31f5d83709743ebd9a636336813a744d4b` | +| `lib/expand.js` | `41ccc196ebfa7b7781a634e721eb744e4e7bcb54cba427a7e3d6806a1b9e58f7` | +| `lib/parse.js` | `e572166565f15fa6ad9865ae49d678218e32aabfd1b3720f6d0d43d39800d310` | +| `lib/stringify.js` | `379f22d77bfa1478341ccd49c5e4267464aabcbba03558bab332aac23fc6f23a` | +| `lib/utils.js` | `b5a7596aa67730412b3c029ef09e84e6b67b8e445cffd35d1d295549c89066c7` | +| `LICENSE` | `35bdd8a44339719441900fb50fbefc5e2dca1ca662cbaed7a687de842c8b70f2` | + +## Patch and verification + +The parser bounds combined brace and parenthesis nesting to 100 structural levels. +Compile, expand, and stringify independently bound recursive internal nodes, including caller-supplied ASTs. +Expansion parent traversal and recursive array helpers also have fixed bounds, and AST text values must be strings to prevent unchecked native array coercion. +Caller options cannot raise or disable these bounds. +Escaped, quoted, and character-class literal braces retain upstream behavior. +This addresses nesting exhaustion; it does not claim to bound every combinatorial expansion or other resource risk. + +Consuming repository tests exercise the actual affected dependency path, micromatch and fast-glob compatibility, public AST entry points, depth boundaries, cycles, alternatives, ranges, and literal handling. +Docker install stages must copy this package before installing local file dependencies. +`npm audit` checks registry dependencies but does not independently establish the security of this private source. +The source requires manual review and the targeted security tests in addition to the repository checks. + +## Retirement + +Replace the override with an upstream fixed release once its patch, compatibility, and advisory status have been verified. +Remove this private package and its formatting exceptions at that time, while keeping regression coverage for the affected consumer. +Do not relabel this package as an unaffected upstream version or suppress the advisory. diff --git a/vendor/braces/index.js b/vendor/braces/index.js new file mode 100644 index 000000000..d222c13b5 --- /dev/null +++ b/vendor/braces/index.js @@ -0,0 +1,170 @@ +'use strict'; + +const stringify = require('./lib/stringify'); +const compile = require('./lib/compile'); +const expand = require('./lib/expand'); +const parse = require('./lib/parse'); + +/** + * Expand the given pattern or create a regex-compatible string. + * + * ```js + * const braces = require('braces'); + * console.log(braces('{a,b,c}', { compile: true })); //=> ['(a|b|c)'] + * console.log(braces('{a,b,c}')); //=> ['a', 'b', 'c'] + * ``` + * @param {String} `str` + * @param {Object} `options` + * @return {String} + * @api public + */ + +const braces = (input, options = {}) => { + let output = []; + + if (Array.isArray(input)) { + for (const pattern of input) { + const result = braces.create(pattern, options); + if (Array.isArray(result)) { + output.push(...result); + } else { + output.push(result); + } + } + } else { + output = [].concat(braces.create(input, options)); + } + + if (options && options.expand === true && options.nodupes === true) { + output = [...new Set(output)]; + } + return output; +}; + +/** + * Parse the given `str` with the given `options`. + * + * ```js + * // braces.parse(pattern, [, options]); + * const ast = braces.parse('a/{b,c}/d'); + * console.log(ast); + * ``` + * @param {String} pattern Brace pattern to parse + * @param {Object} options + * @return {Object} Returns an AST + * @api public + */ + +braces.parse = (input, options = {}) => parse(input, options); + +/** + * Creates a braces string from an AST, or an AST node. + * + * ```js + * const braces = require('braces'); + * let ast = braces.parse('foo/{a,b}/bar'); + * console.log(stringify(ast.nodes[2])); //=> '{a,b}' + * ``` + * @param {String} `input` Brace pattern or AST. + * @param {Object} `options` + * @return {Array} Returns an array of expanded values. + * @api public + */ + +braces.stringify = (input, options = {}) => { + if (typeof input === 'string') { + return stringify(braces.parse(input, options), options); + } + return stringify(input, options); +}; + +/** + * Compiles a brace pattern into a regex-compatible, optimized string. + * This method is called by the main [braces](#braces) function by default. + * + * ```js + * const braces = require('braces'); + * console.log(braces.compile('a/{b,c}/d')); + * //=> ['a/(b|c)/d'] + * ``` + * @param {String} `input` Brace pattern or AST. + * @param {Object} `options` + * @return {Array} Returns an array of expanded values. + * @api public + */ + +braces.compile = (input, options = {}) => { + if (typeof input === 'string') { + input = braces.parse(input, options); + } + return compile(input, options); +}; + +/** + * Expands a brace pattern into an array. This method is called by the + * main [braces](#braces) function when `options.expand` is true. Before + * using this method it's recommended that you read the [performance notes](#performance)) + * and advantages of using [.compile](#compile) instead. + * + * ```js + * const braces = require('braces'); + * console.log(braces.expand('a/{b,c}/d')); + * //=> ['a/b/d', 'a/c/d']; + * ``` + * @param {String} `pattern` Brace pattern + * @param {Object} `options` + * @return {Array} Returns an array of expanded values. + * @api public + */ + +braces.expand = (input, options = {}) => { + if (typeof input === 'string') { + input = braces.parse(input, options); + } + + let result = expand(input, options); + + // filter out empty strings if specified + if (options.noempty === true) { + result = result.filter(Boolean); + } + + // filter out duplicates if specified + if (options.nodupes === true) { + result = [...new Set(result)]; + } + + return result; +}; + +/** + * Processes a brace pattern and returns either an expanded array + * (if `options.expand` is true), a highly optimized regex-compatible string. + * This method is called by the main [braces](#braces) function. + * + * ```js + * const braces = require('braces'); + * console.log(braces.create('user-{200..300}/project-{a,b,c}-{1..10}')) + * //=> 'user-(20[0-9]|2[1-9][0-9]|300)/project-(a|b|c)-([1-9]|10)' + * ``` + * @param {String} `pattern` Brace pattern + * @param {Object} `options` + * @return {Array} Returns an array of expanded values. + * @api public + */ + +braces.create = (input, options = {}) => { + if (input === '' || input.length < 3) { + return [input]; + } + + return options.expand !== true + ? braces.compile(input, options) + : braces.expand(input, options); +}; + +/** + * Expose "braces" + */ + +module.exports = braces; diff --git a/vendor/braces/lib/compile.js b/vendor/braces/lib/compile.js new file mode 100644 index 000000000..15edb2418 --- /dev/null +++ b/vendor/braces/lib/compile.js @@ -0,0 +1,61 @@ +'use strict'; + +const fill = require('fill-range'); +const utils = require('./utils'); + +const compile = (ast, options = {}) => { + const walk = (node, parent = {}, depth = 0) => { + utils.checkNode(node, depth); + const invalidBlock = utils.isInvalidBrace(parent); + const invalidNode = node.invalid === true && options.escapeInvalid === true; + const invalid = invalidBlock === true || invalidNode === true; + const prefix = options.escapeInvalid === true ? '\\' : ''; + let output = ''; + + if (node.isOpen === true) { + return prefix + node.value; + } + + if (node.isClose === true) { + console.log('node.isClose', prefix, node.value); + return prefix + node.value; + } + + if (node.type === 'open') { + return invalid ? prefix + node.value : '('; + } + + if (node.type === 'close') { + return invalid ? prefix + node.value : ')'; + } + + if (node.type === 'comma') { + return node.prev.type === 'comma' ? '' : invalid ? node.value : '|'; + } + + if (node.value) { + return node.value; + } + + if (node.nodes && node.ranges > 0) { + const args = utils.reduce(node.nodes); + const range = fill(...args, { ...options, wrap: false, toRegex: true, strictZeros: true }); + + if (range.length !== 0) { + return args.length > 1 && range.length > 1 ? `(${range})` : range; + } + } + + if (node.nodes) { + for (const child of node.nodes) { + output += walk(child, node, depth + 1); + } + } + + return output; + }; + + return walk(ast); +}; + +module.exports = compile; diff --git a/vendor/braces/lib/constants.js b/vendor/braces/lib/constants.js new file mode 100644 index 000000000..2bb3b8840 --- /dev/null +++ b/vendor/braces/lib/constants.js @@ -0,0 +1,57 @@ +'use strict'; + +module.exports = { + MAX_LENGTH: 10000, + + // Digits + CHAR_0: '0', /* 0 */ + CHAR_9: '9', /* 9 */ + + // Alphabet chars. + CHAR_UPPERCASE_A: 'A', /* A */ + CHAR_LOWERCASE_A: 'a', /* a */ + CHAR_UPPERCASE_Z: 'Z', /* Z */ + CHAR_LOWERCASE_Z: 'z', /* z */ + + CHAR_LEFT_PARENTHESES: '(', /* ( */ + CHAR_RIGHT_PARENTHESES: ')', /* ) */ + + CHAR_ASTERISK: '*', /* * */ + + // Non-alphabetic chars. + CHAR_AMPERSAND: '&', /* & */ + CHAR_AT: '@', /* @ */ + CHAR_BACKSLASH: '\\', /* \ */ + CHAR_BACKTICK: '`', /* ` */ + CHAR_CARRIAGE_RETURN: '\r', /* \r */ + CHAR_CIRCUMFLEX_ACCENT: '^', /* ^ */ + CHAR_COLON: ':', /* : */ + CHAR_COMMA: ',', /* , */ + CHAR_DOLLAR: '$', /* . */ + CHAR_DOT: '.', /* . */ + CHAR_DOUBLE_QUOTE: '"', /* " */ + CHAR_EQUAL: '=', /* = */ + CHAR_EXCLAMATION_MARK: '!', /* ! */ + CHAR_FORM_FEED: '\f', /* \f */ + CHAR_FORWARD_SLASH: '/', /* / */ + CHAR_HASH: '#', /* # */ + CHAR_HYPHEN_MINUS: '-', /* - */ + CHAR_LEFT_ANGLE_BRACKET: '<', /* < */ + CHAR_LEFT_CURLY_BRACE: '{', /* { */ + CHAR_LEFT_SQUARE_BRACKET: '[', /* [ */ + CHAR_LINE_FEED: '\n', /* \n */ + CHAR_NO_BREAK_SPACE: '\u00A0', /* \u00A0 */ + CHAR_PERCENT: '%', /* % */ + CHAR_PLUS: '+', /* + */ + CHAR_QUESTION_MARK: '?', /* ? */ + CHAR_RIGHT_ANGLE_BRACKET: '>', /* > */ + CHAR_RIGHT_CURLY_BRACE: '}', /* } */ + CHAR_RIGHT_SQUARE_BRACKET: ']', /* ] */ + CHAR_SEMICOLON: ';', /* ; */ + CHAR_SINGLE_QUOTE: '\'', /* ' */ + CHAR_SPACE: ' ', /* */ + CHAR_TAB: '\t', /* \t */ + CHAR_UNDERSCORE: '_', /* _ */ + CHAR_VERTICAL_LINE: '|', /* | */ + CHAR_ZERO_WIDTH_NOBREAK_SPACE: '\uFEFF' /* \uFEFF */ +}; diff --git a/vendor/braces/lib/expand.js b/vendor/braces/lib/expand.js new file mode 100644 index 000000000..fada7ed5e --- /dev/null +++ b/vendor/braces/lib/expand.js @@ -0,0 +1,120 @@ +'use strict'; + +const fill = require('fill-range'); +const stringify = require('./stringify'); +const utils = require('./utils'); + +const append = (queue = '', stash = '', enclose = false, depth = 0) => { + utils.checkDepth(depth); + const result = []; + + queue = [].concat(queue); + stash = [].concat(stash); + + if (!stash.length) return queue; + if (!queue.length) { + return enclose ? utils.flatten(stash).map(ele => `{${ele}}`) : stash; + } + + for (const item of queue) { + if (Array.isArray(item)) { + for (const value of item) { + result.push(append(value, stash, enclose, depth + 1)); + } + } else { + for (let ele of stash) { + if (enclose === true && typeof ele === 'string') ele = `{${ele}}`; + result.push(Array.isArray(ele) ? append(item, ele, enclose, depth + 1) : item + ele); + } + } + } + return utils.flatten(result); +}; + +const expand = (ast, options = {}) => { + const rangeLimit = options.rangeLimit === undefined ? 1000 : options.rangeLimit; + + const walk = (node, parent = {}, depth = 0) => { + utils.checkNode(node, depth); + node.queue = []; + + let p = parent; + let q = parent.queue; + let parentDepth = 0; + + while (p.type !== 'brace' && p.type !== 'root' && p.parent) { + utils.checkDepth(++parentDepth); + p = p.parent; + q = p.queue; + } + + if (node.invalid || node.dollar) { + q.push(append(q.pop(), stringify(node, options))); + return; + } + + if (node.type === 'brace' && node.invalid !== true && node.nodes.length === 2) { + q.push(append(q.pop(), ['{}'])); + return; + } + + if (node.nodes && node.ranges > 0) { + const args = utils.reduce(node.nodes); + + if (utils.exceedsLimit(...args, options.step, rangeLimit)) { + throw new RangeError('expanded array length exceeds range limit. Use options.rangeLimit to increase or disable the limit.'); + } + + let range = fill(...args, options); + if (range.length === 0) { + range = stringify(node, options); + } + + q.push(append(q.pop(), range)); + node.nodes = []; + return; + } + + const enclose = utils.encloseBrace(node); + let queue = node.queue; + let block = node; + parentDepth = 0; + + while (block.type !== 'brace' && block.type !== 'root' && block.parent) { + utils.checkDepth(++parentDepth); + block = block.parent; + queue = block.queue; + } + + for (let i = 0; i < node.nodes.length; i++) { + const child = node.nodes[i]; + utils.checkNode(child, depth + 1); + + if (child.type === 'comma' && node.type === 'brace') { + if (i === 1) queue.push(''); + queue.push(''); + continue; + } + + if (child.type === 'close') { + q.push(append(q.pop(), queue, enclose)); + continue; + } + + if (child.value && child.type !== 'open') { + queue.push(append(queue.pop(), child.value)); + continue; + } + + if (child.nodes) { + walk(child, node, depth + 1); + } + } + + return queue; + }; + + return utils.flatten(walk(ast)); +}; + +module.exports = expand; diff --git a/vendor/braces/lib/parse.js b/vendor/braces/lib/parse.js new file mode 100644 index 000000000..70cdee2f8 --- /dev/null +++ b/vendor/braces/lib/parse.js @@ -0,0 +1,334 @@ +'use strict'; + +const stringify = require('./stringify'); +const utils = require('./utils'); + +/** + * Constants + */ + +const { + MAX_LENGTH, + CHAR_BACKSLASH, /* \ */ + CHAR_BACKTICK, /* ` */ + CHAR_COMMA, /* , */ + CHAR_DOT, /* . */ + CHAR_LEFT_PARENTHESES, /* ( */ + CHAR_RIGHT_PARENTHESES, /* ) */ + CHAR_LEFT_CURLY_BRACE, /* { */ + CHAR_RIGHT_CURLY_BRACE, /* } */ + CHAR_LEFT_SQUARE_BRACKET, /* [ */ + CHAR_RIGHT_SQUARE_BRACKET, /* ] */ + CHAR_DOUBLE_QUOTE, /* " */ + CHAR_SINGLE_QUOTE, /* ' */ + CHAR_NO_BREAK_SPACE, + CHAR_ZERO_WIDTH_NOBREAK_SPACE +} = require('./constants'); + +/** + * parse + */ + +const parse = (input, options = {}) => { + if (typeof input !== 'string') { + throw new TypeError('Expected a string'); + } + + const opts = options || {}; + const max = typeof opts.maxLength === 'number' ? Math.min(MAX_LENGTH, opts.maxLength) : MAX_LENGTH; + if (input.length > max) { + throw new SyntaxError(`Input length (${input.length}), exceeds max characters (${max})`); + } + + const ast = { type: 'root', input, nodes: [] }; + const stack = [ast]; + let block = ast; + let prev = ast; + let brackets = 0; + const length = input.length; + let index = 0; + let depth = 0; + let value; + + /** + * Helpers + */ + + const advance = () => input[index++]; + const push = node => { + if (node.type === 'text' && prev.type === 'dot') { + prev.type = 'text'; + } + + if (prev && prev.type === 'text' && node.type === 'text') { + prev.value += node.value; + return; + } + + block.nodes.push(node); + node.parent = block; + node.prev = prev; + prev = node; + return node; + }; + + push({ type: 'bos' }); + + while (index < length) { + block = stack[stack.length - 1]; + value = advance(); + + /** + * Invalid chars + */ + + if (value === CHAR_ZERO_WIDTH_NOBREAK_SPACE || value === CHAR_NO_BREAK_SPACE) { + continue; + } + + /** + * Escaped chars + */ + + if (value === CHAR_BACKSLASH) { + push({ type: 'text', value: (options.keepEscaping ? value : '') + advance() }); + continue; + } + + /** + * Right square bracket (literal): ']' + */ + + if (value === CHAR_RIGHT_SQUARE_BRACKET) { + push({ type: 'text', value: '\\' + value }); + continue; + } + + /** + * Left square bracket: '[' + */ + + if (value === CHAR_LEFT_SQUARE_BRACKET) { + brackets++; + + let next; + + while (index < length && (next = advance())) { + value += next; + + if (next === CHAR_LEFT_SQUARE_BRACKET) { + brackets++; + continue; + } + + if (next === CHAR_BACKSLASH) { + value += advance(); + continue; + } + + if (next === CHAR_RIGHT_SQUARE_BRACKET) { + brackets--; + + if (brackets === 0) { + break; + } + } + } + + push({ type: 'text', value }); + continue; + } + + /** + * Parentheses + */ + + if (value === CHAR_LEFT_PARENTHESES) { + utils.checkDepth(stack.length); + block = push({ type: 'paren', nodes: [] }); + stack.push(block); + push({ type: 'text', value }); + continue; + } + + if (value === CHAR_RIGHT_PARENTHESES) { + if (block.type !== 'paren') { + push({ type: 'text', value }); + continue; + } + block = stack.pop(); + push({ type: 'text', value }); + block = stack[stack.length - 1]; + continue; + } + + /** + * Quotes: '|"|` + */ + + if (value === CHAR_DOUBLE_QUOTE || value === CHAR_SINGLE_QUOTE || value === CHAR_BACKTICK) { + const open = value; + let next; + + if (options.keepQuotes !== true) { + value = ''; + } + + while (index < length && (next = advance())) { + if (next === CHAR_BACKSLASH) { + value += next + advance(); + continue; + } + + if (next === open) { + if (options.keepQuotes === true) value += next; + break; + } + + value += next; + } + + push({ type: 'text', value }); + continue; + } + + /** + * Left curly brace: '{' + */ + + if (value === CHAR_LEFT_CURLY_BRACE) { + utils.checkDepth(stack.length); + depth++; + + const dollar = prev.value && prev.value.slice(-1) === '$' || block.dollar === true; + const brace = { + type: 'brace', + open: true, + close: false, + dollar, + depth, + commas: 0, + ranges: 0, + nodes: [] + }; + + block = push(brace); + stack.push(block); + push({ type: 'open', value }); + continue; + } + + /** + * Right curly brace: '}' + */ + + if (value === CHAR_RIGHT_CURLY_BRACE) { + if (block.type !== 'brace') { + push({ type: 'text', value }); + continue; + } + + const type = 'close'; + block = stack.pop(); + block.close = true; + + push({ type, value }); + depth--; + + block = stack[stack.length - 1]; + continue; + } + + /** + * Comma: ',' + */ + + if (value === CHAR_COMMA && depth > 0) { + if (block.ranges > 0) { + block.ranges = 0; + const open = block.nodes.shift(); + block.nodes = [open, { type: 'text', value: stringify(block) }]; + } + + push({ type: 'comma', value }); + block.commas++; + continue; + } + + /** + * Dot: '.' + */ + + if (value === CHAR_DOT && depth > 0 && block.commas === 0) { + const siblings = block.nodes; + + if (depth === 0 || siblings.length === 0) { + push({ type: 'text', value }); + continue; + } + + if (prev.type === 'dot') { + block.range = []; + prev.value += value; + prev.type = 'range'; + + if (block.nodes.length !== 3 && block.nodes.length !== 5) { + block.invalid = true; + block.ranges = 0; + prev.type = 'text'; + continue; + } + + block.ranges++; + block.args = []; + continue; + } + + if (prev.type === 'range') { + siblings.pop(); + + const before = siblings[siblings.length - 1]; + before.value += prev.value + value; + prev = before; + block.ranges--; + continue; + } + + push({ type: 'dot', value }); + continue; + } + + /** + * Text + */ + + push({ type: 'text', value }); + } + + // Mark imbalanced braces and brackets as invalid + do { + block = stack.pop(); + + if (block.type !== 'root') { + block.nodes.forEach(node => { + if (!node.nodes) { + if (node.type === 'open') node.isOpen = true; + if (node.type === 'close') node.isClose = true; + if (!node.nodes) node.type = 'text'; + node.invalid = true; + } + }); + + // get the location of the block on parent.nodes (block's siblings) + const parent = stack[stack.length - 1]; + const index = parent.nodes.indexOf(block); + // replace the (invalid) block with it's nodes + parent.nodes.splice(index, 1, ...block.nodes); + } + } while (stack.length > 0); + + push({ type: 'eos' }); + return ast; +}; + +module.exports = parse; diff --git a/vendor/braces/lib/stringify.js b/vendor/braces/lib/stringify.js new file mode 100644 index 000000000..94ddda245 --- /dev/null +++ b/vendor/braces/lib/stringify.js @@ -0,0 +1,32 @@ +'use strict'; + +const utils = require('./utils'); + +module.exports = (ast, options = {}) => { + const stringify = (node, parent = {}, depth = 0) => { + utils.checkNode(node, depth); + const invalidBlock = options.escapeInvalid && utils.isInvalidBrace(parent); + const invalidNode = node.invalid === true && options.escapeInvalid === true; + let output = ''; + + if (node.value) { + if ((invalidBlock || invalidNode) && utils.isOpenOrClose(node)) { + return '\\' + node.value; + } + return node.value; + } + + if (node.value) { + return node.value; + } + + if (node.nodes) { + for (const child of node.nodes) { + output += stringify(child, {}, depth + 1); + } + } + return output; + }; + + return stringify(ast); +}; diff --git a/vendor/braces/lib/utils.js b/vendor/braces/lib/utils.js new file mode 100644 index 000000000..9f6353ad9 --- /dev/null +++ b/vendor/braces/lib/utils.js @@ -0,0 +1,136 @@ +'use strict'; + +// Bound recursive work independently of caller-supplied AST depth fields. +exports.checkDepth = depth => { + if (depth > 100) throw new SyntaxError('Pattern nesting exceeds maximum depth (100)'); +}; + +exports.checkNode = (node, depth) => { + if (node.nodes) exports.checkDepth(depth); + if (node.value !== undefined && typeof node.value !== 'string') { + throw new TypeError('AST values must be strings'); + } +}; + +exports.isInteger = num => { + if (typeof num === 'number') { + return Number.isInteger(num); + } + if (typeof num === 'string' && num.trim() !== '') { + return Number.isInteger(Number(num)); + } + return false; +}; + +/** + * Find a node of the given type + */ + +exports.find = (node, type) => node.nodes.find(node => node.type === type); + +/** + * Find a node of the given type + */ + +exports.exceedsLimit = (min, max, step = 1, limit) => { + if (limit === false) return false; + if (!exports.isInteger(min) || !exports.isInteger(max)) return false; + return ((Number(max) - Number(min)) / Number(step)) >= limit; +}; + +/** + * Escape the given node with '\\' before node.value + */ + +exports.escapeNode = (block, n = 0, type) => { + const node = block.nodes[n]; + if (!node) return; + + if ((type && node.type === type) || node.type === 'open' || node.type === 'close') { + if (node.escaped !== true) { + node.value = '\\' + node.value; + node.escaped = true; + } + } +}; + +/** + * Returns true if the given brace node should be enclosed in literal braces + */ + +exports.encloseBrace = node => { + if (node.type !== 'brace') return false; + if ((node.commas >> 0 + node.ranges >> 0) === 0) { + node.invalid = true; + return true; + } + return false; +}; + +/** + * Returns true if a brace node is invalid. + */ + +exports.isInvalidBrace = block => { + if (block.type !== 'brace') return false; + if (block.invalid === true || block.dollar) return true; + if ((block.commas >> 0 + block.ranges >> 0) === 0) { + block.invalid = true; + return true; + } + if (block.open !== true || block.close !== true) { + block.invalid = true; + return true; + } + return false; +}; + +/** + * Returns true if a node is an open or close node + */ + +exports.isOpenOrClose = node => { + if (node.type === 'open' || node.type === 'close') { + return true; + } + return node.open === true || node.close === true; +}; + +/** + * Reduce an array of text nodes. + */ + +exports.reduce = nodes => nodes.reduce((acc, node) => { + exports.checkNode(node, 0); + if (node.type === 'text') acc.push(node.value); + if (node.type === 'range') node.type = 'text'; + return acc; +}, []); + +/** + * Flatten an array + */ + +exports.flatten = (...args) => { + const result = []; + + const flat = (arr, depth = 0) => { + exports.checkDepth(depth); + for (let i = 0; i < arr.length; i++) { + const ele = arr[i]; + + if (Array.isArray(ele)) { + flat(ele, depth + 1); + continue; + } + + if (ele !== undefined) { + result.push(ele); + } + } + return result; + }; + + flat(args); + return result; +}; diff --git a/vendor/braces/package.json b/vendor/braces/package.json new file mode 100644 index 000000000..5a73b5e87 --- /dev/null +++ b/vendor/braces/package.json @@ -0,0 +1,18 @@ +{ + "name": "@diffex-cloud/braces", + "version": "3.0.3-diffex.1", + "private": true, + "description": "Reviewed local depth-guard patch of upstream braces 3.0.3", + "type": "commonjs", + "main": "index.js", + "license": "MIT", + "files": [ + "index.js", + "lib", + "LICENSE", + "README.md" + ], + "dependencies": { + "fill-range": "7.1.1" + } +} From f8a98ea758f08ff161c9e61fe899eaea8399ef91 Mon Sep 17 00:00:00 2001 From: Jeffrey Tseng Date: Fri, 2 Oct 2026 21:45:17 -0700 Subject: [PATCH 3/3] fix(coding-agent): apply portable brace override Apply the reviewed local braces patch through a root override so npm 10 and npm 11 resolve it consistently across workspace build dependencies. Preserve the private package identity and unchanged generated lockfile, and document the current development-only consumer scope. --- package.json | 4 +--- vendor/braces/README.md | 4 +++- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/package.json b/package.json index c7350cabc..36f6be2c3 100644 --- a/package.json +++ b/package.json @@ -68,9 +68,7 @@ }, "version": "0.0.3", "overrides": { - "shx": { - "braces": "$braces" - }, + "braces": "$braces", "nanoid": "3.3.18", "protobufjs": "7.6.5", "rimraf": "6.1.2", diff --git a/vendor/braces/README.md b/vendor/braces/README.md index 0244bbbd1..c027b6bce 100644 --- a/vendor/braces/README.md +++ b/vendor/braces/README.md @@ -2,7 +2,9 @@ This private package preserves the upstream `braces` 3.0.3 API and MIT license while bounding nesting to address [GHSA-vfj7-8cjw-p6xm](https://github.com/advisories/GHSA-vfj7-8cjw-p6xm). It is named `@diffex-cloud/braces` at version `3.0.3-diffex.1` because this is our reviewed patch, not an upstream fixed release. -Each consuming repository scopes its npm override to the affected dependency chain and tests the installed consumer rather than changing its functionality. +Each consuming repository wires npm overrides to the affected dependencies and tests the installed consumer rather than changing its functionality. +Diffex uses a root override because npm 10 does not reliably propagate an ancestor-scoped override through workspace dependencies. +Its current affected dependency chain is the development tool shx; the local patch is not included in shipped production locks. ## Provenance