mirror of
https://github.com/czcdr/dsh-plugin-rea.git
synced 2026-11-07 10:25:59 -10:00
bundle: fix the dry-run failure a bare machine sees, plus three side accounts
`--dry-run` reported the whole chain as broken on a clean machine. Every planned
component returns `{ planned: true }` with no path, and only a real path was
recorded in `context.resolved`, so each dependent plan entry was reported as
"required component ... is unavailable" — four FAIL lines and exit 1, for exactly
the reader the README tells to run `--dry-run` first. Adoption on a developer
machine hid it: with `--reuse` everything resolves and the identical command
exits 0.
Also:
* verify-branch.ps1 asserted "dry-run exits 0" through `--reuse`, so it passed
precisely where the defect could not appear and would have failed on a bare
machine. It now runs without `--reuse`, asserts that no dependency is reported
unavailable, and checks its own BOM (it is the script edited most often).
* release.yml pinned its npm self-update to `npm@^11` rather than `latest`, so a
publishing pipeline cannot acquire a new npm major on release day.
* check-updates.ps1's engines verdict answered "unsatisfied" for patterns it does
not implement (`22.x`, `>=22`), sending users to upgrade a Node that is fine. It
now answers "cannot be parsed". Verified through Windows PowerShell 5.1 against
fake REA packages: 22.x → cannot parse, >=99.0.0 → unsatisfied, ^24.11.0 → ok,
and removing the guard makes 22.x unsatisfied again.
* the audit compares the two READMEs' section and subsection counts, because the
bilingual pair is maintained by hand and drifts the same way the patch did.
Verified: audit clean with 6/6 deliberate sabotages caught; 17/17 unit tests on
Windows and on Linux; `--dry-run` exits 0 both with and without `--reuse`; 25/25
end-to-end path checks; verify-branch ALL CHECKS PASSED; and the row → shim → MCP
handshake still returns rea 6.4.0 with 170 tools.
This commit is contained in:
1 parent
419235ad45
commit
65a2963029
6 files changed
+67
-9
No files matched your search
@@ -71,7 +71,12 @@ jobs:
|
||||
registry-url: 'https://registry.npmjs.org'
|
||||
|
||||
- name: npm CLI must support OIDC trusted publishing (>= 11.15.0)
|
||||
run: npm install -g npm@latest && npm --version
|
||||
# Pinned to the major that provides trusted publishing. `npm@latest` would
|
||||
# silently follow npm into a future major on release day, which is the one
|
||||
# moment a publishing pipeline should not acquire new behaviour.
|
||||
run: |
|
||||
npm install -g 'npm@^11'
|
||||
npm --version
|
||||
|
||||
- name: Publish to npm via trusted publishing
|
||||
run: npm publish --provenance --access public
|
||||
+14
-3
@@ -42,19 +42,30 @@
|
||||
转发只能原样传参、**无法追加 flag**,于是"裸跑一个叫 status 的命令"会掉进启动路径:在已供给的机器上
|
||||
启动 REA,在未供给的机器上**开始约 800 MB 下载** —— 与这个名字承诺的正好相反。现在无参数时打印用法并
|
||||
退出(真实退出码 0),MCP 行不受影响,因为它始终显式传 `mcp`。
|
||||
- **`--dry-run` 在裸机上误报失败并退出 1。** 计划项返回 `{ planned: true }`(没有 `path`),而只有真实
|
||||
`path` 才被计入 `context.resolved`,于是每个依赖前序组件的计划项都被判成"依赖不可用":在**裸机** —— 恰恰
|
||||
是 README 建议先跑 `--dry-run` 的那台机器 —— 整条链报 4 条 FAIL 且退出码为 1。现在计划项同样满足下游的
|
||||
`requires`。(本机 `--reuse` 会 adopt 成功,所以这个缺陷只在干净机器上可见。)
|
||||
- **`release.yml` 的 npm 自更新**由 `npm@latest` 钉到 `npm@^11`:发布当天不该让流水线获得新行为。
|
||||
- **`check-updates.ps1` 的 engines 判定**:不认识的 pattern(`22.x`、`>=22` 之类)此前返回"不满足",误导
|
||||
用户去升级一个本来就满足的 Node;现在返回"无法解析"。三条实测:`22.x` → 无法解析、`>=99.0.0` → 不满足、
|
||||
`^24.11.0` → 满足。
|
||||
- **README 的「先装插件也可以」改为诚实描述。** 发布的行指向的镜像 shim **由 setup 创建**,所以在第一次
|
||||
供给之前该行以 `MODULE_NOT_FOUND` 退出 —— 没有任何东西能启动后台供给。首次必须手动跑一次
|
||||
`setup.mjs`,此后才由 shim 自动补供给。
|
||||
|
||||
### 回归防护
|
||||
|
||||
- `audit-manifest.mjs` 新增五项,全部做过反向验证(**故意写坏 5/5 都被抓住**):`!!js` 裸标量 mapping
|
||||
- `audit-manifest.mjs` 新增六项,全部做过反向验证(**故意写坏 6/6 都被抓住**):`!!js` 裸标量 mapping
|
||||
检测、`DSH_HOME` 三态(未设/空/已设)求值一致性、README 与 patch 表达式不得漂移、镜像清单必须含
|
||||
manifest、镜像清单**不得**携带 `cordis.patch.yml`(它是 shim 区分两份副本的判据,被镜像进去会让镜像
|
||||
副本退回 `DSH_HOME` 规则)。另外把「`DSH_HOME`/`USERPROFILE`/`HOME` 全空 → 根路径」这个**已知无害
|
||||
行为**钉成 warn(此前无覆盖):该情形下该行报 `MODULE_NOT_FOUND`,不写文件、不下载,harness 照常。
|
||||
副本退回 `DSH_HOME` 规则)、**两份 README 结构平行**(节/子节数量,双语靠手工同步)。另外把
|
||||
「`DSH_HOME`/`USERPROFILE`/`HOME` 全空 → 根路径」这个**已知无害行为**钉成 warn(此前无覆盖):该情形下
|
||||
该行报 `MODULE_NOT_FOUND`,不写文件、不下载,harness 照常。
|
||||
- `validate.yml`:YAML 步骤注册 `!!js` 标量构造器(原先 `safe_load` 直接拒绝这个仓库要发布的行 ——
|
||||
**CI 一直是红的**);行契约步骤断言 `args[0]` 是标量、不是 mapping;新增 `bundle:test` 与 `bundle:audit` 两步。
|
||||
- `verify-branch.ps1`:dry-run 断言改为**不带 `--reuse`**(旧写法在本机 adopt 成功时正好掩盖了上面那个
|
||||
裸机缺陷),并新增"不得出现依赖不可用"一条;它现在也检查**自己**的 BOM,因为它是被编辑得最频繁的脚本。
|
||||
- 单元测试新增四条**真的去 spawn shim**的用例(镜像布局、checkout 布局、`REA_BUNDLE_ROOT` 覆盖、裸跑只
|
||||
打印用法),并逐条做过反向验证:把 shim 改回"一律用自身位置"时 checkout 那条会红;去掉裸跑守卫时裸跑
|
||||
那条会红(后者自带桩保护,即使回退也只会跑到桩、不会下载)。
|
||||
|
||||
@@ -46,6 +46,10 @@ function Test-NodeEngines([string]$node, [string]$engines) {
|
||||
# 之后 $node.Major 为 $null,所有 ^ / ~ 分支都会判假(曾因此把 Node 24 判成不满足)。
|
||||
$v = Get-NumericVersion $node
|
||||
if (-not $v) { return $null }
|
||||
# 只要有一个 term 的形态不认识,整个判断就只能给"无法解析":返回 $false 会把
|
||||
# `22.x` / `>=22` 这类合法但未实现的 pattern 误报成"不满足",让用户去升级一个
|
||||
# 本来就满足的 Node。
|
||||
$recognized = $true
|
||||
foreach ($term in ($engines -split '\|\|')) {
|
||||
$t = $term.Trim()
|
||||
if ($t -match '^\^(\d+\.\d+\.\d+)$') {
|
||||
@@ -56,8 +60,11 @@ function Test-NodeEngines([string]$node, [string]$engines) {
|
||||
} elseif ($t -match '^~(\d+\.\d+\.\d+)$') {
|
||||
$base = [version]$Matches[1]
|
||||
if ($v.Major -eq $base.Major -and $v.Minor -eq $base.Minor -and $v -ge $base) { return $true }
|
||||
} else {
|
||||
$recognized = $false
|
||||
}
|
||||
}
|
||||
if (-not $recognized) { return $null }
|
||||
return $false
|
||||
}
|
||||
|
||||
|
||||
@@ -369,6 +369,27 @@ if (manifest) {
|
||||
}
|
||||
}
|
||||
|
||||
/* ---------------------------------- 9b. the two READMEs stay parallel */
|
||||
|
||||
// They are maintained by hand, and an edit that lands in only one of them leaves
|
||||
// half the readers with stale instructions — the patch expression above is the
|
||||
// one piece already compared, but sections drift the same way. The prose differs
|
||||
// by language, so the check compares the structure that must stay parallel.
|
||||
const headingCounts = (doc) => {
|
||||
const text = readFileSync(path.join(HERE, "..", doc), "utf8");
|
||||
const count = (marker) => (text.match(new RegExp(`^${marker} `, "gm")) ?? []).length;
|
||||
return { sections: count("##"), subsections: count("###") };
|
||||
};
|
||||
const englishHeadings = headingCounts("README.md");
|
||||
const chineseHeadings = headingCounts("README.zh-CN.md");
|
||||
if (englishHeadings.sections !== chineseHeadings.sections || englishHeadings.subsections !== chineseHeadings.subsections) {
|
||||
add(
|
||||
"error",
|
||||
"README.md",
|
||||
`the two READMEs drifted apart in structure: README.md has ${englishHeadings.sections} sections / ${englishHeadings.subsections} subsections, README.zh-CN.md has ${chineseHeadings.sections} / ${chineseHeadings.subsections}`,
|
||||
);
|
||||
}
|
||||
|
||||
/* ------------------------------------------- 10. the mirror list is complete */
|
||||
|
||||
// Another real bug: mirrorLauncher() copied the shim and setup.mjs but not the
|
||||
|
||||
+7
-2
@@ -1157,8 +1157,13 @@ for (const name of INSTALL_ORDER) {
|
||||
}
|
||||
const resolvedValue = await provisionComponent(name, component, context);
|
||||
results[name] = resolvedValue;
|
||||
// Only a real path may satisfy another component's `requires`.
|
||||
if (resolvedValue && typeof resolvedValue.path === "string") {
|
||||
// A component satisfies another's `requires` when it has a real path — or when
|
||||
// this run only *planned* it. In dry-run every component returns
|
||||
// `{ planned: true }` with no path, so counting only real paths made each
|
||||
// dependent plan entry look like a missing dependency: on a bare machine, which
|
||||
// is exactly the machine the README tells to run `--dry-run` first, the whole
|
||||
// chain reported FAIL and the command exited 1.
|
||||
if (resolvedValue && (typeof resolvedValue.path === "string" || resolvedValue.planned === true)) {
|
||||
context.resolved[name] = resolvedValue;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,7 +18,9 @@ foreach ($f in @('bin\rea-shim.mjs','scripts\setup.mjs','scripts\audit-manifest.
|
||||
}
|
||||
|
||||
Write-Host "`n=== 2. PowerShell parse + BOM ===" -ForegroundColor Cyan
|
||||
foreach ($f in @('check-updates.ps1','assets\make-screenshots.ps1','scripts\rea-bundle-bootstrap.ps1')) {
|
||||
# This script checks itself too: it is edited as often as the others, and an editor
|
||||
# that drops the BOM would otherwise go unnoticed until someone adds CJK text here.
|
||||
foreach ($f in @('check-updates.ps1','assets\make-screenshots.ps1','scripts\rea-bundle-bootstrap.ps1','scripts\verify-branch.ps1')) {
|
||||
$p = Join-Path $root $f
|
||||
$bytes = [System.IO.File]::ReadAllBytes($p)
|
||||
$bom = ($bytes[0] -eq 0xEF -and $bytes[1] -eq 0xBB -and $bytes[2] -eq 0xBF)
|
||||
@@ -80,10 +82,17 @@ foreach ($script in @('bundle:setup', 'bundle:status', 'bundle:audit', 'bundle:t
|
||||
|
||||
Write-Host "`n=== 7. dry-run still plans the whole chain ===" -ForegroundColor Cyan
|
||||
$env:REA_BUNDLE_ROOT = Join-Path $env:TEMP 'rea-verify-dryrun'
|
||||
$dry = & node scripts\setup.mjs --root $env:REA_BUNDLE_ROOT --reuse --dry-run 2>&1
|
||||
# Deliberately WITHOUT --reuse. Adoption of whatever this machine happens to have
|
||||
# installed used to hide a defect that only a bare machine sees: every planned
|
||||
# component returned `{ planned: true }` with no path, so the dependents of each
|
||||
# plan entry were reported as "required component is unavailable" and the command
|
||||
# exited 1 — for the exact reader the README sends to `--dry-run`.
|
||||
$dry = & node scripts\setup.mjs --root $env:REA_BUNDLE_ROOT --dry-run 2>&1
|
||||
$planned = @($dry | Select-String -Pattern '^\[plan\]').Count
|
||||
Check 'dry-run exits 0' ($LASTEXITCODE -eq 0) (($dry | Select-Object -Last 3) -join ' ')
|
||||
$unmet = @($dry | Select-String -Pattern 'is unavailable').Count
|
||||
Check 'dry-run exits 0 without --reuse' ($LASTEXITCODE -eq 0) (($dry | Select-Object -Last 3) -join ' ')
|
||||
Check 'dry-run plans every component' ($planned -ge 4) "planned=$planned"
|
||||
Check 'dry-run reports no unavailable dependency' ($unmet -eq 0) "unavailable=$unmet"
|
||||
Remove-Item Env:\REA_BUNDLE_ROOT -ErrorAction SilentlyContinue
|
||||
|
||||
Write-Host ''
|
||||
|
||||
Reference in new issue
Block a user