diff --git a/AGENTS.md b/AGENTS.md index d9cdd70..2779381 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -130,7 +130,7 @@ docker run --rm -it -v "$PWD/secrets:/app/secrets" ghcr.io/iceean/codebuddy2api: - 路由页面的主动导航统一使用 `chunkLoadRecovery.push()` / `replace()`;恢复器必须在 `app.use(router)` 前安装。Vite 的 `vite:preloadError` 也会覆盖 chunk 下载成功后的模块求值异常,不能单凭该事件判断资源加载失败;恢复器只处理已确认的路由资源获取或预加载错误,其他路由错误必须保留原始 Promise 拒绝、写入控制台并显示通用提示。 - chunk 首次失败最多自动刷新一次,并在新文档按原 push/replace 语义续接目标;刷新仍在进行时,后发 chunk 失败只更新为最新恢复目标,不得启动第二次刷新。成功、重定向、守卫中止或更新导航会消费记录。刷新取消或重复失败时允许留在当前页;用户选择留下后,本页后续失败只能手动刷新。退出等临界操作用 `deferReload()` 延迟刷新。 - 修改 chunk 恢复流程后必须运行 `pnpm run e2e`,用 Chromium 验证跨版本资源失效、历史栈、`beforeunload` 取消和防循环行为。 -- 前端开发/构建要求 Node.js 24.11+。Vite 8/Rolldown 手动分包使用 `rollupOptions.output.codeSplitting.groups`,不要恢复对象形式 `manualChunks`;TypeScript 配置保留 `vite/client` 类型。 +- 前端开发/构建要求 Node.js 24.15+。Vite 8/Rolldown 手动分包使用 `rollupOptions.output.codeSplitting.groups`,不要恢复对象形式 `manualChunks`;TypeScript 配置保留 `vite/client` 类型。 ## Docker 与发布 diff --git a/Dockerfile b/Dockerfile index be00bb9..9e7daee 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,9 +1,9 @@ # syntax=docker/dockerfile:1 -ARG NODE_VERSION=24.11.1 +ARG NODE_VERSION=24.15.0 ARG PYTHON_VERSION=3.12 -# 使用满足 Babel 8 / Vite 8 最低版本要求的 Node 构建 Vue 管理台。 +# 使用满足前端工具链最低版本要求的 Node 构建 Vue 管理台。 FROM --platform=$BUILDPLATFORM node:${NODE_VERSION}-slim AS frontend-build WORKDIR /frontend diff --git a/README.md b/README.md index 67fe846..6a5bc65 100644 --- a/README.md +++ b/README.md @@ -550,7 +550,7 @@ python3 web.py ### 前端开发运行 -前端开发和构建要求 Node.js 24.11+ 与 pnpm 10.29+。 +前端开发和构建要求 Node.js 24.15+ 与 pnpm 10.29+。 前端开发服务器会把 `/auth`、`/api`、`/codebuddy`、`/openai`、`/anthropic`、`/health`、`/docs`、`/redoc` 和 `/openapi.json` 代理到本地后端 `127.0.0.1:8001`。 diff --git a/frontend/package.json b/frontend/package.json index 2b69b82..259df7f 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -5,7 +5,7 @@ "type": "module", "packageManager": "pnpm@10.29.2", "engines": { - "node": ">=24.11.0", + "node": ">=24.15.0", "pnpm": ">=10.29.2" }, "scripts": { @@ -36,7 +36,7 @@ "@vitejs/plugin-vue": "^6.0.8", "@vitest/coverage-v8": "^4.1.11", "@vue/test-utils": "^2.4.11", - "jsdom": "^29.1.1", + "jsdom": "^30.0.1", "oxlint": "^1.79.0", "prettier": "^3.9.6", "prettier-plugin-tailwindcss": "^0.8.1", diff --git a/frontend/pnpm-lock.yaml b/frontend/pnpm-lock.yaml index a76939a..0e48abd 100644 --- a/frontend/pnpm-lock.yaml +++ b/frontend/pnpm-lock.yaml @@ -46,8 +46,8 @@ importers: specifier: ^2.4.11 version: 2.4.11(@vue/compiler-dom@3.5.41)(@vue/server-renderer@3.5.41)(vue@3.5.41(typescript@6.0.3)) jsdom: - specifier: ^29.1.1 - version: 29.1.1 + specifier: ^30.0.1 + version: 30.0.1 oxlint: specifier: ^1.79.0 version: 1.79.0 @@ -68,27 +68,20 @@ importers: version: 8.2.2(@types/node@26.2.0)(jiti@2.7.0)(sass@1.101.0)(yaml@2.9.0) vitest: specifier: ^4.1.11 - version: 4.1.11(@types/node@26.2.0)(@vitest/coverage-v8@4.1.11)(jsdom@29.1.1)(vite@8.2.2(@types/node@26.2.0)(jiti@2.7.0)(sass@1.101.0)(yaml@2.9.0)) + version: 4.1.11(@types/node@26.2.0)(@vitest/coverage-v8@4.1.11)(jsdom@30.0.1)(vite@8.2.2(@types/node@26.2.0)(jiti@2.7.0)(sass@1.101.0)(yaml@2.9.0)) vue-tsc: specifier: ^3.3.10 version: 3.3.10(typescript@6.0.3) packages: - '@asamuzakjp/css-color@5.1.11': - resolution: {integrity: sha512-KVw6qIiCTUQhByfTd78h2yD1/00waTmm9uy/R7Ck/ctUyAPj+AEDLkQIdJW0T8+qGgj3j5bpNKK7Q3G+LedJWg==} - engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0} - - '@asamuzakjp/dom-selector@7.1.1': - resolution: {integrity: sha512-67RZDnYRc8H/8MLDgQCDE//zoqVFwajkepHZgmXrbwybzXOEwOWGPYGmALYl9J2DOLfFPPs6kKCqmbzV895hTQ==} - engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0} - - '@asamuzakjp/generational-cache@1.0.1': - resolution: {integrity: sha512-wajfB8KqzMCN2KGNFdLkReeHncd0AslUSrvHVvvYWuU8ghncRJoA50kT3zP9MVL0+9g4/67H+cdvBskj9THPzg==} - engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0} + '@asamuzakjp/css-color@6.0.7': + resolution: {integrity: sha512-vC/bk1Lz7Tn/EfU9/apOTBk80/8dyGyWMowPoV1tJ52muDGsDqt2HPT2klrFUiY60MQmQv9q8yIht15JnBgDGw==} + engines: {node: ^22.13.0 || >=24.0.0} - '@asamuzakjp/nwsapi@2.3.9': - resolution: {integrity: sha512-n8GuYSrI9bF7FFZ/SjhwevlHc8xaVlb/7HmHelnc/PZXBD2ZR49NnN9sMMuDdEGPeeRQ5d0hqlSlEpgCX3Wl0Q==} + '@asamuzakjp/dom-selector@8.3.2': + resolution: {integrity: sha512-93Z1N+BQNXysodoicpOIyNh2drHfz/CTf9nnT0FEx72GJcIiwgydD7tGAr78j41LsYn3hlRn+LdGPuBLn1Bl8Q==} + engines: {node: ^22.13.0 || >=24.0.0} '@babel/generator@8.0.0': resolution: {integrity: sha512-NT9NrVwJsbSV6Y2FSstWa71EETOnzrjkL5/wX3D2mYHtKM+qvqB1DvR4D0Setb/gDBsHzRICifwEWMO8CnTF6g==} @@ -145,19 +138,19 @@ packages: resolution: {integrity: sha512-ctxtJ/eA+t+6q2++vj5j7FYX3nRu311q1wfYH3xjlLOsczhlhxAg2FWNUXhpGvAw3BWo1xBcvOV6/YLc2r5FJw==} hasBin: true - '@csstools/color-helpers@6.0.2': - resolution: {integrity: sha512-LMGQLS9EuADloEFkcTBR3BwV/CGHV7zyDxVRtVDTwdI2Ca4it0CCVTT9wCkxSgokjE5Ho41hEPgb8OEUwoXr6Q==} + '@csstools/color-helpers@6.1.1': + resolution: {integrity: sha512-gLNsunvwf3mCi5u5o46/Z/JcJMnhbHSaZ69rkgPzNM3J4s8hWwpPUQB6/tt0EDFyCiWzxANlx+2LJwpYj4zS1w==} engines: {node: '>=20.19.0'} - '@csstools/css-calc@3.2.1': - resolution: {integrity: sha512-DtdHlgXh5ZkA43cwBcAm+huzgJiwx3ZTWVjBs94kwz2xKqSimDA3lBgCjphYgwgVUMWatSM0pDd8TILB1yrVVg==} + '@csstools/css-calc@3.3.0': + resolution: {integrity: sha512-c5ihYsPkdG6JCkU2zTMm4+k6r7RXuGxtWYhu5DHMIiF1FHzrfmHL5so11AoFpUv/tu61xfcmT4AmKoFfMPoqdQ==} engines: {node: '>=20.19.0'} peerDependencies: '@csstools/css-parser-algorithms': ^4.0.0 '@csstools/css-tokenizer': ^4.0.0 - '@csstools/css-color-parser@4.1.8': - resolution: {integrity: sha512-3chWb7PRLijpJpPIKkDxdu6IBeO5MrFACND57On0j8OPpc0wZibcGc3xAHrSEbOx/KDRyMHoIxGn0w1PhXMYHw==} + '@csstools/css-color-parser@4.2.0': + resolution: {integrity: sha512-5+5LEmFuY1AjXdYhmgjTJogtQnP1evJ1zrBZGUNZ0thkpwnnmKxcHdAMn/OtFjAb25zA+jKDVYVRl+5G7rjv1A==} engines: {node: '>=20.19.0'} peerDependencies: '@csstools/css-parser-algorithms': ^4.0.0 @@ -169,8 +162,8 @@ packages: peerDependencies: '@csstools/css-tokenizer': ^4.0.0 - '@csstools/css-syntax-patches-for-csstree@1.1.5': - resolution: {integrity: sha512-oNjBvzLq2GPZtJphCjLqXow/cHySHSgtxvKZb7OqSZ/xHgw6NWNhfad+6AB9cLeVm6eA9d/qMll3JdEHjy6M+A==} + '@csstools/css-syntax-patches-for-csstree@1.1.8': + resolution: {integrity: sha512-CpMLjAvwQg3BL5S0IeqsZNMH7EQrEWi0kLKOC13ZBF0ZwERiLWlibNPJr8G1kdU3Ms/r2KiNrF81pUh2HwAHdg==} peerDependencies: css-tree: ^3.2.1 peerDependenciesMeta: @@ -1028,11 +1021,11 @@ packages: js-tokens@10.0.0: resolution: {integrity: sha512-lM/UBzQmfJRo9ABXbPWemivdCW8V2G8FHaHdypQaIy523snUjog0W71ayWXTjiR+ixeMyVHN2XcpnTd/liPg/Q==} - jsdom@29.1.1: - resolution: {integrity: sha512-ECi4Fi2f7BdJtUKTflYRTiaMxIB0O6zfR1fX0GXpUrf6flp8QIYn1UT20YQqdSOfk2dfkCwS8LAFoJDEppNK5Q==} - engines: {node: ^20.19.0 || ^22.13.0 || >=24.0.0} + jsdom@30.0.1: + resolution: {integrity: sha512-52v7mUVUfNQVYYqE1lcdaymWL0njO7lTLUog6ZvW2U5KsbiLk/GnZlVJ+qx0xfNJZ6Gn+KSpPNE52vurbxZwrA==} + engines: {node: ^22.22.2 || ^24.15.0 || >=26.0.0} peerDependencies: - canvas: ^3.0.0 + canvas: ^3.2.3 peerDependenciesMeta: canvas: optional: true @@ -1202,8 +1195,8 @@ packages: lru-cache@10.4.3: resolution: {integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==} - lru-cache@11.5.1: - resolution: {integrity: sha512-RPimw/7aMdv2oqRrxKwvZXcPfwBrn/JZ2xYcY9Hus/6LaS3VOAKVWKWgNLCFSiOm1ESXinjsDlidVU7JlnCN2A==} + lru-cache@11.5.2: + resolution: {integrity: sha512-4pfM1Ff0x50o0tQwb5ucw/RzNyD0/YJME6IVcStalZuMWxdt3sR3huStTtxz4PUmvZfRguvDejasvQ2kifR11g==} engines: {node: 20 || >=22} magic-string-ast@1.0.3: @@ -1503,15 +1496,15 @@ packages: resolution: {integrity: sha512-yau8yJdTt989Mm0Bd/236QnzEiPf2xLLTqUZRUJOo/3CB078LSwzei343DgtJVmfJKJE3TMINY1u42SQsP6mXw==} engines: {node: '>=14.0.0'} - tldts-core@7.4.4: - resolution: {integrity: sha512-vwVLJVvvpslm7vqAH7+XNj/neA/Ynq7DT2EEcMuwc5YzN5XaMyRAqxwU+uX3azZ1FQtB2gvrvnLnAEkvYlVdfg==} + tldts-core@7.4.10: + resolution: {integrity: sha512-KnQjp53ZekKgm/r3l+u8kJGGzYgrWdP8+Mql7a4vijh2WE0IrZWspQj/TpTxDho/YxO+AnOZnIjQcCD+q6iJsw==} - tldts@7.4.4: - resolution: {integrity: sha512-kFXFK7O4WPextIUAOk8qtnw9dxR9UIXP9CjuH1cTBVBZMDeQcUPgr/IazGiw1B0Yiw5L75gHLWeW4iD793r90g==} + tldts@7.4.10: + resolution: {integrity: sha512-GgouD1B+sWwvkaEq8vXC15DjQitxbvs12oIXELpconwm+Tg3zfcEv4jgzq3vtKverDXsg3VI8aRgNL2Nra0Iog==} hasBin: true - tough-cookie@6.0.1: - resolution: {integrity: sha512-LktZQb3IeoUWB9lqR5EWTHgW/VTITCXg4D21M+lvybRVdylLrRMnqaIONLVb5mav8vM19m44HIcGq4qASeu2Qw==} + tough-cookie@6.0.2: + resolution: {integrity: sha512-exgYmnmL/sJpR3upZfXG5PoatXQii55xAiXGXzY+sROLZ/Y+SLcp9PgJNI9Vz37HpQ74WvDcLT8eqm+kV3FzrA==} engines: {node: '>=16'} tr46@6.0.0: @@ -1529,9 +1522,9 @@ packages: undici-types@8.3.0: resolution: {integrity: sha512-j375ScV60dom+YkPFIfTLcOiPxkN/buHz5GobjLhixFuANaNs3C9l4GmrWqejgXWJ7BbJcFYpTEUkS1Ge8bpZQ==} - undici@7.28.0: - resolution: {integrity: sha512-cRZYrTDwWznlnRiPjggAGxZXanty6M8RV1ff8Wm4LWXBp7/IG8v5DnOm74DtUBp9OONpK75YlPnIjQqX0dBDtA==} - engines: {node: '>=20.18.1'} + undici@8.10.0: + resolution: {integrity: sha512-HvltHd7avK13QIw/oLe4qoOLyoVSoafqJ2jYOrtMRBkbYT31eiBQ8O0ehRKZiEZCMEyLFQNIADpgCWC5fALvYQ==} + engines: {node: '>=22.19.0'} unplugin-utils@0.3.2: resolution: {integrity: sha512-xVToRh2CTmLk2HnEG7ac4rl1MJTT3RFkpS8B++/SnB0kXvuaavD+n3m/vrzyWQOdJNSZQACnbz01pnppbwV5BA==} @@ -1722,6 +1715,10 @@ packages: resolution: {integrity: sha512-1to4zXBxmXHV3IiSSEInrreIlu02vUOvrhxJJH5vcxYTBDAx51cqZiKdyTxlecdKNSjj8EcxGBxNf6Vg+945gw==} engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0} + whatwg-url@17.1.0: + resolution: {integrity: sha512-3GeworPmc2ZfEEHP7lEbUfBX/L75wdEsi0rLNhXcXxnoN5jyq0SL5gCy06SGW2cyTIZdTvWIDQNQoza++vKeaw==} + engines: {node: ^22.14.0 || >=24.0.0} + which@2.0.2: resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} engines: {node: '>= 8'} @@ -1754,25 +1751,20 @@ packages: snapshots: - '@asamuzakjp/css-color@5.1.11': + '@asamuzakjp/css-color@6.0.7': dependencies: - '@asamuzakjp/generational-cache': 1.0.1 - '@csstools/css-calc': 3.2.1(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0))(@csstools/css-tokenizer@4.0.0) - '@csstools/css-color-parser': 4.1.8(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0))(@csstools/css-tokenizer@4.0.0) + '@csstools/css-calc': 3.3.0(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0))(@csstools/css-tokenizer@4.0.0) + '@csstools/css-color-parser': 4.2.0(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0))(@csstools/css-tokenizer@4.0.0) '@csstools/css-parser-algorithms': 4.0.0(@csstools/css-tokenizer@4.0.0) '@csstools/css-tokenizer': 4.0.0 + lru-cache: 11.5.2 - '@asamuzakjp/dom-selector@7.1.1': + '@asamuzakjp/dom-selector@8.3.2': dependencies: - '@asamuzakjp/generational-cache': 1.0.1 - '@asamuzakjp/nwsapi': 2.3.9 bidi-js: 1.0.3 css-tree: 3.2.1 is-potential-custom-element-name: 1.0.1 - - '@asamuzakjp/generational-cache@1.0.1': {} - - '@asamuzakjp/nwsapi@2.3.9': {} + lru-cache: 11.5.2 '@babel/generator@8.0.0': dependencies: @@ -1824,17 +1816,17 @@ snapshots: dependencies: css-tree: 3.2.1 - '@csstools/color-helpers@6.0.2': {} + '@csstools/color-helpers@6.1.1': {} - '@csstools/css-calc@3.2.1(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0))(@csstools/css-tokenizer@4.0.0)': + '@csstools/css-calc@3.3.0(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0))(@csstools/css-tokenizer@4.0.0)': dependencies: '@csstools/css-parser-algorithms': 4.0.0(@csstools/css-tokenizer@4.0.0) '@csstools/css-tokenizer': 4.0.0 - '@csstools/css-color-parser@4.1.8(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0))(@csstools/css-tokenizer@4.0.0)': + '@csstools/css-color-parser@4.2.0(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0))(@csstools/css-tokenizer@4.0.0)': dependencies: - '@csstools/color-helpers': 6.0.2 - '@csstools/css-calc': 3.2.1(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0))(@csstools/css-tokenizer@4.0.0) + '@csstools/color-helpers': 6.1.1 + '@csstools/css-calc': 3.3.0(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0))(@csstools/css-tokenizer@4.0.0) '@csstools/css-parser-algorithms': 4.0.0(@csstools/css-tokenizer@4.0.0) '@csstools/css-tokenizer': 4.0.0 @@ -1842,7 +1834,7 @@ snapshots: dependencies: '@csstools/css-tokenizer': 4.0.0 - '@csstools/css-syntax-patches-for-csstree@1.1.5(css-tree@3.2.1)': + '@csstools/css-syntax-patches-for-csstree@1.1.8(css-tree@3.2.1)': optionalDependencies: css-tree: 3.2.1 @@ -2173,7 +2165,7 @@ snapshots: obug: 2.1.4 std-env: 4.2.0 tinyrainbow: 3.1.1 - vitest: 4.1.11(@types/node@26.2.0)(@vitest/coverage-v8@4.1.11)(jsdom@29.1.1)(vite@8.2.2(@types/node@26.2.0)(jiti@2.7.0)(sass@1.101.0)(yaml@2.9.0)) + vitest: 4.1.11(@types/node@26.2.0)(@vitest/coverage-v8@4.1.11)(jsdom@30.0.1)(vite@8.2.2(@types/node@26.2.0)(jiti@2.7.0)(sass@1.101.0)(yaml@2.9.0)) '@vitest/expect@4.1.11': dependencies: @@ -2546,28 +2538,28 @@ snapshots: js-tokens@10.0.0: {} - jsdom@29.1.1: + jsdom@30.0.1: dependencies: - '@asamuzakjp/css-color': 5.1.11 - '@asamuzakjp/dom-selector': 7.1.1 + '@asamuzakjp/css-color': 6.0.7 + '@asamuzakjp/dom-selector': 8.3.2 '@bramus/specificity': 2.4.2 - '@csstools/css-syntax-patches-for-csstree': 1.1.5(css-tree@3.2.1) + '@csstools/css-syntax-patches-for-csstree': 1.1.8(css-tree@3.2.1) '@exodus/bytes': 1.15.1 css-tree: 3.2.1 data-urls: 7.0.0 decimal.js: 10.6.0 html-encoding-sniffer: 6.0.0 is-potential-custom-element-name: 1.0.1 - lru-cache: 11.5.1 + lru-cache: 11.5.2 parse5: 8.0.1 saxes: 6.0.0 symbol-tree: 3.2.4 - tough-cookie: 6.0.1 - undici: 7.28.0 + tough-cookie: 6.0.2 + undici: 8.10.0 w3c-xmlserializer: 5.0.0 webidl-conversions: 8.0.1 whatwg-mimetype: 5.0.0 - whatwg-url: 16.0.1 + whatwg-url: 17.1.0 xml-name-validator: 5.0.0 transitivePeerDependencies: - '@noble/hashes' @@ -2682,7 +2674,7 @@ snapshots: lru-cache@10.4.3: {} - lru-cache@11.5.1: {} + lru-cache@11.5.2: {} magic-string-ast@1.0.3: dependencies: @@ -2924,15 +2916,15 @@ snapshots: tinyrainbow@3.1.1: {} - tldts-core@7.4.4: {} + tldts-core@7.4.10: {} - tldts@7.4.4: + tldts@7.4.10: dependencies: - tldts-core: 7.4.4 + tldts-core: 7.4.10 - tough-cookie@6.0.1: + tough-cookie@6.0.2: dependencies: - tldts: 7.4.4 + tldts: 7.4.10 tr46@6.0.0: dependencies: @@ -2944,7 +2936,7 @@ snapshots: undici-types@8.3.0: {} - undici@7.28.0: {} + undici@8.10.0: {} unplugin-utils@0.3.2: dependencies: @@ -2974,7 +2966,7 @@ snapshots: sass: 1.101.0 yaml: 2.9.0 - vitest@4.1.11(@types/node@26.2.0)(@vitest/coverage-v8@4.1.11)(jsdom@29.1.1)(vite@8.2.2(@types/node@26.2.0)(jiti@2.7.0)(sass@1.101.0)(yaml@2.9.0)): + vitest@4.1.11(@types/node@26.2.0)(@vitest/coverage-v8@4.1.11)(jsdom@30.0.1)(vite@8.2.2(@types/node@26.2.0)(jiti@2.7.0)(sass@1.101.0)(yaml@2.9.0)): dependencies: '@vitest/expect': 4.1.11 '@vitest/mocker': 4.1.11(vite@8.2.2(@types/node@26.2.0)(jiti@2.7.0)(sass@1.101.0)(yaml@2.9.0)) @@ -2999,7 +2991,7 @@ snapshots: optionalDependencies: '@types/node': 26.2.0 '@vitest/coverage-v8': 4.1.11(vitest@4.1.11) - jsdom: 29.1.1 + jsdom: 30.0.1 transitivePeerDependencies: - msw @@ -3080,6 +3072,14 @@ snapshots: transitivePeerDependencies: - '@noble/hashes' + whatwg-url@17.1.0: + dependencies: + '@exodus/bytes': 1.15.1 + tr46: 6.0.0 + webidl-conversions: 8.0.1 + transitivePeerDependencies: + - '@noble/hashes' + which@2.0.2: dependencies: isexe: 2.0.0 diff --git a/frontend/src/__tests__/apiDocsView.test.ts b/frontend/src/__tests__/apiDocsView.test.ts index 0e5140b..bec6317 100644 --- a/frontend/src/__tests__/apiDocsView.test.ts +++ b/frontend/src/__tests__/apiDocsView.test.ts @@ -31,7 +31,7 @@ describe('ApiDocsView', () => { expect(wrapper.get('header').text()).toBe('Swagger API 文档'); expect(wrapper.find('header a').exists()).toBe(false); - const link = wrapper.get('section > div > a'); + const link = wrapper.get(':scope > div > a'); expect(link.text()).toContain('打开 Swagger 文档'); expect(link.attributes('href')).toBe('/docs'); expect(link.attributes('target')).toBe('_blank'); diff --git a/tests/test_server_startup.py b/tests/test_server_startup.py index c765a60..985ca23 100644 --- a/tests/test_server_startup.py +++ b/tests/test_server_startup.py @@ -112,6 +112,7 @@ def test_dockerfile_uses_recommended_runtime_and_hash_command(self): dockerfile = (self.repository_root / "Dockerfile").read_text(encoding="utf-8") self.assertIn("ARG PYTHON_VERSION=3.12", dockerfile) + self.assertIn("ARG NODE_VERSION=24.15.0", dockerfile) self.assertIn( "FROM --platform=$BUILDPLATFORM node:${NODE_VERSION}-slim AS frontend-build", dockerfile, @@ -153,6 +154,15 @@ def test_frontend_package_uses_application_version(self): self.assertEqual(package["version"], web.app.version) + def test_frontend_package_requires_supported_node_version(self): + package = json.loads( + (self.repository_root / "frontend" / "package.json").read_text( + encoding="utf-8" + ) + ) + + self.assertEqual(package["engines"]["node"], ">=24.15.0") + def test_readme_documents_releases_frontend_toolchain_and_openai_dependency(self): readme = (self.repository_root / "README.md").read_text(encoding="utf-8") @@ -160,7 +170,7 @@ def test_readme_documents_releases_frontend_toolchain_and_openai_dependency(self "[releases](https://github.com/IceeAn/codebuddy2api/releases)", readme, ) - self.assertIn("Node.js 24.11+", readme) + self.assertIn("Node.js 24.15+", readme) self.assertIn("pnpm 10.29+", readme) self.assertIn("python3 -m pip install openai", readme) self.assertIn("#### 使用更新脚本更新", readme)