Skip to content

Releases

v0.13.0

Choose a tag to compare

@github-actions github-actions released this 09 Oct 04:53
38808cf

升级须知

  • remote sync、pull、adopt、remote add 被中断(进程被杀、恢复失败)后,plan、status、apply、pull、adopt、remote add/sync/remove 以退出码 3 拒绝,并给出 dshenv rollback <快照 id> --yes;apply 被中断只警告,重跑 apply 后消失。
  • profiles/<名字>/ 已存在但 package.json 缺失、损坏或缺 dsh.profile 时,该 Profile 的计划为 BLOCKED,不再当作新建。
  • 团队 lock 只能包含团队 manifest(或团队 overlay)声明的插件;团队仓库限 1 万个文件、单文件 10MB、总计 100MB。
  • 不带 -p 的 source clone/sync 不能再指向 envctl/sources 下的托管克隆。
  • 新快照带递增序号,rollback 与 gc 按序号排新旧,不再受时钟回拨影响;旧快照视为比所有新快照更早。

新增

  • remote add / remote sync 新增 --expect <commit>:要接受的 commit 不是它时以退出码 3 拒绝;预览末尾给出带 --expect 的命令。

修复

  • apply 失败回滚不再删除已存在的 Profile 目录(package.json 损坏时曾连同 sessions 一起删除)。
  • 恢复软链接的 skills 目录时按真实路径解析链接目标;envctl 本身是软链接、skills 是相对链接时,rollback 曾删掉旁边同名的无关目录。
  • 两个 migrate --to 同一空目录不再删掉先完成的那份 envctl;目标只在为空时原子替换,staging 名带随机后缀,中断后重跑可以续做。
  • purge 对克隆目录及其父目录取真实路径校验,中间层软链接不能再把 envctl 外的仓库移进 trash。
  • gc 删除快照前先改名为隐藏目录,中途被杀不会留下能被 rollback 选中的半份快照;gc 也清理 DSH skills 目录里残留的 .tmp-*。
  • dsh plugin add 装好但以非 0 退出的插件,失败的 apply 也记录归属,之后可以照常卸载。
  • skill 的临时目录改为 .tmp- 开头,被杀后不再被当成新 skill;跨设备移动 skill 时先复制到临时目录再改名,不会只删掉一半。
  • apply 的撤销步骤失败时写进错误信息与 journal;中断时已提交的 apply 先说明已完成再退出;Ctrl-C 也会立即停止 DSH 版本探测与 --dump-config。
  • pull 写入开始/结束记录,pull、adopt 恢复失败时写明原因并给出快照 id;adopt 的归属检查与随后的 pull 在同一把锁内,写入前建快照。
  • 环境锁:不接管另一个 pid 命名空间的锁;释放前核对内容;修正刚释放的锁文件 inode 被复用时把新持有者的锁当成陈旧锁删除的竞争;写锁失败时删除空锁文件;残留的 reclaim 目录超过 5 秒自动清除。
  • Profile 锁在 dshenv 退出时释放,包括第二次 Ctrl-C;快照与 journal 写入后 fsync;rollback 恢复 skills 先复制到临时目录再替换,中途失败的报错给出 pre-rollback 快照 id。
  • 读 DSH 目录时跳过 FIFO 等非普通文件,不再永久挂起;悬空软链接目标拒绝写入;root 运行时保留被覆盖文件的属主。
  • 团队仓库改为 git cat-file --batch 一次读取;overlay use 写选择文件时持环境锁。

v0.12.1

Choose a tag to compare

@github-actions github-actions released this 09 Oct 03:29
6bcfec5

修复

  • 同一进程内并发获取环境锁时,后到者可能把刚创建、还没登记的锁误判为前一次运行留下的锁并删掉,两方同时持锁,其中一方的清单改动丢失。现在锁在创建成功的同时登记,并按每次持锁唯一的内容识别。

v0.12.0

Choose a tag to compare

@github-actions github-actions released this 09 Oct 02:59
1185a48

升级须知

  • rollback <id> 只接受完整快照 id 或完整 operation id,不再按任意 - 后缀匹配;rollback '' 报错而不是恢复最新快照。
  • envctl 目录不能是 DSH home 本身,也不能位于 <home>/profiles、<home>/skills 之内;已这样配置的需先把目录移走。
  • config set / tools config set 的值以 { / [ 开头却不是合法 JSON 时报错,作字符串写入要加引号('"[WIP] x"');超出安全整数或非有限的数字同样拒绝。
  • overlay 名不能以 . 或 - 开头;--as 不能以 . 或 - 开头、不能含 / 或 \;profile 名限 100 字符,npm 包名按 npm 规则限 214 字符。

修复

  • scp 形式(user:pass@host:path)的 git URL 也按内嵌凭据拒绝;URL 带 ?token= 时报错不再回显 token。
  • 拒绝 ext:: 等 <transport>:: git URL,所有 git 调用限定 GIT_ALLOW_PROTOCOL=file:git:http:https:ssh。
  • git ref 与 remote 分支名按 git check-ref-format 主要规则校验,空 ref 在克隆前拒绝;a#b#c 这种多个 # 的 spec 报错。
  • install 遇到损坏的 lock 不再在写入 manifest 后报失败;update 在 lock 损坏时不改 manifest。
  • 显式传入的空参数(--as ''、--ref ''、capture -o ''、status ''、adopt ''、--harness-source '')报错,不再当作没传;file: 空路径报错。
  • web start --port 拒绝 fetch 不会连接的端口;web stop -p 写错 profile 名时报错并提示相近名;pull -p、capture -p 同样提示相近名。
  • source clone 认 git+ 前缀,--as/--package/--new-profile 没给 --profile 时报错,--package 在克隆前校验;source show 目录不存在时报错。
  • --json 下 config set 不再往 stderr 写纯文本警告;tools config unset 与 config unset 统一校验配置路径。

v0.11.0

Choose a tag to compare

@github-actions github-actions released this 09 Oct 02:19
929a4f9

升级须知

  • source sync(旧名 source pull)改为不带 --yes 只预览,与 remote sync 一致:脚本里直接移动检出和 lock 的调用要加 --yes。
  • 本地插件与 skill 的源码摘要改为带长度边界和类型标记的新格式,lock/state 里的旧摘要不再兼容。升级后首次 plan 会为本地插件列出一次 update,apply 成功后写入新摘要。请在 DSH 里修改 skill 之前先执行一次 apply --yes 重建 skill 基线;否则只在 DSH 改过的 skill 会被 plan 报为清单改动,pull 报双侧冲突,需要用 --prefer 指定保留哪一侧。回滚到升级前的快照同理,其中的 skill 基线失效,原有 skill 按未管理处理。
  • 新快照会保存单个软链接 skill 目录的实际内容;恢复时该 skill 变为独立目录,不改写外部链接目标。旧快照只有链接的内容无法追溯补齐。

新增

  • source sync 新增 --dry-run / --yes:不带 --yes 时 fetch 后预览检出与 lock 会移到哪个 commit,有变化时退出码 2,不移动任何东西。
  • verify --timeout <秒>:插件还在热加载时继续查询,最多等这么久,与 apply --verify-timeout 相同;默认只查一次。
  • dshenv plugins official 列出已安装的 DSH 自带的官方 bundle(默认关闭、在 Profile 里选中才加载的那些,随 DSH 版本变化),标出清单在哪些 Profile 声明了它们,并给出 install in-box: 命令;--json 输出 dshVersion 与 bundles。
  • Profile 还不存在、名字是 DSH 的模板 Profile(acp、headless、sdk、sdk-minimal、web)时,apply 先让 DSH 按自己的模板创建它(dsh --profile <名字> --dump-config),再写 bundle 与补丁。此前只声明官方 bundle 或补丁的新 Profile 一律 blocked,因为只有安装 npm 插件才会创建 Profile。预览在 Profiles DSH creates from its own template first 下列出,plan --json 新增 createdProfiles。
  • doctor 注明数据目录来自 --envctl-dir、DSHENV_HOME 还是默认位置,--json 新增 paths.managerDirSource。
  • 管理全局补丁 $DSH_HOME/cordis.patch.yml:清单与 overlay 新增顶层 patches:,apply 写进该文件的受管块,pull(不带 --profile 时)收回手写的条目,plan 列出未纳管的全局条目,并提示被全局条目覆盖、实际不生效的 Profile 条目。--profile 不涉及全局文件,但仍提示全局条目对该 Profile 的覆盖;覆盖按字段比较,全局条目写了 disabled 的 id 单独注明(DSH 插件页启停不了它);plan --json 新增 homePatchOperations、unmanagedHomePatches、shadowedPatches(项里的 disabled 列出这类 id)。
  • dshenv 数据目录可以放在 DSH 主目录之外:--envctl-dir <path> 或环境变量 DSHENV_HOME 指定,默认仍是 <DSH 主目录>/envctl。DSH 不读这个目录,无需改动 DSH。
  • dshenv migrate --to <dir> --yes 把现有数据目录搬到新位置:
    • 先复制并核对,再在持有环境锁时先写下记着新位置的 dshenv.moved,然后清空旧目录(先删 manifest.yaml、lock.json、state.json)。之后在旧位置运行的命令——包括搬迁时正在等锁的——以退出码 3 拒绝并给出新位置,不会在旧位置悄悄建出新环境;清空中途失败时旧位置也已有标记。
    • 软链接形式的数据目录按内容复制,链接与目标都保留,只在目标里写 dshenv.moved;路径结尾带分隔符时同样按软链接处理。
    • 不是 dshenv 数据目录(没有 manifest.yaml、lock.json、state.json)的不搬;再次对旧位置运行会说明已移到哪里,也可以把数据目录移回原处。
    • 清单、overlay、lock 与 backups/ 快照(含 existing-overlays/)中指向旧数据目录内部的路径改写为新位置;读不了的快照原样保留并列出。之后 plan / apply --yes 让 DSH 按新路径重装对应插件。
    • 数据目录与 DSH 主目录在不同文件系统上时,skill 移入 trash 改为复制后删除。
  • init 持环境锁执行。
  • 明文密钥检查:补丁里凭据类的键名(以 apiKey、secret、secretKey、privateKey、accessKey、password、token、Authorization、credentials 结尾,或以 PAT 结尾,如 OPENAI_API_KEY、clientSecret、AWS_SECRET_ACCESS_KEY、GH_PAT;以 Env 结尾的如 apiKeyEnv 除外,maxTokens、max_token 这类计数也不算)下的非空字符串,password 类键下的数字,任何键下带密码或 token 的 URL(如 postgres://u:pw@host/db),以及 MCP 客户端行(@deepseek-ai/dsh-mcp-client)headers 里的全部值;它的 env 按键名判断。输出只给出 目标 / 条目 / 键路径,从不打印值;判断"新的"明文按值比较,清单里已有的同一个值不算新。
    • pull 不收含新明文的条目,把它们留在 cordis.patch.yml 里、放到 dshenv 受管块之后(它可能覆盖块里条目插入的行),同一 Profile 的其他条目照常同步。新明文写进了 dshenv 受管块时,这个目标的补丁不收,apply 也被阻断,直到在 DSH 里改成 *Env 写法;--prefer skip 时它算作跳过。清单里已有的明文旁边改了别的字段,照常收回。
    • config set、tools config set 等写清单或 overlay 的命令拒绝写入新的明文值(退出码 3),包括替换已有的明文值。
    • plan、status、doctor 在清单或 overlay 已有明文时在 stderr 警告,不影响退出码。
    • 团队仓库的清单或 overlay 含明文时,remote add / sync 拒绝。
  • apply 先用 dsh --dump-config 在临时的 DSH 主目录副本里组合一遍要写入的 Profile 补丁与全局补丁:预览列出 DSH 会因为 id 匹配不到(或 name 不符)而跳过的条目。apply --yes 只在两种情况下停下、不做任何改动:Profile 条目的 id 现在在任何一层都匹配得到、写入后却匹配不到;全局条目的 id 在每个已有 Profile 里都没有对应的行。已经匹配不到的 id(例如 0.2 起移进 preset 的 time-context)换层也照常放行;本次 apply 要装、启用、停用或卸载插件的 Profile 不检查,因为它的行要等插件步骤之后才确定。预览的 --json 新增 patchTargets。
  • 全局补丁有变化时,apply 探测每个已有 Profile 的热重载状态,热重载关闭的列为需要重启。
  • status 与 doctor 报告 DSH 加载时跳过的 bundle(dsh: skipping profile bundle …),status 因此为 degraded(退出码 5)。status 只在 DSH 版本通过门禁时才运行 --dump-config,DSH 每次运行它都会重写 Profile 的 cordis.yml。status 还列出各 Profile compatibility.json 里 DSH 认可的版本豁免(不合规的记录在 stderr 警告),它们绑定精确的 DSH 版本,不进清单;以及清单仍启用的退役 bundle。给出插件时只列与它有关的项。status --json 新增 skippedBundles、versionExemptions、retiredBundles。
  • pull --prefer skip:两边都改过的补丁目标(一个 Profile 或全局层)和 skill 原样跳过,基线不动,下次 pull 仍报告,其余照常收进清单。有跳过时退出码为 6,--json 的 skipped 列出它们。
  • 清单声明并启用了已退役的 bundle(@deepseek-ai/dsh-experimental-schedule-bundle,DSH 0.2.1-alpha.1 退役)时,plan 警告并给出 remove 命令(别名只在 overlay 里声明时带 --layer overlay):DSH 0.2.1 每次加载都会把它从 Profile 删掉,它会一直显示为漂移。plan --json 新增 retiredBundles。

变更

  • 声明 DSH 官方 bundle 时(install in-box:、capture),默认别名去掉 dsh-experimental- 前缀和 -profile、-bundle 后缀,如 agent-team、voice-input;已有的别名不变。

  • 用旧名 source pull 时在 stderr 提醒它就是 source sync,方向与 dshenv pull 相反。

  • 帮助文字:self-update 说明它直接执行、不需要 --yes;overlay use --none 与 --no-overlay 互相说明区别;plan 提示用 status <alias> 看单个插件。

  • 清单与 overlay 允许 ${...}:DSH 不做插值,按原文读取。此前一律拒绝,含 ${ 的配置(如提示词模板)所在的整个 Profile 都无法用 pull 收回,config set 也不会抄 DSH 组合出的配置。

  • 版本门禁放行 DSH 0.2.1 版本族:冒烟(scripts/smoke-dsh.sh)默认改用 DSH 官方 bundle @deepseek-ai/dsh-experimental-agent-team-profile,它的版本跟随 DSH,0.1.7-rc.2、0.2.0-rc.2、0.2.1-alpha.1 都不带豁免 13 步全部通过;compat 矩阵把 0.2.1-alpha.1 列为必须通过。第三方插件是否支持 0.2.1 仍看它自己的 peer 范围(如 @nanmicoder/dsh-agent-teams@0.1.22 只到 0.2.0-rc.2,DSH 会拒装)。dshenv new 生成的 peer 范围加上 >=0.2.1-0 <0.3.0-0,否则按 npm 默认语义 0.2.1-alpha.1 不匹配。

  • 版本门禁放行 DSH 0.2.0 版本族(npm 0.2.0-rc.2 冒烟全部通过),0.1.7 照常放行。dshenv new 生成的插件 peer 范围改为 >=0.1.7-0 <0.2.0-0 || >=0.2.0-0 <0.3.0-0,可以装进 DSH 0.2(按 npm 的预发布版规则,每个 minor 单写一段,0.2.0-rc.2 才能匹配)。兼容性冒烟的默认插件改为 @nanmicoder/dsh-agent-teams@0.1.22。

  • 数据目录本身或其中任何顶层条目(文件或目录)是软链接时,命令以退出码 3 拒绝,并提示改用 DSHENV_HOME 与 migrate。此前用软链接把它们放到别处的环境,升级后先运行 dshenv migrate --to <新位置> --yes,再把 export DSHENV_HOME=<新位置> 写进 shell 配置、CI 与容器环境;输出里有 rewrote 时再 dshenv apply --yes,让 DSH 按新路径重装本地插件。

修复

  • source sync -p 从读取清单、检查团队所有权到更新 Git 与 lock 全程持有环境锁,损坏的 lock 在改源码之前拒绝;提交校验或 lock 写入失败时恢复原提交和分支,如期间出现外部修改则保留并报告恢复失败。
  • 源码摘要明确分隔文件路径、内容、类型和可执行标记,避免不同文件树因拼接结果相同而漏报变化。
  • 单个 skill 目录为软链接时,快照不再随外部目录的修改或删除而改变;技能内部的软链接仍按原样保存。
  • pull 把 insert 行里以 ./、../ 开头的插件名视为本机路径,收进本机 overlay:DSH 按补丁文件所在目录解析它,换一台机器或换一层(Profile 层 / 全局层)就指向别处。此前它进了团队共享的 base 清单。
  • 停用的插件不再在 cordis.patch.yml 里留着补丁块:DSH 不加载停用的插件,它的补丁每次启动都报 entry not found,plan 却显示已同步。补丁仍保留在清单里,重新启用后 apply 写回。(升级后第一次 plan 会为带补丁的停用插件列出一次 configure。)
  • 文档说明改清单的命令会按固定格式重写 manifest.yaml 与 overlay 文件,去掉其中的注释(包括 overlay create 生成的示例注释)。
  • 团队 skill 目录里本机新增的文件算作漂移:remote show 列为 added locally,remote sync 拒绝,--discard-local-changes 时一并删掉;此前不报漂移,团队删掉这个 skill 后只剩本机文件,apply 会把一个没有 SKILL.md 的 skill 装进 DSH。
  • 团队仓库的 skill 里有 node_modules/ 或 .tmp-* 文件时,remote add/sync 以退出码 3 说明它们不会复制进 DSH;此前接受下来,却永远到不了 DSH(.tmp-* 的改动也不会触发更新)。skill 的复制与摘要现在跳过同一组文件。
  • 团队仓库里只差大小写的 skill 名、目录或文件(如 skills/Foo 与 skills/foo)以退出码 3 拒绝;在 macOS/Windows 不区分大小写的文件系统上它们是同一个,此前之后每次 sync 都会以本机改动为由拒绝。
  • 对 overlay 已 remove 掉的插件 install --layer overlay 同一来源时,只撤掉这次删除,不再顺带把来源固定在 overlay 里;update --layer overlay 到当前生效的版本时报告没有变化、不写入。此前这两种情况都会把 overlay 固定在 base 的来源上,之后 base 升级到不了这台机器。
  • 本地 overlay 可以用 update --layer overlay 改团队 lock 固定的 npm 插件(与 install --layer overlay 一致),团队的 lock 条目保持不变;此前以「pinned by the team lock」拒绝。
  • remove --layer base 后,若选中的 overlay 还有这个别名的条目,在 stderr 提示它会套到之后以同一别名声明的插件上,并给出 remove <别名> --layer overlay;这条命令现在也能删掉 base 已没有的别名在 overlay 里的残留条目。
  • 没有 npm 时 self-update 说明 npm 不在 PATH 里;此前报「exit code undefined」。
  • purge 预览与真正执行一样拒绝指向 DSH_HOME 之外的补丁文件或受管克隆;此前预览说「Would purge」,加 --yes 才拒绝。
  • init 遇到没有清单但已有 lock.json 或 state.json 时,写任何文件之前就拒绝并说明;此前先写出清单再失败,之后再 init 报「already initialized」,state.json 一直没写出。
  • 容器示例 README 的版本 tag 改为 v<版本> 占位(此前停在 v0.3.0);DSH 版本升级文档说明门禁由 VERIFIED_FAMILIES 决定,isCompatibleDshVersion 与 knownDshFamily 都读它。

v0.10.2

Choose a tag to compare

@github-actions github-actions released this 07 Oct 03:51
57c01ed

升级须知

  • tools 系列与 plugins config set 也检查 DSH 版本:tools 遇到未测试的 DSH 版本以退出码 4 结束(可加 --allow-untested-dsh),找不到 DSH 时退出码 4(此前 3)。
  • 选中的 overlay 无法与 base 合并时,doctor 以退出码 3 结束(0.10.1 只警告)。
  • 插件补丁 id 对不上 DSH 加载它的那一行时,下一次 plugins config set 会把补丁改到正确的 id,清单随之变化。
  • 0.10.1 的「别名不能以 @ 开头」放宽为只拒绝 @profile 和 @mount:…;按 0.10.1 须知改过名的别名无需改回。

修复

  • 插件别名只拒绝 dshenv 自己的块名 @profile 和以 @mount: 开头的名字,lock.json 不再套用这条限制。0.10.1 拒绝所有以 @ 开头的别名,清单里已有 @x 这类别名时 remove、install --as、plan 全部以退出码 3 失败,升级须知里的办法也执行不了;手工改好清单后 lock.json 里的旧别名还会让 plan 报错。
  • 撤销一次清掉了 overlay 选择的 rollback(dshenv rollback --yes 恢复它留下的快照)时,重新选中那个 overlay;此前 overlay 文件回来了但选择丢了,之后的 plan/apply 只用 base,会卸载 overlay 声明的插件。期间已另选了 overlay 时保持不变。
  • 被结束的 DSH 没有被回收、成了僵尸进程时(如 dshenv 在容器里以 PID 1 运行且没加 --init),中断 apply 后照样释放它留下的 package.json.lock;dshenv.lock 的持有者是僵尸进程时同样接管。此前锁一直留着,之后的命令要等到超时。
  • dshenv.lock 里的 pid 正好是当前进程(容器重启后 pid 相同)时按陈旧锁接管;拿不到锁时报错写出持有者的 pid、主机名和加锁时间,并说明 pid 被复用或主机名变了时可删除锁文件。此前一直报 Environment lock is already held,没有处理办法。
  • 再次 adopt 由 dshenv 安装的 git 插件时,保留 base 声明的 ref/commit 和 URL 写法;此前 DSH 里记的 URL 带 git+ 前缀,与清单对不上,ref/commit 被丢掉、URL 被改写。
  • source clone --profile 用另一种写法(结尾的 /、.git 有无)指向清单里的同一个仓库时,仍克隆并锁定清单固定的 commit,清单与 lock 沿用清单的 URL 写法;此前会悄悄删掉固定的 commit,lock 锁到最新提交。
  • Windows 上 DSH_CLI 指向 PATH 里没有的命令时也以退出码 4 结束(此前为 5):命令名先按 PATH 与 PATHEXT 查找。
  • plugins config set 发现插件已有的补丁 id 对不上 DSH 加载它的那一行时(apply 前写的、或 0.9.x 留下的),把补丁移到正确的 id 上并说明;在 overlay 里写而补丁属于 base 时以退出码 3 提示先用 --layer base。此前补丁永远不生效,plan 却显示已同步。
  • tools config set 写 base 时,base 已有这一条但没有自己的 config(如只做过 disable),同样不抄 overlay 补丁里的值或本机路径(退出码 3)。
  • doctor 选中的 overlay 无法与 base 合并时以退出码 3 报错(0.10.1 起被当作 base 无效、只警告);lock.json 无效时在 stderr 警告。
  • tools 系列与 plugins config set 读取 DSH 组合配置前检查 DSH 版本:tools 遇到不支持的版本或找不到 DSH 时以退出码 4 结束(此前照用旧 DSH 的结果写清单,找不到时退出码 3),config set 不抄组合配置并说明原因。
  • envctl/skills 是软链接时,rollback 到没有 skills 的快照只删除链接本身;此前会把链接指向的外部目录(如 dotfiles 里的 skills,连同其中非 skill 的文件)整个删掉,且不进 trash。链接悬空时内容写回原目标并保留链接。
  • 旧写法 tools config <tool> <路径> <值> 带 --help、--version(或写成 help tools config …)时只显示帮助或版本;此前会真的写入清单并固定整个预设。
  • 团队配置里写成 link:…、file:/…、workspace:… 的 Git 地址按本机路径拒绝;此前被当成网络地址放行,pnpm 会把它当本地目录链接安装。

v0.10.1

Choose a tag to compare

@github-actions github-actions released this 06 Oct 06:01
55c5a64

升级须知

  • 插件别名不能再以 @ 开头;清单里已有这样的别名时,先用 --as 换个名字重新声明。
  • install in-box:<包> 遇到不是 bundle 的包(能从 DSH 安装位置找到时)以退出码 3 拒绝。
  • skill 摘要计入可执行位:envctl/skills 与 DSH 副本只差可执行位的 skill,升级后第一次 plan 会列为更新。
  • 退出码调整:DSH_CLI 指向 PATH 里没有的命令为 4(此前 5),self-update --to <不存在的版本> 为 3(此前 1)。

修复

  • 团队提交只改了可执行位时,remote sync 也会同步,skill 摘要同样计入可执行位,改动会一直到 DSH 里的副本;此前显示「Files: no changes」,副本一直不可执行。(升级后 envctl/skills 与 DSH 副本只差可执行位的 skill 会在 plan 中列为更新。)
  • remote sync --ref <同一分支上更旧的 commit> 说明它比固定的 commit 旧、要退回请用 rollback;此前报成「历史被改写」。
  • 子命令组里的 help(如 dshenv plugins help config set、dshenv web help foo)与顶层 help 一样:显示所指命令的帮助,未知命令以退出码 3 报错;此前显示的是上一级的帮助并以 0 结束。
  • DSH_CLI 指向 PATH 里没有的命令时以退出码 4(找不到 DSH)结束,与指向不存在的路径一致;此前退出码 5、只提示「probe execution failed」。
  • 选中 overlay 时 base 清单无效,doctor 也只警告并照常探测 DSH;此前直接以退出码 3 结束。
  • dsh web 已在运行时,web start --port <另一个端口> 以退出码 3 说明它在哪个端口、需先 web stop;此前静默返回原来的地址。
  • self-update --to <npm 上没有的版本> 以退出码 3 报「npm has no version …」,与 install 一致;此前退出码 1。
  • 被生效 overlay remove: true 去掉的插件,enable/disable --layer base 也在 stderr 提示这台机器上不会变(此前只有 update、install 提示)。
  • 插件别名不能以 @ 开头;此前 --as @mount:foo 被接受,其受管块与 foo 的挂载块同名,apply 会删掉 foo 的挂载。
  • install in-box:<包> 在能从 DSH 安装位置找到该包时,拒绝不是 bundle 的包(退出码 3);此前写进清单、apply 后 DSH 每次启动都跳过它,plan 却显示已同步。
  • purge 被拒绝(软链接指向 DSH_HOME 之外)时不再留下空的 trash 目录和只有开始的 journal 记录。
  • 结束 DSH 子进程树时,没有 ps(如 slim 容器镜像)的 Linux 改从 /proc 找后代进程;此前只结束直接子进程,pnpm --dir … dsh 的孙进程留着管道,超时失效、环境锁一直被占。
  • rollback 与 gc --dry-run 的帮助说明按实际范围更正。

v0.10.0

Choose a tag to compare

@github-actions github-actions released this 06 Oct 04:43
b2ebf0b

升级须知

  • 同时设置了 DSH_CLI 又传 --harness-source 时,现在用 --harness-source 指定的源码目录(此前 DSH_CLI 优先)。
  • DSH_HOME 开头的 ~ 会展开为用户主目录,为空时回退到 ~/.dsh;此前因此被管理在别处(如当前目录下的 ~/)的环境需要迁移过去。
  • skill 的摘要改为算整个目录:envctl/skills 与 DSH 副本在 package.json files 名单外的文件上不一致时,升级后第一次 plan 会列出更新,apply 用清单的副本(DSH 副本移进 trash)。
  • tools 写 base 遇到已生效的 overlay 补丁或本机路径、config set 遇到全部禁用的补丁时,以退出码 3 拒绝;改用 --layer overlay,或先启用补丁。
  • 已用相对路径订阅的 remote.json 不会自动改写;remote remove --yes 后重新 remote add 一次即记为 file:// 地址。

变更

  • 显式的 --harness-source 优先于环境变量 DSH_CLI(此前被 DSH_CLI 静默覆盖,doctor 还提示「请提供 --harness-source」);清单的 environment.harness.sourceDir 仍排在 DSH_CLI 之后。

修复

  • DSH_HOME、--dsh-home 开头的 ~(~、~/、~\)按 DSH 的规则展开,DSH_HOME 为空或只有空白时视为未设置;此前 dshenv 管的是当前目录下字面量 ~ 的目录或直接报错,与 DSH 实际读取的目录不同。
  • remote add <本机路径> 把相对路径记为 file:// 地址;此前原样记下,换个目录再 clone(如 rollback 后 remote sync)会失败或拿到别的仓库,origin 校验也被跳过。
  • 选中的 overlay 对某个插件只改了 enabled(或补丁)时,adopt 仍把 base 更新到实际安装的版本,base 自己的 enabled 不变;此前直接跳过,base 停在旧版本,下一次 apply 会降级。
  • tools config set、tools enable/disable 写 base 时,若 base 还没有这一条而 DSH 当前组合出的配置已含 dshenv 补丁(如已 apply 的 overlay 写的),或含本机路径,以退出码 3 拒绝;此前把 overlay 的值(本机路径等)抄进共享的 base。
  • install --layer overlay 装的版本与生效的来源相同时不再写 overlay;此前提示「nothing changed」却在 overlay 里固定了来源,之后 base 的升级到不了这台机器。
  • plugins config set 只把键写进 enabled 不为 false 的补丁,全部禁用时以退出码 3 拒绝;config get 同样跳过禁用的补丁。此前写进禁用的补丁,apply 跳过它,值永远到不了 DSH。
  • rollback 到 remote add(或 pull)之前时,若删掉的正是选中的 overlay,会清掉选择并在输出里说明;此前选择悬空,之后所有命令都报 Overlay 'team' not found。
  • rollback 后仍在安装着、清单仍声明同一路径的本地来源插件,保留回滚前 lock.json 记录的摘要;此前恢复旧 lock 丢掉摘要,清单没变也会重装并要求重启。
  • skill 的摘要算整个目录,不再套用其 package.json 的 files 过滤;此前名单外文件(如 run.sh)的改动在 plan 中显示已同步,永远到不了 DSH。
  • plugins config set 新建补丁时用 DSH 实际加载该插件的那一行的 id(bundle 插件、--as 改名的插件与别名不同),并在 stderr 说明;此前用别名,DSH 报 entry not found、配置从不生效,plan 却显示已同步。
  • 再次 adopt 时,只有 overlay 声明插件的 Profile 保留它在 lock.json 里的条目和所有权记录;此前输出「Nothing to adopt」却把它们清空,之后 plan 要求重装、锁定的版本或 commit 丢失。
  • plugins config set 只在没有 dshenv 补丁生效时抄 DSH 组合出的配置;此前有生效 overlay 给该插件写了补丁时,--layer base 会把 overlay 的值(本机路径、内网地址等)抄进共享的 base。抄来的配置含本机路径时,写 base 以退出码 3 拒绝。
  • plugins config set 读不到 DSH 的组合配置(Profile 未创建、找不到 DSH、--dump-config 失败)时在 stderr 说明原因;此前静默只写这个键,与 0.9.0 的说明不符。
  • 成功的 apply 从 lock.json 删掉 base 与所有 overlay 都不再声明的别名的条目(团队条目保留);此前删掉的 Git 插件用同一别名、另一个 ref 重新加入时,plan 不报 blocked,apply 装回旧 commit。
  • 再次 adopt 由 dshenv 安装的 Git 插件时保留 base 声明的 ref/commit(commit 跟随实际安装的版本);此前被替换成只有 URL 的来源。
  • source clone --profile 读到的 package.json 包名与 install 按仓库名记下的不同时,同一仓库地址的条目改用读到的包名;此前以别名冲突拒绝。install --package 的帮助改为说明 Git 来源默认取仓库名。
  • Git 地址里的本机路径(相对路径、不带 # 的 /abs/x.git)统一记为 file:// 地址;此前 repos/x 会被 pnpm 当成 GitHub 简写。install 把 ssh://、git:// 地址按 Git 处理;此前不带 .git 时被当成 npm 包名。
  • source sync --profile 可以把受管 clone 退回到更旧的 commit,plan 提示的 --ref <清单 commit> 由此生效(此前输出「Updated … from X to X」并以 0 退出,什么都没变);detached HEAD 不给 --ref 时跟随清单的 ref 或远端默认分支(此前报错);移动后与清单锁定的 commit 不一致时在 stderr 提示。对 envctl 之外的检出指向更旧的 commit 时以退出码 3 拒绝,不再静默成功。install <url>#<commit> 与 lock 中的 commit 不同时提示如何锁定。
  • 写 base 的命令(install 等、adopt、pull、remote sync)在 --no-overlay 或 --overlay <其他> 下也检查新 base 能否与本机保存的选中 overlay 合并,不能时以退出码 3 拒绝并说明;此前会写成之后所有命令都报 cannot change package 或 Duplicate package 的状态。
  • 快照与 rollback(以及 pull、sync 失败时的恢复)原样保留 envctl/skills 里的软链接;此前相对链接被改成绝对路径,plan 随之报告 skill 改动。
  • skills 目录下的 node_modules(在 skills 目录里 npm install 留下的)不再被当作 skill,团队仓库的 skills/node_modules/ 也被忽略;此前 pull --yes、adopt --yes 因此报 ENOENT 失败。
  • 子命令层面的未知命令加 --help(如 dshenv web foo --help、dshenv help web foo)与未知命令加 --version(dshenv foo --version)按未知命令处理,退出码 3;dshenv help web start 显示 web start 的帮助,不再是 web 的。
  • 文档:使用教程关于 rollback 跨过 remote add --replace 与「不带 id 的 rollback」的说明、锁的重试间隔已更正;GitHub Actions 示例的注释不再说 plan 会以 4 结束;模板 README 改用 mark-restarted;README 说明 DSH 配置了 webserver.port 时忽略 --port。
  • install --layer base 在生效 overlay 用 remove: true 去掉或改了来源的插件上,像 update 一样在 stderr 提示这台机器上实际没变(update、config set/unset 写被 overlay 去掉的插件时同样提示)。
  • install 的本地路径必须是目录;此前一个文件(如打包的 .tgz)被登记成链接目录,到 apply 才失败。
  • DSH 组合出的插件配置含 ${...} 时,config set 不再抄它(清单不允许),只写这个键并说明;此前以退出码 3 失败。
  • config unset 从该插件所有设置了这个键的补丁里删掉它;此前只删第一个,其余补丁里的值仍然生效。
  • adopt 选别名时也避开 lock.json 里已有的别名(它们可能属于其他 overlay);此前会覆盖那条锁定。
  • 选中的团队 overlay 只因 DSH 里删掉了它的条目而需要改写时,pull 的预览也以退出码 3 拒绝;此前预览通过,--yes 才被拒绝。
  • envctl/skills 本身是软链接时,快照保存其内容、rollback 写回链接指向的目录;此前快照只存链接,回滚不会恢复内容。
  • 插件改了别名后,purge <包名> 清理新别名下的配置块;此前按所有权记录里的旧别名查找,报「Nothing to purge」。
  • purge 在 git 无法判断受管 clone 是否干净时拒绝执行;还没有提交的 clone 里的未跟踪文件也算未提交改动。此前这两种情况都当作干净,把 clone 移进 trash。
  • remote 系列命令调用 git 时不再继承 GIT_WORK_TREE、GIT_DIR 等变量(source 系列 0.8.0 已如此);此前在 git hook 里运行时 remote add 报仓库没有 envctl/manifest.yaml。

v0.9.0

Choose a tag to compare

@github-actions github-actions released this 05 Oct 04:46
f3d72b0

升级须知

  • plugins config set 为插件新建补丁时,把 DSH 当前为该插件组合出的全部配置抄进清单,之后的 config set 只改各自的键;DSH 还没有该插件时照旧只写这个键并在 stderr 提示。已有的只含个别键的补丁不会自动补全:要找回丢失的默认值,先 config unset 去掉这些键、apply,再重新 config set。
  • source clone <本机路径> 把路径记为 file:// 地址;install 本地路径时要求目录存在,带 #<ref> 的本地路径被拒绝(退出码 3)。
  • 没有清单时 status 只输出缺少清单的错误(--json 时 stdout 为空)。

修复

  • 没有清单时 status 只报缺少清单(与 plan 相同,--json 时是 stderr 上的 JSON 错误),不再同时输出一份 degraded 状态报告;0.8.0 只改了退出码。
  • 插件的受管配置块已经清掉后,再次 purge 输出「Nothing to purge」、退出码 0,不再每次把整个 cordis.patch.yml 复制进 trash。
  • 输出接到提前关闭的管道(如 dshenv --help | head -1)时不再以 EPIPE 调用栈崩溃;命令照常执行完,之后的输出被丢弃。
  • source sync 不带目录也不带 --profile 时作用于当前目录,与 README 及 source show 一致;此前报「requires or --profile」。
  • source clone <本机路径> --profile 把路径记为 file:// 地址;此前记成普通路径,apply 时 pnpm 把它当本地目录链接,失败并在 Profile 的 package.json 里留下名字带 #<commit> 的坏依赖。
  • install 本地路径时检查目录存在(退出码 3),file:// 地址按其路径解析,带 #<ref> 的本地路径被拒绝并提示 git+file://;此前 file:///repo#<sha> 会登记成别名 repo#<sha>、路径不存在的本地插件。
  • 有生效 overlay 时,update --layer base、plugins config set/unset --layer base 写的值被 overlay 覆盖时在 stderr 提示(与 enable/disable 相同);此前静默写入,这台机器上实际没变。
  • remote add --replace 与 remote sync --discard-local-changes 的预览末尾给出的接受命令保留这个参数;此前照提示执行会以退出码 3 失败。
  • remote add 遇到同名本机 skill 时提示「then run remote add again」;此前提示「sync again」。
  • plugins config set 为插件新建补丁时,先把 DSH 当前为该插件组合出的全部配置(dsh --dump-config)抄进补丁再改这个键,与 tools config 相同;此前补丁只含这个键,而 DSH 用它整体替换插件配置,apply 后插件的其他默认值(如 agent-teams 的 memberProvider)全部丢失。DSH 还没有这个插件时照旧只写这个键,并在 stderr 说明。
  • 插件的受管配置块把 { __jsExpr } 写回 !!js 表达式(与 Profile 块相同);此前会写成字面的 __jsExpr 映射。

v0.8.1

Choose a tag to compare

@github-actions github-actions released this 04 Oct 14:12
1134950

修复

  • 失败的 apply 恢复 lock.json 后,补记失败前已装上的本地来源插件的摘要;此前下一次 plan 会以「Local source has no recorded digest」重装同样的代码,并标记为需要重启。
  • rollback 不再把 mark-restarted 已清除的 restart-required 带回来;重启状态以回滚前为准(DSH 进程不随 rollback 改变)。
  • 没有 state.json 时,一次「已同步」的 apply 也记录 DSH 已有的声明 skill 的所有权与生效 overlay;此前什么都不记录,之后从清单删掉这类 skill 时被当作未管理,不会移除。
  • pull 需要写的 overlay(选中的,或要新建的 local)归团队所有时,预览就以退出码 3 拒绝;此前预览说会写进去,加 --yes 才被拒绝。
  • remote sync 的预览不再把用软链接放进 envctl/skills 的本机 skill 列为「remove」;只为这次同步涉及的 skill 重算摘要。
  • remote sync --no-overlay(或 --overlay 其他名字)不再绕过「本机选中的 overlay 被团队删除」的检查;此前同步成功后,之后的命令都报 Overlay '<名字>' not found。
  • doctor 只原样显示常见的预发布标签(如 rc.2、beta.1),其他标签显示为「(a prerelease)」;此前完整打印 DSH_CLI 包装脚本输出的版本,可能带出凭据(不支持版本的报错早已如此处理)。
  • dshenv help <不存在的命令>、dshenv <不存在的命令> --help 按未知命令处理,退出码 3 并给出相近命令(--json 时输出 JSON 错误);此前打印根帮助、退出码 0。
  • README 关于 verify 地址来源的说明前后矛盾(「只从 DSHENV_DSH_URL 读取」),改为说明显式地址只能经该环境变量给出;使用教程不再说 web start 的地址「只打印这一次」,并统一用 mark-restarted。

v0.8.0

Choose a tag to compare

@github-actions github-actions released this 04 Oct 13:06
b73f2c7

升级须知

  • gc --yes 现在也删除 envctl/backups 中早于 --older-than(默认 7 天)的快照,始终保留最近 10 个;rollback 只能回到还在的快照。需要更早的快照时,先用 --older-than 调大期限,或在 gc 前备份 envctl/backups。
  • --harness-source 指向不存在的目录时以退出码 3 报错,不再改用清单的 sourceDir 或 PATH 上的 dsh;相对路径按当前目录解析。
  • source clone --profile --ref <ref> 把该 ref 写进清单(替换原来声明的 commit/ref);不带 --ref 时克隆并锁定清单已声明的 commit 或 ref,不再总是锁定默认分支的 HEAD。别名已指向另一个包时拒绝(退出码 3),默认别名去掉 dsh-plugin-、dsh- 前缀。
  • 包名(含作用域)不能以 - 开头。
  • 没有清单时 status 以退出码 3 结束(此前为 5);tools list --all --preset 以退出码 3 拒绝。

修复

  • install <git 地址>#<分支或 tag> 把 # 后的内容记为 ref,不再因「不是 commit」报 schema 错误;README 的 Git 示例改用会锁定 commit 的 source clone --profile。
  • 包名(含作用域)不能以 - 开头,避免被 pnpm 当成选项。
  • source show/sync/clone 调用 git 时不再继承 GIT_DIR、GIT_WORK_TREE 等变量;此前从 git hook 或 CI 步骤里运行时会检查、快进或锁定另一个仓库。
  • remote sync 发现本地克隆的 origin 与 remote.json 的 URL 不一致(如 rollback 跨过了一次 remote add)时重新克隆;此前会从旧仓库取内容。
  • 团队仓库中直接放在 skills/ 下的文件(如 README.md、.DS_Store)被忽略,不再让整个提交被拒;使用教程的团队仓库布局补上 skills/ 与 __jsExpr 限制。
  • 有生效 overlay 时,--layer base 的 enable、disable、remove 等能改 overlay 用 remove: true 去掉的 base 插件;此前按合并后的清单找别名,报「not found」。
  • 没有清单时 status 以退出码 3 结束(与 plan 一致),不再报告为 degraded(退出码 5)。
  • tools list --all 与 --preset 同时使用时报错(退出码 3),不再静默忽略 --preset。
  • 对已经全部纳管的候选执行 adopt --yes 时输出「Nothing to adopt」,不再报告「Adopted N plugin(s)」并列出它们。
  • 写 overlay 的命令(plugins config set、tools config set、install 等加 --layer overlay)拒绝含 ${...} 的值(退出码 3),与写 base 一致;此前会写进 overlay,之后所有读取它的命令都以退出码 3 失败,只能手改文件。
  • 有生效 overlay 时,update --layer base 与 plugins config set --layer base 能改 overlay 用 remove: true 去掉的 base 插件,update --layer base 按 base 中的来源判断是否为 npm;此前前者崩溃(退出码 1),后者按 overlay 覆盖后的来源拒绝。
  • overlay 里只调整某个 base 插件(没有 package)、而 base 已不再声明它时,install/source clone --profile 加 --layer overlay 写入完整的 package;此前输出「Added」,插件却不在生效清单中。
  • source clone --profile 克隆并锁定清单为该别名声明的 commit 或 ref(同一仓库时),清单里保留它;给了 --ref 时写入该 ref。此前总是锁定默认分支的 HEAD 并删掉清单里的 commit/ref,照 plan 的提示操作会悄悄换掉固定的代码。
  • source clone --profile 的别名已指向另一个包时拒绝(退出码 3,base 与 overlay 都是),与 install 一致;此前写 base 时整条替换、丢掉原包的 patches 与启用状态,写 overlay 时让清单与 lock 的包名不一致。
  • source clone 的默认别名与 install 相同(去掉 dsh-plugin-、dsh- 前缀);此前 install 之后按 README 再 source clone 会因重复包报错。
  • base 已声明、但本机 DSH 从本地路径(link:、file:)安装的插件,adopt --yes 保留 base 中的条目,把本机路径写进 overlay(没有生效 overlay 时新建并选中 local);此前会把本机路径写进共享的 base,推到团队仓库时被拒。
  • 对 base 已按安装方式声明的本地来源插件再次 adopt --yes,保留 lock.json 中 apply 记录的摘要并输出「Nothing to adopt」;此前会抹掉摘要,之后 plan 对每个这类插件都提示更新。
  • pull 与 adopt 给新插件选别名时避开当前 overlay 新增的别名;此前与 overlay 别名相同时,前者整体失败、后者被拒绝(「an overlay cannot change package」)。
  • 团队 skill 里同一路径在文件与目录之间互换时,remote sync 能正常预览与接受(先删除再写入);此前预览报 EEXIST(退出码 1),或误报该路径「not owned by the remote」(退出码 3),之后每次 sync 都失败。目录里仍有本机文件时照旧拒绝。
  • 快照另存当时所有 overlay 文件;rollback 跨过一次 remote add --replace 时,把被团队接管的本机 overlay 恢复为原内容;此前会删除它。
  • apply 删除插件后,purge <包名> 能清理它留在 envctl/sources 下的 clone(清单不再声明该包时);此前因所有权记录已去掉而拒绝,与 remove 帮助所说的流程不符。
  • --harness-source 指向不存在的目录时以退出码 3 报错;此前静默改用清单的 sourceDir 或 PATH 上的 dsh,doctor、apply、web start 跑的是另一个 DSH。
  • --harness-source 的相对路径按当前目录解析;此前被解析两次(hs/hs),相对路径总是失败。
  • 容器示例的 .dockerignore 排除 envctl/run/(web start 的记录,含带 token 的 dsh web 登录地址)、remote.json、remote/ 与锁的 .wanted/.reclaim 文件;此前用过 web start 的配置仓库构建镜像时,token 会进入镜像层。
  • 帮助的环境变量部分补上 DSHENV_NPM_CHECK;README 与使用教程中需要 --layer 的命令补上 plugins config unset 与 tools reset;README 说明没有快照时的 rollback 与没有订阅时的 remote remove 以退出码 3 结束。

变更

  • gc 同时删除 envctl/backups 中早于 --older-than 的快照(始终保留最近 10 个),以及被中断的操作留下、超过同一期限的 .…partial 临时目录;此前快照只增不减,每次有变更的 apply 都会复制一份 envctl/skills。