feat(web): 模型设置页复刻官方交互 + 官方推荐插件按 dsh 版本过滤(档案 91/92/93)

档案 91 ——「模型设置」页折行 + 复刻官方交互(插件 0.3.15)
· 折行根因不是"窄":原「我已添加的厂家」是 4 列表格(列宽 auto)⇒ 名称/状态/两按钮三处折行同源;
  改官方 dsh-client-ui-settings-models 的**卡片行**(rowHead + rowActions margin-left:auto,两侧 nowrap)
· 「新增」改官方**两步式**:默认两个虚线按钮 → 点开才出卡片,主字段只剩「API 密钥」
  (官方原文:页面从不询问环境变量名);次要字段收进 <details>「自定义设置」
· CSS 数值逐值照抄官方 CSS 模块;顺修「由 admin 配置」「密钥可留空」两处错文案,补删除二次确认

档案 92 —— 官方推荐插件列表按 dsh 版本过滤(插件 0.3.16)
· 官方目录不带 dsh 版本字段 ⇒ 逐包查 npm 声明与平台真实版本比,分类 match/none/newer/older/unknown
· 默认隐藏「仅兼容更旧版本」,「需更高版本」橙色标注;勾选框为逃生口;说明行给隐藏计数(不静默消失)
· ⚠️ 判 satisfies 必须带 includePrerelease(平台是 prerelease,默认语义会把在跑的 dshmarket 之类判成更旧)

档案 93 —— 兼容判定收口(服务器 CI 由红转绿)
· 「单测长期红」真相 = 服务器源码落后于 git(本机 48/0 全绿)⇒ 同步即修,非代码问题
· 伞包 @deepseek-ai/dsh 收口到 dsh-install.platformPackageVersion()(它不在自己的 node_modules 里,
  原先恒判 null ⇒ 声明在伞包上的"要求更高版本"全被放行);闸门与列表共用同一份版本表
· 闸门判据 A 加 prerelease 兜底:实测抽样 300 里 prerelease-artifact 117 条(≈39% 假阳性,
  含在跑的 dshmarket)⇒ 容忍下能满足则只计数(prereleaseOnly)不阻断

校验
· 新增 scripts/verify-dsh-compat.mjs(21 条回归锚点)与 verify-models-dict.mjs / verify-models-render.cjs
· verify-platform-admin-section.mjs:断言从旧 UI(表格/下拉「自定义厂家…」)改成断言新 UI
  (含模拟点击两个新增入口 + 选中目录厂家)
· 两个仓库外的动作:服务器 npm run build + ci.sh(CI OK)+ systemctl restart dshs;插件 0.3.16 已铺发

⚠️ 本提交未包含 src/supervisor/orchestrator.ts —— 那是别人在途的内存配额改动
(BASE 160→448 / MIN 384→512 / MAX 1024→1536 / mcn 128→256),其对应的客户端常量尚未同步,
本机 verify-mem-model 因此有 4 项红;提交后仓库树两边均为旧值,该断言在 HEAD 上一致。
This commit is contained in:
admin committed 2026-09-14 21:13:32 +08:00
1 parent 1d72e8f9c8
commit 29c57a8207
11 files changed
+1474 -209

No files matched your search

+36 -19
View File
@@ -33,7 +33,7 @@ import { pathToFileURL } from 'node:url'
// 平台内置包的落点**不能写死**:`npm root -g` 随发行版变(`/usr/local/lib` vs `/usr/lib`),
// 写死只会在另一种布局上静默退化成「平台包目录不可读」而不报错(测试服实测 = 0)。
// 统一走 `dsh-install.ts` 的按序探测。
import { dshScopeDir } from './dsh-install.js'
import { dshScopeDir, platformPackageVersion } from './dsh-install.js'
const DS_SCOPE = '@deepseek-ai/'
@@ -53,6 +53,11 @@ export interface CompatResult {
platformPkgs: number
/** 是否真的看到了 @deepseek-ai 的依赖声明或 import(区分 ok / unknown 用) */
sawPlatformRef: boolean
/**
* 有几条声明「按 semver 默认语义不满足、按 prerelease 容忍满足」——**平台是 prerelease**
* 的语义产物,**不计入 `findings`、不阻断**,只留个可观测计数(2026-09-14,档案 92)。
*/
prereleaseOnly?: number
/** 判定过程出错时的说明(此时 level=unknown) */
note?: string
}
@@ -61,7 +66,6 @@ export interface CompatResult {
* 平台侧:版本表(读 package.json)与导出符号(按需 import,带缓存)
* ------------------------------------------------------------------ */
const versionCache = new Map<string, string | null>()
const exportCache = new Map<string, Set<string> | null>()
function shortName(pkg: string): string {
@@ -94,22 +98,15 @@ export function platformPkgCount(): number {
}
}
/** 平台内置某包的版本;平台没有该包 → null。 */
/** 平台内置某包的版本;平台没有该包 → `null`。
*
* 2026-09-14(档案 92):改为走 `dsh-install.platformPackageVersion()` —— 原实现只查
* `<scope>/<短名>/package.json`,而**伞包 `@deepseek-ai/dsh` 不在自己的 `node_modules` 里**
* ⇒ 对它恒判 `null`,被当作「平台没这个包,不算不兼容」而放行(实测那 3 条"要求更高版本"的
* 插件全部只写在伞包上)。收口后该判据**含伞包**,与 `plugin-dsh-compat` 共用同一份版本表。
*/
function platformVersion(pkg: string): string | null {
const hit = versionCache.get(pkg)
if (hit !== undefined) return hit
let v: string | null = null
try {
const pj = join(platformPkgDir(pkg), 'package.json')
if (existsSync(pj)) {
const meta = JSON.parse(readFileSync(pj, 'utf8')) as { version?: unknown }
v = typeof meta.version === 'string' ? meta.version : null
}
} catch {
v = null
}
versionCache.set(pkg, v)
return v
return platformPackageVersion(pkg)
}
function resolveEntryFile(pkg: string): string | null {
@@ -159,7 +156,7 @@ async function platformExports(pkg: string): Promise<Set<string> | null> {
return keys
}
type SemverLike = { satisfies(v: string, r: string): boolean }
type SemverLike = { satisfies(v: string, r: string, o?: { includePrerelease?: boolean }): boolean }
let semverPromise: Promise<SemverLike | null> | null = null
function loadSemver(): Promise<SemverLike | null> {
@@ -303,8 +300,25 @@ export async function checkPluginCompat(root: string): Promise<CompatResult> {
continue
}
let ok: boolean
let prereleaseOnly = false
try {
ok = semver.satisfies(v, range) // **默认语义**:与 pnpm 的实际安装判定一致
// ① 先按**默认语义**判(与 pnpm 的实际安装判定一致)
ok = semver.satisfies(v, range)
if (!ok) {
// ② 不满足时再看是不是**prerelease 语义产物**。
// 平台版本是 prerelease(`0.1.5-rc.1`、子包 `0.1.5-rc.2`),而 semver 默认语义下
// prerelease **不满足** `*`、`^0.1.2` 这类不含 prerelease 的范围 —— 于是
// 「声明 `*`(= 任意版本)」会被判成不兼容。
// 实测 2026-09-14(抽样 300,见 `04-调整方案/92`):
// real-newer 3 | narrow-pin 22 | **prerelease-artifact 117** | match 98
// ⇒ 若把这 117 也当"不兼容",闸门会有 ~39% 假阳性(`dshmarket`、`dsh-context`
// 这些**在平台上跑得好好的**都会被拦)。所以:**只有 prerelease 容忍下也不满足,
// 才算真不兼容**;容忍下能满足的只记一条 note(可观测,不阻断)。
if (semver.satisfies(v, range, { includePrerelease: true })) {
ok = true
prereleaseOnly = true
}
}
} catch {
continue // 范围写法无法解析:不据此断言
}
@@ -314,6 +328,9 @@ export async function checkPluginCompat(root: string): Promise<CompatResult> {
pkg,
detail: `平台为 ${v},插件要求 ${range}(不满足)`,
})
} else if (prereleaseOnly) {
// 保持可观测:这一条是"按 pnpm 语义不满足、按 prerelease 容忍满足"的平台效应
out.prereleaseOnly = (out.prereleaseOnly ?? 0) + 1
}
}