fix(aggregate): drop the retire override for a row alpha.2 no longer mounts

DSH 0.1.7-alpha.2 no longer mounts ui-settings-unarchive-sessions, so the
aggregate's retire override named a foreign row no bundle inserts and made
every profile boot log a patch-not-found warning. The retire mechanism
stays in scripts/aggregate.mjs for a foreign row that genuinely exists;
declaring a target again requires proving it in the same cohort with
dsh --profile <name> --dump-config. dsh-session-archive's takeover facts
(module comment, spec header, bilingual README) and the two cohort notes
are updated to the same-cohort reality.
This commit is contained in:
zhu1090093659
2026-09-23 17:19:59 +08:00
parent 76c95ad277
commit 53ec2ed18e
13 changed files with 46 additions and 41 deletions
@@ -33,7 +33,7 @@ The cohort adds official features that overlap plugin surface. Each overlap was
| Official feature | Our implementation | Native now provides | Decision |
| --- | --- | --- | --- |
| `workspace.unarchiveSession` + the Archived sessions settings page | `dsh-session-archive`: its own first-level `settings.section` (id `dsh-session-archive`, order 152), plus an unarchive that reached into the registry's private `requireState`/`setState` handles because no public verb existed | A public idempotent unarchive verb, and an official `archived-sessions` section at order 25 | **Supersede, do not sit beside**: the private-state workaround is deleted in favour of the public verb, and the plugin now seats the official `archived-sessions` id and order instead of a parallel entry; `dsh-web-all` retires the official row through the aggregate's new `retire:` manifest section. The inventory, batch archive/unarchive, cascade physical delete and auto-maintenance policies are kept, because native ships none of them (the official page lists and restores only, and offers no deletion) |
| `workspace.unarchiveSession` + the Archived sessions settings page | `dsh-session-archive`: its own first-level `settings.section` (id `dsh-session-archive`, order 152), plus an unarchive that reached into the registry's private `requireState`/`setState` handles because no public verb existed | A public idempotent unarchive verb, and an official `archived-sessions` section at order 25 | **Supersede, do not sit beside**: the private-state workaround is deleted in favour of the public verb, and the plugin now seats the official `archived-sessions` id and order instead of a parallel entry; `dsh-web-all` needs no retirement override, because DSH `0.1.7-alpha.2` no longer mounts the official page. The inventory, batch archive/unarchive, cascade physical delete and auto-maintenance policies are kept, because native ships none of them (the official page lists and restores only, and offers no deletion) |
| Native SSH remote-workspace provider (`dsh-ssh`, `dsh-fs-ssh`, `dsh-sandbox-ssh`, all first published at this cohort) | `dsh-ssh` | An SSH filesystem and POSIX sandbox provider that makes the standard file/command tools operate on a remote workspace | **Recorded exception, complementary**: native changes *where* the standard tools run; ours is a management surface (host CRUD, connection pool, SFTP browsing, tunnels, cluster execution) plus `ssh_*` agent tools. Mounting native neither replaces nor regresses ours. Adopting the provider as a workspace mode is follow-up feature work, not compatibility repair |
| Archived-session restore in the settings shell | `dsh-session-archive`'s own settings section | A dedicated restore page | **Kept**: the two sections have different scopes (restore list versus management console); no capability is duplicated by deleting either |
| Official plugin inventory settings page | `dsh-plugin-manager` | The `settings.plugins.tab` host section | **Already a native extension**: the manager registers a tab into the official section rather than mounting a parallel page |
@@ -41,15 +41,15 @@ The cohort adds official features that overlap plugin surface. Each overlap was
## One archived-sessions entry, not two
The settings shell renders one nav row per `settings.section` registration, sorted by `order`, with no `id` de-duplication, and a section can only expose extension points that its own owner declared through `children`. The official `archived-sessions` page declares none and is mounted by the constant `dsh-web-app` roster, so a plugin cannot merge into it. Sitting beside it therefore always produces two near-identical first-level entries.
The settings shell renders one nav row per `settings.section` registration, sorted by `order`, with no `id` de-duplication, and a section can only expose extension points that its own owner declared through `children`. The official `archived-sessions` page declared none and was mounted by the constant `dsh-web-app` roster, so a plugin could not merge into it: seating the same id and order was the only route to a single first-level entry.
The consolidation is therefore a takeover plus a composition retirement:
The consolidation is therefore a takeover:
- `dsh-session-archive` seats the official `archived-sessions` id at the official order 25 (the section already opened on the archived view), so the single entry keeps the position users know, and its `arch.nav` copy reads exactly like the official one.
- The aggregate gains a `retire:` manifest section that renders a bare `disabled: true` override naming a FOREIGN row id verbatim (never namespaced). `scripts/aggregate.mjs` validates that a retired id is a non-empty string, is not one of the aggregate's own rows, and is not listed twice.
- `aggregate.yml` retires `ui-settings-unarchive-sessions`. Verified on the composed alpha profile: the row reads `- id: ui-settings-unarchive-sessions` / `disabled: true` under `# == @deepseek-ai/dsh-web-app, patched by @linxin666/dsh-web-all`, so only the family entry mounts.
- The aggregate keeps a `retire:` manifest section for a foreign row a family plugin supersedes: it renders a bare `disabled: true` override naming the FOREIGN row id verbatim (never namespaced), and `scripts/aggregate.mjs` validates that a retired id is a non-empty string, is not one of the aggregate's own rows, and is not listed twice.
- No target is declared. The `0.1.6-alpha.1` alpha profile needed one because `dsh-web-app` mounted `ui-settings-unarchive-sessions`; `0.1.7-alpha.2` mounts no such row (the id appears nowhere in the installed host tree, and `dsh --profile web --dump-config` composes no row for it), so the override would only make every boot log `patch: entry "ui-settings-unarchive-sessions" not found`. Declaring a target again requires proving the foreign row exists in the SAME cohort with `--dump-config`.
A standalone install beside the official page still shows two entries; the package READMEs tell the user to disable one row. That limit is inherent to the slot contract and is recorded rather than papered over.
A standalone install mounts the same single entry: on the supported cohort nothing else registers the `archived-sessions` section id. The one-entry outcome now depends on upstream continuing to omit its own page, and the retirement override comes back the day it does not.
## Alpha-only: no bundled better-sidebar
On 2026-09-17 the alpha branch dropped the aggregate's external right-panel plugin. `dsh-better-sidebar@0.19.1` declares every consumed `@deepseek-ai/dsh-*` peer as `^0.1.5-rc.1`, and a prerelease range only matches its own `[major,minor,patch]` tuple, so none of those peers is satisfied by the `0.1.6-alpha.1` cohort this branch builds against. The plugin is now absent from `aggregate.yml` (no `rows` entry), from the aggregate's own `package.json` dependencies, from `pnpm-workspace.yaml`'s release-age exclusion list and from the mount-smoke lane, whose assertions are inverted to prove the absence; `cordis.patch.yml` was regenerated without its row. The isolated alpha home was re-installed afterwards so its linked profile no longer resolves the package, and the right panel is therefore simply absent on this branch.
@@ -66,4 +66,4 @@ Keeping the alpha cohort on `dev` was rejected: it would have moved the user's l
## Testing
`pnpm typecheck`, `sync-shared:check`, `skin-center:check`, `community:check`, `libs:check`, `build`, `test`, `test:scripts`, `test:desktop`, `runtime-deps:check`, `aggregate:check`, `docs:check`, `i18n:check` and `market:check` pass in the alpha worktree. `dsh --profile alpha-web --dump-config` composes the alpha host with the family rows from the isolated home and shows `ui-settings-unarchive-sessions` disabled under `dsh-web-app, patched by @linxin666/dsh-web-all`, so exactly one archive settings entry mounts. Two tests pin the consolidation: `tests/section-identity.spec.ts` in dsh-session-archive asserts the seated id and order, and `scripts/aggregate.test.mjs` asserts every `retire:` entry renders a verbatim (non-namespaced) `disabled: true` override. Live GUI acceptance against a running alpha instance is not covered by this change and remains open.
`pnpm typecheck`, `sync-shared:check`, `skin-center:check`, `community:check`, `libs:check`, `build`, `test`, `test:scripts`, `test:desktop`, `runtime-deps:check`, `aggregate:check`, `docs:check`, `i18n:check` and `market:check` pass in the alpha worktree. `dsh --profile alpha-web --dump-config` composes the alpha host with the family rows from the isolated home, and Settings mounts exactly one archive entry (`web-ui-session-archive`) with no foreign row to retire. Two tests pin the consolidation: `tests/section-identity.spec.ts` in dsh-session-archive asserts the seated id and order, and `scripts/aggregate.test.mjs` asserts the aggregate declares no `retire:` target that a same-cohort composition check has not confirmed. Live GUI acceptance against a running alpha instance is not covered by this change and remains open.
@@ -33,7 +33,7 @@ Status: implemented
| 官方特性 | 我们的实现 | 原生现在提供 | 决策 |
| --- | --- | --- | --- |
| `workspace.unarchiveSession` 与归档会话设置页 | `dsh-session-archive` 自己的一级 `settings.section`(id `dsh-session-archive`、order 152),以及当时因缺少公开动词而伸手进 registry 私有 `requireState`/`setState` 句柄的取消归档 | 公开、幂等的取消归档动词,以及 order 25 的官方 `archived-sessions` section | **接管而非并列**:删除私有状态变通实现改用公开动词;插件同时改用官方 `archived-sessions` 的 id 与 order,不再另起平行入口,`dsh-web-all` 通过聚合新增的 `retire:` 清单段关闭官方那一行。保留插件的清点、批量归档/取消归档、级联物理删除与自动维护策略,因为原生并不提供这些(官方页面只列出与恢复,且不提供删除) |
| `workspace.unarchiveSession` 与归档会话设置页 | `dsh-session-archive` 自己的一级 `settings.section`(id `dsh-session-archive`、order 152),以及当时因缺少公开动词而伸手进 registry 私有 `requireState`/`setState` 句柄的取消归档 | 公开、幂等的取消归档动词,以及 order 25 的官方 `archived-sessions` section | **接管而非并列**:删除私有状态变通实现改用公开动词;插件同时改用官方 `archived-sessions` 的 id 与 order,不再另起平行入口;DSH `0.1.7-alpha.2` 起官方不再挂载那一页,聚合包因此不需要退役覆盖。保留插件的清点、批量归档/取消归档、级联物理删除与自动维护策略,因为原生并不提供这些(官方页面只列出与恢复,且不提供删除) |
| 原生 SSH 远端工作区提供者(`dsh-ssh`、`dsh-fs-ssh`、`dsh-sandbox-ssh`,均在本 cohort 首次发布) | `dsh-ssh` | SSH 文件系统与 POSIX 沙箱提供者,使标准文件/命令工具作用于远端工作区 | **已记录例外,属互补**:原生改变标准工具"在哪里运行",我们提供的是管理面(主机 CRUD、连接池、SFTP 浏览、端口转发、集群执行)与 `ssh_*` 智能体工具。挂载原生既不取代也不回退我们的能力。把该提供者作为工作区模式接入属于后续功能开发,而非兼容性修复 |
| 设置 shell 中的归档会话恢复 | `dsh-session-archive` 自己的设置区 | 专用的恢复页面 | **保留**:两者作用域不同(恢复列表 vs 管理控制台),删掉任何一方都不会造成能力重复 |
| 官方插件清单设置页 | `dsh-plugin-manager` | `settings.plugins.tab` 宿主区段 | **本就是原生扩展**:管理器是向官方区段注册标签页,而非另起平行页面 |
@@ -41,15 +41,15 @@ Status: implemented
## 归档只保留一条一级入口
设置外壳对每条 `settings.section` 注册各渲染一个导航项、按 `order` 排序、**不按 `id` 去重**;而一个 section 只能暴露其属主在注册时用 `children` 声明的扩展点。官方 `archived-sessions` 页面没有声明任何子槽位,且由 `dsh-web-app` 常量名册挂载,插件无法并入其中。因此与它并列必然产生两个近似的一级入口。
设置外壳对每条 `settings.section` 注册各渲染一个导航项、按 `order` 排序、**不按 `id` 去重**;而一个 section 只能暴露其属主在注册时用 `children` 声明的扩展点。官方 `archived-sessions` 页面没有声明任何子槽位,且由 `dsh-web-app` 常量名册挂载,插件无法并入其中:注册同一个 id 与 order 才是只保留一条一级入口的唯一路径。
合并因此采用「接管 + 组合退役」两步:
合并因此采用「接管」一步:
- `dsh-session-archive` 注册官方的 `archived-sessions` id 与官方 order 25(该页面本就打开在已归档视图),单条入口保持用户熟悉的位置,`arch.nav` 文案与官方一致。
- 聚合包新增 `retire:` 清单段,渲染一条原样写出**外部**行 id 的裸 `disabled: true` 覆盖(绝不做命名空间化)。`scripts/aggregate.mjs` 校验:被退役的 id 必须是非空字符串、不得是本聚合自己的行、不得重复列出。
- `aggregate.yml` 退役 `ui-settings-unarchive-sessions`。已在 alpha profile 的真实组合上验证:该行输出为 `- id: ui-settings-unarchive-sessions` / `disabled: true`,位于 `# == @deepseek-ai/dsh-web-app, patched by @linxin666/dsh-web-all` 之下,因此只有家族入口会挂载。
- 聚合包保留 `retire:` 清单段,用于家族插件取代**外部**行的场景:渲染一条原样写出该外部行 id 的裸 `disabled: true` 覆盖(绝不做命名空间化)。`scripts/aggregate.mjs` 校验:被退役的 id 必须是非空字符串、不得是本聚合自己的行、不得重复列出。
- 当前不声明任何目标。`0.1.6-alpha.1` 的 alpha profile 需要它,是因为 `dsh-web-app` 那时挂载 `ui-settings-unarchive-sessions`;`0.1.7-alpha.2` 不挂载该行(该 id 在已安装宿主树里完全不出现,`dsh --profile web --dump-config` 也组合不出这一行),写了覆盖只会让每次启动都记录 `patch: entry "ui-settings-unarchive-sessions" not found`。要重新声明目标,必须先在同一 cohort 上用 `--dump-config` 证明该外部行存在。
单独安装并与官方页面并存时仍会出现两个入口,包 README 已提示用户在插件里停用其中之一。这是槽位契约本身的限制,记录在案而非掩盖。
单独安装同样只挂载这一条入口:在受支持的 cohort 上没有任何其他注册方占用 `archived-sessions` 这个 section id。单入口的结果现在取决于上游继续不挂载自己的页面;上游一旦挂回,退役覆盖就要跟着回来。
## 仅 alpha:不内置 better-sidebar
2026-09-17,alpha 分支移除了聚合包的外部右侧面板插件。`dsh-better-sidebar@0.19.1` 把全部被消费的 `@deepseek-ai/dsh-*` peer 声明为 `^0.1.5-rc.1`,而带预发布标识的区间只匹配同 `[major,minor,patch]` 元,因此本分支构建所依据的 `0.1.6-alpha.1` cohort 一个都满足不了。该插件现已从 `aggregate.yml`(不再有 `rows` 条目)、聚合包自身的 `package.json` 依赖、`pnpm-workspace.yaml` 的发布时限排除清单以及挂载冒烟 lane(其断言改为证明「不挂载」)中消失;`cordis.patch.yml` 已按不含该行的清单重新生成。随后重装了隔离的 alpha home,使其链接 profile 不再解析该包;因此本分支上右侧面板直接缺席。
@@ -66,4 +66,4 @@ Status: implemented
## Testing
在 alpha 工作树中 `pnpm typecheck`、`sync-shared:check`、`skin-center:check`、`community:check`、`libs:check`、`build`、`test`、`test:scripts`、`test:desktop`、`runtime-deps:check`、`aggregate:check`、`docs:check`、`i18n:check`、`market:check` 均通过。`dsh --profile alpha-web --dump-config` 能从隔离 home 组合出 alpha 宿主与家族插件行,并显示 `ui-settings-unarchive-sessions` 在 `dsh-web-app, patched by @linxin666/dsh-web-all` 之下为 disabled,因此只挂载一条归档设置入口。两处测试锁定该合并:dsh-session-archive 的 `tests/section-identity.spec.ts` 断言注册的 id 与 order,`scripts/aggregate.test.mjs` 断言每个 `retire:` 条目都渲染出原样(未命名空间化)的 `disabled: true` 覆盖。针对运行中 alpha 实例的实时 GUI 验收不在本次变更范围内,仍是未完成项。
在 alpha 工作树中 `pnpm typecheck`、`sync-shared:check`、`skin-center:check`、`community:check`、`libs:check`、`build`、`test`、`test:scripts`、`test:desktop`、`runtime-deps:check`、`aggregate:check`、`docs:check`、`i18n:check`、`market:check` 均通过。`dsh --profile alpha-web --dump-config` 能从隔离 home 组合出 alpha 宿主与家族插件行,设置里只挂载一条归档入口(`web-ui-session-archive`),没有需要退役的外部行。两处测试锁定该合并:dsh-session-archive 的 `tests/section-identity.spec.ts` 断言注册的 id 与 order,`scripts/aggregate.test.mjs` 断言聚合包不声明任何未经同 cohort 组合校验的 `retire:` 目标。针对运行中 alpha 实例的实时 GUI 验收不在本次变更范围内,仍是未完成项。
@@ -1,5 +1,5 @@
# Bilingual-pair consistency record (docs/i18n.md): the git blob hash of each
# side as of the last confirmed-consistent state. Both languages carry equal authority;
# after editing either side, bring the other along and re-record with git hash-object.
2026-09-23-sdk-cohort-0.1.7-alpha.2.md: 54d4814838720b45e2f639cd4c4cff486dcbe1cb
2026-09-23-sdk-cohort-0.1.7-alpha.2.zh.md: 26efc8cd1b215441e32a1d63f7a1546b610ffb71
2026-09-23-sdk-cohort-0.1.7-alpha.2.md: d5e725c6b77b1d5166f1cfd25a1ef913bd5ca12b
2026-09-23-sdk-cohort-0.1.7-alpha.2.zh.md: 81ac0efa758acc72b0335e9f0fe626305e6410b2
@@ -9,6 +9,7 @@ The integration line declared `0.1.7-alpha.1` while the machine's installed host
- **The shell stopped publishing most of its custom properties inline.** The retired shell-only token contract held 278 `--dsw-*` names; alpha.2's shell bundle publishes 70 non-static names because the definitions moved into `@deepseek-ai/dsh-client-ui-theme`, whose `lib/client.js` now carries 290. The equivalent official surface is the union of the two, 293 names, and no contract token disappeared.
- **The first scan pass measured the delta against the wrong authority.** Comparing alpha.2 with the retired 278-name shell contract suggested five alpha.2 additions. Re-measuring alpha.1 and alpha.2 from their own published tarballs under the union rule gives 291 → 293: only `--dsw-alias-code-diff-added` and `--dsw-alias-code-diff-deleted` are genuinely new, and the other 13 names are pre-existing coverage gaps of the shell-only scan.
- **The class-name contract skins depend on is unchanged.** alpha.2 CSS Modules still hash as `_<local>_<hash>_<line>`, which is what the skin patch probes match on; the scan found zero source-level hard breakage across 1170 hand-written files.
- **The official archived-sessions settings page is gone.** The row id `ui-settings-unarchive-sessions` — which the `0.1.6-alpha.1` profile still mounted and whose takeover the [native-first consolidation](2026-09-15-sdk-cohort-0.1.6-alpha.1-alpha-branch.md) recorded — appears nowhere in the installed alpha.2 host tree, and `dsh --profile web --dump-config` composes no row for it. The aggregate's `retire:` override therefore named a row no bundle inserts and made every profile boot log `patch: entry "ui-settings-unarchive-sessions" not found`. The loader row roster is the one surface the compatibility scan did not cover.
Leaving the skew in place would have shipped a fallback-derivation universe authored against 278 names, stale mount-smoke pins, a stale desktop host pin, and an `engines.dsh` floor below the host the plugins run on.
@@ -51,5 +52,6 @@ The 15 names the retired contract never covered are now contract members; 13 of
- `pnpm install` at the new cohort needed the installed tree removed first. pnpm verifies the *installed* `node_modules/.pnpm/lock.yaml` against the minimum-release-age policy, so a stale tree keeps failing `[ERR_PNPM_MINIMUM_RELEASE_AGE_VIOLATION]` even when the root lockfile is already forward-dated and `minimumReleaseAge` is unset.
- The archive report's first-pass numbers were corrected in place (2 rather than 5 new tokens, 13 rather than 10 pre-existing gaps) and it now carries a follow-up section stating that this change supersedes its "not implemented" framing. The report is a one-off record in `docs/archive/`, not the authority for current behavior.
- Four packages commit `lib/`: the Skin Center `lib/` and `scripts/lib-artifact-fingerprints.json` are rebuilt and re-recorded here because the guard and registry changed; `packages/dsh-market/lib/index.js` is rebuilt only because its dependency comments changed.
- The stale `retire:` target is removed from `aggregate.yml`, `cordis.patch.yml` is regenerated, and the takeover facts in `dsh-session-archive` (module comment, spec header, bilingual README) state that this cohort's only archive entry is the family `archived-sessions` section and that no composition retirement is needed. The `retire:` mechanism stays in `scripts/aggregate.mjs` for a foreign row that genuinely exists, and `scripts/aggregate.test.mjs` pins the manifest to declare no target until one is confirmed in the same cohort with `--dump-config`.
- Residual, deliberately out of scope: twelve usage-only `--dsw-*` names that no official surface defines stay outside the contract (documented as a coverage gap rather than imported into it); the skin probe residue found by the scan (198 occurrences probing historically removed class names, 15 probing names alpha.2 genuinely removed, 6 probing renamed names) is not repaired here; `desktop/runtime/profile-web` still pins `@linxin666/dsh-web-all` 0.3.19 against this repository's 0.3.24.
- The running GUI's `lib/` output is live on the next page load, but anything that reaches a bundle row or `cordis.patch.yml` needs the operator to restart the DSH service; this change is verified in the worktree and in the shared checkout with that restart still pending.
@@ -9,6 +9,7 @@ Status: implemented
- **官方壳不再内联发布大部分自定义属性。** 已退役的「仅壳」token 契约收录 278 个 `--dsw-*` 名字;alpha.2 的壳 bundle 只发布 70 个非 static 名字,因为定义搬进了 `@deepseek-ai/dsh-client-ui-theme`,其 `lib/client.js` 现在带 290 个。等效的官方面是两者的并集 293 个,且没有任何契约内 token 消失。
- **扫描第一轮量错了权威源。** 拿 alpha.2 对比退役的 278 名字壳契约会得出「alpha.2 新增 5 个」;按并集口径从 alpha.1、alpha.2 各自的已发布 tarball 重新测量得到 291 → 293:只有 `--dsw-alias-code-diff-added` 与 `--dsw-alias-code-diff-deleted` 是真正新增,另外 13 个名字是「仅壳」扫描一直漏收的既有缺口。
- **皮肤依赖的类名契约没有变。** alpha.2 的 CSS Modules 仍然哈希为 `_<local>_<hash>_<line>`,正是皮肤 patch 探针所匹配的形态;扫描在 1170 个手写文件里没有发现任何源码级硬性破坏。
- **官方的归档会话设置页已经消失。** 行 id `ui-settings-unarchive-sessions`——`0.1.6-alpha.1` profile 当时仍挂载、其接管决策记录在[原生优先合并](2026-09-15-sdk-cohort-0.1.6-alpha.1-alpha-branch.md)里——在已安装的 alpha.2 宿主树里完全不出现,`dsh --profile web --dump-config` 也组合不出这一行。聚合包的 `retire:` 覆盖因此指向了没有任何 bundle 插入的行,让每次 profile 启动都记录 `patch: entry "ui-settings-unarchive-sessions" not found`。loader 行名册是本次兼容性扫描唯一没有覆盖的官方面。
放任这处错位,就等于发布一套按 278 个名字编写的 fallback 派生宇宙,外加过期的 mount-smoke 固定值、过期的桌面宿主固定值和低于实际宿主的 `engines.dsh` 下限。
@@ -51,5 +52,6 @@ Status: implemented
- 新 cohort 下的 `pnpm install` 必须先删掉已安装树。pnpm 校验的是**已安装**的 `node_modules/.pnpm/lock.yaml` 是否符合最小发布年龄策略,因此即使根 lockfile 已前移且 `minimumReleaseAge` 未设置,陈旧树仍会持续报 `[ERR_PNPM_MINIMUM_RELEASE_AGE_VIOLATION]`。
- 归档报告的首轮数字已就地更正(新增 2 个而非 5 个,既有缺口 13 个而非 10 个),并追加了「后续进展」一节,声明本次变更取代其「本次未实施」的表述。该报告是 `docs/archive/` 里的一次性记录,不是当前行为的权威。
- 四个包提交 `lib/`:Skin Center 的 `lib/` 与 `scripts/lib-artifact-fingerprints.json` 因守卫与注册表变化在本变更内重建并重录;`packages/dsh-market/lib/index.js` 仅因其依赖注释变化而重建。
- 过期的 `retire:` 目标已从 `aggregate.yml` 移除,`cordis.patch.yml` 已重新生成;`dsh-session-archive` 的接管事实(模块注释、spec 头注释、双语 README)已改写为本 cohort 的现状:唯一的归档入口就是家族 `archived-sessions` section,无需组合层退役。`retire:` 机制保留在 `scripts/aggregate.mjs` 中,供确实存在的外部行使用;`scripts/aggregate.test.mjs` 会钉住清单,直到某个目标在同一 cohort 上用 `--dump-config` 得到确认。
- 明确留在范围外的残留:十二个只被使用、没有任何官方面定义的 `--dsw-*` 名字仍留在契约之外(记录为覆盖缺口而非收进契约);扫描发现的皮肤探针残留(198 处探向历史上被移除的类名、15 处探向 alpha.2 真正移除的名字、6 处探向改名后的名字)不在本次修复;`desktop/runtime/profile-web` 仍固定 `@linxin666/dsh-web-all` 0.3.19,而本仓库已是 0.3.24。
- 运行中 GUI 的 `lib/` 产物在下次页面加载即生效,但任何触及 bundle 行或 `cordis.patch.yml` 的改动都需要由用户重启 DSH 服务;本次验证在工作树与共享 checkout 内完成,该重启仍待用户执行。
@@ -2,5 +2,5 @@
# side as of the last confirmed-consistent state. Both languages carry equal authority;
# after editing either side, bring the other along and re-record with:
# node scripts/verify-docs.mjs --write <dir>
README.md: 418e3a4a8fa57b2433a246ed9e5168855ccc0f68
README.zh.md: 39baeab69ce2d6d3d4f76f5e729b1d0867837fca
README.md: e4944a4157838e622c3cf3bdd374b692c506b9a7
README.zh.md: 7a2b7681be7f348477bee441963c59f7df79b80f
+2 -2
View File
@@ -26,9 +26,9 @@ The family bundle (`dsh-web-all`) includes this plugin. For a standalone profile
dsh plugin --profile web add link:/path/to/dsh-web/packages/dsh-session-archive
```
Restart `dsh web`. The plugin **takes over the official "Archived sessions" Settings entry** rather than adding a parallel first-level one: it seats the same `settings.section` id (`archived-sessions`) and nav order (25) that `@deepseek-ai/dsh-client-ui-settings-unarchive-sessions` uses, and `dsh-web-all` retires that official row, so Settings shows a single archive entry carrying both the official restore behaviour (the section opens on the archived view) and this plugin's management surface.
Restart `dsh web`. The plugin **owns the "Archived sessions" Settings entry** instead of adding a parallel first-level one: it seats the official `settings.section` id (`archived-sessions`) at nav order (25), so Settings shows a single archive entry carrying both the native restore behaviour (the section opens on the archived view) and this plugin's management surface. DSH `0.1.7-alpha.2` no longer mounts the official `@deepseek-ai/dsh-client-ui-settings-unarchive-sessions` page that used to own that id, so no composition-layer retirement is needed.
With the aggregate the consolidation is automatic. A standalone install next to the official page renders two entries instead; disable one of the two rows in Plugins so only one archive entry mounts.
A standalone install mounts the same single entry: nothing else registers the `archived-sessions` section id on the supported cohort.
## Configuration
+2 -2
View File
@@ -26,9 +26,9 @@ pnpm add @linxin666/dsh-session-archive
dsh plugin --profile web add link:/path/to/dsh-web/packages/dsh-session-archive
```
重启 `dsh web` 后,插件**接管官方的「已归档会话」设置入口**,不再新增并行的一级入口:注册的 `settings.section` id(`archived-sessions`)与导航 order(25)都与 `@deepseek-ai/dsh-client-ui-settings-unarchive-sessions` 一致,聚合包会关闭官方那一行,因此设置里只有一条归档入口,同时承载官方恢复行为(打开即已归档视图)与本插件的管理面。
重启 `dsh web` 后,插件**接管「已归档会话」设置入口**,不新增并行的一级入口:注册的 `settings.section` id(`archived-sessions`)与导航 order(25)沿用官方口径,因此设置里只有一条归档入口,同时承载原生恢复行为(打开即已归档视图)与本插件的管理面。DSH `0.1.7-alpha.2` 起官方不再挂载曾占用该 id 的 `@deepseek-ai/dsh-client-ui-settings-unarchive-sessions` 页面,因此无需组合层退役。
使用聚合包时该合并自动生效。若单独安装且官方页面同时存在,会出现两个入口,请在「插件」里停用其中之一,只保留一条归档入口。
单独安装同样只挂载这一条入口:在受支持的 cohort 上,该 section id 没有其他注册方。
## 配置
@@ -1,14 +1,14 @@
/**
* dsh-session-archive browser half — takes over the official
* `archived-sessions` settings section instead of seating a parallel
* first-level entry. The official
* `@deepseek-ai/dsh-client-ui-settings-unarchive-sessions` page owns that
* section id at order 25, and `dsh-web-all` retires its row, so exactly one
* 「已归档会话」 nav entry remains and it carries both the native restore
* behaviour (the section opens on the archived view) and this plugin's batch,
* delete and retention surfaces. All session enumeration and mutation happens
* in the host half over loopback-fenced routes; this bundle renders the
* inventory document and drives the batch pipelines.
* dsh-session-archive browser half — owns the `archived-sessions` settings
* section (the official id, at nav order 25) instead of seating a parallel
* first-level entry. DSH 0.1.7-alpha.2 no longer mounts the official
* `@deepseek-ai/dsh-client-ui-settings-unarchive-sessions` page that used to
* own that id, so this section is the only 「已归档会话」 nav entry and it
* carries both the native restore behaviour (the section opens on the archived
* view) and this plugin's batch, delete and retention surfaces. All session
* enumeration and mutation happens in the host half over loopback-fenced
* routes; this bundle renders the inventory document and drives the batch
* pipelines.
* @module @linxin666/dsh-session-archive/client
*/
@@ -1,10 +1,10 @@
/**
* Section-identity contract for the 2026-09-15 native-first decision: the
* plugin takes over the OFFICIAL archived-sessions settings section (the id
* and order that @deepseek-ai/dsh-client-ui-settings-unarchive-sessions seats)
* instead of registering a parallel first-level entry, and dsh-web-all retires
* the official row. A regression here puts two near-identical archive entries
* back into Settings.
* plugin owns the OFFICIAL archived-sessions settings section (the id and
* order `@deepseek-ai/dsh-client-ui-settings-unarchive-sessions` seated before
* DSH 0.1.7-alpha.2 stopped mounting that page) instead of registering a
* parallel first-level entry. A regression here puts two near-identical
* archive entries back into Settings.
*/
import { describe, expect, it } from 'vitest'
import { apply } from '../src/client/index.ts'
+3 -2
View File
@@ -77,8 +77,9 @@ inactive:
- web-ui-liangshen
- web-ui-skill-explorer
# 归档设置入口(2026-09-15 原生优先决策):dsh-session-archive 注册官方 section id
# archived-sessions 与 order 25 接管该入口。>=0.1.7-alpha.2 的官方 dsh-web-app 不再
# 挂载 ui-settings-unarchive-sessions 行,所以这里没有 retire 目标:对不存在的行写
# archived-sessions 与 order 25 接管该入口,把「原生恢复列表 + 家族批量归档/删除/
# 自动策略」放在同一页。>=0.1.7-alpha.2 的官方 dsh-web-app 不再挂载
# ui-settings-unarchive-sessions 行,所以这里没有 retire 目标:对不存在的行写
# disabled 覆盖只会让 loader 每次启动都报 "patch: entry ... not found"。加回 retire
# 目标前必须先在当前 cohort 上用 dsh --profile <name> --dump-config 确认该外部行存在。
# 兼容退役子插件导出:避免老用户 profile 残留旧条目时 Node.js 抛出 ERR_PACKAGE_PATH_NOT_EXPORTED
File diff suppressed because one or more lines are too long
+1 -1
View File
@@ -1,6 +1,6 @@
{
"packages/dsh-market": "4683bfdf292bfe7854fdb32fc4844f74127ee0d1e0b08de603874b8cb5cdbf76",
"packages/dsh-preset-center": "71d8ddcbce1c6ab6deaf3a2ca70c0e7196084f0a3d120da7d2380934c98812bf",
"packages/dsh-web-all": "44e8ca0ecd5faef54d420067ee332631d49c8d458abe9c1f81363594b7282d65",
"packages/dsh-web-all": "3298efd17d4be3d4abed10a7c17a1e59b8636419ef56dc0f06a400fcb42425d2",
"packages/skins/skin-center": "a102ad0e31fce1b4474bf270e364be91d288543690ec94481637d4b59a00e7e0"
}