#!/usr/bin/env node /** * verify-dsh-compat.mjs —— 「官方推荐插件列表按 dsh 版本过滤」(档案 92)的**回归锚点**。 * * 为什么需要:这条链路的关键判据**全都不是"跑得通/跑不通"能暴露的** —— * · 少了 `includePrerelease: true`:功能照跑,但会把**在平台上跑得好好的**插件 * (`dsh-univer-office`、`dshmarket` …)判成「只兼容更旧版本」而被隐藏。 * 2026-09-14 实测:TOP300 默认语义 `match 97 / older 139`;prerelease 容忍 `match 214 / older 22`。 * · 少了「伞包 `@deepseek-ai/dsh` 单独解析」:所有"要求 dsh ≥ 0.1.5-rc.2"的插件都判不出来 * (伞包**不在自己的 node_modules 里**)—— 而那恰恰是用户要标注的那一类 * (实测 TOP300 的 3 条 `newer` **全部**只写在伞包上)。 * · 前端少了「隐藏计数/说明」:条目会**静默消失**,正是本库反复强调要避免的。 * 以上都会"静默降级",所以钉成断言。 * * 用法:node scripts/verify-dsh-compat.mjs 退出码 0=全绿 / 1=有失败 */ import { readFileSync } from 'node:fs' import { fileURLToPath } from 'node:url' import { dirname, join } from 'node:path' const ROOT = join(dirname(fileURLToPath(import.meta.url)), '..') const read = (p) => readFileSync(join(ROOT, p), 'utf8') let failed = 0 const ok = (name, cond, extra = '') => { console.log((cond ? ' ✓ ' : ' ✗ ') + name + (extra ? ' ' + extra : '')) if (!cond) failed++ } const compat = read('src/web/plugin-dsh-compat.ts') const route = read('src/web/routes/whitelist.ts') const client = read('poc/business-plugins/lib/client.js') const install = read('src/web/dsh-install.ts') const legacy = read('src/web/plugin-compat.ts') // ── ① 后端判据:prerelease 语义 + 伞包解析(两条都是"静默降级"型)── ok('判定用 prerelease 容忍语义(includePrerelease: true)', /includePrerelease:\s*true/.test(compat)) ok('伞包解析收口在 dsh-install.platformPackageVersion(单独读 /package.json)', /export function platformPackageVersion\(/.test(install) && /full === PKG_NAME \? dshPackageRoot\(\)/.test(install)) ok('两处消费方共用同一份版本表(不再各写一遍)', /platformPackageVersion/.test(compat) && /platformPackageVersion/.test(legacy) && !/versionTable/.test(compat) && !/versionCache/.test(legacy)) ok('分类枚举含 newer / older / match / none / unknown', ['newer', 'older', 'match', 'none', 'unknown'].every((k) => new RegExp(`'${k}'`).test(compat))) ok('"要求更高"优先于"只兼容更旧"(newer 先返回)', /if \(newer !== null\)[\s\S]{0,200}kind: 'newer'[\s\S]{0,200}if \(older\.length > 0\)/.test(compat)) ok('semver 不可用时降级为 unknown(而不是判兼容/不兼容)', /semver === null\)\s*return \{ kind: 'unknown'/.test(compat)) // 闸门(判据 A)也必须先按默认语义、再容忍 prerelease —— 否则「声明 `*`」会被判不兼容。 // 实测:抽样 300 里这类"prerelease 产物"有 117 条(dshmarket 等能跑的都在其中)。 ok('闸门判据 A 有 prerelease 兜底(默认语义不满足时先看 includePrerelease)', /semver\.satisfies\(v, range\)[\s\S]{0,2000}includePrerelease: true/.test(legacy)) ok('prerelease 产物只计数、不进 findings(不阻断)', /prereleaseOnly/.test(legacy) && /out\.findings\.push[\s\S]{0,200}prereleaseOnly/.test(legacy)) // ── ② 路由:过滤 + 标注 + 缓存 + 预热 + 不静默 ── ok('GET 尊重 dshCompat 参数(=all 时只标注不过滤)', /dshCompat !== 'all'/.test(route)) ok('只隐藏 older,其余(含 unknown)照常显示', /kind !== 'older'/.test(route)) ok('响应带 hiddenByDsh(供前端说明隐藏了多少)', /hiddenByDsh/.test(route)) ok('响应带 dshVersion(当前版本)', /dshVersion: platformDshVersion\(\)/.test(route)) ok('判定结果落盘缓存(避免每次搜索打 npm)', /npm-dsh-compat\.json/.test(route)) ok('有后台预热,避免冷启动全判 unknown', /warmCompat/.test(route)) ok('请求内只给预算:取不到判 unknown 并仍显示', /COMPAT_BUDGET_MS/.test(route)) // ── ③ 前端:徽章 + 说明 + 逃生口 ── ok('前端有兼容徽章函数 wlCompat', /function wlCompat\(/.test(client)) ok('「需更高版本」用醒目徽章(pending/橙色)', /cls = "pending"/.test(client)) ok('查询串带 dshCompat=all 逃生口', /&dshCompat=all/.test(client)) ok('说明行给出隐藏计数(不静默消失)', /pa\.pl\.cmpHidden/.test(client) && /hiddenByDsh/.test(client)) ok('表格新增 dsh 版本列', /pa\.pl\.compatCol/.test(client)) console.log(failed === 0 ? '\n全部通过(dsh 版本兼容过滤:判据 + 过滤 + 标注)' : `\n${failed} 项失败`) process.exit(failed === 0 ? 0 : 1)