DSH-PackForge 规范仓库
DSH-PackForge specs repository
别名:规范仓库、规范与协议仓库、契约仓库、DSH-PackForge/specs
生态里所有契约的定义者:`manifest`(清单)、`pack-structure`(`.dspack` 容器)、`index`(市场索引)、`publishing`(发布流程)、`launcher-registry`(启动器 canonical ID 表)、`workspace-config`(`.dshpkcfg`)六份规范都在 `DSH-PackForge/DSH-PackForge` 这一个仓库里。本站「有争议时以规范为准」指的就是它。
一句话
生态里所有「契约」都写在同一个仓库里:DSH-PackForge/DSH-PackForge 的 specs/ 目录。所以本站说的「有争议时以规范仓库的文件为准」,指的是这一个仓库,而不是某个实现、某个启动器或某个包的现状。
把它们拆成八条词条没有必要——它们同属一个仓库、互相引用:manifest 决定容器里装什么,pack-structure 决定怎么装进去,index 决定市场怎么索引,publishing 决定怎么才会被收录。这一条做总览,需要细节再点进去看。
仓库里有哪些
| 规范 | 管什么 | 状态 |
|---|---|---|
manifest | 清单契约:包里声明什么、字段什么意思 | 现行 v5 |
pack-structure | 容器契约:.dspack 长什么样、文件落到哪 | 现行 v3 |
index | 市场索引契约:index.json 放什么、什么懒加载 | 现行(schemaVersion 2) |
publishing | 发布契约:怎么建仓、怎么发 Release 才会被自动收录 | 现行 v1 |
launcher-registry | 启动器 canonical ID 认领表 + 版本比较规则 | 现行 |
workspace-config | .dshpkcfg:导出工作区快照的本地文件格式 | 现行 v1 |
manifest/v1–v4、pack-structure/v1–v2 | 历史版本,读旧包时用 | 历史 |
六份现行规范各自的外链:manifest v5 · pack-structure v3 · index · publishing v1 · launcher-registry · workspace-config v1
清单契约:manifest v5
(原先单独成条的 manifest v5,按评审并进这里。)
manifest v5 是 .dspack 的清单头契约,也是「一切字段争议的最终裁判」:有争议时以规范仓库的文件为准,而不是以某个包的现状或某个启动器的实现为准。
一句话概括 v5 相对 v4 的变化:v4 只会描述「一个 profile」,v5 用 type 同时描述「一个 profile」和「一整个 $DSH_HOME」。
type: "profile" | type: "dshhome" | |
|---|---|---|
| 是什么 | 单 profile 的层栈(即 v4 契约) | 整个 $DSH_HOME 快照 |
| 必需字段 | bundles、dependencies | defaultProfile、profiles |
| 可选字段 | profileName、patch、files | presets、skills、instructions、files |
| 承载容器 | .dspack v3(overrides/ → profile 根,可选 home/ → home 根) | .dspack v3(overrides/ → $DSH_HOME 根) |
两条容易踩的:
"collection"仍然预留、校验器直接拒绝——看到type: "collection"的包,它不是新形态,是无效包;- dshhome 的范围是硬约束:明确排除
~/.agents(另一个共享 agent 配置根),也排除项目级内容(项目根下的.dsh/、.agents/、AGENTS.md/CLAUDE.md跟随 cwd,不随包分发); profiles只含用户自定义 profile,不得含web/headless——这两个是 DSH 安装自带的模板,由dshVersion决定、不进包,校验器会拒。
r2 追加的两组可选字段
dshVersions:枚举,不是 range。 它是作者实测过的兼容版本枚举集(string[])。规范不用 semver range 的理由是:range 会诱导声明未实测的未来版本,而 DSH 版本带 rc 后缀、range 比较易错。安装决策是确定性的:dshVersions ∩ 本机已装 非空 → 命中多个时优先 dshVersion 指定者、其次集合内最新;交集为空 → 按 dshVersion 提示安装;两者全缺省 → 本机最新已装。老消费者只读 dshVersion,行为不变。
launchers:提示机制,不是门禁。 简式与全式语义等价(归一化后只剩全式);全式锁定三个字段:supported(唯一权威判定位)、minVersion(语义是「≥」,不精确钉死——启动器会自动更新)、reason(supported:false 时的理由)。未列出的 ID = 未声明(第三态),不等于「不支持」;判定核心是警告放行、不硬拒,且放行要在安装日志留痕。
导入时按什么顺序决策
两形态共有的前置是两步:启动器判定(警告放行)与 DSH 版本决策(上面的交集规则)。之后 profile 形态走「建实例 → overrides/ 落 profile 根 → pnpm install → 重建 profile → 可选 home/ 落 $DSH_HOME 根」;dshhome 形态要先确保 dshVersion 的 DSH 已安装(未装直接报错),再逐 profile 各自安装,最后设 defaultProfile。files[] / skills[] 下载校验失败会整体回滚。
读旧包的正确姿势
| 你看到的 | 该怎么办 |
|---|---|
manifestVersion: 4 的包 | 按 v4 的规则读它,别拿 v5 判它。v4 没有 launchers 字段,也没有 dshhome 形态 |
manifestVersion: 5 但没有 dshVersions | 正常。缺省视同 [dshVersion],老消费者本来就只读这个 |
type: "collection" | 无效包,校验器拒绝 |
「按声明的版本读」不是洁癖:市场里实测有包声明 manifestVersion: 4(快照 2026-09-30),它的 manifest 里连 launchers 字段都不存在——这不是它「拒绝了所有启动器」,而是那个版本根本没有这个字段。同样地,市场里 8 个包只有 2 个写了 launchers(一个全式、一个简式),其余 6 个一个都没写——所以「没写」是常态,不是不支持。
容器契约:pack-structure v3
.dspack = 纯 ZIP 内核 + 根 dspack.json({"format":"dspack","version":3})标记,同一个容器承载两种形态:
type: "profile" | type: "dshhome" | |
|---|---|---|
| 装的是 | 单个 profile 的层栈 | 整个 $DSH_HOME 快照 |
overrides/ 落到 | $DSH_HOME/profiles/<name>/ | $DSH_HOME/(按相对路径平铺) |
home/(可选) | 落到 $DSH_HOME/(上一级目录) | 不用(overrides/ 本身就是 home 根) |
加载器判定四步:能当 ZIP 打开 → 有根 dspack.json → format/version 对 → 再按 manifest 的 type 分形态。overrides/ 与 home/ 的语义是文件级复制替换,不是字段级合并——真正的合并式覆盖由 cordis.patch.yml(concept/1)承担。
home/ 的存在理由值得单独说:skill 与 agent preset 在 DSH 里是 home 级(profile 目录的上一级,见 concept/3),v2 的容器装不进它们,只能升级成整个 dshhome 快照;v3 让「单 profile 包顺带带几个全局单元」成为可能。
安全过滤:打包时排除凭据与运行时状态(.credentials.yaml、.anonymous-user-id、attachments/、settings.yaml、skills/.system/,以及 dshhome 形态下的 profiles/web/、profiles/headless/)。重内容(大文件、重技能)不进包体,走 files[] / skills[] 下载,按 sha256 + size 校验,任一失败整体回滚。
市场索引:index
「精简指针制」两段式——索引文件只放列表、搜索、安装命令必需的字段(下载三要素 downloadUrl + sha256 + size,加上展示元数据与计数),不含 bundles[] / dependencies{} / profiles / presets / skills 这些可能很大的字段;完整 manifest 与源仓库 README 拆到 packs/<owner>.<repo>/,点开详情时懒加载。它是本站整合包分区的数据上游。
发布契约:publishing v1
目标是零人工登记:作者只要按规范建仓 + 发 Release,采集器就能自动发现并收录,不用向任何地方提 PR。三个「必需」:
- 仓库公开(采集器读不到私有仓库);
- 打主题标签
dsh-pack(这是全网唯一的发现入口,没打就永远扫不到); - 默认分支根部放
manifest.json。
Release 是默认下载来源,配 sha256 侧车文件;也可以用 downloadUrl 直链替代。进索引的下载三要素就是 downloadUrl + sha256 + size。
启动器注册表:launcher-registry
manifest v5 的 launchers 字段引用的 canonical ID 认领表(安装端判定见 pack-structure §9.1),当前 5 条:
| ID | 是谁 |
|---|---|
dshl | PCL-Deepseek-Harness-Launcher(PCL2 魔改) |
hdsl | HDSL · Hello DeepSeek Launcher(HMCL 内核 JavaFX) |
dsh-packforge-app | DSH PackForge GUI / dspack CLI |
official-desktop | DeepSeek Harness 官方桌面端 |
dsh-cli | 裸 dsh 命令行(无启动器) |
⚠️ 别混淆:
dshl(PCL 系)与hdsl(Hello 系)只差一个字母、完全无关——本站启动器分区里这两条也各是各的。
版本比较规则:按 . 分段、逐段数值比较、缺段视为 0,不做 rc 之类预发布语义;启动器要自报版本号。不满足 minVersion 只提示、不硬拒。
工作区配置:workspace-config v1(.dshpkcfg)
PackForge 桌面端在导出流程里持久化的「导出工作区快照」——保存整合包名、版本、作者、内容开关、输出目录等,下次点「读取」恢复。它是工具本地文件、不进入整合包(打包时命中安全过滤清单被排除);一个目录一份,形态由所在目录区分(文件内没有 kind 字段)。
历史版本
manifest 有 v1–v4、pack-structure 有 v1–v2,都保留在仓库里可读——读它们不是为了守着旧写法,而是为了两件事:
- 读旧包:市场里实测仍有包声明
manifestVersion: 4(甚至.tgz时代的包)。读旧包要按它声明的版本去读对应文件,别拿 v5 的规则去判它。 - 理解字段怎么长出来的:v5 的
type/dshhome形态、v3 的home/,都是前面几版长出问题的答案。
本站怎么用它
- 词条里凡是写「以规范为准」的地方,指的都是这个仓库的对应文件;
- 分区页把每份规范按「现行 / 历史」列出来,外链直达仓库里的文件;
- 规范要改,就向该仓库提 PR——不要在实现里私自分叉,这是这一层存在的意义。
未核实
- 本页按公开 URL 逐份读到
specs/下 12 个文件,没有本机 checkout 副本对照; - 「发布契约」与「市场索引」描述的是规范要求,不是「采集器当前实现完全符合」的实测结论;
- 上游最后一次提交是 2026-10-01(快照日),此后若有改动,以仓库里的文件为准。
谁引用了这一条
信息表
- category
- ecosystem.spec
- maintainers
- hxh230802
- repo
- DSH-PackForge/DSH-PackForge
- titleEn
- DSH-PackForge specs repository
- updatedAt
- 2026-10-02
- url
- https://github.com/DSH-PackForge/DSH-PackForge
被 2 条词条引用