Chuyển đến nội dung chính

dsh-compat-guard

Đã xác minh

dsh-compat-guard · v0.1.0 · MIT

Compatibility governance for DeepSeek Harness: upgrade pre-flight gate, storage-format fingerprinting, $DSH_HOME backup, session migration, per-profile lockfile with rollback, and a machine-readable plugin x DSH compatibility matrix + CI workflow.

Cài đặt

dsh plugin add dsh-compat-guard

Xác nhận layer đã áp bằng dsh --profile default --dump-config — xem hướng dẫn cài plugin.

Mã nguồn

Phát hành lên npm mà không có repository công khai. Hãy kiểm tra nội dung package trước khi cài.

Thẻ

Tác giả

Readme

dsh-compat-guard

兼容性治理插件包:升级前置闸门 + 存储格式指纹 + 自动备份 + 会话迁移 + profile 级锁文件 + 插件×DSH 兼容矩阵。一个 npm 包,六个能力,全部零运行时依赖(纯 Node ≥ 20)。

dsh-guard status            # 当前版本 / dist-tags / 存储指纹 / 锁文件状态
dsh-guard preflight         # 升级前检查(闸门):插件兼容 × 存储格式 × 自动备份
dsh-guard upgrade           # 闸门 + 执行 dsh 升级 + 事后复检
dsh-guard upgrade-plugins   # 闸门 + 更新 profile 插件 + 重写锁文件
dsh-guard snapshot          # 备份 $DSH_HOME + 写入 dsh.guard.lock.json
dsh-guard restore/rollback  # 一键回滚(先自动做安全快照)
dsh-guard verify            # 与提交的锁文件比对(团队漂移检测)
dsh-guard migrate           # 会话数据迁移(sqlite -> zstd JSONL,先备份)
dsh-guard dsh <args...>     # 透传模式:dsh plugin add/update 前自动过闸门

四个缺口的对应设计

缺口 1 — 升级前置检查(闸门)→ preflight

一次 dsh-guard preflight 回答三个问题,任何一个是"破坏性"就 exit 1 拒绝升级(有警告则 exit 2):

  1. 插件兼容:对目标 DSH 版本,逐个已装插件查
    • 兼容矩阵注册表(机器跑出来的 compat.json,缺口 2 的输出)
    • 作者元数据(插件 package.json 里的 dsh.compat.tested/requires
    • 都没有 → untested 警告,不硬拦
  2. 存储格式破坏性变更:对 $DSH_HOME 做指纹(见下),与 lib/formats.json + 注册表里目标版本的事实比对。格式不同 → BLOCKED(这正是 rc.8 会话全丢事故的闸门)。
  3. 自动备份:闸门通过时先拍 $DSH_HOME 快照(tar + sha256 + manifest)。

为什么闸门只能靠 wrapper + 引导期探针,而不是插件树内钩子? 这是读源码后的事实约束:

  • dsh plugin 是 launcher 里的薄 pnpm 转发器(bin.js 的 switch 分支),没有前置钩子——没有任何插件能挂进 pnpm update 之前。
  • 树内插件解析命令行的路也被堵死:dsh-web-appweb-startup无条件调用 parseCmdline,commander 拒绝未知命令,第二个解析行在同 profile 里必然炸掉整个启动树。

所以设计是:

  • 真正的工作在 独立 bin dsh-guard(不 boot 任何 profile,纯文件检查 + spawn)。
  • cordis.patch.yml 里只挂一个被动行guard-drift):每次 boot 记录 dsh 版本到 $DSH_HOME/.guard-state.json,发现版本变了就打印一行"你没过闸门就升级了"的告警。所有逻辑 try/catch,绝不 fail-loud。
  • 日常纪律用别名:alias dsh='dsh-guard dsh'(PowerShell 里包一层 function)。dsh-guard dsh plugin add/update/install 先过闸门再转发真实 dsh

缺口 2 — 自动化兼容矩阵 → compat/

把"作者有空才写文章"变成机器数据,三层:

  1. 元数据契约:插件在 package.json 声明 dsh.compat
    "dsh": {
      "bundle": { "patch": "./cordis.patch.yml" },
      "compat": {
        "requires": ">=0.1.1-rc.1",
        "tested": ["0.1.0-rc.7", "0.1.1-rc.1"],
        "storageFormats": ["zstd-jsonl"],
        "kind": "tooling"
      }
    }
    
  2. CI 矩阵compat/compat-matrix.yml(可复制到任意插件仓库或中央调度仓库)+ compat/report.mjs。每个 job 在全新 profile(隔离 DSH_HOME)里 npm i -g @deepseek-ai/dsh@<ver>dsh plugin --profile ci add <plugin>dsh --profile ci --dump-config(boot 冒烟:树能组装出来就是过了)→ 输出一行 JSON。collector 合并成 compat.json 并提交。
  3. 注册表 + 徽章compat.jsoncompat/schema.json 组织,托管在 Blue-Whale-Harness 的 compat/ 目录 (已推送,2026-08-25 首版含 8/8 实测数据),CDN 源 cdn.jsdelivr.net/gh/Shizuku-keop/Blue-Whale-Harness@main/compat/compat.jsonlib/registry.js 默认,含 raw + GitHub API base64 回退)。徽章用 shields.io dynamic JSON 直接指 CDN 文件。preflight 消费同一份数据—— 货架上的"保质期标签"。

首版实测数据(2026-08-25,compat/local-matrix.ps1,隔离 DSH_HOME + pnpm 11):

插件 \ DSH 0.1.0-rc.7 0.1.0-rc.8 0.1.1-rc.1 0.1.1-rc.2
dsh-better-sidebar 0.15.2 ✅ pass ✅ pass ✅ pass ✅ pass
dsh-mnemon 0.2.16 ✅ pass ✅ pass ✅ pass ✅ pass

注意:矩阵验证的是插件 API 兼容(安装 + mount)。rc.8 的存储格式变更 (社区报告的数据丢失事故)在数据层——注册表 storageFormats 里 rc.8 仍是 unknown,升级闸门靠存储指纹拦截,不依赖插件 pass。

注册表条目示例:

{ "schema": 1, "updated": "2026-08-25T03:00:00Z",
  "plugins": { "dsh-better-sidebar": { "0.1.1-rc.2":
    { "status": "pass", "testedAt": "2026-08-25T03:00:00Z",
      "by": "run 1234", "evidence": "dsh-install:0 plugin-install:0 boot:0" } } },
  "storageFormats": { "0.1.1-rc.2": { "sessionFormat": "zstd-jsonl", "projcacheVersion": 3 } } }

缺口 3 — 会话数据迁移 → migrate

安全优先管线:detect → backup → transform → verify → checkpoint

  • detectLegacy 扫描 $DSH_HOME/sessions/** 的文件头:zstd(28 B5 2F FD)/ sqlite(SQLite format 3)/ gzip / 未知。不知道的格式拒绝转换,只备份——绝不猜。
  • sqlite → zstd JSONL:读用 Node ≥ 22.5 内置 node:sqlite(零原生依赖),写 zstd 帧用外部 zstd CLI 或可选 fzstd;两个都没有就拒绝(裸 .jsonl DSH 读不了)。
  • 原文件在验证通过后才改名 .legacy.bak,新文件先写 .migrating 再原子改名。
  • 诚实边界:每版 DSH 的 session JSONL 记录 schema 必须对照目标版本读文件确认——lib/formats.json 里逐版本登记,没登记就是 unknown(preflight 会因此警告,不会静默放行)。

缺口 4 — profile 级锁文件 → snapshot / verify / rollback

profiles/<name>/dsh.guard.lock.json(随团队仓库提交):

{ "schema": 1, "profile": "web",
  "dsh": { "version": "0.1.1-rc.2", "integrity": "sha256:…" },
  "plugins": { "dsh-better-sidebar": { "version": "0.15.2", "integrity": "sha256:…", "bundle": true } },
  "storage": { "sessionFormat": "zstd-jsonl", "sessionCount": 74, "projcacheVersion": 3 },
  "configHash": { "cordis.patch.yml": "sha256:…", "pnpm-workspace.yaml": "sha256:…", "settings.yaml": "sha256:…" },
  "backup": "backups/2026-08-25T03-00-00-000Z/snapshot.tar" }
  • dsh-guard snapshot:拍快照 + 写锁文件(锁里记录备份路径)。
  • dsh-guard verify:把本机实况与锁文件比对——插件版本、内容完整性、配置 hash、存储格式逐项 diff,输出"你跑得了我跑不了"的具体差异。
  • rollback / restore:解 tar 回写,恢复 pnpm-lock.yaml 后自动 pnpm install --frozen-lockfile;恢复前先做安全快照(永远有回头路)。
  • 快照默认排除凭据文件.credentials.yamlpet.json.gh_*.env),--include-secrets 显式开启——备份是可交给同事的东西,不是泄露源。

关键技术事实(源码核实)

事实 影响
dsh plugin = 薄 pnpm 转发器,launcher 无前置钩子 闸门只能 wrapper/别名 + 引导期探针
dsh-web-app 无条件 parseCmdline,commander 拒绝未知命令 同树内不能有第二个解析命令行的插件 → CLI 必须独立 bin
sessions = session-<uuid>/session.jsonl.zstd(zstd 魔数 28 B5 2F FD,本机实测) 格式指纹 = 魔数扫描,廉价可靠,不用解码
storages/session_projcache.jsonunit.version(本机 = 3) 缓存格式版本号可进指纹,版本变化 = 警告(会重建,非数据丢失)
bundle 插件 = npm 包声明 dsh.bundle.patchmain 导出 {name,inject,apply},loader 取 exports.default 插件包可同时是 CLI + 被动 cordis 行(default 导出插件,命名导出库 API)
$DSH_HOME = $DSH_HOME 环境变量 → ~/.dshdsh-home-paths 源码) 路径解析完全对齐官方
版本号权威来源 = launcher package.jsondsh --version);dist-tags 每周在变 永远运行时解析 next/latest,绝不硬编码(本文档引用的 rc 号已经过时)

安装与使用

# 作为 CLI(不装进 profile 也能用)
npm i -g dsh-compat-guard        # 或 pnpm add -g

# 装进 profile(可选:获得 boot 期漂移探针)
dsh plugin --profile web add dsh-compat-guard

# 日常纪律:把 dsh 包一层
# bash:  alias dsh='dsh-guard dsh'
# pwsh:  function dsh { dsh-guard dsh @args }

已知边界(诚实声明)

  1. 闸门不是强制性的——launcher 没有钩子,纪律靠别名/团队约定;探针只能事后告警。上游要根治需给 dsh plugin 加 pre-hook,本包是社区侧能做的全部。
  2. 注册表已托管:默认指向 Blue-Whale-Harness 的 compat/(jsDelivr CDN,多源回退),lib/registry.jsDEFAULT_REGISTRY_URL 可换;离线时用 $DSH_HOME/.guard-cache/ 缓存并降级为"只警告"。
  3. lib/formats.json 是种子数据:本机只实测过 0.1.1-rc.2(zstd-jsonl / projcache v3)。rc.7/rc.1 的存储布局必须有人实测登记(或等注册表 storageFormats 补上)——未知 = 警告而非静默放行。
  4. 迁移的 JSONL schema 必须对照目标版本读文件确认;工具对未知格式只备份不转换。
  5. verify 的 integrity 是 sha256(插件 package.json)——检测内容漂移够用,不是 npm integrity 的替代。

开发

node --test test/        # 单元测试(node:test,零依赖)
node lib/cli.js status   # 本机实况(只读)
node lib/cli.js preflight --target next   # 对真实 $DSH_HOME 干跑(会备份!)

License

MIT