From 9b4aacb41adacd1a91eadc3c04f54a9bc31ac02f Mon Sep 17 00:00:00 2001 From: Turtle Date: Fri, 23 Oct 2026 12:03:07 +0800 Subject: [PATCH 1/2] refactor(util): collect hardcoded official plugin lists in dsh-official-bundles Move @deepseek-ai/dsh-official-bundles from packages/boot to packages/util and move the plugin manager's protected plugin list and the Web plugin page's hidden, ordered, and experimental bundle lists into it, so editing any of these lists no longer touches app-boot or either plugin manager package. --- ...6-09-15-shipped-optional-bundles.i18n.yaml | 4 +- .../2026-09-15-shipped-optional-bundles.md | 2 +- .../2026-09-15-shipped-optional-bundles.zh.md | 2 +- apps/cli/tsconfig.json | 2 +- apps/desktop/tsconfig.host.json | 2 +- docs/config-catalog.md | 2 +- docs/config-catalog.zh.md | 2 +- docs/module-graph.md | 4 +- docs/module-graph.zh.md | 4 +- .../official-bundle-lists/guide.i18n.yaml | 4 +- .../official-bundle-lists/guide.md | 2 +- .../official-bundle-lists/guide.zh.md | 2 +- packages/boot/README.i18n.yaml | 4 +- packages/boot/README.md | 1 - packages/boot/README.zh.md | 1 - packages/boot/app-boot/README.i18n.yaml | 4 +- packages/boot/app-boot/README.md | 2 +- packages/boot/app-boot/README.zh.md | 2 +- packages/boot/app-boot/tsconfig.json | 2 +- packages/boot/plugin-manager/src/index.ts | 18 +---- packages/boot/plugin-manager/tsconfig.json | 2 +- packages/client/tsdown.client.ts | 2 +- .../client/ui-plugin-manager/README.i18n.yaml | 4 +- packages/client/ui-plugin-manager/README.md | 2 +- .../client/ui-plugin-manager/README.zh.md | 2 +- .../client/ui-plugin-manager/package.json | 1 + .../src/client/PluginManagerPage.tsx | 35 +--------- .../src/client/presentation.ts | 19 +----- .../ui-plugin-manager/tsconfig.client.json | 3 + .../webworker-packer/README.i18n.yaml | 4 +- .../experimental/webworker-packer/README.md | 2 +- .../webworker-packer/README.zh.md | 2 +- .../webworker-packer/tsconfig.json | 2 +- packages/util/README.i18n.yaml | 4 +- packages/util/README.md | 1 + packages/util/README.zh.md | 1 + .../official-bundles/README.i18n.yaml | 25 +++---- .../{boot => util}/official-bundles/README.md | 14 ++-- .../official-bundles/README.zh.md | 14 ++-- .../official-bundles/package.json | 4 +- .../official-bundles/src/bundles.ts | 0 .../official-bundles/src/catalog.generated.ts | 0 .../official-bundles/src/index.ts | 3 +- .../official-bundles/src/plugin-manager.ts | 66 +++++++++++++++++++ .../tests/official-bundles.spec.ts | 0 .../official-bundles/tsconfig.json | 2 +- pnpm-lock.yaml | 33 +++++----- scripts/check-workspace-constraints.ts | 2 +- scripts/doc-standard.spec.ts | 2 +- scripts/gen-official-bundle-catalog.spec.ts | 4 +- scripts/gen-official-bundle-catalog.ts | 6 +- scripts/local-bundle-registry.spec.ts | 2 +- scripts/optional-bundles.spec.ts | 2 +- scripts/release/families.spec.ts | 2 +- scripts/release/families.ts | 2 +- .../release/installed-product-isolation.ts | 2 +- .../verify-default-product-isolation.spec.ts | 2 +- scripts/verify-default-product-isolation.ts | 2 +- .../verify-package-readme-model-experience.ts | 2 +- scripts/verify-product-use.spec.ts | 8 +-- scripts/verify-product-use.ts | 2 +- tsconfig.base.json | 2 +- tsconfig.host.json | 2 +- 63 files changed, 193 insertions(+), 164 deletions(-) rename packages/{boot => util}/official-bundles/README.i18n.yaml (77%) rename packages/{boot => util}/official-bundles/README.md (68%) rename packages/{boot => util}/official-bundles/README.zh.md (67%) rename packages/{boot => util}/official-bundles/package.json (76%) rename packages/{boot => util}/official-bundles/src/bundles.ts (100%) rename packages/{boot => util}/official-bundles/src/catalog.generated.ts (100%) rename packages/{boot => util}/official-bundles/src/index.ts (77%) create mode 100644 packages/util/official-bundles/src/plugin-manager.ts rename packages/{boot => util}/official-bundles/tests/official-bundles.spec.ts (100%) rename packages/{boot => util}/official-bundles/tsconfig.json (81%) diff --git a/.agents/notes/implemented/process/2026-09-15-shipped-optional-bundles.i18n.yaml b/.agents/notes/implemented/process/2026-09-15-shipped-optional-bundles.i18n.yaml index 0633a2745d..9e538f26c6 100644 --- a/.agents/notes/implemented/process/2026-09-15-shipped-optional-bundles.i18n.yaml +++ b/.agents/notes/implemented/process/2026-09-15-shipped-optional-bundles.i18n.yaml @@ -9,8 +9,8 @@ en: dc43ba84345e1405 zh: dbc03572ab7710d2 /agent-note-ship-optional-bundles-with-the-installation/decision: - en: 64a2cb7602842c44 - zh: bfcb3ef4a81773b4 + en: 2f20e356517715a6 + zh: 35c7ff8c4cd8a712 /agent-note-ship-optional-bundles-with-the-installation/alternatives-considered: en: 95b48b61757f1f13 zh: e9fb2d6ea492a4bc diff --git a/.agents/notes/implemented/process/2026-09-15-shipped-optional-bundles.md b/.agents/notes/implemented/process/2026-09-15-shipped-optional-bundles.md index a94f480378..74f824fc88 100644 --- a/.agents/notes/implemented/process/2026-09-15-shipped-optional-bundles.md +++ b/.agents/notes/implemented/process/2026-09-15-shipped-optional-bundles.md @@ -10,7 +10,7 @@ The Web plugin page manages only the bundles a person installed into the profile ## Decision -The launcher names in `OPTIONAL_BUNDLES` (`packages/boot/official-bundles/src/bundles.ts`, beside the profile templates) the bundles the installation ships for a person to switch on. Each must be a runtime dependency of `apps/cli` that declares `dsh.bundle.patch`, and no shipped profile template selects it. The plugin manager's `listBundles` reports such a bundle as `optional`: switched off until selected, never removable, resolved from the installation like any installation-supplied bundle. The Web plugin page presents offered optional bundles in its Official group, tagged experimental when the package is experimental, ahead of the profile's own installed bundles. The [persistent-terminal bundle](../../../../packages/experimental/terminal-bundle/README.md) remains available to the Host but has no page switch, even when enabled; its existing profile selection remains intact. +The launcher names in `OPTIONAL_BUNDLES` (`packages/util/official-bundles/src/bundles.ts`, beside the profile templates) the bundles the installation ships for a person to switch on. Each must be a runtime dependency of `apps/cli` that declares `dsh.bundle.patch`, and no shipped profile template selects it. The plugin manager's `listBundles` reports such a bundle as `optional`: switched off until selected, never removable, resolved from the installation like any installation-supplied bundle. The Web plugin page presents offered optional bundles in its Official group, tagged experimental when the package is experimental, ahead of the profile's own installed bundles. The [persistent-terminal bundle](../../../../packages/experimental/terminal-bundle/README.md) remains available to the Host but has no page switch, even when enabled; its existing profile selection remains intact. Default-product isolation keeps its rules with one declared exception: an optional bundle's dependency graph is outside the default product. The static gate skips the `dependencies` edge from `@deepseek-ai/dsh` to a listed bundle and still rejects a runtime import, a shipped composition, a preset, or a default template that names it, an experimental dependency the list does not name, and a listed name that is not a runtime dependency or not a bundle. The workspace-constraints check accepts the same `dependencies` edges and no other runtime section, and the packed-install release check skips them from the installed entry package while requiring each listed bundle to be installed. diff --git a/.agents/notes/implemented/process/2026-09-15-shipped-optional-bundles.zh.md b/.agents/notes/implemented/process/2026-09-15-shipped-optional-bundles.zh.md index e96a316ccd..129f76c454 100644 --- a/.agents/notes/implemented/process/2026-09-15-shipped-optional-bundles.zh.md +++ b/.agents/notes/implemented/process/2026-09-15-shipped-optional-bundles.zh.md @@ -10,7 +10,7 @@ Web 插件页只管理用户装进 profile 的组合包。像 Agent Teams 这样 ## 决策 -启动器在 `OPTIONAL_BUNDLES`(`packages/boot/official-bundles/src/bundles.ts`,与 profile 模板并列)里点名安装随附、供用户开启的组合包。每一个都必须是 `apps/cli` 声明了 `dsh.bundle.patch` 的运行时依赖,且不被任何随附 profile 模板选中。插件管理器的 `listBundles` 把这类组合包报告为 `optional`:选中前保持关闭、永不可卸载、像其他安装提供的组合包一样从安装目录解析。Web 插件页在「官方」分组展示可供选择的可选组合包,属于实验包的带实验性标签,排在 profile 自己已安装的组合包之前。[持久终端组合包](../../../../packages/experimental/terminal-bundle/README.zh.md)仍可供 Host 使用,但即使已启用也不提供页面开关;已有的 profile 选择保持不变。 +启动器在 `OPTIONAL_BUNDLES`(`packages/util/official-bundles/src/bundles.ts`,与 profile 模板并列)里点名安装随附、供用户开启的组合包。每一个都必须是 `apps/cli` 声明了 `dsh.bundle.patch` 的运行时依赖,且不被任何随附 profile 模板选中。插件管理器的 `listBundles` 把这类组合包报告为 `optional`:选中前保持关闭、永不可卸载、像其他安装提供的组合包一样从安装目录解析。Web 插件页在「官方」分组展示可供选择的可选组合包,属于实验包的带实验性标签,排在 profile 自己已安装的组合包之前。[持久终端组合包](../../../../packages/experimental/terminal-bundle/README.zh.md)仍可供 Host 使用,但即使已启用也不提供页面开关;已有的 profile 选择保持不变。 默认产品隔离的规则保持不变,只声明一个例外:可选组合包的依赖图在默认产品之外。静态门禁跳过从 `@deepseek-ai/dsh` 到列表中组合包的 `dependencies` 边,仍然拒绝运行时 import、随附组合、preset 或默认模板对它的引用,拒绝列表没有点名的实验依赖,也拒绝不是运行时依赖或不是组合包的列表项。workspace 约束检查接受同样的 `dependencies` 边而不接受其他运行时依赖段;发布时的 packed-install 检查对已安装入口包跳过这些边,并要求列表中的每个组合包都已安装。 diff --git a/apps/cli/tsconfig.json b/apps/cli/tsconfig.json index 254a5a4f73..c52e4793e2 100644 --- a/apps/cli/tsconfig.json +++ b/apps/cli/tsconfig.json @@ -21,7 +21,7 @@ "path": "../../packages/boot/app-boot" }, { - "path": "../../packages/boot/official-bundles" + "path": "../../packages/util/official-bundles" }, { "path": "../../packages/boot/cmdline" diff --git a/apps/desktop/tsconfig.host.json b/apps/desktop/tsconfig.host.json index 21cda5fcf8..b0bcc315f0 100644 --- a/apps/desktop/tsconfig.host.json +++ b/apps/desktop/tsconfig.host.json @@ -12,7 +12,7 @@ "path": "../../packages/boot/app-boot" }, { - "path": "../../packages/boot/official-bundles" + "path": "../../packages/util/official-bundles" }, { "path": "../../packages/util/home-paths" diff --git a/docs/config-catalog.md b/docs/config-catalog.md index 635a6bf5bb..58536f99b4 100644 --- a/docs/config-catalog.md +++ b/docs/config-catalog.md @@ -4864,7 +4864,7 @@ Imported as libraries by other packages; a `cordis.yml` cannot load them. | `@deepseek-ai/dsh-llm-mock-server` | — | [`packages/test-support/llm-mock-server/src/index.ts`](../packages/test-support/llm-mock-server/src/index.ts) | | `@deepseek-ai/dsh-loader-smoke` | — | [`packages/test-support/loader-smoke/src/index.ts`](../packages/test-support/loader-smoke/src/index.ts) | | `@deepseek-ai/dsh-native-command` | — | [`packages/util/native-command/src/index.ts`](../packages/util/native-command/src/index.ts) | -| `@deepseek-ai/dsh-official-bundles` | — | [`packages/boot/official-bundles/src/index.ts`](../packages/boot/official-bundles/src/index.ts) | +| `@deepseek-ai/dsh-official-bundles` | — | [`packages/util/official-bundles/src/index.ts`](../packages/util/official-bundles/src/index.ts) | | `@deepseek-ai/dsh-output-retention` | — | [`packages/util/output-retention/src/index.ts`](../packages/util/output-retention/src/index.ts) | | `@deepseek-ai/dsh-package-manifest` | — | [`packages/util/package-manifest/src/index.ts`](../packages/util/package-manifest/src/index.ts) | | `@deepseek-ai/dsh-plugin-detail` | — | [`packages/util/plugin-detail/src/index.ts`](../packages/util/plugin-detail/src/index.ts) | diff --git a/docs/config-catalog.zh.md b/docs/config-catalog.zh.md index 05dfab89c0..c7cc4b27f9 100644 --- a/docs/config-catalog.zh.md +++ b/docs/config-catalog.zh.md @@ -4866,7 +4866,7 @@ export interface Config { | `@deepseek-ai/dsh-llm-mock-server` | — | [`packages/test-support/llm-mock-server/src/index.ts`](../packages/test-support/llm-mock-server/src/index.ts) | | `@deepseek-ai/dsh-loader-smoke` | — | [`packages/test-support/loader-smoke/src/index.ts`](../packages/test-support/loader-smoke/src/index.ts) | | `@deepseek-ai/dsh-native-command` | — | [`packages/util/native-command/src/index.ts`](../packages/util/native-command/src/index.ts) | -| `@deepseek-ai/dsh-official-bundles` | — | [`packages/boot/official-bundles/src/index.ts`](../packages/boot/official-bundles/src/index.ts) | +| `@deepseek-ai/dsh-official-bundles` | — | [`packages/util/official-bundles/src/index.ts`](../packages/util/official-bundles/src/index.ts) | | `@deepseek-ai/dsh-output-retention` | — | [`packages/util/output-retention/src/index.ts`](../packages/util/output-retention/src/index.ts) | | `@deepseek-ai/dsh-package-manifest` | — | [`packages/util/package-manifest/src/index.ts`](../packages/util/package-manifest/src/index.ts) | | `@deepseek-ai/dsh-plugin-detail` | — | [`packages/util/plugin-detail/src/index.ts`](../packages/util/plugin-detail/src/index.ts) | diff --git a/docs/module-graph.md b/docs/module-graph.md index 7308d7df9d..492f4ed711 100644 --- a/docs/module-graph.md +++ b/docs/module-graph.md @@ -17,6 +17,7 @@ flowchart TD pkg_launch_environment["launch-environment"] pkg_lazy_require["lazy-require"] pkg_native_command["native-command"] + pkg_official_bundles["official-bundles"] pkg_output_retention["output-retention"] pkg_package_manifest["package-manifest"] pkg_plugin_detail["plugin-detail"] @@ -134,7 +135,6 @@ flowchart TD pkg_cmdline["cmdline"] pkg_config_editor["config-editor"] pkg_hmr["hmr"] - pkg_official_bundles["official-bundles"] pkg_plugin_manager["plugin-manager"] pkg_plugin_market["plugin-market"] end @@ -1467,6 +1467,7 @@ flowchart TD | [`launch-environment`](../packages/util/launch-environment) | `util` | — | | [`lazy-require`](../packages/util/lazy-require) | `util` | — | | [`native-command`](../packages/util/native-command) | `util` | — | +| [`official-bundles`](../packages/util/official-bundles) | `util` | — | | [`output-retention`](../packages/util/output-retention) | `util` | — | | [`package-manifest`](../packages/util/package-manifest) | `util` | — | | [`plugin-detail`](../packages/util/plugin-detail) | `util` | — | @@ -1486,7 +1487,6 @@ flowchart TD | [`api-remote-access`](../packages/api/remote-access) | `api` | — | | [`api-workspace-files`](../packages/api/workspace-files) | `api` | — | | [`cmdline`](../packages/boot/cmdline) | `boot` | — | -| [`official-bundles`](../packages/boot/official-bundles) | `boot` | — | | [`acp-app`](../packages/bundle/acp-app) | `bundle` | — | | [`base`](../packages/bundle/base) | `bundle` | — | | [`sdk-app`](../packages/bundle/sdk-app) | `bundle` | — | diff --git a/docs/module-graph.zh.md b/docs/module-graph.zh.md index ecce1ba225..9c086c9ac7 100644 --- a/docs/module-graph.zh.md +++ b/docs/module-graph.zh.md @@ -19,6 +19,7 @@ flowchart TD pkg_launch_environment["launch-environment"] pkg_lazy_require["lazy-require"] pkg_native_command["native-command"] + pkg_official_bundles["official-bundles"] pkg_output_retention["output-retention"] pkg_package_manifest["package-manifest"] pkg_plugin_detail["plugin-detail"] @@ -136,7 +137,6 @@ flowchart TD pkg_cmdline["cmdline"] pkg_config_editor["config-editor"] pkg_hmr["hmr"] - pkg_official_bundles["official-bundles"] pkg_plugin_manager["plugin-manager"] pkg_plugin_market["plugin-market"] end @@ -1469,6 +1469,7 @@ flowchart TD | [`launch-environment`](../packages/util/launch-environment) | `util` | — | | [`lazy-require`](../packages/util/lazy-require) | `util` | — | | [`native-command`](../packages/util/native-command) | `util` | — | +| [`official-bundles`](../packages/util/official-bundles) | `util` | — | | [`output-retention`](../packages/util/output-retention) | `util` | — | | [`package-manifest`](../packages/util/package-manifest) | `util` | — | | [`plugin-detail`](../packages/util/plugin-detail) | `util` | — | @@ -1488,7 +1489,6 @@ flowchart TD | [`api-remote-access`](../packages/api/remote-access) | `api` | — | | [`api-workspace-files`](../packages/api/workspace-files) | `api` | — | | [`cmdline`](../packages/boot/cmdline) | `boot` | — | -| [`official-bundles`](../packages/boot/official-bundles) | `boot` | — | | [`acp-app`](../packages/bundle/acp-app) | `bundle` | — | | [`base`](../packages/bundle/base) | `bundle` | — | | [`sdk-app`](../packages/bundle/sdk-app) | `bundle` | — | diff --git a/docs/upgrade-guide/v0.2.1-rc.2/official-bundle-lists/guide.i18n.yaml b/docs/upgrade-guide/v0.2.1-rc.2/official-bundle-lists/guide.i18n.yaml index 5697bed51b..e0d389e024 100644 --- a/docs/upgrade-guide/v0.2.1-rc.2/official-bundle-lists/guide.i18n.yaml +++ b/docs/upgrade-guide/v0.2.1-rc.2/official-bundle-lists/guide.i18n.yaml @@ -12,5 +12,5 @@ en: 0d8984d9bead43c6 zh: 60939a14fcf1ba9a /import-bundle-lists-from-deepseek-ai-dsh-official-bundles/migration: - en: 6db29a6197a38b9e - zh: f1b445be37526806 + en: ef2f3d6258a3b2bb + zh: 65a79e9551f8b237 diff --git a/docs/upgrade-guide/v0.2.1-rc.2/official-bundle-lists/guide.md b/docs/upgrade-guide/v0.2.1-rc.2/official-bundle-lists/guide.md index 602fa01af5..1316bd299f 100644 --- a/docs/upgrade-guide/v0.2.1-rc.2/official-bundle-lists/guide.md +++ b/docs/upgrade-guide/v0.2.1-rc.2/official-bundle-lists/guide.md @@ -15,4 +15,4 @@ English | [中文](guide.zh.md) 1. Add `@deepseek-ai/dsh-official-bundles` to the `dependencies` of each package that imports one of these names. 2. Change those imports from `@deepseek-ai/dsh-app-boot` to `@deepseek-ai/dsh-official-bundles`, for example `import { PROFILE_TEMPLATES } from '@deepseek-ai/dsh-official-bundles'`. Keep importing every other name, such as `initProfile` or `loadProfile`, from `@deepseek-ai/dsh-app-boot`. -3. Run your type check or build; it succeeds when no import of a moved name from `@deepseek-ai/dsh-app-boot` remains. See the [package README](../../../../packages/boot/official-bundles/README.md) for each list. +3. Run your type check or build; it succeeds when no import of a moved name from `@deepseek-ai/dsh-app-boot` remains. See the [package README](../../../../packages/util/official-bundles/README.md) for each list. diff --git a/docs/upgrade-guide/v0.2.1-rc.2/official-bundle-lists/guide.zh.md b/docs/upgrade-guide/v0.2.1-rc.2/official-bundle-lists/guide.zh.md index bff51e358a..50047b0522 100644 --- a/docs/upgrade-guide/v0.2.1-rc.2/official-bundle-lists/guide.zh.md +++ b/docs/upgrade-guide/v0.2.1-rc.2/official-bundle-lists/guide.zh.md @@ -15,4 +15,4 @@ description: "组合包列表和 profile 模板从 @deepseek-ai/dsh-app-boot 移 1. 在每个导入这些名称的包的 `dependencies` 中加入 `@deepseek-ai/dsh-official-bundles`。 2. 把这些导入从 `@deepseek-ai/dsh-app-boot` 改为 `@deepseek-ai/dsh-official-bundles`,例如 `import { PROFILE_TEMPLATES } from '@deepseek-ai/dsh-official-bundles'`。其他名称(如 `initProfile` 或 `loadProfile`)仍从 `@deepseek-ai/dsh-app-boot` 导入。 -3. 运行类型检查或构建;不再有从 `@deepseek-ai/dsh-app-boot` 导入已移动名称的代码时即通过。各列表的说明见[包 README](../../../../packages/boot/official-bundles/README.zh.md)。 +3. 运行类型检查或构建;不再有从 `@deepseek-ai/dsh-app-boot` 导入已移动名称的代码时即通过。各列表的说明见[包 README](../../../../packages/util/official-bundles/README.zh.md)。 diff --git a/packages/boot/README.i18n.yaml b/packages/boot/README.i18n.yaml index 1c4b79c79d..0a33b9fd4f 100644 --- a/packages/boot/README.i18n.yaml +++ b/packages/boot/README.i18n.yaml @@ -15,8 +15,8 @@ en: 09848f4d056e4fc1 zh: 8df6139cff0288f6 /boot-shared-app-bin-boot-glue/packages: - en: c97ae01c92f6756e - zh: 2ebb832078874b7a + en: 358a944a024ffeb1 + zh: f430e25832085068 /boot-shared-app-bin-boot-glue/related-documentation: en: 77af4b40ee7b98a3 zh: e9b4e817823b973d diff --git a/packages/boot/README.md b/packages/boot/README.md index 9ace015e65..04e4325fe3 100644 --- a/packages/boot/README.md +++ b/packages/boot/README.md @@ -23,7 +23,6 @@ The boot group launches profile applications and manages their installed composi | Package | Role | ctx key | |---|---|---| | [`app-boot`](app-boot/README.md) | Boots a dsh app from a `cordis.yml`: loads `.env`, applies profile and patch layers, and reports startup failures clearly | (library for the bins) | -| [`official-bundles`](official-bundles/README.md) | Lists the bundles the installation ships in profile templates, offers switched off, installs on demand, or retires | (library) | | [`cmdline`](cmdline/README.md) | Lets the app own its flags, `--help`, and exit code; passes everything after the launcher's flags through verbatim | `cmdlineArgs`, `appExit` | | [`hmr`](hmr/README.md) | Coordinates module and configuration reloads with package mutations | `hmr` | | [`config-editor`](config-editor/README.md) | Persists active profile configuration through Loader reconciliation | `configEditor` | diff --git a/packages/boot/README.zh.md b/packages/boot/README.zh.md index aa0c6d3d37..afdee696e2 100644 --- a/packages/boot/README.zh.md +++ b/packages/boot/README.zh.md @@ -23,7 +23,6 @@ boot 组负责启动 profile 应用并管理其已安装组合。`app-boot` 解 | 包 | 职责 | ctx 键 | |---|---|---| | [`app-boot`](app-boot/README.zh.md) | 从 `cordis.yml` 启动 dsh 应用:加载 `.env`、应用 profile 与 patch 层,并清晰报告启动失败 | (供各 bin 使用的库) | -| [`official-bundles`](official-bundles/README.zh.md) | 列出安装随附于 profile 模板、默认关闭提供、按需安装或已退役的组合包 | (库) | | [`cmdline`](cmdline/README.zh.md) | 让应用持有自己的 flag、`--help` 与退出码;启动器自身 flag 之后的一切原样传入 | `cmdlineArgs`、`appExit` | | [`hmr`](hmr/README.zh.md) | 协调模块与配置重载,并与包修改互斥执行 | `hmr` | | [`config-editor`](config-editor/README.zh.md) | 通过 Loader 应用并持久化当前 profile 配置 | `configEditor` | diff --git a/packages/boot/app-boot/README.i18n.yaml b/packages/boot/app-boot/README.i18n.yaml index 7170485221..0c16677a8b 100644 --- a/packages/boot/app-boot/README.i18n.yaml +++ b/packages/boot/app-boot/README.i18n.yaml @@ -33,8 +33,8 @@ en: c4a301652b851ce9 zh: 784871e19cd9db0a /deepseek-ai-dsh-app-boot/use-this-package/reading-plugin-display-metadata: - en: b737278c1bc065e7 - zh: f42bdbfe267581d1 + en: 91d80c444ac0cfe5 + zh: e7db496043528ffb /deepseek-ai-dsh-app-boot/use-this-package/startup-and-reload-failures: en: dc13dfa1f79292e4 zh: d51682ced7a18ac2 diff --git a/packages/boot/app-boot/README.md b/packages/boot/app-boot/README.md index 53c72680be..20204ef7c8 100644 --- a/packages/boot/app-boot/README.md +++ b/packages/boot/app-boot/README.md @@ -86,7 +86,7 @@ The projector preserves native omission behavior by checking literal defaults ag Use `readPluginMeta(specifier, parentURL)` or `ctx.pluginPackages.metaOf(specifier, parentURL)` to read installed package display text without importing or activating the plugin. Lookup uses the complete package specifier and the caller's resolution base, respecting Node exports. File paths and file URLs return no metadata without resolving resources. For a package-root specifier, missing locale fields fall back to the accessible `package.json`; a subpath specifier never reads a `package.json`. Malformed metadata returns an `error` diagnostic. Results retain translations for Client-side language selection. The reader also loads an image data URL, even when locale text is complete: a package root uses its manifest `icon`, or `/icon` when that field is omitted; a subpath uses `/icon`. An icon error preserves valid text alongside the diagnostic. See [Plugin display metadata](../../../docs/cookbook/adding-a-package.md#plugin-display-metadata) for the author format. -The profile templates, installation-owned profile tuples, and retired bundle list that app-boot applies live in [`@deepseek-ai/dsh-official-bundles`](../official-bundles/README.md), together with the installation's default, optional, and on-demand bundle lists. +The profile templates, installation-owned profile tuples, and retired bundle list that app-boot applies live in [`@deepseek-ai/dsh-official-bundles`](../../util/official-bundles/README.md), together with the installation's default, optional, and on-demand bundle lists. ### Startup and reload failures diff --git a/packages/boot/app-boot/README.zh.md b/packages/boot/app-boot/README.zh.md index a22b7eabab..eb59327df8 100644 --- a/packages/boot/app-boot/README.zh.md +++ b/packages/boot/app-boot/README.zh.md @@ -86,7 +86,7 @@ profile 导入插件前,DSH 会将其声明的 DSH 版本要求与 `getDshRunt 使用 `readPluginMeta(specifier, parentURL)` 或 `ctx.pluginPackages.metaOf(specifier, parentURL)` 读取已安装包的展示文本,无需导入或激活插件。查询使用完整包标识与调用方的解析基准,并遵循 Node exports。文件路径与文件 URL 不解析资源,直接返回无元信息。包根标识缺失的 locale 字段回退到可访问的 `package.json`;子路径标识从不读取 `package.json`。格式错误的元信息返回 `error` 诊断。结果保留翻译,由 Client 选择语言。即使 locale 文本完整,读取器也会加载图片 data URL:包根使用清单 `icon`,省略该字段时使用 `<包名>/icon`;子路径使用 `<标识>/icon`。图标出错时,保留有效文本并附上诊断。作者格式见[插件展示元信息](../../../docs/cookbook/adding-a-package.zh.md#plugin-display-metadata)。 -app-boot 应用的 profile 模板、安装方拥有的 profile 组合包元组和已退役组合包列表位于 [`@deepseek-ai/dsh-official-bundles`](../official-bundles/README.zh.md),安装方的默认、可选和按需组合包列表也在该包中。 +app-boot 应用的 profile 模板、安装方拥有的 profile 组合包元组和已退役组合包列表位于 [`@deepseek-ai/dsh-official-bundles`](../../util/official-bundles/README.zh.md),安装方的默认、可选和按需组合包列表也在该包中。 ### 启动与重载失败 diff --git a/packages/boot/app-boot/tsconfig.json b/packages/boot/app-boot/tsconfig.json index c1dcee4ba2..b5b42ed67a 100644 --- a/packages/boot/app-boot/tsconfig.json +++ b/packages/boot/app-boot/tsconfig.json @@ -27,7 +27,7 @@ "path": "../../util/home-paths" }, { - "path": "../official-bundles" + "path": "../../util/official-bundles" }, { "path": "../../util/package-manifest" diff --git a/packages/boot/plugin-manager/src/index.ts b/packages/boot/plugin-manager/src/index.ts index a9e8b56a25..44d652a408 100644 --- a/packages/boot/plugin-manager/src/index.ts +++ b/packages/boot/plugin-manager/src/index.ts @@ -24,7 +24,7 @@ import { setProfileVersionExemption, PROFILE_COMPATIBILITY_FILENAME, getDshRuntimeVersion, ResolutionRestartRequired, } from '@deepseek-ai/dsh-app-boot' -import { OPTIONAL_BUNDLES, OFFICIAL_ON_DEMAND_CATALOG } from '@deepseek-ai/dsh-official-bundles' +import { OPTIONAL_BUNDLES, OFFICIAL_ON_DEMAND_CATALOG, PROTECTED_PLUGINS } from '@deepseek-ai/dsh-official-bundles' import type {} from '@deepseek-ai/dsh-hmr' import type { ProfileContext, ProfileManifest } from '@deepseek-ai/dsh-app-boot' import { bundleManifest, readProfileRegistry, registryArguments, runProfilePnpm, saveManifest, viewProfilePackage } from './operations.ts' @@ -92,18 +92,6 @@ const DETAIL_FILE_PATH = '/api/plugin-manager/detail-file' /** An http(s) URL, as pnpm's `--registry` takes it. */ const REGISTRY_URL = /^https?:\/\/\S+$/ -const protectedModules = new Set([ - '@deepseek-ai/dsh-plugin-manager', '@deepseek-ai/cordis-plugin-loader', - '@deepseek-ai/cordis-plugin-include', '@deepseek-ai/dsh-api-gateway', - '@deepseek-ai/dsh-host-webserver', '@deepseek-ai/dsh-client-modules', - '@deepseek-ai/dsh-client-ui-settings-plugin-inventory', '@deepseek-ai/dsh-client-ui-plugin-manager', - '@deepseek-ai/dsh-host-plugin-inventory', '@deepseek-ai/dsh-typert-registry', - '@deepseek-ai/dsh-api-remotes', '@deepseek-ai/dsh-api-remote-access', - '@deepseek-ai/cordis-plugin-timer', '@deepseek-ai/dsh-client-connection', - '@deepseek-ai/dsh-host-frontend-static', '@deepseek-ai/dsh-tools', - '@deepseek-ai/dsh-hmr', -]) - /** The profile files an installation writes and a failed or cancelled one restores. */ const RESTORED_FILES = ['package.json', 'pnpm-lock.yaml'] as const @@ -456,7 +444,7 @@ export class PluginManager extends TypertRemoteService { const actual = [...this.ctx.loader.entries()].find(row => row.id === entry.entryId) const candidates = rows.filter(row => row.id === actual?.options.id) const candidate = candidates[0] - if (protectedModules.has(entry.moduleName) || entry.entryId === this.ownerEntryId) { + if (PROTECTED_PLUGINS.has(entry.moduleName) || entry.entryId === this.ownerEntryId) { return { ...entry, readOnlyReason: 'management-required' as const } } if (candidate === undefined || candidates.length > 1 || candidate.name !== entry.moduleName @@ -1167,7 +1155,7 @@ export class PluginManager extends TypertRemoteService { // Unreadable bundles contribute no new rows; listBundles reports their diagnostics. return false } - const protectedBundle = rows.some(row => protectedModules.has(row.name) || `include:${row.id}` === this.ownerEntryId) + const protectedBundle = rows.some(row => PROTECTED_PLUGINS.has(row.name) || `include:${row.id}` === this.ownerEntryId) if (protectedBundle) this.managementBundles.add(name) return protectedBundle } diff --git a/packages/boot/plugin-manager/tsconfig.json b/packages/boot/plugin-manager/tsconfig.json index 02a2169c8e..97732ec2d5 100644 --- a/packages/boot/plugin-manager/tsconfig.json +++ b/packages/boot/plugin-manager/tsconfig.json @@ -24,7 +24,7 @@ "path": "../app-boot" }, { - "path": "../official-bundles" + "path": "../../util/official-bundles" }, { "path": "../../util/atomic-write" diff --git a/packages/client/tsdown.client.ts b/packages/client/tsdown.client.ts index c80b06b289..ca7bbc4154 100644 --- a/packages/client/tsdown.client.ts +++ b/packages/client/tsdown.client.ts @@ -82,7 +82,7 @@ function styleInjectionModule( * Everything else under @deepseek-ai/* is either a module-table entry * (external) or a leak the purity gate rejects. */ -export const INLINE_SAFE = /^(?:@deepseek-ai\/dsh-(?:file-reference|session|llm|tools|brand|deque|output-retention|typert-protocol|util-crypto|util-values|util-workspace-path)(?:\/|$)|@deepseek-ai\/dsh-util-file-drag$|@deepseek-ai\/dsh-token-meter\/client$|@deepseek-ai\/dsh-native-command\/types$|@deepseek-ai\/dsh-host-open-in-app\/shared$|@deepseek-ai\/dsh-plugin-manager\/registry$|@deepseek-ai\/dsh-agent-preset-registry\/display$|@deepseek-ai\/dsh-api-workspace-controller\/default-workspace$|@deepseek-ai\/dsh-spill-policy\/notice$)/ +export const INLINE_SAFE = /^(?:@deepseek-ai\/dsh-(?:file-reference|session|llm|tools|brand|official-bundles|deque|output-retention|typert-protocol|util-crypto|util-values|util-workspace-path)(?:\/|$)|@deepseek-ai\/dsh-util-file-drag$|@deepseek-ai\/dsh-token-meter\/client$|@deepseek-ai\/dsh-native-command\/types$|@deepseek-ai\/dsh-host-open-in-app\/shared$|@deepseek-ai\/dsh-plugin-manager\/registry$|@deepseek-ai\/dsh-agent-preset-registry\/display$|@deepseek-ai\/dsh-api-workspace-controller\/default-workspace$|@deepseek-ai\/dsh-spill-policy\/notice$)/ /** * Vendored framework libraries: rescoped into @deepseek-ai, so the gate below diff --git a/packages/client/ui-plugin-manager/README.i18n.yaml b/packages/client/ui-plugin-manager/README.i18n.yaml index 16a9ce7a2c..1fe97166b2 100644 --- a/packages/client/ui-plugin-manager/README.i18n.yaml +++ b/packages/client/ui-plugin-manager/README.i18n.yaml @@ -48,8 +48,8 @@ en: 21a0bbe8eb92229c zh: 096ff63db61992bb /deepseek-ai-dsh-client-ui-plugin-manager/understand-the-implementation/configuration-slots: - en: b3b8bd3606fc9e97 - zh: 7cd90e182073c8eb + en: 2b34cac9647abe63 + zh: 1929fc24aee6793c /deepseek-ai-dsh-client-ui-plugin-manager/further-exploration: en: f9a42dfed0360d6a zh: 455a70bcb6c69624 diff --git a/packages/client/ui-plugin-manager/README.md b/packages/client/ui-plugin-manager/README.md index 5a659bc446..bc7802a592 100644 --- a/packages/client/ui-plugin-manager/README.md +++ b/packages/client/ui-plugin-manager/README.md @@ -142,7 +142,7 @@ While the Plugins page has access, other Client plugins can read `pluginNavigati Custom item pages use the Host entry id as their registration id; row pages use the bundle package and row id. The page owner supplies `form.state` and `form.mutate(operations, expectedRevision)` when the entry exposes editable Config fields. A custom page owns its draft and validation display, and may reuse `ConfigField` from ui-primitives. Bundle-wide pages can contain several entries and have no single form. -The page's `main` registration declares `plugins.item`, `plugins.bundle.config`, and `plugins.row.config` as its children, so the slots exist while the page does and a registrant's `ctx.slots.inject` waits for them. `configLedgerSource` projects the three ledgers into one observable — the official items in ledger order with their labels resolved in the active locale, and the bundle and row keys — cached until a ledger or the locale moves; the page binds it as `useConfigLedger` beside the store and never names a configurable plugin itself. The registration-owned navigation store selects the main list, the full experimental plugin list, a bundle, an official plugin, or a bundle row; switching away from the Plugins panel resets it to the list, while React remounts preserve the selected target. A fresh registration starts on the main list. Installation highlighting scrolls to a card only when it is on the current page; it does not change the selected page. Other Client plugins read `pluginNavigation` optionally, through `ctx.get` or `ctx.inject`, and call its `openBundle(packageName)` to open bundle details without changing the current Session; listing it in a plugin's `inject` keeps that plugin pending on a page without access. The target survives the initial inventory load; an absent bundle displays the list. A registration lives with the browser half that made it. `dsh-client-modules` attaches a package's browser half to the Loader row whose specifier is the bare package name, so every page a bundle registers, for itself or for any of its rows, goes away when that row is switched off; a sub-plugin whose page must outlive the other rows ships as its own package. Cards and detail pages show the Experimental marker only for packages in `EXPERIMENTAL_BUNDLES` in [presentation.ts](src/client/presentation.ts); package-name prefixes do not select the marker. +The page's `main` registration declares `plugins.item`, `plugins.bundle.config`, and `plugins.row.config` as its children, so the slots exist while the page does and a registrant's `ctx.slots.inject` waits for them. `configLedgerSource` projects the three ledgers into one observable — the official items in ledger order with their labels resolved in the active locale, and the bundle and row keys — cached until a ledger or the locale moves; the page binds it as `useConfigLedger` beside the store and never names a configurable plugin itself. The registration-owned navigation store selects the main list, the full experimental plugin list, a bundle, an official plugin, or a bundle row; switching away from the Plugins panel resets it to the list, while React remounts preserve the selected target. A fresh registration starts on the main list. Installation highlighting scrolls to a card only when it is on the current page; it does not change the selected page. Other Client plugins read `pluginNavigation` optionally, through `ctx.get` or `ctx.inject`, and call its `openBundle(packageName)` to open bundle details without changing the current Session; listing it in a plugin's `inject` keeps that plugin pending on a page without access. The target survives the initial inventory load; an absent bundle displays the list. A registration lives with the browser half that made it. `dsh-client-modules` attaches a package's browser half to the Loader row whose specifier is the bare package name, so every page a bundle registers, for itself or for any of its rows, goes away when that row is switched off; a sub-plugin whose page must outlive the other rows ships as its own package. Cards and detail pages show the Experimental marker only for packages in `EXPERIMENTAL_BUNDLES` in [`dsh-official-bundles`](../../util/official-bundles/README.md#plugin-manager-lists); package-name prefixes do not select the marker. `plugins.bundle.config` supplies bundle detail configuration, keyed by npm package name. Client plugins can subscribe to the read-only `ctx.pluginChanges.bundle(packageName)` source to pause their queries while a bundle or one of its rows is being changed. Notifications precede the management request and continue when the page closes; subscribers release their observation on disposal. `plugins.bundle.activation` offers bundle-owned guidance after explicit enablement from the list, with callbacks to dismiss it or open the bundle details. It does not appear merely because an enabled bundle was listed. diff --git a/packages/client/ui-plugin-manager/README.zh.md b/packages/client/ui-plugin-manager/README.zh.md index f58f0478c5..5be88a24b2 100644 --- a/packages/client/ui-plugin-manager/README.zh.md +++ b/packages/client/ui-plugin-manager/README.zh.md @@ -142,7 +142,7 @@ Host 入口通过生成的 Remote 接口暴露 `pluginRegistryProbe.fastest()` 自定义条目页以 Host 条目 id 作为注册 id;行页面使用 bundle 包名和行 id。当条目提供可编辑 Config 字段时,页面宿主传入 `form.state` 和 `form.mutate(operations, expectedRevision)`。自定义页面负责草稿和校验提示,并可复用 ui-primitives 的 `ConfigField`。整个 bundle 的页面可以包含多个条目,因此没有单一表单。 -页面的 `main` 注册把 `plugins.item`、`plugins.bundle.config` 与 `plugins.row.config` 声明为子 slot,因此它们与页面同生,注册方的 `ctx.slots.inject` 会等到它们出现。`configLedgerSource` 把三份账本投影成一个可观察对象——按账本顺序排列、标签按当前语言解析的官方条目,以及组合包与行的键——在账本或语言变化前保持缓存;页面把它作为 `useConfigLedger` 绑在 store 旁边,自身从不点名任何可配置插件。注册拥有的导航 store 选择主列表、完整的实验性插件列表、某个组合包、某个官方插件或组合包的某一行;切换离开插件面板时重置为列表,React 重新挂载则保留所选目标。新的注册从主列表开始。安装后的高亮仅在当前页面有对应卡片时滚动定位,不改变所选页面。其他 Client 插件经 `ctx.get` 或 `ctx.inject` 以可选方式读取 `pluginNavigation`,调用其 `openBundle(packageName)` 即可打开组合包详情,不改变当前 Session;把它写进插件的 `inject` 会让该插件在无权限的页面上一直等待。首次读取清单期间保留导航目标;组合包不存在时显示列表。注册与做出它的浏览器半侧同生共死。`dsh-client-modules` 只把一个包的浏览器半侧挂在说明符恰为包名的那一行 Loader 行上,所以组合包为自己或任一行注册的页面,都会在那一行被关闭时一起消失;需要在其他行关闭时仍保留页面的子插件,应作为独立的包发布。 卡片和详情页仅为 [presentation.ts](src/client/presentation.ts) 中 `EXPERIMENTAL_BUNDLES` 名单内的包显示实验性标签,包名前缀不决定标签。 +页面的 `main` 注册把 `plugins.item`、`plugins.bundle.config` 与 `plugins.row.config` 声明为子 slot,因此它们与页面同生,注册方的 `ctx.slots.inject` 会等到它们出现。`configLedgerSource` 把三份账本投影成一个可观察对象——按账本顺序排列、标签按当前语言解析的官方条目,以及组合包与行的键——在账本或语言变化前保持缓存;页面把它作为 `useConfigLedger` 绑在 store 旁边,自身从不点名任何可配置插件。注册拥有的导航 store 选择主列表、完整的实验性插件列表、某个组合包、某个官方插件或组合包的某一行;切换离开插件面板时重置为列表,React 重新挂载则保留所选目标。新的注册从主列表开始。安装后的高亮仅在当前页面有对应卡片时滚动定位,不改变所选页面。其他 Client 插件经 `ctx.get` 或 `ctx.inject` 以可选方式读取 `pluginNavigation`,调用其 `openBundle(packageName)` 即可打开组合包详情,不改变当前 Session;把它写进插件的 `inject` 会让该插件在无权限的页面上一直等待。首次读取清单期间保留导航目标;组合包不存在时显示列表。注册与做出它的浏览器半侧同生共死。`dsh-client-modules` 只把一个包的浏览器半侧挂在说明符恰为包名的那一行 Loader 行上,所以组合包为自己或任一行注册的页面,都会在那一行被关闭时一起消失;需要在其他行关闭时仍保留页面的子插件,应作为独立的包发布。 卡片和详情页仅为 [`dsh-official-bundles`](../../util/official-bundles/README.zh.md#plugin-manager-lists) 中 `EXPERIMENTAL_BUNDLES` 名单内的包显示实验性标签,包名前缀不决定标签。 `plugins.bundle.config` 以 npm 包名为 key,提供 Bundle 详情配置。Client 插件可订阅只读的 `ctx.pluginChanges.bundle(packageName)`,在组合包或其组件行变更期间暂停查询。通知先于管理请求发出,页面关闭后仍会更新;订阅方在卸载时释放观察。`plugins.bundle.activation` 在用户从列表显式启用后提供 Bundle 自有引导,并传入关闭引导和打开详情的回调。仅列出已启用的 Bundle 不会触发引导。 diff --git a/packages/client/ui-plugin-manager/package.json b/packages/client/ui-plugin-manager/package.json index a9eceb424d..068208b79d 100644 --- a/packages/client/ui-plugin-manager/package.json +++ b/packages/client/ui-plugin-manager/package.json @@ -65,6 +65,7 @@ "@deepseek-ai/dsh-client-ui-renderer": "workspace:*", "@deepseek-ai/dsh-client-ui-sidebar": "workspace:*", "@deepseek-ai/dsh-client-ui-slots": "workspace:*", + "@deepseek-ai/dsh-official-bundles": "workspace:*", "@deepseek-ai/dsh-package-manifest": "workspace:*", "@testing-library/react": "^16.3.3", "clsx": "^2.1.1", diff --git a/packages/client/ui-plugin-manager/src/client/PluginManagerPage.tsx b/packages/client/ui-plugin-manager/src/client/PluginManagerPage.tsx index 95020799b0..50c0ede3d5 100644 --- a/packages/client/ui-plugin-manager/src/client/PluginManagerPage.tsx +++ b/packages/client/ui-plugin-manager/src/client/PluginManagerPage.tsx @@ -21,6 +21,7 @@ import { type IconProps, type StateDotState, type TerminalBlockLabels, } from '@deepseek-ai/dsh-client-ui-primitives' import type { InjectFace, PropsLocale, PropsRenderSlots, PropsRuntime, PropsStore } from '@deepseek-ai/dsh-client-ui-slots' +import { EXTENSION_BUNDLES, HIDDEN_BUNDLES, MORE_BUNDLES } from '@deepseek-ai/dsh-official-bundles' import type { createNavigationStore } from './navigation-store.ts' import type { PluginHeaderLayoutFace } from './header-scroll.ts' import { rowConfigKey, type OfficialItem } from './config-ledger.ts' @@ -98,40 +99,6 @@ function AddPluginMenu({ t, disabled, openInstall, renderSlot }: { /** How long the list marks a package an install just enabled. */ const HIGHLIGHT_MS = 2_400 -/** - * Built-in profile bundles and persistent terminals have no management page. - * Their Host availability and activation stay intact. - */ -const HIDDEN_BUNDLES = new Set([ - '@deepseek-ai/dsh-base', - '@deepseek-ai/dsh-web-app', - '@deepseek-ai/dsh-headless', - '@deepseek-ai/dsh-sdk-app', - '@deepseek-ai/dsh-acp-app', - '@deepseek-ai/dsh-sdk-minimal', - '@deepseek-ai/dsh-experimental-terminal-bundle', -]) - -/** The optional bundles the main list always holds, in this order; new bundles join the main list. */ -const EXTENSION_BUNDLES = [ - '@deepseek-ai/dsh-experimental-agent-team-profile', - '@deepseek-ai/dsh-experimental-voice-input-bundle', - '@deepseek-ai/dsh-experimental-plugin-market-bundle', - '@deepseek-ai/dsh-experimental-auto-review', -] -/** The optional bundles the main list holds back until selected; the More list includes eligible entries. */ -const MORE_BUNDLES = [ - '@deepseek-ai/dsh-experimental-inspector-profile', - '@deepseek-ai/dsh-cua-bundle', - '@deepseek-ai/dsh-experimental-tool-worktree', - '@deepseek-ai/dsh-experimental-cot-translation-bundle', - '@deepseek-ai/dsh-experimental-session-search', - '@deepseek-ai/dsh-experimental-session-titles-bundle', - '@deepseek-ai/dsh-experimental-badge-skill-bundle', - '@deepseek-ai/dsh-experimental-ralph-bundle', - '@deepseek-ai/dsh-subagent-codex', - '@deepseek-ai/dsh-subagent-claude-code', -] /** * Whether the main list shows an official optional bundle: the always-held ones, and any held-back one the profile enabled. * @param pkg - the official bundle as the Host reports it. diff --git a/packages/client/ui-plugin-manager/src/client/presentation.ts b/packages/client/ui-plugin-manager/src/client/presentation.ts index c817e84f46..23a95913bf 100644 --- a/packages/client/ui-plugin-manager/src/client/presentation.ts +++ b/packages/client/ui-plugin-manager/src/client/presentation.ts @@ -1,5 +1,6 @@ /** Display labels and toast sentences for global plugin management. */ +import { EXPERIMENTAL_BUNDLES } from '@deepseek-ai/dsh-official-bundles' import type { IncompatiblePlugin, ManagementError, Registry, RestartReason } from '@deepseek-ai/dsh-api-remotes/client' import type { PropsLocale } from '@deepseek-ai/dsh-client-ui-slots' import type { PluginManagerLocaleKey } from './locales.ts' @@ -108,22 +109,6 @@ export function shortName(name: string): string { return unscoped.replace(/^dsh-(?:host-|client-)?/, '') } -/** Official bundles that display the Experimental badge. */ -const EXPERIMENTAL_BUNDLES: readonly string[] = [ - '@deepseek-ai/dsh-cua-bundle', - '@deepseek-ai/dsh-experimental-agent-team-profile', - '@deepseek-ai/dsh-experimental-voice-input-bundle', - '@deepseek-ai/dsh-experimental-auto-review', - '@deepseek-ai/dsh-experimental-inspector-profile', - '@deepseek-ai/dsh-experimental-tool-worktree', - '@deepseek-ai/dsh-experimental-cot-translation-bundle', - '@deepseek-ai/dsh-experimental-session-search', - '@deepseek-ai/dsh-experimental-session-titles-bundle', - '@deepseek-ai/dsh-experimental-badge-skill-bundle', - '@deepseek-ai/dsh-experimental-ralph-bundle', - '@deepseek-ai/dsh-experimental-plugin-market-bundle', -] - /** * Resolve installed package metadata without changing its technical identity. * @param pkg - package identity and local metadata. @@ -136,7 +121,7 @@ export function packageText( return { title: pkg.meta?.title === undefined ? pkg.name : resolveText(pkg.meta.title), description: pkg.meta?.description === undefined ? undefined : resolveText(pkg.meta.description) || undefined, - beta: EXPERIMENTAL_BUNDLES.includes(pkg.name), + beta: EXPERIMENTAL_BUNDLES.has(pkg.name), } } diff --git a/packages/client/ui-plugin-manager/tsconfig.client.json b/packages/client/ui-plugin-manager/tsconfig.client.json index 5f8c1f5e42..eefbe67b00 100644 --- a/packages/client/ui-plugin-manager/tsconfig.client.json +++ b/packages/client/ui-plugin-manager/tsconfig.client.json @@ -9,6 +9,9 @@ { "path": "../../util/package-manifest" }, + { + "path": "../../util/official-bundles" + }, { "path": "../../../vendor/cordis" }, diff --git a/packages/experimental/webworker-packer/README.i18n.yaml b/packages/experimental/webworker-packer/README.i18n.yaml index a352cfee61..3604dcd3db 100644 --- a/packages/experimental/webworker-packer/README.i18n.yaml +++ b/packages/experimental/webworker-packer/README.i18n.yaml @@ -15,8 +15,8 @@ en: 4e53164159b5ce41 zh: 89582dc0294d0776 /deepseek-ai-dsh-experimental-webworker-packer/use-this-package: - en: 4d6954171c1237f2 - zh: 1a0b1d15583435dd + en: 6a4ec925ea6681f5 + zh: 4af12d1d3de38dbd /deepseek-ai-dsh-experimental-webworker-packer/model-experience: en: e16b355530dadc1c zh: 8488e03b253b7b33 diff --git a/packages/experimental/webworker-packer/README.md b/packages/experimental/webworker-packer/README.md index 5ce722438f..1e6c3289f7 100644 --- a/packages/experimental/webworker-packer/README.md +++ b/packages/experimental/webworker-packer/README.md @@ -29,7 +29,7 @@ The packer owns the internal `dsh.configTrees` declaration, its validation, and The pack is a three-layer standard stack: -1. **Roster** — the shipped profile template's bundles and every bundle in `OPTIONAL_BUNDLES` from [`dsh-official-bundles`](../../boot/official-bundles/README.md), each resolved from the CLI manifest as the launcher resolves it, plus every package their patch files name (insert lists and grouped rows included), plus the rows of every config tree the CLI declares in its `package.json` `dsh.configTrees`, materialized as a Node-style dependency closure. External peer edges never bind the worker; workspace peers stay on the chain. The CLI manifest itself enters the image alone at `node_modules/@deepseek-ai/dsh/package.json`, as the worker's bundle resolution anchor; the manifest records its name and the profile. +1. **Roster** — the shipped profile template's bundles and every bundle in `OPTIONAL_BUNDLES` from [`dsh-official-bundles`](../../util/official-bundles/README.md), each resolved from the CLI manifest as the launcher resolves it, plus every package their patch files name (insert lists and grouped rows included), plus the rows of every config tree the CLI declares in its `package.json` `dsh.configTrees`, materialized as a Node-style dependency closure. External peer edges never bind the worker; workspace peers stay on the chain. The CLI manifest itself enters the image alone at `node_modules/@deepseek-ai/dsh/package.json`, as the worker's bundle resolution anchor; the manifest records its name and the profile. 2. **Publish view** — each workspace or vendored package contributes its built npm slice (`files` through picomatch) without source or workspace `dist/`. External packages retain published JavaScript under both `src/` and `dist/` because their `main` or `exports` may point there; only generic test, map, declaration, and archive exclusions apply. 3. **Reachability sweep** — the runtime loader's own resolution walks from every non-wildcard workspace runtime export plus the worker assembly's seeds (`IMAGE_ENTRY_SEEDS`), lowering each reached module to the wrapper contract at pack time. Declaration-only condition trees do not seed the sweep; runtime requests for those exports still fail. The transform reports statically named imports, re-exports, and dynamic imports; calls through `require`; and module-scope direct calls of the form `createRequire(import.meta.url)('pkg')` through a named import from `node:module` or `module`, including an import alias. Page assets (`lib/client.js` behind `./client` exports) ship verbatim; an unresolvable request from our own code fails the pack, third-party ones are tolerated to fail loud at require time. 4. **Lazy chunks** — every page chunk a page asset requests as a literal `require.async("./client..js")`, the only form the dynamic Client build emits, leaves the base image unless a `./client` export names it. Each becomes its own deterministic archive named `lazy/.tar.gz` beside the base image, and the manifest registers its path, size, and archive for the worker's lazy filesystem. A request for a chunk the package does not publish fails the pack. diff --git a/packages/experimental/webworker-packer/README.zh.md b/packages/experimental/webworker-packer/README.zh.md index 283a7dc401..fc760a4f65 100644 --- a/packages/experimental/webworker-packer/README.zh.md +++ b/packages/experimental/webworker-packer/README.zh.md @@ -29,7 +29,7 @@ VFS 镜像打包器:把一份随附 profile 的 bundle 和安装提供的 opti 打包是三层标准栈: -1. **Roster**——随附 profile 模板的 bundle 和 [`dsh-official-bundles`](../../boot/official-bundles/README.zh.md) `OPTIONAL_BUNDLES` 中的每个 bundle(各自按启动器的方式从 CLI manifest 解析),加上它们 patch 文件点名的每个包(含 insert 列表与分组行),再加上 CLI(命令行界面)在 `package.json` `dsh.configTrees` 里声明的每棵配置树的行,按 Node 式依赖闭包物化。外部 peer 边绝不会绑定到 worker,workspace peer 保留在链上。CLI manifest 本身单独进入镜像,位于 `node_modules/@deepseek-ai/dsh/package.json`,作为 worker 解析 bundle 的锚点;manifest 记录它的名称和 profile。 +1. **Roster**——随附 profile 模板的 bundle 和 [`dsh-official-bundles`](../../util/official-bundles/README.zh.md) `OPTIONAL_BUNDLES` 中的每个 bundle(各自按启动器的方式从 CLI manifest 解析),加上它们 patch 文件点名的每个包(含 insert 列表与分组行),再加上 CLI(命令行界面)在 `package.json` `dsh.configTrees` 里声明的每棵配置树的行,按 Node 式依赖闭包物化。外部 peer 边绝不会绑定到 worker,workspace peer 保留在链上。CLI manifest 本身单独进入镜像,位于 `node_modules/@deepseek-ai/dsh/package.json`,作为 worker 解析 bundle 的锚点;manifest 记录它的名称和 profile。 2. **发布视图**——每个 workspace 或 vendored 包贡献其构建后的 npm 切片(`files` 走 picomatch),不带源码和 workspace `dist/`。外部包的 `main` 或 `exports` 可能指向 `src/` 或 `dist/`,因此两处发布 JavaScript 都会保留,只应用通用的测试、map、声明与归档排除规则。 3. **可达性 sweep**——用运行时加载器自己的解析, 从全部不含通配符的 workspace 运行时导出加 worker 装配种子 (`IMAGE_ENTRY_SEEDS`) 出发, 打包时把每个可达模块转换为符合包装层约定的形式. 仅含类型声明的条件树不作为扫描入口; 运行时代码请求这些导出仍会失败. 该转换会报告名称可静态确定的 import、re-export 与动态 import、经 `require` 发起的调用, 以及通过 `node:module` 或 `module` 具名导入 (含导入别名) 在模块作用域直接发起的 `createRequire(import.meta.url)('pkg')` 调用. 页面资产 (`./client` 导出背后的 `lib/client.js`) 原样直发; 自家代码的不可解析请求会让打包失败, 第三方不可解析请求则允许延后到 require 时明确失败. 4. **懒加载 chunk**——页面资产以字面量 `require.async("./client..js")`(动态 Client 构建产出的唯一形式)请求的每个页面 chunk,除非被 `./client` 导出点名,否则移出基础镜像。每个 chunk 成为基础镜像旁的一个独立确定性归档,命名为 `lazy/<归档的 sha256>.tar.gz`;manifest 为 worker 的懒加载文件系统登记其路径、大小和归档。请求包未发布的 chunk 会让打包失败。 diff --git a/packages/experimental/webworker-packer/tsconfig.json b/packages/experimental/webworker-packer/tsconfig.json index a656fe2b9f..ec51dc67fb 100644 --- a/packages/experimental/webworker-packer/tsconfig.json +++ b/packages/experimental/webworker-packer/tsconfig.json @@ -18,7 +18,7 @@ "path": "../../boot/app-boot" }, { - "path": "../../boot/official-bundles" + "path": "../../util/official-bundles" }, { "path": "../webworker-runtime" diff --git a/packages/util/README.i18n.yaml b/packages/util/README.i18n.yaml index fcd63ec242..890fd678fe 100644 --- a/packages/util/README.i18n.yaml +++ b/packages/util/README.i18n.yaml @@ -15,8 +15,8 @@ en: 1eb35b015a6c423f zh: a8a3dceee2c9e943 /util-shared-utilities/packages: - en: 6f788656548ee4e0 - zh: 227695dafaa9476d + en: 069dbd056a60b42d + zh: d11751704d34daf4 /util-shared-utilities/related-documentation: en: 432ae81110914571 zh: c5bf4efc007311f3 diff --git a/packages/util/README.md b/packages/util/README.md index c305e1fb69..bc90ff961a 100644 --- a/packages/util/README.md +++ b/packages/util/README.md @@ -30,6 +30,7 @@ Each package provides one primitive; open a package page for how to use it. | [`package-manifest/`](package-manifest/README.md) | Shared TypeScript declarations for package manifests | | [`plugin-detail/`](plugin-detail/README.md) | Selects plugin detail documents and reads them from local packages and npm file CDNs | | [`plugin-market-index/`](plugin-market-index/README.md) | Validates plugin market index format 1 and builds pinned install arguments | +| [`official-bundles/`](official-bundles/README.md) | Lists the official bundle and plugin packages the installation ships, offers, installs on demand, retires, and the plugin manager protects or presents | | [`crypto/`](crypto/README.md) | Mints RFC 9562 v4 UUIDs from the cross-runtime `crypto.getRandomValues` primitive | | [`deque/`](deque/README.md) | Provides amortized constant-time queue operations with bounded vacant storage | | [`chunked-list/`](chunked-list/README.md) | Retains immutable list versions with bounded append copying and checkpoint validation | diff --git a/packages/util/README.zh.md b/packages/util/README.zh.md index 5dc7a201a6..f32779c769 100644 --- a/packages/util/README.zh.md +++ b/packages/util/README.zh.md @@ -30,6 +30,7 @@ kind: "package-group" | [`package-manifest/`](package-manifest/README.zh.md) | 包 manifest(元数据清单)的共享 TypeScript 声明 | | [`plugin-detail/`](plugin-detail/README.zh.md) | 选择插件详细介绍文档,并从本地包和 npm 文件 CDN 读取它们 | | [`plugin-market-index/`](plugin-market-index/README.zh.md) | 校验插件市场索引格式 1,并生成锁定版本的安装参数 | +| [`official-bundles/`](official-bundles/README.zh.md) | 列出安装随附、提供、按需安装或已退役的官方组合包和插件包,以及插件管理器保护或展示的包 | | [`crypto/`](crypto/README.zh.md) | 基于跨运行时 `crypto.getRandomValues` 原语生成 RFC 9562 v4 UUID | | [`deque/`](deque/README.zh.md) | 提供摊销常数时间的队列操作和有界空闲存储 | | [`chunked-list/`](chunked-list/README.zh.md) | 通过有界追加复制和检查点校验保留不可变列表版本 | diff --git a/packages/boot/official-bundles/README.i18n.yaml b/packages/util/official-bundles/README.i18n.yaml similarity index 77% rename from packages/boot/official-bundles/README.i18n.yaml rename to packages/util/official-bundles/README.i18n.yaml index de5b0232da..861c53a0c8 100644 --- a/packages/boot/official-bundles/README.i18n.yaml +++ b/packages/util/official-bundles/README.i18n.yaml @@ -1,16 +1,16 @@ # Bilingual-pair consistency record for README.md (docs/i18n/README.md): per heading # section, a hash of its English and Chinese blocks outside code blocks and generated regions. # After editing either side, bring the other along and re-record with: -# pnpm run verify-translation-pairing --write packages/boot/official-bundles/README.md +# pnpm run verify-translation-pairing --write packages/util/official-bundles/README.md /: - en: bf83ae511baf1048 - zh: f8966b8dd39c5b9a + en: 1dfa0833c0b8092b + zh: 4f3d474695e1d2b7 /deepseek-ai-dsh-official-bundles: - en: bb5c2cd3ee2ee02b - zh: cf78cfef3b92ab25 + en: 9095133679593012 + zh: ac6b05dc3eff68b6 /deepseek-ai-dsh-official-bundles/summary: - en: 3d64166b71a685bc - zh: 424e1f77fc987115 + en: fa3e54ab1672f7ea + zh: 6ab2abb75f1365b4 /deepseek-ai-dsh-official-bundles/table-of-contents: en: 80b31a934611cb4a zh: 05f3f7f9cb2fd881 @@ -21,8 +21,11 @@ en: 60ef21314c76c3ec zh: f769091957235e12 /deepseek-ai-dsh-official-bundles/use-this-package/optional-and-retired-bundles: - en: c0940eb304bbacd1 - zh: bbc4f72b7a49c676 + en: 8d94e2b44efb9c1d + zh: c049a19e471d188b +/deepseek-ai-dsh-official-bundles/use-this-package/plugin-manager-lists: + en: e90cf0b517add5d1 + zh: 3513bb01159d58ae /deepseek-ai-dsh-official-bundles/use-this-package/on-demand-bundles: en: 10dac368736afde3 zh: 7684ca22ba4b5a67 @@ -30,8 +33,8 @@ en: 2986cf8f3115a483 zh: 3eb2dade2666bbc6 /deepseek-ai-dsh-official-bundles/understand-the-implementation/source-map: - en: af30ccf226fbb7d4 - zh: f39ae7a50b2aaa80 + en: bbd3b4f82e6349d9 + zh: f1e056d14620519d /deepseek-ai-dsh-official-bundles/further-exploration: en: 16a331e64c81b2a5 zh: abfe9b1a1294b6b3 diff --git a/packages/boot/official-bundles/README.md b/packages/util/official-bundles/README.md similarity index 68% rename from packages/boot/official-bundles/README.md rename to packages/util/official-bundles/README.md index 7fb4babfa0..3313ed91ba 100644 --- a/packages/boot/official-bundles/README.md +++ b/packages/util/official-bundles/README.md @@ -1,5 +1,5 @@ --- -description: "Installation-owned lists of official dsh bundles: shipped profile templates, the default bundle list, and the optional, on-demand, and retired bundles." +description: "Installation-owned lists of official dsh packages: shipped profile templates, the default bundle list, the optional, on-demand, and retired bundles, and the plugin manager's protected and presented packages." kind: "package-library" --- @@ -9,7 +9,7 @@ English | [中文](README.zh.md) ## Summary -`@deepseek-ai/dsh-official-bundles` holds the bundle package names the dsh installation decides on: which bundles each shipped profile starts with, which bundles it ships switched off, which official bundles install on request, and which bundles earlier releases shipped and profiles drop. [`dsh-app-boot`](../app-boot/README.md) applies these lists when it loads a profile; the plugin manager, the CLI, Desktop, the WebWorker image packer, and repository checks read them directly. The package holds data only, so adding or removing a bundle leaves app-boot untouched. Use it as a direct library dependency, not through `cordis.yml`. +`@deepseek-ai/dsh-official-bundles` holds the bundle package names the dsh installation decides on: which bundles each shipped profile starts with, which bundles it ships switched off, which official bundles install on request, which bundles earlier releases shipped and profiles drop, and which packages the plugin manager protects, hides, orders, or marks experimental. [`dsh-app-boot`](../../boot/app-boot/README.md) applies these lists when it loads a profile; the plugin manager, the CLI, Desktop, the image packer, and repository checks read them directly. The package holds data only, so changing a list leaves app-boot and the plugin manager untouched. Use it as a direct library dependency, not through `cordis.yml`. ## Table of Contents @@ -32,7 +32,12 @@ Edit this package when the installation's bundle selection changes; read it wher ### Optional and retired bundles -`OPTIONAL_BUNDLES` names the bundles the installation ships for a person to switch on. Each must be a runtime dependency of the `dsh` app that declares `dsh.bundle.patch`, an icon, and `./locale/*.json` display metadata, and no template may select it; [`verify-default-product-isolation`](../../../scripts/verify-default-product-isolation.ts) checks these rules. The [plugin manager](../plugin-manager/README.md#use-this-package) reports these bundles as `optional`. `RETIRED_BUNDLES` names bundles the installation no longer carries; app-boot removes them from a profile's bundle list when it loads the profile. +`OPTIONAL_BUNDLES` names the bundles the installation ships for a person to switch on. Each must be a runtime dependency of the `dsh` app that declares `dsh.bundle.patch`, an icon, and `./locale/*.json` display metadata, and no template may select it; [`verify-default-product-isolation`](../../../scripts/verify-default-product-isolation.ts) checks these rules. The [plugin manager](../../boot/plugin-manager/README.md#use-this-package) reports these bundles as `optional`. `RETIRED_BUNDLES` names bundles the installation no longer carries; app-boot removes them from a profile's bundle list when it loads the profile. + + +### Plugin manager lists + +`PROTECTED_PLUGINS` names the plugin packages the [plugin manager](../../boot/plugin-manager/README.md) keeps read-only because management needs them; a bundle that contains one is a management bundle. The [Web plugin page](../../client/ui-plugin-manager/README.md) hides the `HIDDEN_BUNDLES`, keeps the `EXTENSION_BUNDLES` on its main list in their order, holds the `MORE_BUNDLES` back on its More list until selected, and marks the `EXPERIMENTAL_BUNDLES` with the Experimental badge. ### On-demand bundles @@ -53,6 +58,7 @@ Repository checks read the lists in `src/bundles.ts` as TypeScript literals with | File | Role | |---|---| | [`src/bundles.ts`](src/bundles.ts) | Profile templates and the default, installation-owned, retired, optional, and on-demand bundle lists | +| [`src/plugin-manager.ts`](src/plugin-manager.ts) | Protected plugin packages and the Web plugin page's hidden, ordered, and experimental bundle lists | | [`src/catalog.generated.ts`](src/catalog.generated.ts) | Generated offline metadata for the on-demand bundles | | [`src/index.ts`](src/index.ts) | Public exports and the catalog entry type | @@ -63,7 +69,7 @@ Repository checks read the lists in `src/bundles.ts` as TypeScript literals with ## Further Exploration -- [dsh-app-boot](../app-boot/README.md) — profile loading that applies the templates and retired list. +- [dsh-app-boot](../../boot/app-boot/README.md) — profile loading that applies the templates and retired list. - [Shipped optional bundles](../../../.agents/notes/implemented/process/2026-09-15-shipped-optional-bundles.md) — why the installation owns the optional list. - [Official on-demand bundles](../../../.agents/notes/implemented/architecture/2026-10-05-official-on-demand-bundles.md) — the offline catalog decision. diff --git a/packages/boot/official-bundles/README.zh.md b/packages/util/official-bundles/README.zh.md similarity index 67% rename from packages/boot/official-bundles/README.zh.md rename to packages/util/official-bundles/README.zh.md index 2d5ec91e4e..91b2d84f82 100644 --- a/packages/boot/official-bundles/README.zh.md +++ b/packages/util/official-bundles/README.zh.md @@ -1,5 +1,5 @@ --- -description: "由安装方持有的官方 dsh 组合包列表:随附 profile 模板、默认组合包列表,以及可选、按需和已退役的组合包。" +description: "由安装方持有的官方 dsh 包列表:随附 profile 模板、默认组合包列表,可选、按需和已退役的组合包,以及插件管理器保护和展示的包。" kind: "package-library" --- @@ -9,7 +9,7 @@ kind: "package-library" ## 概述 -`@deepseek-ai/dsh-official-bundles` 保存由 dsh 安装决定的组合包名称:每个随附 profile 以哪些组合包启动、随附但默认关闭哪些组合包、哪些官方组合包按请求安装,以及哪些组合包曾由早期版本随附、现在要从 profile 中移除。[`dsh-app-boot`](../app-boot/README.zh.md) 在加载 profile 时应用这些列表;插件管理器、CLI、Desktop、WebWorker 镜像打包器和仓库检查直接读取它们。本包只含数据,因此增加或移除组合包不会改动 app-boot。请把它作为直接的库依赖使用,而不是通过 `cordis.yml` 使用。 +`@deepseek-ai/dsh-official-bundles` 保存由 dsh 安装决定的组合包名称:每个随附 profile 以哪些组合包启动、随附但默认关闭哪些组合包、哪些官方组合包按请求安装,哪些组合包曾由早期版本随附、现在要从 profile 中移除,以及插件管理器保护、隐藏、排序或标记为实验性的包。[`dsh-app-boot`](../../boot/app-boot/README.zh.md) 在加载 profile 时应用这些列表;插件管理器、CLI、Desktop、镜像打包器和仓库检查直接读取它们。本包只含数据,因此修改列表不会改动 app-boot 和插件管理器。请把它作为直接的库依赖使用,而不是通过 `cordis.yml` 使用。 ## 目录 @@ -32,7 +32,12 @@ kind: "package-library" ### 可选与已退役组合包 -`OPTIONAL_BUNDLES` 列出安装随附、供用户开启的组合包。每一项都必须是 `dsh` 应用的运行时依赖,并声明 `dsh.bundle.patch`、图标和 `./locale/*.json` 显示元信息,且不能被任何模板选中;[`verify-default-product-isolation`](../../../scripts/verify-default-product-isolation.ts) 检查这些规则。[插件管理器](../plugin-manager/README.zh.md#use-this-package)把这些组合包报告为 `optional`。`RETIRED_BUNDLES` 列出安装不再携带的组合包;app-boot 在加载 profile 时将它们从该 profile 的组合包列表中移除。 +`OPTIONAL_BUNDLES` 列出安装随附、供用户开启的组合包。每一项都必须是 `dsh` 应用的运行时依赖,并声明 `dsh.bundle.patch`、图标和 `./locale/*.json` 显示元信息,且不能被任何模板选中;[`verify-default-product-isolation`](../../../scripts/verify-default-product-isolation.ts) 检查这些规则。[插件管理器](../../boot/plugin-manager/README.zh.md#use-this-package)把这些组合包报告为 `optional`。`RETIRED_BUNDLES` 列出安装不再携带的组合包;app-boot 在加载 profile 时将它们从该 profile 的组合包列表中移除。 + + +### 插件管理器列表 + +`PROTECTED_PLUGINS` 列出[插件管理器](../../boot/plugin-manager/README.zh.md)因管理功能依赖而保持只读的插件包;包含其中任一插件的组合包是管理组合包。[Web 插件页](../../client/ui-plugin-manager/README.zh.md)隐藏 `HIDDEN_BUNDLES`,把 `EXTENSION_BUNDLES` 按顺序保留在主列表,把 `MORE_BUNDLES` 留在「更多」列表直到被选中,并为 `EXPERIMENTAL_BUNDLES` 显示实验性标记。 ### 按需组合包 @@ -53,6 +58,7 @@ kind: "package-library" | 文件 | 职责 | |---|---| | [`src/bundles.ts`](src/bundles.ts) | Profile 模板,以及默认、安装持有、已退役、可选和按需组合包列表 | +| [`src/plugin-manager.ts`](src/plugin-manager.ts) | 受保护的插件包,以及 Web 插件页的隐藏、排序和实验性组合包列表 | | [`src/catalog.generated.ts`](src/catalog.generated.ts) | 按需组合包的生成离线元信息 | | [`src/index.ts`](src/index.ts) | 公开导出与目录条目类型 | @@ -63,7 +69,7 @@ kind: "package-library" ## 进一步探索 -- [dsh-app-boot](../app-boot/README.zh.md)——应用模板和退役列表的 profile 加载。 +- [dsh-app-boot](../../boot/app-boot/README.zh.md)——应用模板和退役列表的 profile 加载。 - [随附可选组合包](../../../.agents/notes/implemented/process/2026-09-15-shipped-optional-bundles.zh.md)——为什么由安装持有可选列表。 - [Official 按需组合包](../../../.agents/notes/implemented/architecture/2026-10-05-official-on-demand-bundles.zh.md)——离线目录的决策。 diff --git a/packages/boot/official-bundles/package.json b/packages/util/official-bundles/package.json similarity index 76% rename from packages/boot/official-bundles/package.json rename to packages/util/official-bundles/package.json index d3fa8e16b3..4a710687de 100644 --- a/packages/boot/official-bundles/package.json +++ b/packages/util/official-bundles/package.json @@ -1,6 +1,6 @@ { "name": "@deepseek-ai/dsh-official-bundles", - "description": "Installation-owned lists of official dsh bundles: shipped profile templates, optional, on-demand, and retired bundles", + "description": "Installation-owned lists of official dsh packages: shipped profile templates, optional, on-demand, and retired bundles, and the plugin manager's protected and presented packages", "version": "0.2.1-rc.2", "publishConfig": { "access": "public" @@ -8,7 +8,7 @@ "repository": { "type": "git", "url": "git+https://github.com/deepseek-ai/deepseek-harness.git", - "directory": "packages/boot/official-bundles" + "directory": "packages/util/official-bundles" }, "type": "module", "main": "lib/index.js", diff --git a/packages/boot/official-bundles/src/bundles.ts b/packages/util/official-bundles/src/bundles.ts similarity index 100% rename from packages/boot/official-bundles/src/bundles.ts rename to packages/util/official-bundles/src/bundles.ts diff --git a/packages/boot/official-bundles/src/catalog.generated.ts b/packages/util/official-bundles/src/catalog.generated.ts similarity index 100% rename from packages/boot/official-bundles/src/catalog.generated.ts rename to packages/util/official-bundles/src/catalog.generated.ts diff --git a/packages/boot/official-bundles/src/index.ts b/packages/util/official-bundles/src/index.ts similarity index 77% rename from packages/boot/official-bundles/src/index.ts rename to packages/util/official-bundles/src/index.ts index a3df744226..fc234e80a8 100644 --- a/packages/boot/official-bundles/src/index.ts +++ b/packages/util/official-bundles/src/index.ts @@ -1,5 +1,5 @@ /** - * Installation-owned lists of official DSH bundle packages, kept apart from the boot code that applies them. + * Installation-owned lists of official DSH bundle and plugin packages, kept apart from the code that applies them. * @module @deepseek-ai/dsh-official-bundles */ @@ -9,6 +9,7 @@ export { DEFAULT_PROFILE_BUNDLES, INSTALLATION_OWNED_PROFILE_TUPLES, ON_DEMAND_BUNDLES, OPTIONAL_BUNDLES, PROFILE_TEMPLATES, RETIRED_BUNDLES, type ProfileTemplate, } from './bundles.ts' +export { EXPERIMENTAL_BUNDLES, EXTENSION_BUNDLES, HIDDEN_BUNDLES, MORE_BUNDLES, PROTECTED_PLUGINS } from './plugin-manager.ts' /** Offline discovery metadata; installation state and the requested version belong to the running host. */ export interface OfficialBundleCatalogEntry { diff --git a/packages/util/official-bundles/src/plugin-manager.ts b/packages/util/official-bundles/src/plugin-manager.ts new file mode 100644 index 0000000000..129a86aa1a --- /dev/null +++ b/packages/util/official-bundles/src/plugin-manager.ts @@ -0,0 +1,66 @@ +/** The package names the plugin manager protects, hides, orders, or marks experimental. */ + +/** Plugin packages the plugin manager refuses to disable or remove, because management itself needs them. */ +export const PROTECTED_PLUGINS: ReadonlySet = new Set([ + '@deepseek-ai/dsh-plugin-manager', '@deepseek-ai/cordis-plugin-loader', + '@deepseek-ai/cordis-plugin-include', '@deepseek-ai/dsh-api-gateway', + '@deepseek-ai/dsh-host-webserver', '@deepseek-ai/dsh-client-modules', + '@deepseek-ai/dsh-client-ui-settings-plugin-inventory', '@deepseek-ai/dsh-client-ui-plugin-manager', + '@deepseek-ai/dsh-host-plugin-inventory', '@deepseek-ai/dsh-typert-registry', + '@deepseek-ai/dsh-api-remotes', '@deepseek-ai/dsh-api-remote-access', + '@deepseek-ai/cordis-plugin-timer', '@deepseek-ai/dsh-client-connection', + '@deepseek-ai/dsh-host-frontend-static', '@deepseek-ai/dsh-tools', + '@deepseek-ai/dsh-hmr', +]) + +/** + * Built-in profile bundles and persistent terminals, which have no plugin manager page. + * Their Host availability and activation stay intact. + */ +export const HIDDEN_BUNDLES: ReadonlySet = new Set([ + '@deepseek-ai/dsh-base', + '@deepseek-ai/dsh-web-app', + '@deepseek-ai/dsh-headless', + '@deepseek-ai/dsh-sdk-app', + '@deepseek-ai/dsh-acp-app', + '@deepseek-ai/dsh-sdk-minimal', + '@deepseek-ai/dsh-experimental-terminal-bundle', +]) + +/** The optional bundles the plugin manager's main list always holds, in this order; unlisted bundles join the main list. */ +export const EXTENSION_BUNDLES: readonly string[] = [ + '@deepseek-ai/dsh-experimental-agent-team-profile', + '@deepseek-ai/dsh-experimental-voice-input-bundle', + '@deepseek-ai/dsh-experimental-plugin-market-bundle', + '@deepseek-ai/dsh-experimental-auto-review', +] + +/** The optional bundles the plugin manager's main list holds back until selected, in More-list order. */ +export const MORE_BUNDLES: readonly string[] = [ + '@deepseek-ai/dsh-experimental-inspector-profile', + '@deepseek-ai/dsh-cua-bundle', + '@deepseek-ai/dsh-experimental-tool-worktree', + '@deepseek-ai/dsh-experimental-cot-translation-bundle', + '@deepseek-ai/dsh-experimental-session-search', + '@deepseek-ai/dsh-experimental-session-titles-bundle', + '@deepseek-ai/dsh-experimental-badge-skill-bundle', + '@deepseek-ai/dsh-experimental-ralph-bundle', + '@deepseek-ai/dsh-subagent-codex', + '@deepseek-ai/dsh-subagent-claude-code', +] + +/** Official bundles the plugin manager marks with the Experimental badge. */ +export const EXPERIMENTAL_BUNDLES: ReadonlySet = new Set([ + '@deepseek-ai/dsh-cua-bundle', + '@deepseek-ai/dsh-experimental-agent-team-profile', + '@deepseek-ai/dsh-experimental-voice-input-bundle', + '@deepseek-ai/dsh-experimental-auto-review', + '@deepseek-ai/dsh-experimental-inspector-profile', + '@deepseek-ai/dsh-experimental-tool-worktree', + '@deepseek-ai/dsh-experimental-cot-translation-bundle', + '@deepseek-ai/dsh-experimental-session-search', + '@deepseek-ai/dsh-experimental-session-titles-bundle', + '@deepseek-ai/dsh-experimental-badge-skill-bundle', + '@deepseek-ai/dsh-experimental-ralph-bundle', + '@deepseek-ai/dsh-experimental-plugin-market-bundle', +]) diff --git a/packages/boot/official-bundles/tests/official-bundles.spec.ts b/packages/util/official-bundles/tests/official-bundles.spec.ts similarity index 100% rename from packages/boot/official-bundles/tests/official-bundles.spec.ts rename to packages/util/official-bundles/tests/official-bundles.spec.ts diff --git a/packages/boot/official-bundles/tsconfig.json b/packages/util/official-bundles/tsconfig.json similarity index 81% rename from packages/boot/official-bundles/tsconfig.json rename to packages/util/official-bundles/tsconfig.json index 8c7c155cb3..fa498d7165 100644 --- a/packages/boot/official-bundles/tsconfig.json +++ b/packages/util/official-bundles/tsconfig.json @@ -9,7 +9,7 @@ ], "references": [ { - "path": "../../util/package-manifest" + "path": "../package-manifest" } ] } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index bc495fa07a..ac9bc182b2 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -396,7 +396,7 @@ importers: version: link:../../packages/mcp/mcp-resources '@deepseek-ai/dsh-official-bundles': specifier: workspace:* - version: link:../../packages/boot/official-bundles + version: link:../../packages/util/official-bundles '@deepseek-ai/dsh-persona': specifier: workspace:* version: link:../../packages/preset/persona @@ -743,7 +743,7 @@ importers: version: link:../../packages/util/home-paths '@deepseek-ai/dsh-official-bundles': specifier: workspace:* - version: link:../../packages/boot/official-bundles + version: link:../../packages/util/official-bundles '@deepseek-ai/dsh-util-file-drag': specifier: workspace:* version: link:../../packages/util/file-drag @@ -1963,7 +1963,7 @@ importers: version: link:../../util/atomic-write '@deepseek-ai/dsh-official-bundles': specifier: workspace:* - version: link:../official-bundles + version: link:../../util/official-bundles '@deepseek-ai/dsh-package-manifest': specifier: workspace:* version: link:../../util/package-manifest @@ -2115,16 +2115,6 @@ importers: specifier: ^0.28.2 version: 0.28.2 - packages/boot/official-bundles: - dependencies: - '@deepseek-ai/dsh-package-manifest': - specifier: workspace:* - version: link:../../util/package-manifest - devDependencies: - '@deepseek-ai/cordis': - specifier: workspace:~ - version: link:../../../vendor/cordis - packages/boot/plugin-manager: dependencies: '@deepseek-ai/dsh-app-boot': @@ -2135,7 +2125,7 @@ importers: version: link:../../util/atomic-write '@deepseek-ai/dsh-official-bundles': specifier: workspace:* - version: link:../official-bundles + version: link:../../util/official-bundles '@deepseek-ai/dsh-plugin-detail': specifier: workspace:* version: link:../../util/plugin-detail @@ -5004,6 +4994,9 @@ importers: '@deepseek-ai/dsh-client-ui-slots': specifier: workspace:* version: link:../ui-slots + '@deepseek-ai/dsh-official-bundles': + specifier: workspace:* + version: link:../../util/official-bundles '@deepseek-ai/dsh-package-manifest': specifier: workspace:* version: link:../../util/package-manifest @@ -10405,7 +10398,7 @@ importers: version: link:../webworker-runtime '@deepseek-ai/dsh-official-bundles': specifier: workspace:* - version: link:../../boot/official-bundles + version: link:../../util/official-bundles '@deepseek-ai/dsh-session-format': specifier: workspace:* version: link:../../session/session-format @@ -16167,6 +16160,16 @@ importers: specifier: workspace:~ version: link:../../../vendor/cordis + packages/util/official-bundles: + dependencies: + '@deepseek-ai/dsh-package-manifest': + specifier: workspace:* + version: link:../package-manifest + devDependencies: + '@deepseek-ai/cordis': + specifier: workspace:~ + version: link:../../../vendor/cordis + packages/util/output-retention: devDependencies: '@deepseek-ai/cordis': diff --git a/scripts/check-workspace-constraints.ts b/scripts/check-workspace-constraints.ts index b16efe233c..8b2c7a3d41 100644 --- a/scripts/check-workspace-constraints.ts +++ b/scripts/check-workspace-constraints.ts @@ -21,7 +21,7 @@ import { hasTypertRemoteNavigation, isForbiddenPublicationFile } from './publica import type { DshBundleManifest } from '../packages/util/package-manifest/src/types.ts' import { detailPath } from '../packages/util/plugin-detail/src/document.ts' import { bundlePatchFiles } from '../packages/boot/app-boot/src/profile.ts' -import { OPTIONAL_BUNDLES } from '../packages/boot/official-bundles/src/bundles.ts' +import { OPTIONAL_BUNDLES } from '../packages/util/official-bundles/src/bundles.ts' import { PACKAGE_ASSET_EXPORT, PACKAGE_ASSET_EXPORT_TARGET, diff --git a/scripts/doc-standard.spec.ts b/scripts/doc-standard.spec.ts index 535f5869d1..739dae3227 100644 --- a/scripts/doc-standard.spec.ts +++ b/scripts/doc-standard.spec.ts @@ -59,7 +59,7 @@ const PACKAGE_LIBRARIES: Readonly> = { 'packages/experimental/browser-use-runtime': 'Provider-owned browser resource management and MCP integration helpers; no plugin entry.', 'packages/boot/app-boot': 'Boot library the app bins import; plain helper exports.', 'packages/boot/cmdline': 'Command-line library the app bins import; plain module exports.', - 'packages/boot/official-bundles': 'Bundle-list data library the launcher and plugin manager import; plain constant exports.', + 'packages/util/official-bundles': 'Bundle-list data library the launcher and plugin manager import; plain constant exports.', 'packages/client/store': 'Browser-side state primitives; plain function/type exports.', 'packages/client/ui-primitives': 'Browser-side UI component library; plain component exports.', 'packages/client/ui-slots': 'Browser-side slot-map declarations; plain type exports.', diff --git a/scripts/gen-official-bundle-catalog.spec.ts b/scripts/gen-official-bundle-catalog.spec.ts index a6d243d373..8c43099bfe 100644 --- a/scripts/gen-official-bundle-catalog.spec.ts +++ b/scripts/gen-official-bundle-catalog.spec.ts @@ -4,13 +4,13 @@ import { existsSync, mkdirSync, mkdtempSync, readFileSync, rmSync, statSync, uti import { tmpdir } from 'node:os' import { dirname, join } from 'node:path' import { afterEach, describe, expect, it } from 'vitest' -import { ON_DEMAND_BUNDLES } from '../packages/boot/official-bundles/src/index.ts' +import { ON_DEMAND_BUNDLES } from '../packages/util/official-bundles/src/index.ts' import { generateOfficialBundleCatalog, renderOfficialBundleCatalog, syncOfficialBundleCatalog } from './gen-official-bundle-catalog.ts' import { SHIPPED_LOCALE_IDS } from './shipped-locales.ts' const roots: string[] = [] -const output = 'packages/boot/official-bundles/src/catalog.generated.ts' +const output = 'packages/util/official-bundles/src/catalog.generated.ts' function write(root: string, path: string, content: unknown): void { mkdirSync(dirname(join(root, path)), { recursive: true }) diff --git a/scripts/gen-official-bundle-catalog.ts b/scripts/gen-official-bundle-catalog.ts index 0bc5b7aaf6..c6056c75f0 100644 --- a/scripts/gen-official-bundle-catalog.ts +++ b/scripts/gen-official-bundle-catalog.ts @@ -5,13 +5,13 @@ import { resolve } from 'node:path' import { fileURLToPath, pathToFileURL } from 'node:url' import ts from 'typescript' import type { LocalizedText } from '../packages/util/package-manifest/src/types.ts' -import { ON_DEMAND_BUNDLES } from '../packages/boot/official-bundles/src/bundles.ts' -import type { OfficialBundleCatalogEntry } from '../packages/boot/official-bundles/src/index.ts' +import { ON_DEMAND_BUNDLES } from '../packages/util/official-bundles/src/bundles.ts' +import type { OfficialBundleCatalogEntry } from '../packages/util/official-bundles/src/index.ts' import { readPluginMeta, resolvePluginResource } from '../packages/boot/app-boot/src/package-meta.ts' import { SHIPPED_LOCALE_IDS } from './shipped-locales.ts' -const OUTPUT = 'packages/boot/official-bundles/src/catalog.generated.ts' +const OUTPUT = 'packages/util/official-bundles/src/catalog.generated.ts' /** * Read complete metadata without importing or activating any provider code. diff --git a/scripts/local-bundle-registry.spec.ts b/scripts/local-bundle-registry.spec.ts index 1b78dd5415..fb2f9fc1e5 100644 --- a/scripts/local-bundle-registry.spec.ts +++ b/scripts/local-bundle-registry.spec.ts @@ -8,7 +8,7 @@ import { join } from 'node:path' import { fileURLToPath } from 'node:url' import { execa } from 'execa' import { describe, expect, it, onTestFinished } from 'vitest' -import { ON_DEMAND_BUNDLES } from '../packages/boot/official-bundles/src/bundles.ts' +import { ON_DEMAND_BUNDLES } from '../packages/util/official-bundles/src/bundles.ts' import { generateOfficialBundleCatalog } from './gen-official-bundle-catalog.ts' import { createRegistryManifest, diff --git a/scripts/optional-bundles.spec.ts b/scripts/optional-bundles.spec.ts index 3514eb2737..b9fad6c27b 100644 --- a/scripts/optional-bundles.spec.ts +++ b/scripts/optional-bundles.spec.ts @@ -9,7 +9,7 @@ import type { EntryOptions } from '@deepseek-ai/cordis-plugin-loader' import { loadOverlayPatches } from '../packages/boot/app-boot/src/index.ts' import { readPluginMeta } from '../packages/boot/app-boot/src/package-meta.ts' import { bundlePatchPaths, composeEntries, initProfile, readProfileManifest } from '../packages/boot/app-boot/src/profile.ts' -import { OPTIONAL_BUNDLES, PROFILE_TEMPLATES } from '../packages/boot/official-bundles/src/bundles.ts' +import { OPTIONAL_BUNDLES, PROFILE_TEMPLATES } from '../packages/util/official-bundles/src/bundles.ts' import type { DshBundleManifest } from '../packages/util/package-manifest/src/types.ts' import { createPluginProfile } from '../apps/desktop/src/project-manager.ts' diff --git a/scripts/release/families.spec.ts b/scripts/release/families.spec.ts index 3eed0e3bed..02b90166b3 100644 --- a/scripts/release/families.spec.ts +++ b/scripts/release/families.spec.ts @@ -5,7 +5,7 @@ import { tmpdir } from 'node:os' import { dirname, join, resolve } from 'node:path' import { afterEach, describe, expect, it, vi } from 'vitest' import { officialClientBuildEnvironment, writeClientBuildRecord } from '../client-build-environment.ts' -import { ON_DEMAND_BUNDLES } from '../../packages/boot/official-bundles/src/bundles.ts' +import { ON_DEMAND_BUNDLES } from '../../packages/util/official-bundles/src/bundles.ts' import { releaseFamily, type ReleaseMember } from './families.ts' import { compareVersions, nextVendorVersion, planShared, reachesPayload } from './bump.ts' diff --git a/scripts/release/families.ts b/scripts/release/families.ts index 1740217bb0..bd6ddbe5dd 100644 --- a/scripts/release/families.ts +++ b/scripts/release/families.ts @@ -16,7 +16,7 @@ import { readClientBuildRecord, } from '../client-build-environment.ts' import { validateTarballPayload } from '../publication-payload.ts' -import { ON_DEMAND_BUNDLES } from '../../packages/boot/official-bundles/src/bundles.ts' +import { ON_DEMAND_BUNDLES } from '../../packages/util/official-bundles/src/bundles.ts' /** * Dependency sections a consumer must publish after, because npm resolves them diff --git a/scripts/release/installed-product-isolation.ts b/scripts/release/installed-product-isolation.ts index a0c7360962..2322873a4d 100644 --- a/scripts/release/installed-product-isolation.ts +++ b/scripts/release/installed-product-isolation.ts @@ -4,7 +4,7 @@ import { existsSync, readFileSync, realpathSync } from 'node:fs' import { createRequire } from 'node:module' import { join } from 'node:path' import { hasExperimentalPackageReference } from '../experimental-package-policy.ts' -import { OPTIONAL_BUNDLES } from '../../packages/boot/official-bundles/src/bundles.ts' +import { OPTIONAL_BUNDLES } from '../../packages/util/official-bundles/src/bundles.ts' interface InstalledManifest { name: string diff --git a/scripts/verify-default-product-isolation.spec.ts b/scripts/verify-default-product-isolation.spec.ts index 3cde8065ca..d385bbd916 100644 --- a/scripts/verify-default-product-isolation.spec.ts +++ b/scripts/verify-default-product-isolation.spec.ts @@ -13,7 +13,7 @@ const roots: string[] = [] const experimental = '@deepseek-ai/dsh-experimental-prototype' const core = '@deepseek-ai/dsh-core' const base = '@deepseek-ai/dsh-base' -const profile = 'packages/boot/official-bundles/src/bundles.ts' +const profile = 'packages/util/official-bundles/src/bundles.ts' const preset = 'packages/bundle/web-app/presets/standard.patch.yml' const patch = 'packages/bundle/base/cordis.patch.yml' diff --git a/scripts/verify-default-product-isolation.ts b/scripts/verify-default-product-isolation.ts index 6fa6285353..da405afe5e 100644 --- a/scripts/verify-default-product-isolation.ts +++ b/scripts/verify-default-product-isolation.ts @@ -23,7 +23,7 @@ import { import { isExperimentalPackageName } from './experimental-package-policy.ts' // The independently published entry package owns platform-engine dependencies. const EXTERNAL_KIT_PACKAGES = new Set(['@deepseek-ai/libreoffice-kit']) -const PROFILE_SOURCE = 'packages/boot/official-bundles/src/bundles.ts' +const PROFILE_SOURCE = 'packages/util/official-bundles/src/bundles.ts' const PRESET_PATTERN = 'packages/bundle/web-app/presets/*.patch.yml' const RUNTIME_SECTIONS = ['dependencies', 'optionalDependencies', 'peerDependencies'] as const diff --git a/scripts/verify-package-readme-model-experience.ts b/scripts/verify-package-readme-model-experience.ts index 59294ce650..8b842649f4 100644 --- a/scripts/verify-package-readme-model-experience.ts +++ b/scripts/verify-package-readme-model-experience.ts @@ -37,7 +37,7 @@ const NO_MODEL_EXPERIENCE_SECTION: Readonly> = { 'packages/util/launch-environment': 'The package only resolves host environment values; model-facing consumers own any rendered use.', 'packages/util/workspace-path': 'The package only formats Workspace paths for browser UI; it never constructs model input.', 'packages/util/values': 'The package only validates, snapshots, compares, freezes, or rejects caller-owned values; consumers own every model-facing use.', - 'packages/boot/official-bundles': 'The package only lists bundle package names and their display metadata; the loaded plugin tree owns model context.', + 'packages/util/official-bundles': 'The package only lists bundle package names and their display metadata; the loaded plugin tree owns model context.', 'packages/util/code-language': 'The package only maps a filename suffix to a syntax-highlighting language id; the read consumer owns the persisted hint.', } diff --git a/scripts/verify-product-use.spec.ts b/scripts/verify-product-use.spec.ts index a4cf5729e7..309fe6fc74 100644 --- a/scripts/verify-product-use.spec.ts +++ b/scripts/verify-product-use.spec.ts @@ -13,7 +13,7 @@ const base = '@deepseek-ai/dsh-base' const core = '@deepseek-ai/dsh-core' const candidate = '@deepseek-ai/dsh-candidate' const candidateDir = 'packages/core/candidate' -const profile = 'packages/boot/official-bundles/src/bundles.ts' +const profile = 'packages/util/official-bundles/src/bundles.ts' const patch = 'packages/bundle/base/cordis.patch.yml' function pkg(root: string, directory: string, name: string, fields: Record = {}): void { @@ -141,7 +141,7 @@ describe('product package use', () => { const root = fixture() pkg(root, candidateDir, candidate) const children = [{ name: candidate }] - if (!initial) write(root, 'packages/boot/official-bundles/src/included.yml', children) + if (!initial) write(root, 'packages/util/official-bundles/src/included.yml', children) write(root, patch, [{ insert: [{ name: core }, { name: 'cordis:include', disabled: true, config: { path: './included.yml', ...(initial ? { initial: children } : {}) }, }] }]) @@ -161,12 +161,12 @@ describe('product package use', () => { it('applies Include patches before collecting runtime mounts and uses files ahead of initial entries', () => { const root = fixture() pkg(root, candidateDir, candidate) - write(root, 'packages/boot/official-bundles/src/included.yml', [{ id: 'child', name: candidate }]) + write(root, 'packages/util/official-bundles/src/included.yml', [{ id: 'child', name: candidate }]) write(root, patch, [{ insert: [{ name: core }, { name: 'cordis:include', config: { path: './included.yml', initial: [{ name: candidate }], patches: [{ id: 'child', disabled: true }], } }] }]) expect(failures(root)).toContain('no product runtime use') - write(root, 'packages/boot/official-bundles/src/included.yml', []) + write(root, 'packages/util/official-bundles/src/included.yml', []) expect(failures(root)).toContain('no product runtime use') }) diff --git a/scripts/verify-product-use.ts b/scripts/verify-product-use.ts index b65208073c..dee30a0727 100644 --- a/scripts/verify-product-use.ts +++ b/scripts/verify-product-use.ts @@ -14,7 +14,7 @@ import { isAgentPresetEntry, isCordisGroupEntry, loadCordisYaml } from './cordis import { PRODUCT_PACKAGE_POLICY, type ProductPackagePolicy } from './product-package-policy.ts' import { collectRuntimeLocalSourceSpecifiers, collectRuntimeSourceSpecifiers } from './verify-client-packages.ts' -const PROFILE_SOURCE = 'packages/boot/official-bundles/src/bundles.ts' +const PROFILE_SOURCE = 'packages/util/official-bundles/src/bundles.ts' const PROFILES = ['acp', 'web', 'headless', 'sdk', 'sdk-minimal'] const PICKER_SOURCE = 'packages/host/directory-picker-auto/src/index.ts' const DYNAMIC_MOUNTS: Readonly> = { diff --git a/tsconfig.base.json b/tsconfig.base.json index dfebbdf673..f40ebb5ae1 100644 --- a/tsconfig.base.json +++ b/tsconfig.base.json @@ -452,7 +452,7 @@ "@deepseek-ai/dsh-message-quotes": ["./packages/session/message-quotes/src"], "@deepseek-ai/dsh-native-command": ["./packages/util/native-command/src"], "@deepseek-ai/dsh-office-to-pdf": ["./packages/document/office-to-pdf/src"], - "@deepseek-ai/dsh-official-bundles": ["./packages/boot/official-bundles/src"], + "@deepseek-ai/dsh-official-bundles": ["./packages/util/official-bundles/src"], "@deepseek-ai/dsh-output-retention": ["./packages/util/output-retention/src"], "@deepseek-ai/dsh-package-manifest": ["./packages/util/package-manifest/src"], "@deepseek-ai/dsh-permission-presets": ["./packages/interaction/permission-presets/src"], diff --git a/tsconfig.host.json b/tsconfig.host.json index 700e866fb6..93f4575c4b 100644 --- a/tsconfig.host.json +++ b/tsconfig.host.json @@ -493,7 +493,7 @@ { "path": "./packages/bundle/sdk-app" }, { "path": "./packages/bundle/sdk-minimal" }, { "path": "./packages/bundle/web-app" }, - { "path": "./packages/boot/official-bundles" }, + { "path": "./packages/util/official-bundles" }, { "path": "./packages/boot/app-boot" }, { "path": "./packages/boot/cmdline" }, { "path": "./packages/sdk/server" }, From 7f324909a91cef1a12b66de9d6e8c044c1be7c35 Mon Sep 17 00:00:00 2001 From: Turtle Date: Fri, 23 Oct 2026 12:11:06 +0800 Subject: [PATCH 2/2] docs(official-bundles): describe the plugin manager lists precisely --- packages/util/official-bundles/README.i18n.yaml | 8 ++++---- packages/util/official-bundles/README.md | 4 ++-- packages/util/official-bundles/README.zh.md | 4 ++-- packages/util/official-bundles/src/plugin-manager.ts | 5 ++++- 4 files changed, 12 insertions(+), 9 deletions(-) diff --git a/packages/util/official-bundles/README.i18n.yaml b/packages/util/official-bundles/README.i18n.yaml index 861c53a0c8..7ffc42dc26 100644 --- a/packages/util/official-bundles/README.i18n.yaml +++ b/packages/util/official-bundles/README.i18n.yaml @@ -15,8 +15,8 @@ en: 80b31a934611cb4a zh: 05f3f7f9cb2fd881 /deepseek-ai-dsh-official-bundles/use-this-package: - en: 62c8aa1af42d91d7 - zh: 39674a200b42b0d2 + en: 1cb89d16a6de115c + zh: 75925ae7a16278ad /deepseek-ai-dsh-official-bundles/use-this-package/profile-templates: en: 60ef21314c76c3ec zh: f769091957235e12 @@ -24,8 +24,8 @@ en: 8d94e2b44efb9c1d zh: c049a19e471d188b /deepseek-ai-dsh-official-bundles/use-this-package/plugin-manager-lists: - en: e90cf0b517add5d1 - zh: 3513bb01159d58ae + en: f2d44e8a4dd084dc + zh: 5db94cd83b30c677 /deepseek-ai-dsh-official-bundles/use-this-package/on-demand-bundles: en: 10dac368736afde3 zh: 7684ca22ba4b5a67 diff --git a/packages/util/official-bundles/README.md b/packages/util/official-bundles/README.md index 3313ed91ba..1b322a4d49 100644 --- a/packages/util/official-bundles/README.md +++ b/packages/util/official-bundles/README.md @@ -24,7 +24,7 @@ English | [中文](README.zh.md) ## Use this package -Edit this package when the installation's bundle selection changes; read it wherever code must agree with the launcher about that selection. +Edit this package when the installation's bundle selection or the plugin manager's protected or presented packages change; read it wherever code must agree with the launcher about that selection. ### Profile templates @@ -37,7 +37,7 @@ Edit this package when the installation's bundle selection changes; read it wher ### Plugin manager lists -`PROTECTED_PLUGINS` names the plugin packages the [plugin manager](../../boot/plugin-manager/README.md) keeps read-only because management needs them; a bundle that contains one is a management bundle. The [Web plugin page](../../client/ui-plugin-manager/README.md) hides the `HIDDEN_BUNDLES`, keeps the `EXTENSION_BUNDLES` on its main list in their order, holds the `MORE_BUNDLES` back on its More list until selected, and marks the `EXPERIMENTAL_BUNDLES` with the Experimental badge. +`PROTECTED_PLUGINS` names the plugin packages the [plugin manager](../../boot/plugin-manager/README.md) keeps read-only because management needs them; a bundle that contains one is a management bundle. The [Web plugin page](../../client/ui-plugin-manager/README.md) hides the `HIDDEN_BUNDLES`, keeps the `EXTENSION_BUNDLES` on its main list in their order, keeps the `MORE_BUNDLES` off its main list until the profile enables them, and marks the `EXPERIMENTAL_BUNDLES` with the Experimental badge. ### On-demand bundles diff --git a/packages/util/official-bundles/README.zh.md b/packages/util/official-bundles/README.zh.md index 91b2d84f82..a7d7ed1e24 100644 --- a/packages/util/official-bundles/README.zh.md +++ b/packages/util/official-bundles/README.zh.md @@ -24,7 +24,7 @@ kind: "package-library" ## 使用本包 -安装的组合包选择发生变化时编辑本包;凡是代码必须与启动器就该选择保持一致的地方,都读取本包。 +安装的组合包选择或插件管理器保护、展示的包发生变化时编辑本包;凡是代码必须与启动器就该选择保持一致的地方,都读取本包。 ### Profile 模板 @@ -37,7 +37,7 @@ kind: "package-library" ### 插件管理器列表 -`PROTECTED_PLUGINS` 列出[插件管理器](../../boot/plugin-manager/README.zh.md)因管理功能依赖而保持只读的插件包;包含其中任一插件的组合包是管理组合包。[Web 插件页](../../client/ui-plugin-manager/README.zh.md)隐藏 `HIDDEN_BUNDLES`,把 `EXTENSION_BUNDLES` 按顺序保留在主列表,把 `MORE_BUNDLES` 留在「更多」列表直到被选中,并为 `EXPERIMENTAL_BUNDLES` 显示实验性标记。 +`PROTECTED_PLUGINS` 列出[插件管理器](../../boot/plugin-manager/README.zh.md)因管理功能依赖而保持只读的插件包;包含其中任一插件的组合包是管理组合包。[Web 插件页](../../client/ui-plugin-manager/README.zh.md)隐藏 `HIDDEN_BUNDLES`,把 `EXTENSION_BUNDLES` 按顺序保留在主列表,在 profile 启用 `MORE_BUNDLES` 之前不把它们放上主列表,并为 `EXPERIMENTAL_BUNDLES` 显示实验性标记。 ### 按需组合包 diff --git a/packages/util/official-bundles/src/plugin-manager.ts b/packages/util/official-bundles/src/plugin-manager.ts index 129a86aa1a..e34fb861e1 100644 --- a/packages/util/official-bundles/src/plugin-manager.ts +++ b/packages/util/official-bundles/src/plugin-manager.ts @@ -35,7 +35,10 @@ export const EXTENSION_BUNDLES: readonly string[] = [ '@deepseek-ai/dsh-experimental-auto-review', ] -/** The optional bundles the plugin manager's main list holds back until selected, in More-list order. */ +/** + * The optional bundles the plugin manager's main list leaves out until the profile enables them; its More list, + * which includes every eligible bundle, ranks them last in this order. + */ export const MORE_BUNDLES: readonly string[] = [ '@deepseek-ai/dsh-experimental-inspector-profile', '@deepseek-ai/dsh-cua-bundle',