@deepseek-ai/dsh-app-boot 0.2.0-rc.2 → 0.2.1-alpha.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.i18n.yaml CHANGED
@@ -21,8 +21,8 @@
21
21
  en: 2fdfe02f2ed4a258
22
22
  zh: d748228ece579c4a
23
23
  /deepseek-ai-dsh-app-boot/use-this-package/starting-the-app:
24
- en: 1099528bde0e2aee
25
- zh: b68772bdb9bb7856
24
+ en: 4a424cd401556f20
25
+ zh: 0b34dd18e0db6cea
26
26
  /deepseek-ai-dsh-app-boot/use-this-package/profiles:
27
27
  en: d50b0fdaf62353dd
28
28
  zh: 0fccb6968602e5de
@@ -33,8 +33,8 @@
33
33
  en: c4a301652b851ce9
34
34
  zh: 784871e19cd9db0a
35
35
  /deepseek-ai-dsh-app-boot/use-this-package/reading-plugin-display-metadata:
36
- en: 480ad3a4d96112f0
37
- zh: 10a92f1013aa5ac4
36
+ en: a9afb263b03d112c
37
+ zh: 31f5e797cd953c15
38
38
  /deepseek-ai-dsh-app-boot/use-this-package/startup-and-reload-failures:
39
39
  en: 09890e218ab49c84
40
40
  zh: e3d86597e7fb1adb
@@ -45,17 +45,17 @@
45
45
  en: f4a2695cb4c8a570
46
46
  zh: 89837235d2f376cf
47
47
  /deepseek-ai-dsh-app-boot/understand-the-implementation/design-notes:
48
- en: 4ac0c33806b5a5b2
49
- zh: cdb56f3adfcb4364
48
+ en: 25a0d1b46fd66d68
49
+ zh: 5cd8b4ac382dccdc
50
50
  /deepseek-ai-dsh-app-boot/understand-the-implementation/helper-behavior:
51
51
  en: f7bc3a8dd4b00bdd
52
52
  zh: 30098428aa769ad0
53
53
  /deepseek-ai-dsh-app-boot/understand-the-implementation/source-map:
54
- en: 25602fd8eb9b2907
55
- zh: 870a33dd34a52c32
54
+ en: 3da01827e3354655
55
+ zh: 06ccfaed83f65a76
56
56
  /deepseek-ai-dsh-app-boot/further-exploration:
57
- en: ffd10e94443a10ca
58
- zh: cd11495bae751bdd
57
+ en: 401269cc5ea8593e
58
+ zh: cd337c356b320565
59
59
  /deepseek-ai-dsh-app-boot/model-experience:
60
60
  en: 769777f1cb1a9408
61
61
  zh: f02b2834179df50d
package/README.md CHANGED
@@ -40,7 +40,7 @@ installFailLoud('dsh')
40
40
  const ctx = await boot('dsh', resolveConfigPath(argv[2], process.env.DSH_SNAPSHOT))
41
41
  ```
42
42
 
43
- `installFailLoud` writes one labelled `util.inspect` diagnostic to stderr for an unhandled rejection or an uncaught exception, awaits the surface's release hook under a fixed timeout, and exits 1; control never returns to the failed operation, because only the throw site knows which state is intact, and the event loop runs only until the release settles or times out. With that entry point, startup keeps every plugin that can activate. An enabled failed plugin produces a labelled warning. A failed required entry makes startup dispose the whole app and exit nonzero; required ids absent from a profile and disabled required entries do not affect startup. The global required list covers shared Agent execution, application endpoints, and Web bootstrap/transport: `agent-loop`, `webserver`, `modules`, `connection`, `headless-runner`, `acp`, and `sdk-jsonrpc-server`.
43
+ `installFailLoud` writes one labelled `util.inspect` diagnostic to stderr for an unhandled rejection or an uncaught exception, awaits the surface's release hook under a fixed timeout, and exits 1; control never returns to the failed operation, because only the throw site knows which state is intact, and the event loop runs only until the release settles or times out. With that entry point, startup keeps every plugin that can activate. An enabled failed plugin produces a labelled warning. A failed required entry makes startup dispose the whole app and exit nonzero; required ids absent from a profile and disabled required entries do not affect startup. The global required list covers shared Agent execution, application endpoints, and Web bootstrap/transport: `agent-loop`, `webserver`, `web-runtime`, `modules`, `connection`, `headless-runner`, `acp`, and `sdk-jsonrpc-server`.
44
44
 
45
45
  <a id="profiles"></a>
46
46
  ### Profiles
@@ -82,7 +82,11 @@ The projector preserves native omission behavior by checking literal defaults ag
82
82
 
83
83
  ### Reading plugin display metadata
84
84
 
85
- 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. Missing locale fields fall back to the accessible `package.json` at that address; malformed metadata returns an `error` diagnostic. Results retain translations for Client-side language selection. The reader also loads `package.json.icon` as an image data URL, even when locale text is complete; 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.
85
+ `resolvePluginResource(specifier, parentURL)` resolves a plugin module or exported resource to its local filesystem path through the active Node ESM resolver without evaluating it. It throws when the resolver is unavailable or the resource cannot resolve to a local file.
86
+
87
+ 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 `<package>/icon` when that field is omitted; a subpath uses `<specifier>/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.
88
+
89
+ `ON_DEMAND_BUNDLES` names the public Official packages installed only on request. `OFFICIAL_ON_DEMAND_CATALOG` embeds their package-owned localized metadata and icons for offline discovery; `pnpm gen-official-bundle-catalog` explicitly updates generated content, and `verify-official-bundle-catalog` checks resource completeness and freshness; builds consume the committed catalog without importing provider code. The catalog contains no install target: [Plugin Manager](../plugin-manager/README.md#use-this-package) derives it from the running version and installation and uses the ordinary bundle installer. The [product-use check](../../../scripts/verify-product-use.ts) composes shipped and on-demand selections against Web without executing providers.
86
90
 
87
91
  <a id="startup-and-reload-failures"></a>
88
92
  ### Startup and reload failures
@@ -135,7 +139,7 @@ This section explains how the outcomes above are realized and points at the code
135
139
  - **Package metadata.** `ctx.pluginPackages.packageOf` locates the owning package without loading code or requiring an exported `package.json`; a subpath selects its package without validating that file. The installed runtime resolution owns selection even for a miss. Low-level embedders that install the service without one retain native lookup. Display metadata uses the separate entry-aware reader described above.
136
140
  - **Two Loader builtins.** `mountRootInclude` registers `cordis:include` and `cordis:group` as Loader builtins: a group row gives one `isolate` realm to a provider and its consumers together, and an agent preset outside this workspace cannot resolve `@deepseek-ai/cordis-plugin-group` by name. Both load through the ambient module pipeline rather than the included tree's own specifier resolution.
137
141
  - **Consumer-owned strictness.** Ordinary Loader groups keep successful siblings. App-boot applies the global required-entry policy after initial settlement; agent presets and dynamic multi-entry compositions own and dispose their separate Loader subtree when they require all-or-nothing setup. App-boot reads failed fibers to report their recorded errors and coalesces duplicate Loader rejection notifications through one process checkpoint.
138
- - **One runtime resolution.** The installation-first and ordered-bundle breadth-first traversal produces the runtime table. Runtime resolution creates no links; runtime resolution entries occupy their package names at `$DSH_HOME/profiles/node_modules`, and every other name sees that directory as an ordinary ancestor. Profile load removes the `.dsh-module-fallback` projections that link-backend releases wrote into a profile; pnpm-installed packages stay. External bare targets selected by package `imports` use the same package order, while Node retains mapping, conditions, and exact target resolution. A complete successor may add package names and update linked-root membership atomically within the existing package-mapping and local-name constraints.
142
+ - **One runtime resolution.** The installation-first and ordered-bundle breadth-first traversal produces the runtime table. Runtime resolution creates no links; runtime resolution entries occupy their package names at `$DSH_HOME/profiles/node_modules`, and every other name sees that directory as an ordinary ancestor. Profile load removes the `.dsh-module-fallback` projections that link-backend releases wrote into a profile; pnpm-installed packages stay. External bare targets selected by package `imports` use the same package order, while Node retains mapping, conditions, and exact target resolution. A complete successor may add package names, remove profile-scoped mappings and profile-local names, and update linked-root membership atomically; retained mappings keep their normalized directory, version, and scope. Installation anchors remain fixed; a profile mapping may change its declarer. [Plugin Manager](../plugin-manager/README.md) publishes successors after package operations ([decision](../../../.agents/notes/implemented/architecture/2026-09-30-profile-package-refresh-and-manifest-invalidation.md)).
139
143
  - **Removing linked interception.** A successor may remove a linked root without restart. Directories outside all remaining roots use native lookup for subsequent requests, which may find a development copy or report a missing package. Existing module references and Node caches stay unchanged. Re-adding the same link name and target is allowed; pointing a previously published name at a different target is rejected even after removal ([generation rules](../../../.agents/notes/implemented/architecture/2026-09-09-profile-resolution-generations.md#immutable-generations)).
140
144
  - **Application-owned profiles.** Application-owned profiles use the same runtime resolution. Links within the active profile directory, including pnpm store links, are not external roots even when the profile is outside the shared profiles tree. Resolution does not modify their `node_modules`; pnpm owns installed packages.
141
145
  - **Owned Workers.** Worker build banners import `@deepseek-ai/dsh-app-boot/worker/profile-resolution-bootstrap` before bundled business code. Each Worker installs the structured-cloned runtime resolution in its own isolate. The bootstrap bundle has no static package imports. Source Worker entries retain their self-contained dependency closure, and third-party Workers receive no injection.
@@ -159,7 +163,6 @@ The exports each own one stage of the boot: config resolution and snapshot repla
159
163
  | [`src/profile-sanitize.ts`](src/profile-sanitize.ts) | Profile patch backup and recovery bundle activation |
160
164
  | [`src/config-schema/`](src/config-schema/) | Profile schema generation, discovery, native projection, and result types |
161
165
  | [`src/profile-resolution/`](src/profile-resolution/) | Runtime resolver, package-metadata service, and built Worker bootstrap |
162
- | — | No runtime invariant companion is published; one interception owns each runtime resolution. |
163
166
 
164
167
  </details>
165
168
 
@@ -177,7 +180,7 @@ Read these pages when the package-level contract is not enough. They move from t
177
180
  - [dsh-home-paths](../../util/home-paths/README.md) — the Harness-home resolver (`resolveDshHome`).
178
181
  - [Configuration source ownership](../../../.agents/notes/implemented/architecture/2026-08-04-configuration-source-ownership.md) — why a discovered file may not decide bootstrap behavior.
179
182
  - [Profile plugin bundles](../../../.agents/notes/implemented/architecture/2026-08-05-profile-plugin-bundles.md) — the profile and bundle composition design.
180
- - [User-patch HMR tests](../../../.agents/notes/implemented/testing/2026-09-09-user-patch-hmr-test-delivery.md) — ownership of live-patch behavior and native filesystem delivery.
183
+ - [User-patch HMR tests](tests/user-patches.spec.ts) — ownership of live-patch behavior and native filesystem delivery.
181
184
 
182
185
  -----
183
186
 
package/README.zh.md CHANGED
@@ -40,7 +40,7 @@ installFailLoud('dsh')
40
40
  const ctx = await boot('dsh', resolveConfigPath(argv[2], process.env.DSH_SNAPSHOT))
41
41
  ```
42
42
 
43
- `installFailLoud` 会为未处理 rejection 或未捕获异常向 stderr 写一条带标签的 `util.inspect` 诊断,在固定超时内等待界面的 release 钩子,然后以 1 退出;控制流不会回到失败的操作,因为只有抛出点知道哪些状态仍然完整,事件循环只运行到 release 结束或超时。有了这个入口,启动会保留所有能够激活的插件。启用但失败的插件会产生带标签的警告。required entry 失败时,启动会拆卸整个应用并以非零码退出;profile 中不存在的 required id 和已禁用的 required entry 不影响启动。全局 required list 覆盖共享 Agent 执行、应用 endpoint,以及 Web 启动与传输:`agent-loop`、`webserver`、`modules`、`connection`、`headless-runner`、`acp` 和 `sdk-jsonrpc-server`。
43
+ `installFailLoud` 会为未处理 rejection 或未捕获异常向 stderr 写一条带标签的 `util.inspect` 诊断,在固定超时内等待界面的 release 钩子,然后以 1 退出;控制流不会回到失败的操作,因为只有抛出点知道哪些状态仍然完整,事件循环只运行到 release 结束或超时。有了这个入口,启动会保留所有能够激活的插件。启用但失败的插件会产生带标签的警告。required entry 失败时,启动会拆卸整个应用并以非零码退出;profile 中不存在的 required id 和已禁用的 required entry 不影响启动。全局 required list 覆盖共享 Agent 执行、应用 endpoint,以及 Web 启动与传输:`agent-loop`、`webserver`、`web-runtime`、`modules`、`connection`、`headless-runner`、`acp` 和 `sdk-jsonrpc-server`。
44
44
 
45
45
  <a id="profiles"></a>
46
46
  ### Profile
@@ -82,7 +82,11 @@ profile 导入插件前,DSH 会检查其 `peerDependencies` 中对 `@deepseek-
82
82
 
83
83
  ### 读取插件展示元信息
84
84
 
85
- 使用 `readPluginMeta(specifier, parentURL)` 或 `ctx.pluginPackages.metaOf(specifier, parentURL)` 读取已安装包的展示文本,无需导入或激活插件。查询使用完整包标识与调用方的解析基准,并遵循 Node exports。文件路径与文件 URL 不解析资源,直接返回无元信息。缺失的 locale 字段回退到该地址下可访问的 `package.json`;格式错误的元信息返回 `error` 诊断。结果保留翻译,由 Client 选择语言。即使 locale 文本完整,读取器也会将 `package.json.icon` 加载为图片 data URL;图标出错时,保留有效文本并附上诊断。作者格式见[插件展示元信息](../../../docs/cookbook/adding-a-package.zh.md#plugin-display-metadata)。
85
+ `resolvePluginResource(specifier, parentURL)` 通过活动的 Node ESM 解析器将插件模块或导出资源解析为本地文件路径,不执行其代码。解析器不可用或资源无法解析为本地文件时会抛出错误。
86
+
87
+ 使用 `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)。
88
+
89
+ `ON_DEMAND_BUNDLES` 列出仅按需安装的官方公开包。`OFFICIAL_ON_DEMAND_CATALOG` 内嵌这些包拥有的本地化元信息和图标,支持离线发现;`pnpm gen-official-bundle-catalog` 显式更新生成内容,`verify-official-bundle-catalog` 检查资源完整性与新鲜度;构建只读取已提交的目录,不导入提供者代码。目录不保存安装目标;[插件管理器](../plugin-manager/README.zh.md#use-this-package)根据当前版本和安装位置确定目标,并使用普通组合包安装器。[产品用途检查](../../../scripts/verify-product-use.ts)将随附和按需选择与 Web 组合,但不执行提供者。
86
90
 
87
91
  <a id="startup-and-reload-failures"></a>
88
92
  ### 启动与重载失败
@@ -135,7 +139,7 @@ Loader 结算后,app-boot 在仅 optional 条目未激活时输出警告。如
135
139
  - **包元数据。** `ctx.pluginPackages.packageOf` 定位所属包,不加载代码,也不要求导出 `package.json`;子路径选择其所属包,不校验该文件。安装 runtime resolution 后,即使查询未命中也以其选包规则为准。仅安装服务而不提供 runtime resolution 的底层嵌入方保留原生查询。展示元数据使用上文另述的入口感知读取器。
136
140
  - **两个 Loader builtin。** `mountRootInclude` 把 `cordis:include` 与 `cordis:group` 注册为 Loader builtin:group 行能把一个提供方与它的消费方放进同一个 `isolate` realm,而位于本工作区之外的 agent preset 无法按名称解析 `@deepseek-ai/cordis-plugin-group`。两者都通过宿主的模块管线加载,而非被包含树自身的说明符解析。
137
141
  - **由 consumer 持有严格语义。** 普通 Loader group 保留成功 sibling。App-boot 在首次结算后应用全局 required-entry policy;agent preset 与动态多 entry 组合在需要 all-or-nothing setup 时,持有并拆卸各自的独立 Loader 子树。App-boot 读取 failed fiber 来报告已记录的错误,并在一个进程检查点内合并 Loader 重复的 rejection 通知。
138
- - **唯一 runtime resolution。** 安装优先、有序 bundle 逐根 breadth-first 遍历生成运行时表。runtime 解析不创建链接;runtime resolution 条目占据 `$DSH_HOME/profiles/node_modules` 上各自的包名位置,其余包名把该目录当作普通祖先。profile 加载时删除 Link 后端发布版写进 profile 的 `.dsh-module-fallback` 投影;pnpm 安装的包保留。package `imports` 选中的外部 bare target 使用相同的选包顺序,映射、conditions 和精确 target 解析仍由 Node 负责。完整后继 runtime resolution 可以在既有包映射和本地包名约束内原子增加 package name、更新 linked root 集合。
142
+ - **唯一 runtime resolution。** 安装优先、有序 bundle 逐根 breadth-first 遍历生成运行时表。runtime 解析不创建链接;runtime resolution 条目占据 `$DSH_HOME/profiles/node_modules` 上各自的包名位置,其余包名把该目录当作普通祖先。profile 加载时删除 Link 后端发布版写进 profile 的 `.dsh-module-fallback` 投影;pnpm 安装的包保留。package `imports` 选中的外部 bare target 使用相同的选包顺序,映射、conditions 和精确 target 解析仍由 Node 负责。完整后继 runtime resolution 可以原子地增加 package name、移除 profile 范围的映射和 profile 本地包名、更新 linked root 集合;保留映射的规范化目录、版本和作用域不变。安装范围的锚点不变;profile 映射可以更换声明来源。[插件管理器](../plugin-manager/README.zh.md)在包操作之后发布后继代([决策](../../../.agents/notes/implemented/architecture/2026-09-30-profile-package-refresh-and-manifest-invalidation.zh.md))。
139
143
  - **移除链接拦截。** 后继 generation 可以移除 linked root,无需重启。目录不再被任何剩余 root 覆盖时,后续请求使用原生查询,可能找到开发副本,也可能报告缺包。已有模块引用和 Node 缓存保持不变。同名、同目标可以重新加入;曾发布的名称改指向不同目标时,即使中间移除过也会被拒绝([generation 规则](../../../.agents/notes/implemented/architecture/2026-09-09-profile-resolution-generations.zh.md#immutable-generations))。
140
144
  - **应用自有 profile。** 应用自有 profile 使用相同的 runtime resolution。目标位于当前 profile 目录内的链接(包括 pnpm store 链接)不算外部 root,即使 profile 位于共享 profiles 树外。解析过程不修改其 `node_modules`;已安装包由 pnpm 管理。
141
145
  - **自有 Worker。** Worker 构建 banner 会在业务 bundle 前导入 `@deepseek-ai/dsh-app-boot/worker/profile-resolution-bootstrap`。每个 Worker 在自己的 isolate 中安装结构化克隆的 runtime resolution。bootstrap bundle 不静态导入任何包。源码 Worker 入口保留自包含依赖,第三方 Worker 不接受注入。
@@ -159,7 +163,6 @@ Loader 结算后,app-boot 在仅 optional 条目未激活时输出警告。如
159
163
  | [`src/profile-sanitize.ts`](src/profile-sanitize.ts) | profile patch 备份与恢复 bundle 启用状态 |
160
164
  | [`src/config-schema/`](src/config-schema/) | Profile schema 生成、发现、原生投影与结果类型 |
161
165
  | [`src/profile-resolution/`](src/profile-resolution/) | 运行时 resolver、package metadata 服务与构建后 Worker bootstrap |
162
- | — | 不发布运行时不变式伴生入口;每个 runtime resolution 只有一个拦截所有。 |
163
166
 
164
167
  </details>
165
168
 
@@ -177,7 +180,7 @@ Loader 结算后,app-boot 在仅 optional 条目未激活时输出警告。如
177
180
  - [dsh-home-paths](../../util/home-paths/README.zh.md)——harness home 解析器(`resolveDshHome`)。
178
181
  - [配置来源归属](../../../.agents/notes/implemented/architecture/2026-08-04-configuration-source-ownership.zh.md)——被发现的文件为何不得决定 bootstrap 行为。
179
182
  - [Profile 插件组合包](../../../.agents/notes/implemented/architecture/2026-08-05-profile-plugin-bundles.zh.md)——profile 与组合包组合设计。
180
- - [用户 patch HMR 测试](../../../.agents/notes/implemented/testing/2026-09-09-user-patch-hmr-test-delivery.zh.md)——实时 patch 行为与原生文件系统投递的验证归属。
183
+ - [用户 patch HMR 测试](tests/user-patches.spec.ts)——实时 patch 行为与原生文件系统投递的验证归属。
181
184
 
182
185
  -----
183
186
 
package/lib/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import { createRequire, isBuiltin } from "node:module";
2
2
  import { fileURLToPath, pathToFileURL } from "node:url";
3
- import fs, { existsSync, mkdirSync, readFileSync, readdirSync, readlinkSync, realpathSync, renameSync, rmSync, statSync, unlinkSync, writeFileSync } from "node:fs";
3
+ import fs, { existsSync, lstatSync, mkdirSync, readFileSync, readdirSync, readlinkSync, realpathSync, renameSync, rmSync, statSync, unlinkSync, writeFileSync } from "node:fs";
4
4
  import { inspect, parseEnv } from "node:util";
5
5
  import { basename, dirname, extname, isAbsolute, join, relative, resolve, sep, win32 } from "node:path";
6
6
  import * as yaml from "js-yaml";
@@ -441,7 +441,7 @@ async function setProfileVersionExemption(profileDir, packageVersion, runtimeVer
441
441
  }
442
442
  //#endregion
443
443
  //#region lib/types/profile-resolution/legacy-links.js
444
- /** Package directory canonicalization through the active runtime carrier's filesystem. */
444
+ /** Package directory and resource canonicalization through the active runtime carrier's filesystem. */
445
445
  /**
446
446
  * Return whether the process reads application modules from pkg's virtual filesystem.
447
447
  * @returns whether pkg owns the module filesystem.
@@ -457,6 +457,15 @@ function isPackagedExecutable() {
457
457
  function realModuleDirectory(path) {
458
458
  return isPackagedExecutable() ? realpathSync(path) : realpathSync.native(path);
459
459
  }
460
+ /** Canonicalize a module resource, preserving physical file aliases.
461
+ * SEA archive files are symlink-free and support stat and reads, while their containing directories support realpath.
462
+ * @param path Existing module resource path.
463
+ * @returns Canonical resource path under the active carrier's filesystem.
464
+ * @throws When the resource or its directory cannot be inspected or resolved.
465
+ */
466
+ function realModuleFile(path) {
467
+ return !isPackagedExecutable() || lstatSync(path).isSymbolicLink() ? realpathSync(path) : join(realModuleDirectory(dirname(path)), basename(path));
468
+ }
460
469
  //#endregion
461
470
  //#region lib/types/profile.js
462
471
  /**
@@ -539,6 +548,11 @@ const INSTALLATION_OWNED_PROFILE_TUPLES = { headless: [
539
548
  "@deepseek-ai/dsh-web-app",
540
549
  "@deepseek-ai/dsh-headless"
541
550
  ] };
551
+ /**
552
+ * Bundles an earlier release shipped and the installation no longer carries;
553
+ * {@link loadProfileDirectory} removes them from the profile's bundle list.
554
+ */
555
+ const RETIRED_BUNDLES = new Set(["@deepseek-ai/dsh-experimental-schedule-bundle"]);
542
556
  /** The bundle list a `dsh plugin` init uses for a name with no shipped template. */
543
557
  const DEFAULT_PROFILE_BUNDLES = ["@deepseek-ai/dsh-base"];
544
558
  /**
@@ -550,10 +564,17 @@ const DEFAULT_PROFILE_BUNDLES = ["@deepseek-ai/dsh-base"];
550
564
  * [admission](../../../../.agents/notes/implemented/architecture/2026-09-21-experimental-capabilities-as-optional-bundles.md)).
551
565
  */
552
566
  const OPTIONAL_BUNDLES = [
567
+ "@deepseek-ai/dsh-experimental-session-search",
568
+ "@deepseek-ai/dsh-experimental-ralph-bundle",
569
+ "@deepseek-ai/dsh-experimental-terminal-bundle",
570
+ "@deepseek-ai/dsh-experimental-badge-skill-bundle",
571
+ "@deepseek-ai/dsh-experimental-session-titles-bundle",
553
572
  "@deepseek-ai/dsh-experimental-agent-team-profile",
554
573
  "@deepseek-ai/dsh-experimental-voice-input-bundle",
574
+ "@deepseek-ai/dsh-experimental-cot-translation-bundle",
555
575
  "@deepseek-ai/dsh-experimental-auto-review",
556
- "@deepseek-ai/dsh-experimental-schedule-bundle"
576
+ "@deepseek-ai/dsh-experimental-inspector-profile",
577
+ "@deepseek-ai/dsh-experimental-tool-worktree"
557
578
  ];
558
579
  const PROFILE_PATCH_TEMPLATE = `# Your patch layer for this dsh profile, applied after every bundle layer:
559
580
  # a top-level YAML array of loader patch entries (id-targeted config
@@ -738,7 +759,11 @@ async function createRuntimeResolution(options) {
738
759
  const localPackageNames = profile === void 0 ? [] : installedProfilePackageNames(profile, manifest);
739
760
  const profilePackages = profile === void 0 ? /* @__PURE__ */ new Map() : collectProfileScopePackages(profile, packageNames, profileDeclarers, profileVersions);
740
761
  const linkedRoots = profile === void 0 ? [] : linkedProfileRoots(profile, profilesDir);
741
- return await Promise.resolve(Object.freeze({
762
+ return await Promise.resolve(new ProfileRuntimeResolution({
763
+ installAnchor,
764
+ profileDir: profile?.dir,
765
+ home
766
+ }, {
742
767
  profilesDir,
743
768
  profileDir: profile?.dir,
744
769
  localPackageNames: Object.freeze(localPackageNames),
@@ -758,6 +783,45 @@ async function createRuntimeResolution(options) {
758
783
  }))])
759
784
  }));
760
785
  }
786
+ /**
787
+ * A runtime resolution that remembers the inputs it was computed from. Worker environment data carries only its
788
+ * fields; the inputs stay private to the thread that computed it.
789
+ */
790
+ var ProfileRuntimeResolution = class {
791
+ profilesDir;
792
+ profileDir;
793
+ localPackageNames;
794
+ entries;
795
+ linkedRoots;
796
+ #source;
797
+ /**
798
+ * @param source - inputs of {@link createRuntimeResolution}, reused by {@link computeLatestResolution}.
799
+ * @param table - the computed package table.
800
+ */
801
+ constructor(source, table) {
802
+ this.#source = source;
803
+ this.profilesDir = table.profilesDir;
804
+ this.profileDir = table.profileDir;
805
+ this.localPackageNames = table.localPackageNames;
806
+ this.entries = table.entries;
807
+ this.linkedRoots = table.linkedRoots;
808
+ Object.freeze(this);
809
+ }
810
+ /**
811
+ * Compute the latest generation from the same installation, profile directory, and Harness home, rereading the
812
+ * profile's manifest, bundle selection, and installed packages from disk, without retaining synthetic layers.
813
+ * With no profile directory, only installation packages are recomputed. This instance is unchanged.
814
+ * @returns a new resolution for the latest generation.
815
+ */
816
+ computeLatestResolution() {
817
+ const { installAnchor, home, profileDir } = this.#source;
818
+ return createRuntimeResolution({
819
+ installAnchor,
820
+ home,
821
+ ...profileDir === void 0 ? {} : { profile: loadProfileDirectory("dsh", profileDir, installAnchor) }
822
+ });
823
+ }
824
+ };
761
825
  /** Synthetic profiles used by direct callers may have no on-disk manifest. */
762
826
  function readOptionalProfileManifest(profile) {
763
827
  if (profile === void 0) return void 0;
@@ -848,6 +912,19 @@ function writeProfileManifest(dir, manifest) {
848
912
  function sameBundles(left, right) {
849
913
  return left.length === right.length && left.every((value, index) => value === right[index]);
850
914
  }
915
+ /** Return `manifest` with `dsh.profile.bundles` replaced, preserving all other fields. */
916
+ function withBundles(manifest, bundles) {
917
+ return {
918
+ ...manifest,
919
+ dsh: {
920
+ ...manifest.dsh,
921
+ profile: {
922
+ ...manifest.dsh?.profile,
923
+ bundles: [...bundles]
924
+ }
925
+ }
926
+ };
927
+ }
851
928
  /**
852
929
  * Normalize an exact installation-owned bundle tuple to its shipped template,
853
930
  * preserving all other manifest fields. Other bundle lists remain untouched.
@@ -858,16 +935,19 @@ function normalizeShippedProfile(name, dir, manifest) {
858
935
  const bundles = manifest.dsh?.profile?.bundles;
859
936
  if (template === void 0 || bundles === void 0) return manifest;
860
937
  if (!(installationOwned !== void 0 && sameBundles(bundles, installationOwned))) return manifest;
861
- const normalized = {
862
- ...manifest,
863
- dsh: {
864
- ...manifest.dsh,
865
- profile: {
866
- ...manifest.dsh?.profile,
867
- bundles: [...template.bundles]
868
- }
869
- }
870
- };
938
+ const normalized = withBundles(manifest, template.bundles);
939
+ writeProfileManifest(dir, normalized);
940
+ return normalized;
941
+ }
942
+ /**
943
+ * Remove {@link RETIRED_BUNDLES} from a profile's bundle list, writing the
944
+ * manifest back only when it listed one.
945
+ */
946
+ function dropRetiredBundles(dir, manifest) {
947
+ const bundles = manifest.dsh?.profile?.bundles ?? [];
948
+ const kept = bundles.filter((bundle) => !RETIRED_BUNDLES.has(bundle));
949
+ if (kept.length === bundles.length) return manifest;
950
+ const normalized = withBundles(manifest, kept);
871
951
  writeProfileManifest(dir, normalized);
872
952
  return normalized;
873
953
  }
@@ -909,7 +989,8 @@ function resolveBundleDir(binName, packageName, installAnchor, profileDir) {
909
989
  * Load an already initialized profile directory without resolving it through
910
990
  * the shared Harness home. This is used by application-owned profiles whose
911
991
  * package project and lifecycle belong to that application.
912
- * Unreadable bundles, and bundles whose own dsh peers the profile does not exempt, are skipped
992
+ * Retired bundles are removed from the stored bundle list first, rewriting the
993
+ * manifest when it listed one. Unreadable bundles, and bundles whose own dsh peers the profile does not exempt, are skipped
913
994
  * without changing the manifest and listed in `skippedBundles`; nothing is printed.
914
995
  * @param binName - the diagnostic prefix on thrown errors.
915
996
  * @param dir - absolute profile package directory.
@@ -918,7 +999,7 @@ function resolveBundleDir(binName, packageName, installAnchor, profileDir) {
918
999
  * @returns the successfully loaded bundle layers and optional user patch layer.
919
1000
  */
920
1001
  function loadProfileDirectory(binName, dir, installAnchor, options = {}) {
921
- const bundles = readProfileManifest(binName, dir).dsh?.profile?.bundles ?? [];
1002
+ const bundles = dropRetiredBundles(dir, readProfileManifest(binName, dir)).dsh?.profile?.bundles ?? [];
922
1003
  const layers = [];
923
1004
  const skippedBundles = [];
924
1005
  const exemptions = bundles.length === 0 ? {} : readProfileVersionExemptions(dir);
@@ -1362,10 +1443,10 @@ var ResolutionRouter = class {
1362
1443
  if (successor.profilesDir !== this.current.profilesDir || successor.profileDir !== this.current.profileDir) throw new Error("profile resolution: a successor cannot change its profile scope");
1363
1444
  for (const [name, current] of this.current.entries) {
1364
1445
  const next = entries.get(name);
1365
- if (next === void 0 || !sameResolution(current.packageDir, next.packageDir) || !sameResolution(current.declarer, next.declarer) || current.version !== next.version || current.scope !== next.scope) throw new Error(`profile resolution: replacing ${JSON.stringify(name)} requires a process restart`);
1446
+ if (next === void 0 && current.scope === "profile") continue;
1447
+ if (next === void 0 || !sameResolution(current.packageDir, next.packageDir) || current.scope === "installation" && !sameResolution(current.declarer, next.declarer) || current.version !== next.version || current.scope !== next.scope) throw new Error(`profile resolution: replacing ${JSON.stringify(name)} requires a process restart`);
1366
1448
  }
1367
1449
  const localPackageNames = new Set(successor.localPackageNames);
1368
- for (const name of this.current.localPackageNames) if (!localPackageNames.has(name)) throw new Error(`profile resolution: removing local package ${JSON.stringify(name)} requires a process restart`);
1369
1450
  for (const name of localPackageNames) if (!this.current.localPackageNames.has(name) && this.current.entries.has(name)) throw new Error(`profile resolution: overriding ${JSON.stringify(name)} locally requires a process restart`);
1370
1451
  for (const root of successor.linkedRoots) {
1371
1452
  const previous = this.linkedTargets.get(root.name);
@@ -1857,26 +1938,44 @@ const ICON_MEDIA_TYPES = new Map([
1857
1938
  [".jpeg", "image/jpeg"],
1858
1939
  [".webp", "image/webp"]
1859
1940
  ]);
1860
- function iconOf(value, manifestPath) {
1861
- const icon = textOf(value, `${manifestPath}: icon`);
1862
- if (icon === void 0) return void 0;
1863
- if (isAbsolute(icon) || win32.isAbsolute(icon) || /^[A-Za-z][A-Za-z\d+.-]*:/u.test(icon)) throw new Error(`${manifestPath}: icon must be a relative file path`);
1864
- const mediaType = ICON_MEDIA_TYPES.get(extname(icon).toLowerCase());
1865
- if (mediaType === void 0) throw new Error(`${manifestPath}: icon must be SVG, PNG, JPEG, or WebP`);
1866
- const directory = realpathSync(dirname(manifestPath));
1867
- const file = realpathSync(resolve(directory, icon));
1868
- const local = relative(directory, file);
1869
- if (local === ".." || local.startsWith(`..${sep}`) || isAbsolute(local)) throw new Error(`${manifestPath}: icon must remain inside its manifest directory`);
1941
+ function iconOf(specifier, packageName, parentURL, manifestPath, value) {
1942
+ const icon = manifestPath === void 0 ? void 0 : textOf(value, `${manifestPath}: icon`);
1943
+ let target;
1944
+ let label;
1945
+ if (manifestPath !== void 0 && icon !== void 0) {
1946
+ if (isAbsolute(icon) || win32.isAbsolute(icon) || /^[A-Za-z][A-Za-z\d+.-]*:/u.test(icon)) throw new Error(`${manifestPath}: icon must be a relative file path`);
1947
+ label = manifestPath;
1948
+ const root = realpathSync(dirname(manifestPath));
1949
+ target = resolve(root, icon);
1950
+ const local = relative(root, realModuleFile(target));
1951
+ if (local === ".." || local.startsWith(`..${sep}`) || isAbsolute(local)) throw new Error(`${label}: icon must remain inside its manifest directory`);
1952
+ } else {
1953
+ const exported = optionalResourcePath(`${specifier}/icon`, parentURL);
1954
+ if (exported === void 0) return void 0;
1955
+ target = label = exported;
1956
+ assertPackageOwned(realModuleFile(target), packageName);
1957
+ }
1958
+ const mediaType = ICON_MEDIA_TYPES.get(extname(target).toLowerCase());
1959
+ if (mediaType === void 0) throw new Error(`${label}: icon must be SVG, PNG, JPEG, or WebP`);
1960
+ const file = realModuleFile(target);
1870
1961
  const stat = statSync(file);
1871
- if (!stat.isFile()) throw new Error(`${manifestPath}: icon must be a regular file`);
1872
- if (stat.size > MAX_ICON_BYTES) throw new Error(`${manifestPath}: icon exceeds 256 KiB`);
1962
+ if (!stat.isFile()) throw new Error(`${label}: icon must be a regular file`);
1963
+ if (stat.size > MAX_ICON_BYTES) throw new Error(`${label}: icon exceeds 256 KiB`);
1873
1964
  const bytes = readFileSync(file);
1874
- if (bytes.length > MAX_ICON_BYTES) throw new Error(`${manifestPath}: icon exceeds 256 KiB`);
1965
+ if (bytes.length > MAX_ICON_BYTES) throw new Error(`${label}: icon exceeds 256 KiB`);
1875
1966
  return `data:${mediaType};base64,${bytes.toString("base64")}`;
1876
1967
  }
1968
+ /** Require an ancestor of the real file whose package.json names the owning package. */
1969
+ function assertPackageOwned(file, name) {
1970
+ for (let directory = dirname(file);; directory = dirname(directory)) {
1971
+ const manifest = join(directory, "package.json");
1972
+ if (existsSync(manifest) && readObject(manifest).name === name) return;
1973
+ if (dirname(directory) === directory) throw new Error(`${file}: icon must remain inside its package directory`);
1974
+ }
1975
+ }
1877
1976
  /**
1878
1977
  * Resolve a plugin resource through the active Node ESM resolver without evaluating it.
1879
- * @param specifier - complete resource module specifier, including its locale filename.
1978
+ * @param specifier - plugin module or exported resource specifier.
1880
1979
  * @param parentURL - owning module-resolution base.
1881
1980
  * @returns the local filesystem path selected by Node and the active profile.
1882
1981
  * @throws when the resolver is unavailable or the resource cannot resolve to a local file.
@@ -1954,24 +2053,29 @@ function localizedText(field, dictionaries, fallback, finalFallback) {
1954
2053
  };
1955
2054
  }
1956
2055
  /**
1957
- * Read localized display text and the icon declared in a plugin's exported package.json.
1958
- * Icons are manifest-relative SVG, PNG, JPEG, or WebP files of at most 256 KiB,
1959
- * contained in the manifest directory after realpath resolution. Icon failures retain display text.
2056
+ * Read plugin locale JSON display text and icon without evaluating JavaScript entries.
2057
+ * Only a package-root specifier reads its exported package.json: `name`/`description` fill missing
2058
+ * locale fields, and a declared `icon` takes priority over the `<specifier>/icon` resource.
2059
+ * A subpath specifier never reads package.json; its icon comes only from `<specifier>/icon`.
2060
+ * Manifest icons remain inside their declaring directory; exported icons remain inside their
2061
+ * owning package after realpath resolution. Both accept SVG, PNG, JPEG, or WebP up to 256 KiB.
2062
+ * Icon failures retain display text without falling back.
1960
2063
  * Non-package specifiers are skipped without invoking the resource resolver.
1961
2064
  * Language files share the directory containing the resolved English resource;
1962
2065
  * each file is resolved through the complete plugin specifier before reading.
1963
- * Missing fields use the same address's package.json name/description. Translation
1964
- * maps retain an English fallback, ultimately the full module specifier for titles and empty for descriptions.
2066
+ * Translation maps retain an English fallback, ultimately the full module specifier
2067
+ * for titles and empty for descriptions.
1965
2068
  * @param specifier - configured plugin module name, including any package subpath.
1966
2069
  * @param parentURL - owning Loader tree's module-resolution base.
1967
- * @returns display fields and any icon diagnostic, or undefined for non-package specifiers or absent metadata.
2070
+ * @returns display fields and any resource diagnostic, or undefined for non-package specifiers or absent metadata.
1968
2071
  */
1969
2072
  function readPluginMeta(specifier, parentURL) {
1970
- if (barePackageName(specifier) === void 0) return void 0;
2073
+ const packageName = barePackageName(specifier);
2074
+ if (packageName === void 0) return void 0;
1971
2075
  try {
1972
2076
  const englishPath = optionalResourcePath(`${specifier}/locale/en.json`, parentURL);
1973
2077
  const dictionaries = englishPath === void 0 ? /* @__PURE__ */ new Map() : dictionariesOf(englishPath, specifier, parentURL);
1974
- const manifestPath = optionalResourcePath(`${specifier}/package.json`, parentURL);
2078
+ const manifestPath = packageName === specifier ? optionalResourcePath(`${specifier}/package.json`, parentURL) : void 0;
1975
2079
  const manifest = manifestPath === void 0 ? void 0 : readObject(manifestPath);
1976
2080
  const title = localizedText("title", dictionaries, fallbackText(manifest?.name), specifier);
1977
2081
  const description = localizedText("description", dictionaries, fallbackText(manifest?.description), "");
@@ -1981,7 +2085,7 @@ function readPluginMeta(specifier, parentURL) {
1981
2085
  };
1982
2086
  let icon;
1983
2087
  try {
1984
- icon = manifestPath === void 0 ? void 0 : iconOf(manifest?.icon, manifestPath);
2088
+ icon = iconOf(specifier, packageName, parentURL, manifestPath, manifest?.icon);
1985
2089
  } catch (error) {
1986
2090
  return {
1987
2091
  ...text,
@@ -2153,6 +2257,42 @@ function prepareProfilePatches(ctx, patches, parentURL, binName = "dsh") {
2153
2257
  return rows.length === 0 ? [] : [{ insert: rows }];
2154
2258
  }
2155
2259
  //#endregion
2260
+ //#region lib/types/official-bundle-packages.js
2261
+ /** Package admission shared by offline catalog generation and release ordering. */
2262
+ /** Public DSH release members available through the ordinary on-demand bundle installer. */
2263
+ const ON_DEMAND_BUNDLES = ["@deepseek-ai/dsh-subagent-claude-code", "@deepseek-ai/dsh-subagent-codex"];
2264
+ //#endregion
2265
+ //#region lib/types/official-bundles.generated.js
2266
+ /** Generated offline Official bundle metadata. Run pnpm gen-official-bundle-catalog; do not edit. */
2267
+ /** Official on-demand entries, independent of installed packages and registry availability. */
2268
+ const OFFICIAL_ON_DEMAND_CATALOG = [{
2269
+ packageName: "@deepseek-ai/dsh-subagent-claude-code",
2270
+ meta: {
2271
+ title: {
2272
+ "en": "Claude Code subagent",
2273
+ "zh": "Claude Code 子智能体"
2274
+ },
2275
+ description: {
2276
+ "en": "Delegate one task to Claude Code using its native authentication and settings.",
2277
+ "zh": "使用 Claude Code 原生认证和设置委派单个任务。"
2278
+ },
2279
+ icon: "data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMzYiIGhlaWdodD0iMzYiIHZpZXdCb3g9IjAgMCAzNiAzNiIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48cmVjdCB4PSIxNC45ODkzIiB5PSIxNS4xODc3IiB3aWR0aD0iMTIuMjM2NSIgaGVpZ2h0PSIxMi4yMzY1IiByeD0iMiIgZmlsbD0idXJsKCNkc2hfcGx1Z2luX2FydF9SMGEpIiBmaWxsLW9wYWNpdHk9IjAuOCI+PC9yZWN0PjxyZWN0IHg9IjguODcxMDkiIHk9IjkuMDY5NyIgd2lkdGg9IjEyLjIzNjUiIGhlaWdodD0iMTIuMjM2NSIgcng9IjIiIGZpbGw9InVybCgjZHNoX3BsdWdpbl9hcnRfUjBiKSIgZmlsbC1vcGFjaXR5PSIwLjgiPjwvcmVjdD48ZGVmcz48bGluZWFyR3JhZGllbnQgaWQ9ImRzaF9wbHVnaW5fYXJ0X1IwYSIgeDE9IjIxLjEwNzUiIHkxPSIxNS4xODc3IiB4Mj0iMjEuMTA3NSIgeTI9IjI3LjQyNDMiIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIj48c3RvcCBzdG9wLWNvbG9yPSIjNDVFN0E0Ij48L3N0b3A+PHN0b3Agb2Zmc2V0PSIxIiBzdG9wLWNvbG9yPSIjMDU5MDlEIj48L3N0b3A+PC9saW5lYXJHcmFkaWVudD48bGluZWFyR3JhZGllbnQgaWQ9ImRzaF9wbHVnaW5fYXJ0X1IwYiIgeDE9IjE0Ljk4OTQiIHkxPSI5LjA2OTciIHgyPSIxNC45ODk0IiB5Mj0iMjEuMzA2MyIgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiPjxzdG9wIHN0b3AtY29sb3I9IiM2OUI5RkYiPjwvc3RvcD48c3RvcCBvZmZzZXQ9IjEiIHN0b3AtY29sb3I9IiMzMjRERTIiPjwvc3RvcD48L2xpbmVhckdyYWRpZW50PjwvZGVmcz48L3N2Zz4K"
2280
+ }
2281
+ }, {
2282
+ packageName: "@deepseek-ai/dsh-subagent-codex",
2283
+ meta: {
2284
+ title: {
2285
+ "en": "Codex subagent",
2286
+ "zh": "Codex 子智能体"
2287
+ },
2288
+ description: {
2289
+ "en": "Delegate one task to Codex using its native authentication and settings.",
2290
+ "zh": "使用 Codex 原生认证和设置委派单个任务。"
2291
+ },
2292
+ icon: "data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMzYiIGhlaWdodD0iMzYiIHZpZXdCb3g9IjAgMCAzNiAzNiIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48cmVjdCB4PSIxNC45ODkzIiB5PSIxNS4xODc3IiB3aWR0aD0iMTIuMjM2NSIgaGVpZ2h0PSIxMi4yMzY1IiByeD0iMiIgZmlsbD0idXJsKCNkc2hfcGx1Z2luX2FydF9SMGEpIiBmaWxsLW9wYWNpdHk9IjAuOCI+PC9yZWN0PjxyZWN0IHg9IjguODcxMDkiIHk9IjkuMDY5NyIgd2lkdGg9IjEyLjIzNjUiIGhlaWdodD0iMTIuMjM2NSIgcng9IjIiIGZpbGw9InVybCgjZHNoX3BsdWdpbl9hcnRfUjBiKSIgZmlsbC1vcGFjaXR5PSIwLjgiPjwvcmVjdD48ZGVmcz48bGluZWFyR3JhZGllbnQgaWQ9ImRzaF9wbHVnaW5fYXJ0X1IwYSIgeDE9IjIxLjEwNzUiIHkxPSIxNS4xODc3IiB4Mj0iMjEuMTA3NSIgeTI9IjI3LjQyNDMiIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIj48c3RvcCBzdG9wLWNvbG9yPSIjNDVFN0E0Ij48L3N0b3A+PHN0b3Agb2Zmc2V0PSIxIiBzdG9wLWNvbG9yPSIjMDU5MDlEIj48L3N0b3A+PC9saW5lYXJHcmFkaWVudD48bGluZWFyR3JhZGllbnQgaWQ9ImRzaF9wbHVnaW5fYXJ0X1IwYiIgeDE9IjE0Ljk4OTQiIHkxPSI5LjA2OTciIHgyPSIxNC45ODk0IiB5Mj0iMjEuMzA2MyIgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiPjxzdG9wIHN0b3AtY29sb3I9IiM2OUI5RkYiPjwvc3RvcD48c3RvcCBvZmZzZXQ9IjEiIHN0b3AtY29sb3I9IiMzMjRERTIiPjwvc3RvcD48L2xpbmVhckdyYWRpZW50PjwvZGVmcz48L3N2Zz4K"
2293
+ }
2294
+ }];
2295
+ //#endregion
2156
2296
  //#region lib/types/config-schema/native.js
2157
2297
  /** Identity checks at the plugin-export and lazy-builder boundaries. */
2158
2298
  /**
@@ -3209,9 +3349,11 @@ var PluginPackages = class extends Service {
3209
3349
  packages = /* @__PURE__ */ new Map();
3210
3350
  interception;
3211
3351
  disposeWorkerResolution;
3352
+ current;
3212
3353
  constructor(ctx, config = {}) {
3213
3354
  super(ctx, "pluginPackages");
3214
3355
  if (config.resolution === void 0) return;
3356
+ this.current = config.resolution;
3215
3357
  const interception = installRuntimeInterception(config.resolution);
3216
3358
  this.disposeWorkerResolution = registerWorkerResolution(config.resolution);
3217
3359
  this.interception = interception;
@@ -3222,17 +3364,30 @@ var PluginPackages = class extends Service {
3222
3364
  }
3223
3365
  /**
3224
3366
  * Publish a complete successor generation for this process and subsequently created Workers.
3225
- * Linked roots may be removed without unloading modules or clearing Node caches.
3367
+ * Profile mappings and local package names may be removed after their plugins stop; linked roots may also be removed.
3368
+ * Retained profile mappings may change their declarer, but not their normalized directory, version, or scope;
3369
+ * installation mappings must remain unchanged. Publication does not unload modules or clear Node caches.
3226
3370
  * @param successor - fully constructed generation accepted by {@link RuntimeInterception.replace}.
3227
3371
  */
3228
3372
  replace(successor) {
3229
3373
  if (this.interception === void 0) throw new Error("plugin-packages: runtime resolution is not installed");
3230
3374
  this.interception.replace(successor);
3375
+ this.current = successor;
3231
3376
  this.packages = /* @__PURE__ */ new Map();
3232
3377
  this.disposeWorkerResolution?.();
3233
3378
  this.disposeWorkerResolution = registerWorkerResolution(successor);
3234
3379
  }
3235
3380
  /**
3381
+ * Publish the latest generation computed by the installed resolution through {@link replace}. Package contents
3382
+ * and loaded modules are not reloaded.
3383
+ * @throws when no resolution is installed, it is plain data rather than a {@link ProfileRuntimeResolution},
3384
+ * reading the latest files fails, or the successor is rejected. A computed resolution without a profile can refresh.
3385
+ */
3386
+ async refresh() {
3387
+ if (!(this.current instanceof ProfileRuntimeResolution)) throw new Error("plugin-packages: the installed runtime resolution cannot be recomputed");
3388
+ this.replace(await this.current.computeLatestResolution());
3389
+ }
3390
+ /**
3236
3391
  * Locate the package named by a specifier without requiring a package export.
3237
3392
  * @param specifier - module specifier whose package owns the requested module.
3238
3393
  * @param parentURL - URL whose Node lookup order applies.
@@ -3836,6 +3991,7 @@ const FIBER_DISPOSED = 4;
3836
3991
  const requiredStartupEntryIds = new Set([
3837
3992
  "agent-loop",
3838
3993
  "webserver",
3994
+ "web-runtime",
3839
3995
  "modules",
3840
3996
  "connection",
3841
3997
  "headless-runner",
@@ -4134,4 +4290,4 @@ function addHarnessSourceSection(ctx, sourceRoot) {
4134
4290
  });
4135
4291
  }
4136
4292
  //#endregion
4137
- export { DEFAULT_PROFILE_BUNDLES, FAIL_LOUD_RELEASE_TIMEOUT_MS, HARNESS_SOURCE_SECTION, LOADER_EXPRESSION_SCHEMA, OPTIONAL_BUNDLES, PROFILES_DIR, PROFILE_COMPATIBILITY_FILENAME, PROFILE_PATCH_FILENAME, PROFILE_TEMPLATES, PluginPackages, StartupError, addHarnessSourceSection, auditStartupEntries, boot, bundlePatchFiles, bundlePatchPaths, composeEntries, createConfigProjector, createRuntimeResolution, evaluatePluginCompatibility, generateConfigSchema, getDshRuntimeVersion, initProfile, installFailLoud, isNativeConfigSchema, loadEnv, loadLayeredEnv, loadOptionalPatches, loadOverlayPatches, loadProfile, loadProfileDirectory, mountRootInclude, pluginCompatibilityWarning, prepareProfileEntries, prepareProfilePatches, readPluginMeta, readProfileCompatibility, readProfileManifest, readProfilePatches, readProfilePlugins, readProfileVersionExemptions, reconcileProfilePatches, reconcileProfilePlugins, removeLinkProjections, renderConfigDump, reportSkippedBundles, resolveBundleDir, resolveConfigPath, resolveProfileDir, resolveTelemetryPatch, sanitizeProfile, setProfileVersionExemption, writeProfileBundles, writeProfileManifest };
4293
+ export { DEFAULT_PROFILE_BUNDLES, FAIL_LOUD_RELEASE_TIMEOUT_MS, HARNESS_SOURCE_SECTION, LOADER_EXPRESSION_SCHEMA, OFFICIAL_ON_DEMAND_CATALOG, ON_DEMAND_BUNDLES, OPTIONAL_BUNDLES, PROFILES_DIR, PROFILE_COMPATIBILITY_FILENAME, PROFILE_PATCH_FILENAME, PROFILE_TEMPLATES, PluginPackages, ProfileRuntimeResolution, StartupError, addHarnessSourceSection, auditStartupEntries, boot, bundlePatchFiles, bundlePatchPaths, composeEntries, createConfigProjector, createRuntimeResolution, evaluatePluginCompatibility, generateConfigSchema, getDshRuntimeVersion, initProfile, installFailLoud, isNativeConfigSchema, loadEnv, loadLayeredEnv, loadOptionalPatches, loadOverlayPatches, loadProfile, loadProfileDirectory, mountRootInclude, pluginCompatibilityWarning, prepareProfileEntries, prepareProfilePatches, readPluginMeta, readProfileCompatibility, readProfileManifest, readProfilePatches, readProfilePlugins, readProfileVersionExemptions, reconcileProfilePatches, reconcileProfilePlugins, removeLinkProjections, renderConfigDump, reportSkippedBundles, resolveBundleDir, resolveConfigPath, resolvePluginResource, resolveProfileDir, resolveTelemetryPatch, sanitizeProfile, setProfileVersionExemption, writeProfileBundles, writeProfileManifest };
@@ -15,7 +15,8 @@ export { sanitizeProfile } from './profile-sanitize.ts';
15
15
  export { getDshRuntimeVersion, evaluatePluginCompatibility, pluginCompatibilityWarning, type PluginCompatibility } from './plugin-compatibility.ts';
16
16
  export { PROFILE_COMPATIBILITY_FILENAME, readProfileCompatibility, readProfileVersionExemptions, setProfileVersionExemption, type ProfileCompatibility, } from './profile-compatibility.ts';
17
17
  export { prepareProfileEntries, prepareProfilePatches } from './compatibility-preflight.ts';
18
- export { readPluginMeta } from './package-meta.ts';
18
+ export { readPluginMeta, resolvePluginResource } from './package-meta.ts';
19
+ export { ON_DEMAND_BUNDLES, OFFICIAL_ON_DEMAND_CATALOG, type OfficialBundleCatalogEntry } from './official-bundles.ts';
19
20
  export { generateConfigSchema, type ConfigSchemaDump, type NativeConfigSchema } from './config-schema/index.ts';
20
21
  export { createConfigProjector, LOADER_EXPRESSION_SCHEMA, type ConfigProjection } from './config-schema/projector.ts';
21
22
  export { isNativeConfigSchema } from './config-schema/native.ts';
@@ -34,7 +35,7 @@ declare module '@deepseek-ai/cordis' {
34
35
  'app-boot/config-reload'(): void;
35
36
  }
36
37
  }
37
- export { composeEntries, createRuntimeResolution, DEFAULT_PROFILE_BUNDLES, OPTIONAL_BUNDLES, bundlePatchFiles, bundlePatchPaths, initProfile, removeLinkProjections, loadProfile, loadProfileDirectory, PROFILE_PATCH_FILENAME, PROFILE_TEMPLATES, PROFILES_DIR, readProfileManifest, reportSkippedBundles, resolveBundleDir, resolveProfileDir, writeProfileManifest, type Profile, type ProfileLayer, type SkippedBundle, type ProfileManifest, type LinkedRoot, type RuntimeResolutionOptions, type RuntimeResolutionEntry, type RuntimeResolution, type ProfileTemplate, } from './profile.ts';
38
+ export { composeEntries, createRuntimeResolution, ProfileRuntimeResolution, DEFAULT_PROFILE_BUNDLES, OPTIONAL_BUNDLES, bundlePatchFiles, bundlePatchPaths, initProfile, removeLinkProjections, loadProfile, loadProfileDirectory, PROFILE_PATCH_FILENAME, PROFILE_TEMPLATES, PROFILES_DIR, readProfileManifest, reportSkippedBundles, resolveBundleDir, resolveProfileDir, writeProfileManifest, type Profile, type ProfileLayer, type SkippedBundle, type ProfileManifest, type LinkedRoot, type RuntimeResolutionOptions, type RuntimeResolutionEntry, type RuntimeResolution, type ProfileTemplate, } from './profile.ts';
38
39
  export { PluginPackages, type PluginPackage, type PluginPackagesConfig, } from './profile-resolution/service.ts';
39
40
  /**
40
41
  * Resolve the config to boot. Replay swaps a `cordis.yml` basename for
@@ -0,0 +1,4 @@
1
+ /** Package admission shared by offline catalog generation and release ordering. */
2
+ /** Public DSH release members available through the ordinary on-demand bundle installer. */
3
+ export declare const ON_DEMAND_BUNDLES: readonly string[];
4
+ //# sourceMappingURL=official-bundle-packages.d.ts.map
@@ -0,0 +1,12 @@
1
+ /** Official bundles offered without installing their provider runtimes in the DSH distribution. */
2
+ import type { PluginLocalizedMeta } from '@deepseek-ai/dsh-package-manifest';
3
+ export { ON_DEMAND_BUNDLES } from './official-bundle-packages.ts';
4
+ /** Offline discovery metadata; installation state and the requested version belong to the running host. */
5
+ export interface OfficialBundleCatalogEntry {
6
+ /** Exact npm package name accepted by the existing bundle installer. */
7
+ readonly packageName: string;
8
+ /** Package-owned localized text and a self-contained icon, embedded without provider code. */
9
+ readonly meta: Required<Pick<PluginLocalizedMeta, 'title' | 'description' | 'icon'>>;
10
+ }
11
+ export { OFFICIAL_ON_DEMAND_CATALOG } from './official-bundles.generated.ts';
12
+ //# sourceMappingURL=official-bundles.d.ts.map
@@ -0,0 +1,5 @@
1
+ /** Generated offline Official bundle metadata. Run pnpm gen-official-bundle-catalog; do not edit. */
2
+ import type { OfficialBundleCatalogEntry } from './official-bundles.ts';
3
+ /** Official on-demand entries, independent of installed packages and registry availability. */
4
+ export declare const OFFICIAL_ON_DEMAND_CATALOG: readonly OfficialBundleCatalogEntry[];
5
+ //# sourceMappingURL=official-bundles.generated.d.ts.map
@@ -2,24 +2,28 @@
2
2
  import type { PluginLocalizedMeta } from '@deepseek-ai/dsh-package-manifest';
3
3
  /**
4
4
  * Resolve a plugin resource through the active Node ESM resolver without evaluating it.
5
- * @param specifier - complete resource module specifier, including its locale filename.
5
+ * @param specifier - plugin module or exported resource specifier.
6
6
  * @param parentURL - owning module-resolution base.
7
7
  * @returns the local filesystem path selected by Node and the active profile.
8
8
  * @throws when the resolver is unavailable or the resource cannot resolve to a local file.
9
9
  */
10
10
  export declare function resolvePluginResource(specifier: string, parentURL: string): string;
11
11
  /**
12
- * Read localized display text and the icon declared in a plugin's exported package.json.
13
- * Icons are manifest-relative SVG, PNG, JPEG, or WebP files of at most 256 KiB,
14
- * contained in the manifest directory after realpath resolution. Icon failures retain display text.
12
+ * Read plugin locale JSON display text and icon without evaluating JavaScript entries.
13
+ * Only a package-root specifier reads its exported package.json: `name`/`description` fill missing
14
+ * locale fields, and a declared `icon` takes priority over the `<specifier>/icon` resource.
15
+ * A subpath specifier never reads package.json; its icon comes only from `<specifier>/icon`.
16
+ * Manifest icons remain inside their declaring directory; exported icons remain inside their
17
+ * owning package after realpath resolution. Both accept SVG, PNG, JPEG, or WebP up to 256 KiB.
18
+ * Icon failures retain display text without falling back.
15
19
  * Non-package specifiers are skipped without invoking the resource resolver.
16
20
  * Language files share the directory containing the resolved English resource;
17
21
  * each file is resolved through the complete plugin specifier before reading.
18
- * Missing fields use the same address's package.json name/description. Translation
19
- * maps retain an English fallback, ultimately the full module specifier for titles and empty for descriptions.
22
+ * Translation maps retain an English fallback, ultimately the full module specifier
23
+ * for titles and empty for descriptions.
20
24
  * @param specifier - configured plugin module name, including any package subpath.
21
25
  * @param parentURL - owning Loader tree's module-resolution base.
22
- * @returns display fields and any icon diagnostic, or undefined for non-package specifiers or absent metadata.
26
+ * @returns display fields and any resource diagnostic, or undefined for non-package specifiers or absent metadata.
23
27
  */
24
28
  export declare function readPluginMeta(specifier: string, parentURL: string): PluginLocalizedMeta | undefined;
25
29
  //# sourceMappingURL=package-meta.d.ts.map
@@ -1,8 +1,15 @@
1
- /** Package directory canonicalization through the active runtime carrier's filesystem. */
1
+ /** Package directory and resource canonicalization through the active runtime carrier's filesystem. */
2
2
  /**
3
3
  * Resolve a directory through the active carrier's filesystem implementation.
4
4
  * @param path - directory path to canonicalize.
5
5
  * @returns the canonical directory path.
6
6
  */
7
7
  export declare function realModuleDirectory(path: string): string;
8
+ /** Canonicalize a module resource, preserving physical file aliases.
9
+ * SEA archive files are symlink-free and support stat and reads, while their containing directories support realpath.
10
+ * @param path Existing module resource path.
11
+ * @returns Canonical resource path under the active carrier's filesystem.
12
+ * @throws When the resource or its directory cannot be inspected or resolved.
13
+ */
14
+ export declare function realModuleFile(path: string): string;
8
15
  //# sourceMappingURL=legacy-links.d.ts.map
@@ -11,11 +11,14 @@ export interface RuntimeInterception {
11
11
  */
12
12
  packageDir(specifier: string, parentURL: string): string | undefined;
13
13
  /**
14
- * Atomically publish a complete successor and fresh caches. Linked roots may be added or removed.
15
- * Removed roots stop intercepting uncovered directories; existing modules and Node caches remain intact.
16
- * @param successor - fully constructed generation retaining existing package mappings and local names.
17
- * @throws when the profile scope or existing mappings change, local names are removed or override
18
- * existing mappings, or a previously published link name selects a different real directory.
14
+ * Atomically publish a complete successor and fresh caches. Profile-scoped mappings, local names, and linked
15
+ * roots may be removed; removed roots stop intercepting uncovered directories. Existing modules and Node caches
16
+ * remain intact, so callers remove a package only after its plugins stop.
17
+ * A retained profile mapping may change its declarer if its normalized directory, version, and scope stay unchanged.
18
+ * @param successor - fully constructed generation retaining the installation mappings.
19
+ * @throws when the profile scope, a retained directory, version, scope, or installation declarer changes;
20
+ * an installation mapping is removed; a new local name overrides an existing mapping; or a previously published
21
+ * link name selects a different real directory.
19
22
  */
20
23
  replace(successor: RuntimeResolution): void;
21
24
  /** Restore the native resolver methods. Interceptions dispose in reverse order. */
@@ -1,7 +1,7 @@
1
1
  /** Package metadata resolved through one runtime interception. */
2
2
  import { Service, type Context } from '@deepseek-ai/cordis';
3
3
  import type { PluginLocalizedMeta } from '@deepseek-ai/dsh-package-manifest';
4
- import type { RuntimeResolution } from '../profile.ts';
4
+ import { type RuntimeResolution } from '../profile.ts';
5
5
  declare module '@deepseek-ai/cordis' {
6
6
  interface Context {
7
7
  /** Deterministic package lookup for configured plugin specifiers. */
@@ -31,13 +31,23 @@ export declare class PluginPackages extends Service {
31
31
  private packages;
32
32
  private readonly interception;
33
33
  private disposeWorkerResolution;
34
+ private current;
34
35
  constructor(ctx: Context, config?: PluginPackagesConfig);
35
36
  /**
36
37
  * Publish a complete successor generation for this process and subsequently created Workers.
37
- * Linked roots may be removed without unloading modules or clearing Node caches.
38
+ * Profile mappings and local package names may be removed after their plugins stop; linked roots may also be removed.
39
+ * Retained profile mappings may change their declarer, but not their normalized directory, version, or scope;
40
+ * installation mappings must remain unchanged. Publication does not unload modules or clear Node caches.
38
41
  * @param successor - fully constructed generation accepted by {@link RuntimeInterception.replace}.
39
42
  */
40
43
  replace(successor: RuntimeResolution): void;
44
+ /**
45
+ * Publish the latest generation computed by the installed resolution through {@link replace}. Package contents
46
+ * and loaded modules are not reloaded.
47
+ * @throws when no resolution is installed, it is plain data rather than a {@link ProfileRuntimeResolution},
48
+ * reading the latest files fails, or the successor is rejected. A computed resolution without a profile can refresh.
49
+ */
50
+ refresh(): Promise<void>;
41
51
  /**
42
52
  * Locate the package named by a specifier without requiring a package export.
43
53
  * @param specifier - module specifier whose package owns the requested module.
@@ -175,7 +175,37 @@ export interface RuntimeResolutionOptions {
175
175
  * @param options - installation anchor, optional loaded profile, and Harness home.
176
176
  * @returns the complete immutable runtime resolution.
177
177
  */
178
- export declare function createRuntimeResolution(options: RuntimeResolutionOptions): Promise<RuntimeResolution>;
178
+ export declare function createRuntimeResolution(options: RuntimeResolutionOptions): Promise<ProfileRuntimeResolution>;
179
+ /** Inputs a {@link ProfileRuntimeResolution} reuses to compute its successor. */
180
+ interface ResolutionSource {
181
+ installAnchor: string;
182
+ home: string;
183
+ profileDir: string | undefined;
184
+ }
185
+ /**
186
+ * A runtime resolution that remembers the inputs it was computed from. Worker environment data carries only its
187
+ * fields; the inputs stay private to the thread that computed it.
188
+ */
189
+ export declare class ProfileRuntimeResolution implements RuntimeResolution {
190
+ #private;
191
+ readonly profilesDir: string;
192
+ readonly profileDir: string | undefined;
193
+ readonly localPackageNames: readonly string[];
194
+ readonly entries: readonly RuntimeResolutionEntry[];
195
+ readonly linkedRoots: readonly LinkedRoot[];
196
+ /**
197
+ * @param source - inputs of {@link createRuntimeResolution}, reused by {@link computeLatestResolution}.
198
+ * @param table - the computed package table.
199
+ */
200
+ constructor(source: ResolutionSource, table: RuntimeResolution);
201
+ /**
202
+ * Compute the latest generation from the same installation, profile directory, and Harness home, rereading the
203
+ * profile's manifest, bundle selection, and installed packages from disk, without retaining synthetic layers.
204
+ * With no profile directory, only installation packages are recomputed. This instance is unchanged.
205
+ * @returns a new resolution for the latest generation.
206
+ */
207
+ computeLatestResolution(): Promise<ProfileRuntimeResolution>;
208
+ }
179
209
  /**
180
210
  * Read a profile's manifest.
181
211
  * @param binName - the diagnostic prefix on the thrown error.
@@ -206,7 +236,8 @@ export declare function resolveBundleDir(binName: string, packageName: string, i
206
236
  * Load an already initialized profile directory without resolving it through
207
237
  * the shared Harness home. This is used by application-owned profiles whose
208
238
  * package project and lifecycle belong to that application.
209
- * Unreadable bundles, and bundles whose own dsh peers the profile does not exempt, are skipped
239
+ * Retired bundles are removed from the stored bundle list first, rewriting the
240
+ * manifest when it listed one. Unreadable bundles, and bundles whose own dsh peers the profile does not exempt, are skipped
210
241
  * without changing the manifest and listed in `skippedBundles`; nothing is printed.
211
242
  * @param binName - the diagnostic prefix on thrown errors.
212
243
  * @param dir - absolute profile package directory.
@@ -242,4 +273,5 @@ export declare function loadProfile(binName: string, name: string, installAnchor
242
273
  * @returns the composed entry list.
243
274
  */
244
275
  export declare function composeEntries(layers: readonly PatchOptions[][], warn?: (message: string) => void): EntryOptions[];
276
+ export {};
245
277
  //# sourceMappingURL=profile.d.ts.map
@@ -249,10 +249,10 @@ var ResolutionRouter = class {
249
249
  if (successor.profilesDir !== this.current.profilesDir || successor.profileDir !== this.current.profileDir) throw new Error("profile resolution: a successor cannot change its profile scope");
250
250
  for (const [name, current] of this.current.entries) {
251
251
  const next = entries.get(name);
252
- if (next === void 0 || !sameResolution(current.packageDir, next.packageDir) || !sameResolution(current.declarer, next.declarer) || current.version !== next.version || current.scope !== next.scope) throw new Error(`profile resolution: replacing ${JSON.stringify(name)} requires a process restart`);
252
+ if (next === void 0 && current.scope === "profile") continue;
253
+ if (next === void 0 || !sameResolution(current.packageDir, next.packageDir) || current.scope === "installation" && !sameResolution(current.declarer, next.declarer) || current.version !== next.version || current.scope !== next.scope) throw new Error(`profile resolution: replacing ${JSON.stringify(name)} requires a process restart`);
253
254
  }
254
255
  const localPackageNames = new Set(successor.localPackageNames);
255
- for (const name of this.current.localPackageNames) if (!localPackageNames.has(name)) throw new Error(`profile resolution: removing local package ${JSON.stringify(name)} requires a process restart`);
256
256
  for (const name of localPackageNames) if (!this.current.localPackageNames.has(name) && this.current.entries.has(name)) throw new Error(`profile resolution: overriding ${JSON.stringify(name)} locally requires a process restart`);
257
257
  for (const root of successor.linkedRoots) {
258
258
  const previous = this.linkedTargets.get(root.name);
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@deepseek-ai/dsh-app-boot",
3
3
  "description": "Shared boot glue for the app bins: .env loading, fail-loud Loader guards, snapshot-aware config resolution, and the Loader boot sequence",
4
- "version": "0.2.0-rc.2",
4
+ "version": "0.2.1-alpha.2",
5
5
  "publishConfig": {
6
6
  "access": "public"
7
7
  },
@@ -32,35 +32,35 @@
32
32
  ],
33
33
  "license": "MIT",
34
34
  "dependencies": {
35
+ "@deepseek-ai/dsh-atomic-write": "0.2.1-alpha.2",
36
+ "@deepseek-ai/dsh-package-manifest": "0.2.1-alpha.2",
35
37
  "@eslint-community/regexpp": "^4.12.2",
36
38
  "ajv": "^8.20.0",
37
- "js-yaml": "^4.2.0",
38
- "node-addon-require-builtin": "^0.1.6",
39
+ "js-yaml": "^4.3.2",
40
+ "node-addon-require-builtin": "^0.1.9",
39
41
  "resolve.exports": "^2.0.3",
40
- "semver": "^7.8.5",
41
- "@deepseek-ai/dsh-package-manifest": "0.2.0-rc.2",
42
- "@deepseek-ai/dsh-atomic-write": "0.2.0-rc.2"
42
+ "semver": "^7.8.5"
43
43
  },
44
44
  "peerDependencies": {
45
- "@deepseek-ai/cordis-plugin-group": "~1.0.4",
46
- "@deepseek-ai/cordis-plugin-include": "~1.0.9",
47
- "@deepseek-ai/cordis-plugin-loader": "~1.0.5",
48
- "@deepseek-ai/dsh-launch-environment": "0.2.0-rc.2",
49
- "@deepseek-ai/dsh-home-paths": "0.2.0-rc.2",
50
- "@deepseek-ai/dsh-system-prompt": "0.2.0-rc.2",
51
- "@deepseek-ai/cordis": "~4.0.4"
45
+ "@deepseek-ai/cordis-plugin-group": "~1.0.5-alpha.1",
46
+ "@deepseek-ai/cordis-plugin-include": "~1.0.10-alpha.1",
47
+ "@deepseek-ai/cordis-plugin-loader": "~1.0.6-alpha.1",
48
+ "@deepseek-ai/dsh-launch-environment": "0.2.1-alpha.2",
49
+ "@deepseek-ai/dsh-home-paths": "0.2.1-alpha.2",
50
+ "@deepseek-ai/dsh-system-prompt": "0.2.1-alpha.2",
51
+ "@deepseek-ai/cordis": "~4.0.5-alpha.1"
52
52
  },
53
53
  "devDependencies": {
54
+ "@deepseek-ai/schemastery": "~3.18.5-alpha.1",
55
+ "@deepseek-ai/cordis-plugin-group": "~1.0.5-alpha.1",
56
+ "@deepseek-ai/cordis-plugin-include": "~1.0.10-alpha.1",
57
+ "@deepseek-ai/cordis-plugin-loader": "~1.0.6-alpha.1",
58
+ "@deepseek-ai/cordis-plugin-timer": "~1.1.7-alpha.1",
59
+ "@deepseek-ai/dsh-launch-environment": "0.2.1-alpha.2",
60
+ "@deepseek-ai/dsh-home-paths": "0.2.1-alpha.2",
61
+ "@deepseek-ai/dsh-system-prompt": "0.2.1-alpha.2",
54
62
  "@types/js-yaml": "^4.0.9",
55
63
  "@types/semver": "^7.8.0",
56
- "@deepseek-ai/schemastery": "~3.18.4",
57
- "@deepseek-ai/cordis-plugin-group": "~1.0.4",
58
- "@deepseek-ai/cordis-plugin-include": "~1.0.9",
59
- "@deepseek-ai/cordis-plugin-loader": "~1.0.5",
60
- "@deepseek-ai/dsh-launch-environment": "0.2.0-rc.2",
61
- "@deepseek-ai/dsh-home-paths": "0.2.0-rc.2",
62
- "@deepseek-ai/dsh-system-prompt": "0.2.0-rc.2",
63
- "@deepseek-ai/cordis": "~4.0.4",
64
- "@deepseek-ai/cordis-plugin-timer": "~1.1.6"
64
+ "@deepseek-ai/cordis": "~4.0.5-alpha.1"
65
65
  }
66
66
  }