sandbase-harness
sandbaseai
Local-first, self-hosted AI agent runtime and MCP bridge with sandboxed sessions, memory, credentials, audit/replay, and a local Console.
PROJECT TOPICS
INSTALL REFERENCE
dsh plugin --profile web add github:Shizuku-keop/dsh-compat-guard
该命令指向仓库当前默认分支;尚无绑定当前 commit 的完整验证结果。
PROJECT README
兼容性治理插件包:升级前置闸门 + 存储格式指纹 + 自动备份 + 会话迁移 + 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 前自动过闸门
preflight一次 dsh-guard preflight 回答三个问题,任何一个是"破坏性"就 exit 1 拒绝升级(有警告则 exit 2):
compat.json,缺口 2 的输出)dsh.compat.tested/requires)untested 警告,不硬拦$DSH_HOME 做指纹(见下),与 lib/formats.json + 注册表里目标版本的事实比对。格式不同 → BLOCKED(这正是 rc.8 会话全丢事故的闸门)。$DSH_HOME 快照(tar + sha256 + manifest)。为什么闸门只能靠 wrapper + 引导期探针,而不是插件树内钩子? 这是读源码后的事实约束:
dsh plugin 是 launcher 里的薄 pnpm 转发器(bin.js 的 switch 分支),没有前置钩子——没有任何插件能挂进 pnpm update 之前。dsh-web-app 的 web-startup 行无条件调用 parseCmdline,commander 拒绝未知命令,第二个解析行在同 profile 里必然炸掉整个启动树。所以设计是:
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。compat/把"作者有空才写文章"变成机器数据,三层:
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"
}
}
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 并提交。compat.json 按 compat/schema.json 组织,托管在
Blue-Whale-Harness 的 compat/ 目录
(已推送,2026-08-25 首版含 8/8 实测数据),CDN 源
cdn.jsdelivr.net/gh/Shizuku-keop/Blue-Whale-Harness@main/compat/compat.json
(lib/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 } } }
migrate安全优先管线:detect → backup → transform → verify → checkpoint。
detectLegacy 扫描 $DSH_HOME/sessions/** 的文件头:zstd(28 B5 2F FD)/ sqlite(SQLite format 3)/ gzip / 未知。不知道的格式拒绝转换,只备份——绝不猜。node:sqlite(零原生依赖),写 zstd 帧用外部 zstd CLI 或可选 fzstd;两个都没有就拒绝(裸 .jsonl DSH 读不了)。.legacy.bak,新文件先写 .migrating 再原子改名。lib/formats.json 里逐版本登记,没登记就是 unknown(preflight 会因此警告,不会静默放行)。snapshot / verify / rollbackprofiles/<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.yaml、pet.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.json 带 unit.version(本机 = 3) |
缓存格式版本号可进指纹,版本变化 = 警告(会重建,非数据丢失) |
bundle 插件 = npm 包声明 dsh.bundle.patch,main 导出 {name,inject,apply},loader 取 exports.default |
插件包可同时是 CLI + 被动 cordis 行(default 导出插件,命名导出库 API) |
$DSH_HOME = $DSH_HOME 环境变量 → ~/.dsh(dsh-home-paths 源码) |
路径解析完全对齐官方 |
版本号权威来源 = launcher package.json(dsh --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 }
dsh plugin 加 pre-hook,本包是社区侧能做的全部。lib/registry.js 的 DEFAULT_REGISTRY_URL 可换;离线时用 $DSH_HOME/.guard-cache/ 缓存并降级为"只警告"。lib/formats.json 是种子数据:本机只实测过 0.1.1-rc.2(zstd-jsonl / projcache v3)。rc.7/rc.1 的存储布局必须有人实测登记(或等注册表 storageFormats 补上)——未知 = 警告而非静默放行。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 干跑(会备份!)
MIT
CLASSIFICATION EVIDENCE
系统优先读取 GitHub Topics,再与站内分类词典和词根规则比对。当前命中: backup、cli、lockfile、migration。