build(workspace): [ENG-01] pin reproducible Node and npm toolchain

This commit is contained in:
Harvey Zhao committed 2026-09-10 18:52:58 +08:00
1 parent 3c759f14c2
commit 3781e6bda1
13 files changed
+17883 -28

No files matched your search

+2 -1
View File
@@ -2,7 +2,8 @@
.vscode
.DS_Store
node_modules
package-lock.json
**/package-lock.json
!/package-lock.json
lerna-debug.log
yarn.lock
refactor/.cache/
+1
View File
@@ -0,0 +1 @@
24.21.0
+17318
View File
File diff suppressed because it is too large. Load diff
+22 -20
View File
@@ -22,7 +22,7 @@
"player"
],
"engines": {
"node": ">= 20.0.0"
"node": "^20.19.0 || >=22.12.0"
},
"scripts": {
"bootstrap": "npx lerna link",
@@ -39,25 +39,27 @@
"dev": "npx cross-env NODE_ENV=development node ./scripts/dev.js",
"build": "npx cross-env NODE_ENV=production node ./scripts/build.js",
"lint": "npx eslint packages/*/{src,types,package.json} scripts/*.js test/* docs/assets/ts/* --fix",
"build:all": "npm run build all && npm run build:i18n && npm run build:ts && npm run build:docs && npm run lint"
"build:all": "npm run build all && npm run build:i18n && npm run build:ts && npm run build:docs && npm run lint",
"check:toolchain": "node scripts/check-toolchain.mjs"
},
"browserslist": "last 1 Chrome version",
"dependencies": {
"@antfu/eslint-config": "^5.1.0",
"cpy": "^13.2.1",
"cross-env": "^10.0.0",
"cross-spawn": "^7.0.6",
"dotenv": "^17.2.1",
"esbuild": "^0.27.3",
"eslint": "^9.32.0",
"eslint-plugin-format": "^2.0.1",
"glob": "^13.0.6",
"lerna": "^8.2.3",
"less": "^4.5.1",
"prompts": "^2.4.2",
"servor": "^4.0.2",
"svgo": "^4.0.1",
"terser": "^5.46.0",
"vite": "^7.3.1"
}
"devDependencies": {
"@antfu/eslint-config": "5.4.1",
"cpy": "13.2.3",
"cross-env": "10.1.0",
"cross-spawn": "7.0.6",
"dotenv": "17.2.4",
"esbuild": "0.27.7",
"eslint": "9.39.2",
"eslint-plugin-format": "2.0.1",
"glob": "13.0.6",
"lerna": "8.2.4",
"less": "4.5.1",
"prompts": "2.4.2",
"servor": "4.0.2",
"svgo": "4.1.0",
"terser": "5.51.2",
"vite": "7.3.6"
},
"packageManager": "npm@11.19.0"
}
+1
View File
@@ -26,6 +26,7 @@
| [docs 页面与编辑器测试](docs-browser-testing.md) | 复用已有 HTML、加载版本、隔离状态和补强文档 smoke |
| [多轮复盘与 npm 准入](release-reviews.md) | Chrome 验证分工、三轮全局复盘、问题闭环和候选发布门槛 |
| [工具链与发布](toolchain-release.md) | TypeScript、Bun、构建、版本管理和发布回退 |
| [已实现的开发环境](toolchain-setup.md) | Node/npm 固定版本、锁文件、安装命令和实际验证范围 |
| [全包大版本策略](version-policy.md) | 每包分别升级一个 major 的目标清单、兼容要求和版本落地步骤 |
| [GitHub CI/CD](github-ci-cd.md) | PR/兼容矩阵、构建报告、Pages、npm 发布及远端准入验证 |
| [AI 协作流程](ai-workflow.md) | AI 接续工作、任务边界、验证、记录和交接模板 |
@@ -0,0 +1,423 @@
{
"task": "ENG-01",
"date": "2026-09-10",
"sourceCommit": "3c759f14",
"node": "24.21.0",
"npm": "11.19.0",
"platform": "win32-x64",
"nodeArchive": {
"url": "https://nodejs.org/dist/v24.21.0/node-v24.21.0-win-x64.zip",
"sha256": "158f7685b44de51f6c0df1d153526cbcd3e1bc739a8dfc607721cef75de9e541",
"bytes": 37618919
},
"rootManifestSha256": "47ea08efc81a787a85b9e764261d9c3f7a4605721b718ef4245a905f3cbf874e",
"lockSha256": "c7688fc76cb0d4e0153df4e88c9c490a6184f9af6ed8adbc86478218b45fb55a",
"lockfileVersion": 3,
"lockEntries": 1262,
"existingResolutionVersionChanges": [],
"cleanInstall": {
"packagesInstalled": 1141,
"lockUnchanged": true,
"command": "npm ci --no-audit --no-fund",
"lifecycleScriptsEnabled": true
},
"tests": {
"isolatedOriginalNodeTests": 19,
"workspaceOriginalAndBaselineNodeTests": 21,
"manifestMismatchRejected": true
},
"libraryBuild": {
"command": "npm run build -- all",
"packages": 21,
"artifacts": [
{
"package": "artplayer",
"file": "artplayer.js",
"bytes": 134939,
"sha256": "9ad044a601dafc24f449b690403fb1c343b40e99ffb31043272189fc3c1e7bfa"
},
{
"package": "artplayer",
"file": "artplayer.legacy.js",
"bytes": 136659,
"sha256": "71eebcca3192000c58e20f2e3cb76e86c05e33b5a1fab0add20436a5933a3e87"
},
{
"package": "artplayer",
"file": "artplayer.mjs",
"bytes": 210198,
"sha256": "ac72f41624383ba853474161affb72b5887644449bf7cb18f6d18edeb2f6f997"
},
{
"package": "artplayer-plugin-ads",
"file": "artplayer-plugin-ads.js",
"bytes": 5620,
"sha256": "ceb2d8a23a6735c161b31a4a427d8a757679aaf8a5a106ef40a6f047061f1df8"
},
{
"package": "artplayer-plugin-ads",
"file": "artplayer-plugin-ads.legacy.js",
"bytes": 5951,
"sha256": "1e10c3a6b51de18e54cd02dd342ab4010fc466de6257659cf1d2e087642aa9a3"
},
{
"package": "artplayer-plugin-ads",
"file": "artplayer-plugin-ads.mjs",
"bytes": 9326,
"sha256": "0919678423424047b28d9d803835d9ebc98f4477e04e58d497e8ed8c48b95008"
},
{
"package": "artplayer-plugin-ambilight",
"file": "artplayer-plugin-ambilight.js",
"bytes": 1844,
"sha256": "8f32290c65a13b0a3026dee0045fef4125a9c9ac788ecb1675aef05f79172693"
},
{
"package": "artplayer-plugin-ambilight",
"file": "artplayer-plugin-ambilight.legacy.js",
"bytes": 1844,
"sha256": "8f32290c65a13b0a3026dee0045fef4125a9c9ac788ecb1675aef05f79172693"
},
{
"package": "artplayer-plugin-ambilight",
"file": "artplayer-plugin-ambilight.mjs",
"bytes": 3329,
"sha256": "77486db6d24f50420c952de5b37d226e404089730c7c1c6be226c836f4e85f9c"
},
{
"package": "artplayer-plugin-asr",
"file": "artplayer-plugin-asr.js",
"bytes": 5064,
"sha256": "7f975b131a9ea207f88a157aafec778bc4906230500db9b30f5bbfbf327b251d"
},
{
"package": "artplayer-plugin-asr",
"file": "artplayer-plugin-asr.legacy.js",
"bytes": 5468,
"sha256": "8b9f07ce97a8ce2e4f29e41e79257be530fd7a76558369d34c3d7497ea606c33"
},
{
"package": "artplayer-plugin-asr",
"file": "artplayer-plugin-asr.mjs",
"bytes": 9057,
"sha256": "f1c4274541e86544b65936ff470413cfc7001999ebc193969f95c123be48cd61"
},
{
"package": "artplayer-plugin-audio-track",
"file": "artplayer-plugin-audio-track.js",
"bytes": 1471,
"sha256": "473f39f1d750f0722cca7e857c12c3c978ebe3c3b2352e325f1248318e508683"
},
{
"package": "artplayer-plugin-audio-track",
"file": "artplayer-plugin-audio-track.legacy.js",
"bytes": 1497,
"sha256": "d8dc74bce76112d7430c98e3165605e32fde5d3c603be4b496eac58f574576cb"
},
{
"package": "artplayer-plugin-audio-track",
"file": "artplayer-plugin-audio-track.mjs",
"bytes": 2238,
"sha256": "4ac599bc5a1a6ecb0cb1942d4269528bfb2cd9d047f988de61fe671a77ad14cd"
},
{
"package": "artplayer-plugin-auto-thumbnail",
"file": "artplayer-plugin-auto-thumbnail.js",
"bytes": 1299,
"sha256": "ce1f1472bf02b836dd85b92eadf2f00786c02cde11a20ac2801136a0f675d12a"
},
{
"package": "artplayer-plugin-auto-thumbnail",
"file": "artplayer-plugin-auto-thumbnail.legacy.js",
"bytes": 1949,
"sha256": "3561e51e0a5f294b56641bf0884a24a4a9e326582d2e99416a04f9526c7d0cc0"
},
{
"package": "artplayer-plugin-auto-thumbnail",
"file": "artplayer-plugin-auto-thumbnail.mjs",
"bytes": 1831,
"sha256": "99da4748422bad54663c669d78963589a64c7cb02102e3544439fec7570a7f8b"
},
{
"package": "artplayer-plugin-chapter",
"file": "artplayer-plugin-chapter.js",
"bytes": 4973,
"sha256": "c2aaee11bf1db765433b01d9f8dd3978e41fa4d39655db00ebd03fc0be3e35e0"
},
{
"package": "artplayer-plugin-chapter",
"file": "artplayer-plugin-chapter.legacy.js",
"bytes": 4973,
"sha256": "c2aaee11bf1db765433b01d9f8dd3978e41fa4d39655db00ebd03fc0be3e35e0"
},
{
"package": "artplayer-plugin-chapter",
"file": "artplayer-plugin-chapter.mjs",
"bytes": 7721,
"sha256": "61342a069b84e0731d44a2464d0dfe637d1514d0037c740371fc866c516d2209"
},
{
"package": "artplayer-plugin-chromecast",
"file": "artplayer-plugin-chromecast.js",
"bytes": 3934,
"sha256": "4959661fc7f22eee3d32363bb0392a486c44499ec4a9c608ccfea55de29aaac6"
},
{
"package": "artplayer-plugin-chromecast",
"file": "artplayer-plugin-chromecast.legacy.js",
"bytes": 4472,
"sha256": "e2ba7aebec099884bb806f3caf77f9ff739ff9f236aefdfd0a4e69a8295c9d01"
},
{
"package": "artplayer-plugin-chromecast",
"file": "artplayer-plugin-chromecast.mjs",
"bytes": 6533,
"sha256": "b6d4e445a78f00fae53a35d239e62cc4a1448086d76058d69d8f9634a5754768"
},
{
"package": "artplayer-plugin-danmuku",
"file": "artplayer-plugin-danmuku.js",
"bytes": 52390,
"sha256": "7c8749288711ef97e80b6f9f00981170aa73f62a8ae25d6d663749a4aef62a8f"
},
{
"package": "artplayer-plugin-danmuku",
"file": "artplayer-plugin-danmuku.legacy.js",
"bytes": 53263,
"sha256": "62db96685c48b8573f0480cead6ac934b1d0382b9fdd0046d17d15d2549c56dc"
},
{
"package": "artplayer-plugin-danmuku",
"file": "artplayer-plugin-danmuku.mjs",
"bytes": 75696,
"sha256": "083d7de2f9a0314955dc83cdeedbc46c36728f7c9a0943ada8c3229edf9264ce"
},
{
"package": "artplayer-plugin-danmuku-mask",
"file": "artplayer-plugin-danmuku-mask.js",
"bytes": 904243,
"sha256": "07cebbfbf77f8ec4b2df6a77d7d7300345b86f2993e220ff14e1aae530e4fb31"
},
{
"package": "artplayer-plugin-danmuku-mask",
"file": "artplayer-plugin-danmuku-mask.legacy.js",
"bytes": 907166,
"sha256": "a678a3c0f6d3920bee3b66af9943b3612935028bff61c96677b8eaf8ef7cc8f0"
},
{
"package": "artplayer-plugin-danmuku-mask",
"file": "artplayer-plugin-danmuku-mask.mjs",
"bytes": 1728250,
"sha256": "48f7a449dc9555ab4060a578902b5431701f81b2f093a7cb0526042a8c417400"
},
{
"package": "artplayer-plugin-dash-control",
"file": "artplayer-plugin-dash-control.js",
"bytes": 3450,
"sha256": "248aa1162ffb2480965f8e12d766ba6b7d2abfc2d80e65e8a6e8db6bdfa750c5"
},
{
"package": "artplayer-plugin-dash-control",
"file": "artplayer-plugin-dash-control.legacy.js",
"bytes": 3450,
"sha256": "248aa1162ffb2480965f8e12d766ba6b7d2abfc2d80e65e8a6e8db6bdfa750c5"
},
{
"package": "artplayer-plugin-dash-control",
"file": "artplayer-plugin-dash-control.mjs",
"bytes": 5905,
"sha256": "2cc039698627a6baaa5da1cc50cc5db5230ae5d31152b1217dda62e38c67aa3e"
},
{
"package": "artplayer-plugin-document-pip",
"file": "artplayer-plugin-document-pip.js",
"bytes": 4624,
"sha256": "261d4ae84579c569ade1b1e7e91d51e3bd00c6efbea8c51a48b8283e0f4f3496"
},
{
"package": "artplayer-plugin-document-pip",
"file": "artplayer-plugin-document-pip.legacy.js",
"bytes": 5356,
"sha256": "8e36b658196dece391add21c249b735f3abfe4082fc968d3dbbbb1ae58a77b31"
},
{
"package": "artplayer-plugin-document-pip",
"file": "artplayer-plugin-document-pip.mjs",
"bytes": 6912,
"sha256": "22b432b5fc958f6f838b83fdfcc7e5ab7144137111b1f8cf081eb2e21afd8382"
},
{
"package": "artplayer-plugin-hls-control",
"file": "artplayer-plugin-hls-control.js",
"bytes": 3156,
"sha256": "7a6ce18a0b16f61f6149e0ea77efbb6e0503f997d39afe84271b59e366759e6d"
},
{
"package": "artplayer-plugin-hls-control",
"file": "artplayer-plugin-hls-control.legacy.js",
"bytes": 3182,
"sha256": "893a3de27f9ed02b4b61f03732aec03bfcaf50d02c9beb15cc8a5767ef9121a0"
},
{
"package": "artplayer-plugin-hls-control",
"file": "artplayer-plugin-hls-control.mjs",
"bytes": 5015,
"sha256": "85c4de4940e031d835b4de3ccf68af449d10aec4f630c89ecaf62f5503348931"
},
{
"package": "artplayer-plugin-jassub",
"file": "artplayer-plugin-jassub.js",
"bytes": 16231,
"sha256": "271d5284e5246fbd04575526510b3e381e5e60d414c030acecce92fcf2e9b10a"
},
{
"package": "artplayer-plugin-jassub",
"file": "artplayer-plugin-jassub.legacy.js",
"bytes": 16947,
"sha256": "0726c96bf0df2aab2662ac8973bb7676a0ca7f8e4cb806aa44cb3ec9de296e64"
},
{
"package": "artplayer-plugin-jassub",
"file": "artplayer-plugin-jassub.mjs",
"bytes": 33771,
"sha256": "31e4be88838ddd786f1f2180d2662792ac3b2bcce00b7ccac977b59b9d659716"
},
{
"package": "artplayer-plugin-multiple-subtitles",
"file": "artplayer-plugin-multiple-subtitles.js",
"bytes": 13433,
"sha256": "c1cb0b511da88347165cc855185de9450a44835bb34bb802281ccdb854ef603c"
},
{
"package": "artplayer-plugin-multiple-subtitles",
"file": "artplayer-plugin-multiple-subtitles.legacy.js",
"bytes": 14099,
"sha256": "0b17644827e5b199afe8293093c44bfda571821014ff5b087c7c918c630dcc18"
},
{
"package": "artplayer-plugin-multiple-subtitles",
"file": "artplayer-plugin-multiple-subtitles.mjs",
"bytes": 26832,
"sha256": "e867c64303299a53d2bf6af62cc1e59044f1c7355aeb55e45b15ab2703448cb0"
},
{
"package": "artplayer-plugin-vast",
"file": "artplayer-plugin-vast.js",
"bytes": 23307,
"sha256": "72842ae0b4a44e44a080f88783c0c9bcd0b572fa0e946d817b2c36d960a08bfe"
},
{
"package": "artplayer-plugin-vast",
"file": "artplayer-plugin-vast.legacy.js",
"bytes": 23571,
"sha256": "4b88cec8d12844d639cc7703f88703136a4fe586781d9939bf2e3a0c93b42b60"
},
{
"package": "artplayer-plugin-vast",
"file": "artplayer-plugin-vast.mjs",
"bytes": 30891,
"sha256": "91fbe929a9d8d780f1656b53697fb0fe400b9375db79370866ec2f4c5313e727"
},
{
"package": "artplayer-plugin-vtt-thumbnail",
"file": "artplayer-plugin-vtt-thumbnail.js",
"bytes": 2325,
"sha256": "2d8e22cbd191bdac5a6c711b641590c2f8a90ba1aae185dd0e02a00baf000f8d"
},
{
"package": "artplayer-plugin-vtt-thumbnail",
"file": "artplayer-plugin-vtt-thumbnail.legacy.js",
"bytes": 2594,
"sha256": "ecbd0abe12c537687fb058de552c328c71ced71d911e454d0e37887192e9a291"
},
{
"package": "artplayer-plugin-vtt-thumbnail",
"file": "artplayer-plugin-vtt-thumbnail.mjs",
"bytes": 4284,
"sha256": "413af5e4f28d47c659521332042a8347da357b17af39cf08c89ce3347897c618"
},
{
"package": "artplayer-proxy-canvas",
"file": "artplayer-proxy-canvas.js",
"bytes": 1927,
"sha256": "ef489570e13f402f1a60eb256ce3900a0021a3d05699c2ba15adfaaeff184d4c"
},
{
"package": "artplayer-proxy-canvas",
"file": "artplayer-proxy-canvas.legacy.js",
"bytes": 2210,
"sha256": "7d25f21170c06d067aeaa1c8e79b15f2c0130a27cff1b410532d6c4ef4d2d45f"
},
{
"package": "artplayer-proxy-canvas",
"file": "artplayer-proxy-canvas.mjs",
"bytes": 3849,
"sha256": "4bb4a881787770093652a3262fc214a2529a1c514ef49affaf152b8abf0f4dc6"
},
{
"package": "artplayer-proxy-mediabunny",
"file": "artplayer-proxy-mediabunny.js",
"bytes": 418518,
"sha256": "376a0fffbac289e71717795532d6fce9f3531f87cc025dfd7694952d44479037"
},
{
"package": "artplayer-proxy-mediabunny",
"file": "artplayer-proxy-mediabunny.legacy.js",
"bytes": 440601,
"sha256": "8a91401e634fa4fe75ea68d6dd17e0793948584a67bcfab8edfe0c574920b0e7"
},
{
"package": "artplayer-proxy-mediabunny",
"file": "artplayer-proxy-mediabunny.mjs",
"bytes": 904277,
"sha256": "5b151b82b4054706d3c7c5c610ffd8ce9f39ef56d8393867b524891331fef8c0"
},
{
"package": "artplayer-tool-iframe",
"file": "artplayer-tool-iframe.js",
"bytes": 2878,
"sha256": "2ec257c8055a9448d12af3fecf1fae8ba58c06f47e85072d02c386cd258b0c86"
},
{
"package": "artplayer-tool-iframe",
"file": "artplayer-tool-iframe.legacy.js",
"bytes": 3108,
"sha256": "c0755d79f316cda71f045da86749648f95faf47c09180d525fb04bb753576d5f"
},
{
"package": "artplayer-tool-iframe",
"file": "artplayer-tool-iframe.mjs",
"bytes": 4094,
"sha256": "cbcdb0516dd5f17ca2572a6b3e363ea63b0cfd9733f3e47689c02088f23f29b9"
},
{
"package": "artplayer-tool-thumbnail",
"file": "artplayer-tool-thumbnail.js",
"bytes": 5984,
"sha256": "f77419cc62eeaa45c0413f4b04d169f78178fd539443cbf7b1e5db4ad4c95c98"
},
{
"package": "artplayer-tool-thumbnail",
"file": "artplayer-tool-thumbnail.legacy.js",
"bytes": 5984,
"sha256": "f77419cc62eeaa45c0413f4b04d169f78178fd539443cbf7b1e5db4ad4c95c98"
},
{
"package": "artplayer-tool-thumbnail",
"file": "artplayer-tool-thumbnail.mjs",
"bytes": 9029,
"sha256": "4d46df8cccdc92d18efc6f12abedf85e8881737023f4ead28697c8b1e85eead1"
}
]
},
"docsBuild": {
"command": "npm --workspace artplayer-vitepress run build",
"passed": true
},
"notVerified": [
"Chrome/API baseline",
"full public type consumers",
"minimum Node/other OS matrix",
"npm publishing"
]
}
@@ -0,0 +1,22 @@
# ENG-01 固定 Node/npm 和依赖
- 日期:2026-09-10;分支:codex/compatible-modernization;起点:3c759f14。
- 提交主题:`build(workspace): [ENG-01] pin reproducible Node and npm toolchain`。
## 改动和原因
根项目先前忽略全部锁文件,CI 使用未固定安装,工具声明允许浮动;最低 Node 20.0 也低于已经使用的 Vite 7 要求。新增 .node-version,指定官方 LTS Node 24.21.0/npm 11.19.0;16 个根工具移到 devDependencies 并按原安装版本精确固定,提交 npm lock v3,发布包依赖和版本不变。
新增 check:toolchain 脚本验证 lock、workspace 与标准运行时,维护说明见 toolchain-setup.md。下载工具到忽略目录后发现 plan.mjs 会扫描第三方 Markdown;改为跳过缓存、依赖和 Git 目录,仍检查全部维护文档。
## 验证
官方 Windows zip 校验 SHA-256 后用于本地隔离测试。全新目录 npm ci 成功(1141 包),锁文件不变,已有解析路径版本差异为零;严格工具检查通过。该环境原 19 项测试、21 库包共 63 产物及 VitePress 构建全部通过。工作区在 Node 24 下原测试加两项基础测试共 21 项通过。
manifest 故意改变的负例被工具检查拒绝,恢复后通过;计划缓存误扫场景修复后校验通过。完整输入及输出摘要见 baselines/toolchain-validation.json。最低 Node 矩阵、生产类型和浏览器测试尚未运行,不能从构建推断通过。
没有生产源/API 或各包版本变更;构建仅写隔离目录,不改 docs/compiled 或包 dist。没有推送或发布。现有 workflow 的 Yarn 安装与只读检查将在下一项 ENG-02 改造。
## 回退与下一步
本提交可恢复原工具声明/锁策略,不涉及用户播放器数据。原本地 node_modules/yarn.lock 留存;缓存目录可按明确路径另行清理。下一项 ENG-02,BASE-02 等待 Chrome 连接恢复。
+3 -2
View File
@@ -4,7 +4,7 @@
基线:`40fcda6a37d0049d42e49c1e64e70d4fd9ba5f7f`。总任务 212 项,范围 22 个包及工作区/示例。
状态:todo 197 / doing 0 / blocked 1 / done 14 / deferred 0。风险 L/M/H 表示兼容风险,不表示工期。
状态:todo 196 / doing 0 / blocked 1 / done 15 / deferred 0。风险 L/M/H 表示兼容风险,不表示工期。
前置依赖是启动条件;验收是完成条件。任务可以继续拆分,但不能复用或悄悄删除旧 ID。
@@ -72,7 +72,7 @@
| ID | 范围 / 步骤 | 前置依赖 | 交付物 | 验收条件 | 风险 | 状态 |
| --- | --- | --- | --- | --- | --- | --- |
| ENG-01 | workspace<br>固定 Node、包管理器与依赖 | BASE-01 | 版本 pin、唯一锁文件、安装说明 | 干净环境可复现,最低 Node 与构建依赖一致,未夹带全量升级 | M | todo |
| ENG-01 | workspace<br>固定 Node、包管理器与依赖 | BASE-01 | 版本 pin、唯一锁文件、安装说明 | 干净环境可复现,最低 Node 与构建依赖一致,未夹带全量升级 | M | done |
| ENG-02 | workspace<br>拆分只读检查并建立 PR CI | ENG-01 | lint/lint:fix、PR 与主线检查、独立部署任务;遵循 github-ci-cd.md,PR/重构分支触发、最小权限及 workflow 静态检查 | 仓库内检查可执行且不改源码、不发布;required checks 的外部设置状态列入发布台账,不阻塞本地框架建设 | M | todo |
| ENG-03 | workspace<br>建立公共行为与单元测试入口 | ENG-02, BASE-03 | 保留现有 node:test,测试目录/夹具/统一入口 | 已有 19 项回归保留,旧版与候选可用同一夹具运行 | M | todo |
| ENG-04 | workspace<br>建立类型测试基础 | ENG-02, BASE-05 | 根与分包 tsconfig、显式 TS 依赖、正反例测试 | 核心/试点与迁移模块严格检查,未迁移第三方/包历史问题独立台账;明确最低/当前 TS 和各环境类型 | M | todo |
@@ -416,3 +416,4 @@
- BASE-01: [记录](changes/2026-09-10-BASE-01-published-baseline.md) [记录](baselines/releases.json)
- BASE-HARNESS-01: [记录](changes/2026-09-10-BASE-HARNESS-01-browser-fixture.md)
- BASE-02: Chrome 工具连接连续失败,重置后仍不可用;用户要求先继续其他任务。恢复连接后执行 api.html 并核对报告,HTTP 服务通过不代表浏览器通过。
- ENG-01: [记录](changes/2026-09-10-ENG-01-reproducible-toolchain.md) [记录](baselines/toolchain-validation.json)
+7 -1
View File
@@ -1,6 +1,12 @@
# 进度与证据
## 当前实施:浏览器夹具已保存,继续 ENG-01
## 当前实施:ENG-01 工具链已验证
Node 24.21.0/npm 11.19.0、16 个直接工具和 npm lock 已固定;干净安装 1141 包、原 19 项测试、21 库包 63 产物与文档站构建全部通过,已有依赖解析版本没有升级。详见 [ENG-01 交付](changes/2026-09-10-ENG-01-reproducible-toolchain.md)。
完成 12 项规划、3 项实施基础任务;BASE-02 仍因 Chrome 连接阻塞,196 项待办。BASE-HARNESS-01 提交为 `3c759f14`。没有生产 TS 迁移、推送或发布。下一项 ENG-02,拆分只读检查并更新 PR/主线 CI。
## 2026-09-10:浏览器夹具已保存
BASE-01 已提交 `1d705b30`。BASE-HARNESS-01 完成发布包采集页面/本地 HTTP 服务及 1 项真实 HTTP 测试,详见 [交付记录](changes/2026-09-10-BASE-HARNESS-01-browser-fixture.md)。BASE-02 因 Chrome 连接失败保持 blocked;用户要求先继续其他实施任务,没有伪造浏览器基线。
+10 -2
View File
@@ -105,8 +105,16 @@ for (const task of data.tasks) {
}
let localLinks = 0
const markdownFiles = fs.readdirSync(dir, { recursive: true })
.filter(file => file.endsWith('.md')).map(file => path.join(dir, file))
function markdownIn(directory) {
return fs.readdirSync(directory, { withFileTypes: true }).flatMap((entry) => {
const filename = path.join(directory, entry.name)
if (entry.isDirectory()) {
return ['.cache', 'node_modules', '.git'].includes(entry.name) ? [] : markdownIn(filename)
}
return entry.isFile() && entry.name.endsWith('.md') ? [filename] : []
})
}
const markdownFiles = markdownIn(dir)
for (const file of [...markdownFiles, path.join(root, 'AGENTS.md')]) {
const content = fs.readFileSync(file, 'utf8')
for (const match of content.matchAll(/\[[^\]]*\]\(([^)]+)\)/g)) {
+5 -2
View File
@@ -383,11 +383,14 @@
"dependsOn": [
"BASE-01"
],
"status": "todo",
"status": "done",
"risk": "M",
"deliverable": "版本 pin、唯一锁文件、安装说明",
"acceptance": "干净环境可复现,最低 Node 与构建依赖一致,未夹带全量升级",
"evidence": []
"evidence": [
"changes/2026-09-10-ENG-01-reproducible-toolchain.md",
"baselines/toolchain-validation.json"
]
},
{
"id": "ENG-02",
+33
View File
@@ -0,0 +1,33 @@
# 可重跑的开发环境
ENG-01 固定开发工具,消费者 API 和各包版本尚未修改。规范运行时是根 .node-version 的 Node 24.21.0,配套 npm 11.19.0;官方二进制已核对 SHA-256。开发依赖版本固定为本机改造前已经解析的版本,package-lock.json 是唯一提交和维护的依赖锁文件。
## 使用
1. 安装/切换到 .node-version 指定版本,确认 `node --version` 和 `npm --version`。实施时采用的 [Node 官方发行索引](https://nodejs.org/dist/index.json) 给出 24.21.0 LTS 与 npm 11.19.0;固定后不能每次 CI 自动取 latest。
2. 从干净 checkout 运行 `npm ci`。它会删除当前 node_modules 并按锁文件安装,不更新锁;在本轮验证中使用独立目录,未删除用户原有依赖。规则参见 [npm ci](https://docs.npmjs.com/cli/commands/npm-ci/)。
3. 执行 `npm run check:toolchain -- --strict`,核对实际 Node/npm、16 个根开发工具及 22 workspace 的锁定声明。无 --strict 时允许满足工具最低要求的 Node,并打印与标准版本的差异。
4. 现有 `npm run test:playback`、`npm run test:dash-control`、`npm run build -- all`、`npm --workspace artplayer-vitepress run build` 继续可用。CI 和只读 lint 的拆分由 ENG-02 接续;当前 lint 仍有 --fix,不当作只读验证。
私有根包的最低工具 Node 改为 ^20.19.0 || >=22.12.0,与已使用 Vite 7 的 engines 一致;这不是改变已发布播放器的 Node/browser 支持声明。本轮实际验证 Node 24.21.0,其他版本矩阵由 CI-01 执行,不能声称已经跑过全部最低环境。
## 安装与锁文件维护
- 原根 dependencies 全部是开发/构建工具,已移入 devDependencies 并固定精确版本;各发布包的 runtime dependencies/peer 范围保持原样。
- 初始锁从现有安装及锁信息生成,确认已有解析路径、直接工具和 workspace runtime 版本没有升级;补齐跨平台可选包供后续 CI 使用。
- 旧本地 yarn.lock 被忽略,留存以免删除用户文件;不作为维护锁或 CI 来源。不要混用 Yarn/Bun 改写依赖。MOD-01 另做 Bun 固定安装对比,结果通过再变更标准工具。
- 新依赖仍按任务需要自主添加,并固定开发依赖版本;将 manifest 和 package-lock.json 同次提交。更新 runtime 范围需独立兼容证据。
- 当前根 postinstall 执行已安装的 Lerna 8.2.4 run prepare;本轮 22 包无 prepare 脚本,输出 No packages found。是否删除空 hook 在 MOD-02 清理,不在初次固定锁时重写所有旧命令。
- npm 11.19.0 本轮报告 esbuild(两个版本)、less、nx 安装脚本尚未列入 allowScripts 策略;未用 ignore-scripts 绕过干净安装。实际安装、构建和 Node 测试成功;后续 CI/Bun 脚本策略需按真实包版本审查,不把警告写成运行失败或自动批准任意脚本。
## 已完成证据
[toolchain-validation.json](baselines/toolchain-validation.json) 保存官方运行时归档 SHA、依赖锁及输入标识、安装计数、测试与构建文件摘要。
- Windows 独立空依赖目录:npm ci 安装 1141 个包,锁文件字节不变;无已有解析版本升级。
- 独立 Node 24.21.0/npm 11.19.0 严格工具检查通过;原 19 项 Node 测试通过。
- 21 个库包的正常构建全部通过(63 个 UMD/legacy/ESM 输出),VitePress 文档站构建通过;输出均在忽略的隔离目录。
- 工具检查器能拒绝 manifest/lock 不一致。已有完整性/HTTP 服务测试加原测试共 21 项通过。
- 计划校验器跳过 .cache/node_modules/.git,不再误扫工具下载和干净安装副本里的第三方文档。
这些结果说明固定工具链能安装并构建原项目,不代表运行时、类型、真实浏览器或 npm 发布验收已完成。Chrome 连接阻塞继续由 BASE-02 登记。
+36
View File
@@ -0,0 +1,36 @@
import assert from 'node:assert/strict'
import fs from 'node:fs'
import path from 'node:path'
import { fileURLToPath } from 'node:url'
const root = fileURLToPath(new URL('../', import.meta.url))
const read = name => JSON.parse(fs.readFileSync(path.join(root, name), 'utf8'))
const manifest = read('package.json')
const lock = read('package-lock.json')
const nodeVersion = fs.readFileSync(path.join(root, '.node-version'), 'utf8').trim()
const [major, minor] = process.versions.node.split('.').map(Number)
assert((major === 20 && minor >= 19) || (major === 22 && minor >= 12) || major >= 23, 'Build tooling requires Node ^20.19.0 || >=22.12.0')
assert.equal(lock.lockfileVersion, 3)
assert.deepEqual(lock.packages[''].devDependencies, manifest.devDependencies, 'Root dependencies differ from lock')
for (const [name, version] of Object.entries(manifest.devDependencies)) {
assert(/^\d+\.\d+\.\d+(?:-[\w.-]+)?$/.test(version), `Unpinned development dependency: ${name}`)
assert.equal(lock.packages[`node_modules/${name}`]?.version, version, `Lock resolution differs: ${name}`)
}
let packages = 0
for (const dir of fs.readdirSync(path.join(root, 'packages'))) {
const filename = `packages/${dir}/package.json`
if (!fs.existsSync(path.join(root, filename))) continue
const workspace = read(filename)
const locked = lock.packages[`packages/${dir}`]
assert(locked, `Workspace missing from lock: ${dir}`)
for (const field of ['version', 'dependencies', 'devDependencies', 'peerDependencies', 'optionalDependencies']) {
assert.deepEqual(locked[field], workspace[field], `Workspace lock differs: ${dir}.${field}`)
}
packages += 1
}
if (process.argv.includes('--strict')) {
assert.equal(process.versions.node, nodeVersion, 'Use the pinned .node-version runtime')
const actualNpm = process.env.npm_config_user_agent?.split(' ')[0]
assert.equal(actualNpm, manifest.packageManager.replace('@', '/'), 'Run with the pinned npm through npm run check:toolchain -- --strict')
}
console.log(`Toolchain verified: ${packages} workspaces, ${Object.keys(manifest.devDependencies).length} pinned tools; Node ${process.versions.node} (canonical ${nodeVersion}), ${manifest.packageManager}`)