Back to home

hili986

dshpack

把一个 dsh 场景导出成可安装、可分享、可审计的 pack,再把 pack 装成标准 dsh profile

Stars
0
Language
TypeScript
Created
Aug 16, 2026
Updated
Aug 16, 2026

Introduction

dshpack

把一个 dsh 场景——skills、MCP、profile patch、权限默认值——导出成一个可安装、可分享、可审计的 pack,再把 pack 装成标准的 dsh profile。

当前状态:M0,预发布,尚未发布到 npm。 pack 格式与 CLI 参数都还不是稳定 API。initpack 两个作者向命令仍未实现。

它不做什么

  • 不分发、不代理、不 fork @deepseek-ai/dsh
  • 不修改 dsh 上游仓库,也不碰你真实的 ~/.dsh(所有操作都要求显式的 DSH_HOME);
  • 不把第三方 install/build script 当可信代码执行;
  • 不热更新正在运行的 dsh 进程;
  • 不把 preset 合进已有内容的 session,也不替你解决 session 迁移冲突。

安装前你会看到什么

install 在写任何东西之前先给出完整计划。下面是真实输出,对 dsh-packs/web-dev--dry-run 得到:

Will install web-dev@0.1.0 as web-dev
SOURCE: {"kind":"directory","path":"...\dsh-packs\web-dev"}
dsh: current=0.1.0-rc.6 tested=0.1.0-rc.6 mismatch=false
pnpm: current=11.7.0
asset skills/frontend-review -> skills/frontend-review action=create collision=false [热生效]
MCP context7: https://mcp.context7.com/mcp -> profile patch action=configure [重启生效]
default permissionPreset=workspace-write [仅空白会话]
write profiles/web-dev [重启生效]
write profiles/web-dev/cordis.patch.yml [重启生效]
write skills/frontend-review [热生效]
write .dshpack/installed/web-dev.json [热生效]
side-effect profiles/web-dev/cordis.yml: dsh --dump-config(E9)
rollback snapshot: enabled=true state=sha256-bSGmM1FiexZIOjjfdgjsYA14kw8egAI8O58sWTaWVro

每一行都带生效时机标签,因为这是 dsh 最容易踩的坑:skills 热生效,插件与 MCP 要重启新进程,preset 只对空白新 session 有意义。计划里还单列了 side-effect——那一行不是我们写的,是 dsh 自己在 dump 时重写 cordis.yml,我们只是触发方,但仍然要告诉你。

--dry-run 期间对 DSH_HOME 的写入数为 0

Quickstart

corepack enable pnpm
corepack prepare pnpm@11.7.0 --activate
pnpm install --frozen-lockfile
pnpm build

# 只读校验一个本地 pack(不调用 dsh,零写入)
node packages/cli/dist/bin.js validate --strict <pack-dir>

# 看安装计划,不写任何东西
node packages/cli/dist/bin.js install --dry-run --as demo --dsh-home <隔离目录> -- <pack-dir>

始终传一个隔离的 --dsh-home,不要拿你真实的 dsh 目录当试验场。

安全模型

这些不是承诺,是有测试锁住、且每条都有能让它转红的 mutant 的行为:

来源必须可复现。 GitHub 源只接受 40 位小写 commit SHA——分支名、tag、短 SHA、甚至 40 位但含大写,一律 exit 20 且在任何子进程启动前就拒绝。HTTPS tarball 必须带 sha512 SRI,URL 不得含 userinfo。

--yes 不能替代危险确认。 它只能省掉那句"确定要装吗"。逐包的 --allow-builddanger-full-access 都仍需各自的显式授权;--replace(覆盖已有 profile)和 --allow-unverified 更是硬门——前者不给就不会发生,后者不给直接失败,都不走"提示一下"这条路。任何交互提示的默认值都是拒绝;非 TTY 环境下缺确认会 exit 21 并打印完整的非交互命令,不会把 CI 卡死。

build script 默认全禁。 依赖的 install/lifecycle script 只有在 pack 的 allowBuilds逐个精确包名列出、且你在安装时逐项授权后才会执行。父包、scope、或某个已授权的依赖,都不会把权限隐式传递出去。这是一份允许名单,不是 sandbox——放行一个 build script 等于允许该依赖以你的用户权限执行代码,所以它应该保持为空。

凭据不外泄,也不"悄悄删掉"。 export 在收集前、写入前、写入后各扫一次,命中直接 exit 31 失败——不会替你删掉再给一个看起来干净、实则不可审计的 pack。诊断只给 path:line:column绝不回显命中的值。扫描分五层:敏感键名、已知 token 形状(含 GitHub / npm / AWS / Google / Stripe / Slack / OpenAI 前缀)、Bearer|Basic、URL userinfo,以及基于 Shannon 熵的未知格式兜底。

一个刻意的取舍:32/40 位十六进制串与 UUID 被判为凭据。它们与 pack 强制要求的 40 位 commit SHA、校验和、以及各种合法 id 完全同形,纳入检测会让每个 pinned source 都误报。所以残余暴露面可以精确表述为:凭据要同时"存放在非敏感键名下""形状与合法标识符碰撞"才可能漏。

装坏了能退回去。 install 是一个带 journal 的事务。任一步失败都会回滚:新 profile 移进 $DSH_HOME/.dshpack/backups/<txid>/不删除),--replace 场景把原 profile 原样 rename 回去,skills/presets 只清理本次事务创建的项,settings 用保存的原文原子恢复。

退出码

含义
0成功
2用法 / schema
10环境(Node / pnpm / dsh 不可用)
20source、网络、完整性
21用户拒绝,或非交互环境缺少确认
22profile 冲突或锁
23dsh 子进程失败
24装后验证失败,但已干净回滚 —— 机器状态等同安装前,重试是安全的
25需人工恢复 —— 机器停在中间态,不要盲目重试,先按打印的恢复路径处理
30契约(patch / skill / settings / profile)
31安全(路径 / 凭据)
70内部错误

24 和 25 必须分开:自动化拿到退出码就要决定要不要重试,而这两种结局要求的响应恰好相反。JSON 输出里的 status 也区分(rolled-back / rollback-failed),但不该要求调用方解析 stdout 才知道能不能重试。

命令

命令作用副作用
validate <source>校验 pack 格式、来源、完整性、凭据零写入,且不调用 dsh
install <source>按计划以可回滚事务安装见上方计划输出
list列出 tracked / untracked / broken profiles只读
switch <profile>校验并打印启动命令默认不 spawn、不改 session;只有 --run 才前台启动 dsh
lock [dir]为手写 pack 生成/更新 pack.lock.yml只写该目录,产物确定且幂等
doctor诊断环境与配置边界会写,见下
export把 profile 导出成本地 packdsh dump 会写 profile/cordis.yml
init / pack作者向未实现

doctor 的副作用要说清楚,因为它容易被误以为只读:走 --dump-* 的检查项会让 dsh 重写 profile/cordis.yml(不是我们写的,但由我们触发),而 dshpack 自己会在 $DSH_HOME/.dshpack/logs/ 写审计日志。--jsonsideEffects 字段把两者都列出来并标注归属:

[
  { "owner": "dsh",     "path": "profile/cordis.yml" },
  { "owner": "dshpack", "path": ".dshpack/logs/<file>" }
]

全命令支持 --dsh-home--no-color--quiet--json。JSON 模式下 stdout 只有一个 object,进度走 stderr。

pack 目录长什么样

pack 目录里的文件分三类,各有各的待遇:

类别成员布局校验会被部署进 lock过凭据扫描
pack 语义文件pack.ymlpack.lock.ymlskills/patch/settings/未知项拒绝
仓库常规物README*LICENSE*.gitignore.github/CHANGELOG*允许
完全忽略.git/node_modules/不遍历

第二类允许但不部署,然而照样要过凭据扫描——README 里贴了 token 是真实且常见的事故。第三类是根本不进去,不是"进去了再忽略"。

pack.lock.yml 是必需的,且应当提交进 git。手写的 pack 用 dshpack lock 生成。

JSON Schema 随 @dshpack/core 一起发布,可以直接 resolve:

import schema from '@dshpack/core/schemas/pack.schema.json' with { type: 'json' };

它由 TypeBox 真源生成,发布前会解包 tarball 逐字节比对——schema 必须在包里,且必须与真源一致,两个方向都有断言。

Starter packs

两个示例 pack 在 dsh-packs org:web-dev(四个前端 skills + 零凭据的 context7 文档检索 MCP)与 research-writing(五个研究写作 skills,刻意不连任何 MCP)。

两者都在 Windows 原生WSL2 Ubuntu 24.04 原生 ext4 上做过端到端认证:install → 新 dsh 进程 --dump-config 行全命中 → doctor --strict 全部 exit 0。矩阵与全部原始 stdout/stderr/exit code 见 docs/starter-pack-certification.md。两个 pack 都不声明 allowBuilds——即没有任何 build script 被授权。安装它们时若出现要求授权 build script 的提示,说明来源不对,请中止。

research-writing 不连 MCP 是设计决定,不是没做完:研究场景处理的是未发表稿件与他人版权材料,任何 MCP 都意味着内容离开你的机器。真实 dump 里已验证它零 MCP 配置。

你需要知道的限制

  1. 插件与 MCP 变更需要新的 dsh 进程,不会热加载。skills 是热生效的。
  2. agent preset 只对空白新 session 生效,不会补写或合并已有 session。M0 的两个 starter pack 都不带 preset。
  3. skills 是提示词内容,不是校验器citation-verification 告诉你怎么核实引用,但不会替你去核。
  4. pack 格式在 M0 不是稳定 API

平台

组件版本状态
Node.js>=22.19.0 <25CI 用 22.19.0;真机实测覆盖 22.19.0 与 24.13.1
pnpm11.7.0Corepack 固定
dsh0.1.0-rc.6契约 smoke 使用;非产品依赖承诺
Windows原生阻塞 CI + 真机认证
UbuntuGitHub runner + WSL2 24.04阻塞 CI + 真机认证

Windows 上开发命令应在 PowerShell 里直接可用,不依赖 Bash 专属语法、符号链接权限或大小写敏感路径。升级固定版本须走独立 PR,同步更新配置、lockfile、CI、本表与 ADR-0002

故障排查

  • init / pack 返回 70:这两个作者向命令尚未实现。
  • exit 10 E_PROBEdshpnpm 不在 PATH 上。注意 Windows 上可能同时存在无扩展名的 dshdsh.CMD
  • exit 25:不要重试。先按输出里的人工恢复路径处理,机器处于中间态。
  • 装完插件但 dsh 没变化:插件变更不热加载,必须完全退出并启动新的 dsh 进程。
  • pnpm install --frozen-lockfile 失败:不要手改 lockfile,确认 Node/pnpm 固定版本后在依赖变更 PR 中重新生成。

报 issue 请给脱敏后的命令、版本、OS 和最小复现;不要上传 token、真实 .dsh 或会话内容

贡献与安全

开发流程与验证命令见 CONTRIBUTING.md。漏洞请走 SECURITY.md 的私密渠道,不要开公开 issue。

MIT License