@deepseek-ai/dsh-app-boot 0.2.1-rc.4 → 0.2.2-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 +8 -8
- package/README.md +9 -5
- package/README.zh.md +9 -5
- package/lib/index.js +156 -92
- package/lib/types/bundle-platform.d.ts +17 -0
- package/lib/types/index.d.ts +7 -3
- package/lib/types/profile-plugins.d.ts +2 -0
- package/lib/types/profile.d.ts +4 -21
- package/lib/types/startup-diagnostics.d.ts +38 -0
- package/lib/worker/profile-resolution-bootstrap.js +5 -5
- package/package.json +19 -18
- package/lib/types/official-bundle-packages.d.ts +0 -4
- package/lib/types/official-bundles.d.ts +0 -12
- package/lib/types/official-bundles.generated.d.ts +0 -5
package/README.i18n.yaml
CHANGED
|
@@ -21,11 +21,11 @@
|
|
|
21
21
|
en: 2fdfe02f2ed4a258
|
|
22
22
|
zh: d748228ece579c4a
|
|
23
23
|
/deepseek-ai-dsh-app-boot/use-this-package/starting-the-app:
|
|
24
|
-
en:
|
|
25
|
-
zh:
|
|
24
|
+
en: 65bf2834b81f87da
|
|
25
|
+
zh: c864ac60a3005b99
|
|
26
26
|
/deepseek-ai-dsh-app-boot/use-this-package/profiles:
|
|
27
|
-
en:
|
|
28
|
-
zh:
|
|
27
|
+
en: a9c82cd220ae8d59
|
|
28
|
+
zh: 8c7c1c97efcdfc25
|
|
29
29
|
/deepseek-ai-dsh-app-boot/use-this-package/previewing-the-effective-configuration:
|
|
30
30
|
en: 646a0ccdd7881ad1
|
|
31
31
|
zh: e3696acb1573dd7b
|
|
@@ -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:
|
|
37
|
-
zh:
|
|
36
|
+
en: 91d80c444ac0cfe5
|
|
37
|
+
zh: e7db496043528ffb
|
|
38
38
|
/deepseek-ai-dsh-app-boot/use-this-package/startup-and-reload-failures:
|
|
39
39
|
en: dc13dfa1f79292e4
|
|
40
40
|
zh: d51682ced7a18ac2
|
|
@@ -42,8 +42,8 @@
|
|
|
42
42
|
en: f4a2695cb4c8a570
|
|
43
43
|
zh: 89837235d2f376cf
|
|
44
44
|
/deepseek-ai-dsh-app-boot/understand-the-implementation/design-notes:
|
|
45
|
-
en:
|
|
46
|
-
zh:
|
|
45
|
+
en: 6eba01e24a2a68ab
|
|
46
|
+
zh: 64af424489087ec7
|
|
47
47
|
/deepseek-ai-dsh-app-boot/understand-the-implementation/helper-behavior:
|
|
48
48
|
en: 6fa850d1bb000d0e
|
|
49
49
|
zh: aa83a40a9d3db295
|
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`, `web-runtime`, `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`, `tool-executor-native`, `tool-executor-ptc`, `webserver`, `web-runtime`, `modules`, `connection`, `headless-runner`, `acp`, and `sdk-jsonrpc-server`.
|
|
44
44
|
|
|
45
45
|
<a id="profiles"></a>
|
|
46
46
|
### Profiles
|
|
@@ -53,7 +53,9 @@ Before a profile imports a plugin, DSH checks its declared DSH requirement again
|
|
|
53
53
|
|
|
54
54
|
Admission happens only at composition boundaries DSH owns, and a denied row is denied in the launcher's own copy of the composition: no profile patch layer, dependency manifest, or bundle list changes. `prepareProfilePatches` composes over the launcher's empty profile root and runs while the root Include is mounted and on every profile recomposition, so a denied plugin never imports its module. `prepareProfileEntries` does the same for a preset's rows. A denied ordinary row becomes a detached `disabled: true` row; a native group stays mounted and its denied children do not load; a native Include that reaches a denied plugin is omitted whole, because its file is never rewritten. A row denied by policy keeps its configured `disabled` value in the profile, and every refusal is reported with the package, versions, and risk. A bundle is not a row, so `loadProfileDirectory` checks each bundle's own DSH requirement when it loads the profile's bundle layers, at startup and on every recomposition; an incompatible bundle without an exemption is skipped like an unreadable one and listed in `skippedBundles`. These boundaries do not cover plugins another embedder mounts through its own `ctx.plugin` call. Two edits made directly to files during a session are judged only at the next recomposition or startup: a running plugin's own `package.json` DSH requirement, and an entry-list file the Loader reads itself, such as the launcher's root config or a nested `cordis:include` file. `--dump-config` reports the configured composition, so a denied plugin row still appears there while a denied bundle contributes no rows, and `--dump-config-schema` imports each composed module to read its schema; run it only against a profile whose plugins you already trust.
|
|
55
55
|
|
|
56
|
-
Exact-version exemptions live in the profile's own `compatibility.json`, not in its `package.json`, so an exemption write never touches the dependency manifest, the bundle list, or Cordis patch files. It maps exact `package-name@version` keys to lists of exact DSH runtime versions; neither a plugin upgrade nor a DSH upgrade inherits permission. A missing file means no exemptions. A malformed one never stops the profile from starting: records the reader accepts still apply, each rejected record is reported on stderr beside the plugin denials, and the file is then treated as read-only, so a grant or revocation refuses and asks the user to repair it by hand instead of overwriting their content. [Plugin Manager](../plugin-manager/README.md#version-compatibility-and-exemptions) owns the grant, revocation, and risk confirmation each change requires.
|
|
56
|
+
Exact-version exemptions live in the profile's own `compatibility.json`, not in its `package.json`, so an exemption write never touches the dependency manifest, the bundle list, or Cordis patch files. It maps exact `package-name@version` keys to lists of exact DSH runtime versions; neither a plugin upgrade nor a DSH upgrade inherits permission. A missing file means no exemptions. A malformed one never stops the profile from starting: records the reader accepts still apply, each rejected record is reported on stderr beside the plugin denials, and the file is then treated as read-only, so a grant or revocation refuses and asks the user to repair it by hand instead of overwriting their content. [Plugin Manager](../plugin-manager/README.md#version-compatibility-and-exemptions) owns the grant, revocation, and risk confirmation each change requires. `validatePluginVersionExemption(packageVersion, runtimeVersion)` validates canonical exact identities without granting permission; invalid identities throw.
|
|
57
|
+
|
|
58
|
+
A bundle may declare `dsh.bundle.platforms` as a nonempty list of Node Host platform names, such as `["darwin"]`. The launcher validates this declaration before reading the bundle patch. An unsupported Host skips the entire layer, retains its saved selection, and reports the reason through `skippedBundles`; other layers remain effective. Omission permits every platform. Values must be Node platform names; aliases such as `macos` are invalid. Browser clients do not determine Host support.
|
|
57
59
|
|
|
58
60
|
Your machine-local preferences also live in the Harness home:
|
|
59
61
|
|
|
@@ -64,7 +66,7 @@ The enabled `dsh-hmr` plugin watches the profile manifest and both user patch fi
|
|
|
64
66
|
|
|
65
67
|
Inserted plugin names may be absolute filesystem paths, file URLs, or package specifiers. Patch loading converts absolute paths and patch-relative `./` or `../` paths to file URLs within `insert` rows and their nested groups; existing-entry name assertions and replacement `config` values remain literal.
|
|
66
68
|
|
|
67
|
-
Before mounting profile rows, the `dsh` launcher computes one immutable runtime resolution from the installation and ordered bundle dependency graphs. Every profile launcher uses runtime resolution, including plain Node, packaged executables, and the Electron Host. It installs the runtime resolution through Node's ESM and CommonJS resolvers without creating fallback links.
|
|
69
|
+
Before mounting profile rows, the `dsh` launcher computes one immutable runtime resolution from the installation and ordered bundle dependency graphs. Every profile launcher uses runtime resolution, including plain Node, packaged executables, and the Electron Host. It installs the runtime resolution through Node's ESM and CommonJS resolvers without creating fallback links. Traversal includes installed optional dependencies and skips those absent from the target installation.
|
|
68
70
|
|
|
69
71
|
`sanitizeProfile(binName, profileDir, bundles)` provides filesystem recovery without loading plugins or parsing patches. Desktop uses it for native fatal recovery. Call it only after stopping the profile and excluding concurrent profile writes. It renames the profile’s `cordis.patch.yml` to a unique `.bak-<timestamp>` sibling and restores the supplied bundle list, preserving installed packages and other manifest fields. The timestamp is Unix time in milliseconds; collisions append an ordinal (`-1`, `-2`, …) without changing it. It returns the backup path, or `undefined` when no patch exists; missing profiles remain absent. Profile initialization recreates an empty patch on the next launch. The home-level patch is unchanged. Invalid profile JSON fails before mutation; later errors propagate and retain completed changes for retry.
|
|
70
72
|
|
|
@@ -86,7 +88,7 @@ The projector preserves native omission behavior by checking literal defaults ag
|
|
|
86
88
|
|
|
87
89
|
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
90
|
|
|
89
|
-
|
|
91
|
+
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.
|
|
90
92
|
|
|
91
93
|
<a id="startup-and-reload-failures"></a>
|
|
92
94
|
### Startup and reload failures
|
|
@@ -143,7 +145,9 @@ This section explains how the outcomes above are realized and points at the code
|
|
|
143
145
|
- **One rejection checkpoint.** `inactiveEntries` keeps the exact reasons it folds into the boot diagnostic visible through the next process rejection checkpoint, so `installFailLoud` coalesces Loader's duplicate notification while unrelated unhandled rejections remain fatal.
|
|
144
146
|
- **Two-stage failure labels.** Outside startup audit failures, `boot()` distinguishes `host preparation failed` — `prepare` threw before any config-tree entry mounted — from `plugin tree failed to load`, and appends the deepest plugin error's stack. Plugin diagnostics retain nested causes and aggregate member failures; cyclic causes stop traversal without replacing the original error.
|
|
145
147
|
|
|
146
|
-
The startup error also retains inactive-entry metadata and raw startup warning/error records without retaining the Loader tree. Its `entries` and `
|
|
148
|
+
The startup error also retains inactive-entry metadata and raw startup warning/error records without retaining the Loader tree. Its `entries`, `startup`, and `composition` fields are non-enumerable: direct access and full diagnostic reports retain them, while ordinary error inspection omits them. Pending-only failures have no `cause`; failures with recorded errors retain their original values in an `AggregateError`. Import errors are collected through the logger before the Loader mounts because no failed Fiber exists for those imports. The temporary exporter is removed when boot settles.
|
|
149
|
+
|
|
150
|
+
The package exports `StartupCompositionDiagnostic`, `StartupPluginState`, and `StartupServiceState` for typed consumers. Before disposal, `composition` captures up to 256 configured plugin rows and 256 missing-service observations, with omission counts. Rows include module, available package version, state and Loader source URL; configuration values are excluded. Registered providers include their state and whether their scope matches the consumer. An empty provider list means ownership is unknown: disabled or failed plugins may never have registered. The Loader source does not identify which overlay last changed a row. Metadata lookup failures leave the version unknown; snapshot failure preserves the original startup error.
|
|
147
151
|
|
|
148
152
|
### Helper behavior
|
|
149
153
|
|
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`、`web-runtime`、`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`、`tool-executor-native`、`tool-executor-ptc`、`webserver`、`web-runtime`、`modules`、`connection`、`headless-runner`、`acp` 和 `sdk-jsonrpc-server`。
|
|
44
44
|
|
|
45
45
|
<a id="profiles"></a>
|
|
46
46
|
### Profile
|
|
@@ -53,7 +53,9 @@ profile 导入插件前,DSH 会将其声明的 DSH 版本要求与 `getDshRunt
|
|
|
53
53
|
|
|
54
54
|
检查只发生在 DSH 自己持有的组合入口,改写的是启动器自己的那份组合:profile 的 patch 层、依赖清单与组合包列表都不会改变。`prepareProfilePatches` 在启动器的空 profile 根之上组合,并在挂载根 Include 时以及每次 profile 重新组合时执行,因此被拒绝的插件永远不会导入其模块;`prepareProfileEntries` 对 preset 行做同样的事。被拒绝的普通行会变成游离的 `disabled: true` 行;原生 group 保持挂载,其被拒绝的子行不会加载;若某个原生 Include 会到达被拒绝的插件,则整体省略该 Include,因为它的文件不会被改写。被策略拒绝的行在 profile 中保留其配置的 `disabled` 值,每次拒绝都会报告包名、版本与风险。组合包本身不是行,因此 `loadProfileDirectory` 在启动和每次重新组合加载 profile 的组合包层时,检查每个组合包自己声明的 DSH 版本要求;没有豁免的不兼容组合包会像无法读取的组合包一样被跳过,并列入 `skippedBundles`。这些入口不覆盖其他嵌入方通过自己的 `ctx.plugin` 调用挂载的插件。会话中直接改文件的两类编辑只在下一次重新组合或启动时才被判定:正在运行的插件自己的 `package.json` DSH 版本要求,以及 Loader 自己读取的入口清单文件(如启动器的根配置或嵌套的 `cordis:include` 文件)。`--dump-config` 报告的是配置出的组合,因此被拒绝的插件行仍会出现在其中,而被拒绝的组合包不提供任何行;`--dump-config-schema` 会导入每个组合模块以读取其 schema,请只对已经信任其插件的 profile 运行。
|
|
55
55
|
|
|
56
|
-
精确版本豁免保存在 profile 自己的 `compatibility.json` 中,而不是 `package.json`,因此写豁免不会触及依赖清单、组合包列表或 Cordis patch 文件。它把精确的 `package-name@version` 键映射到精确 DSH 运行时版本列表;插件升级和 DSH 升级都不继承授权。文件缺失表示没有豁免。文件损坏绝不会阻止 profile 启动:读取器接受的记录仍然生效,每条被拒绝的记录会与插件拒绝信息一起输出到 stderr,此后该文件被视为只读,因此授予或撤销会拒绝执行并要求用户手工修复,而不是覆盖用户的内容。[插件管理器](../plugin-manager/README.zh.md#version-compatibility-and-exemptions)
|
|
56
|
+
精确版本豁免保存在 profile 自己的 `compatibility.json` 中,而不是 `package.json`,因此写豁免不会触及依赖清单、组合包列表或 Cordis patch 文件。它把精确的 `package-name@version` 键映射到精确 DSH 运行时版本列表;插件升级和 DSH 升级都不继承授权。文件缺失表示没有豁免。文件损坏绝不会阻止 profile 启动:读取器接受的记录仍然生效,每条被拒绝的记录会与插件拒绝信息一起输出到 stderr,此后该文件被视为只读,因此授予或撤销会拒绝执行并要求用户手工修复,而不是覆盖用户的内容。[插件管理器](../plugin-manager/README.zh.md#version-compatibility-and-exemptions)负责每次变更所需的授权、撤销与风险确认。`validatePluginVersionExemption(packageVersion, runtimeVersion)` 校验规范的精确身份而不授予权限;身份非法时抛出错误。
|
|
57
|
+
|
|
58
|
+
组合包可以用 `dsh.bundle.platforms` 声明非空的 Node Host 平台名称列表,例如 `["darwin"]`。启动器在读取组合包 patch 前验证此声明。Host 不受支持时会跳过整个配置层,保留已保存的选择,并通过 `skippedBundles` 报告原因;其他配置层继续生效。省略此字段时允许所有平台。值必须是 Node 平台名,`macos` 等别名无效。浏览器所在机器的平台不决定 Host 是否受支持。
|
|
57
59
|
|
|
58
60
|
你的机器本地偏好同样位于 harness home 中:
|
|
59
61
|
|
|
@@ -64,7 +66,7 @@ profile 导入插件前,DSH 会将其声明的 DSH 版本要求与 `getDshRunt
|
|
|
64
66
|
|
|
65
67
|
插入条目的插件名可以是绝对文件系统路径、文件 URL 或包标识符。patch 加载会把 `insert` 条目及其嵌套分组中的绝对路径以及相对于 patch 文件的 `./` 或 `../` 路径转换为文件 URL;对已有条目名称的断言及替换用的 `config` 值保持原样。
|
|
66
68
|
|
|
67
|
-
挂载 profile 条目前,`dsh` launcher 会从安装依赖图与有序 bundle 依赖图计算一份不可变的 runtime resolution。普通 Node、打包可执行文件与 Electron Host 等所有 profile 启动器都使用 runtime 解析,将 runtime resolution 安装到 Node 的 ESM 与 CommonJS 解析器中,不创建 fallback
|
|
69
|
+
挂载 profile 条目前,`dsh` launcher 会从安装依赖图与有序 bundle 依赖图计算一份不可变的 runtime resolution。普通 Node、打包可执行文件与 Electron Host 等所有 profile 启动器都使用 runtime 解析,将 runtime resolution 安装到 Node 的 ESM 与 CommonJS 解析器中,不创建 fallback 链接。依赖遍历包含已安装的可选依赖,跳过目标安装中缺席的包。
|
|
68
70
|
|
|
69
71
|
`sanitizeProfile(binName, profileDir, bundles)` 提供文件恢复,无需加载插件或解析 patch。Desktop 在原生致命错误恢复中调用它。调用前必须停止 profile 并排除并发 profile 写入。它将 profile 的 `cordis.patch.yml` 重命名为带唯一 `.bak-<timestamp>` 后缀的同目录备份,并恢复调用方指定的 bundle 列表,保留已安装包和其他 manifest 字段。时间戳为 Unix 毫秒数;同名备份已存在时追加序号(`-1`、`-2`、……),时间戳保持不变。返回值为备份路径;patch 不存在时返回 `undefined`,缺失的 profile 不会被创建。下次启动的 profile 初始化会重新创建空 patch。home 级 patch 不变。无效 profile JSON 在修改前报错;后续错误向调用方抛出,保留已完成的修改供重试。
|
|
70
72
|
|
|
@@ -86,7 +88,7 @@ profile 导入插件前,DSH 会将其声明的 DSH 版本要求与 `getDshRunt
|
|
|
86
88
|
|
|
87
89
|
使用 `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
90
|
|
|
89
|
-
|
|
91
|
+
app-boot 应用的 profile 模板、安装方拥有的 profile 组合包元组和已退役组合包列表位于 [`@deepseek-ai/dsh-official-bundles`](../../util/official-bundles/README.zh.md),安装方的默认、可选和按需组合包列表也在该包中。
|
|
90
92
|
|
|
91
93
|
<a id="startup-and-reload-failures"></a>
|
|
92
94
|
### 启动与重载失败
|
|
@@ -143,7 +145,9 @@ Loader 结算后,app-boot 在仅 optional 条目未激活时输出警告。如
|
|
|
143
145
|
- **单一 rejection 检查点。** `inactiveEntries` 把折入启动诊断的确切原因保持到下一个进程级 rejection 检查点可见,使 `installFailLoud` 能合并 Loader 的重复通知,而所有无关的未处理 rejection 仍然致命。
|
|
144
146
|
- **两阶段失败标签。** 除启动审计失败外,`boot()` 区分 `host preparation failed`(`prepare` 在任何配置树条目挂载前抛出)与 `plugin tree failed to load`,并追加最深层插件错误的堆栈。插件诊断保留嵌套原因和聚合错误中的各项失败;原因链出现循环时会停止遍历,但不会替换原始错误。
|
|
145
147
|
|
|
146
|
-
启动错误还保留未激活条目的元数据和原始启动警告、错误记录,不保留 Loader tree。其 `entries` 和 `
|
|
148
|
+
启动错误还保留未激活条目的元数据和原始启动警告、错误记录,不保留 Loader tree。其 `entries`、`startup` 和 `composition` 字段不可枚举:直接访问和完整诊断报告保留这些字段,常规错误检查输出则省略它们。只有等待条目时没有 `cause`;存在已记录错误时,`AggregateError` 保留其原始值。收集器在 Loader 挂载前通过 logger 收集导入错误,因为这些导入尚无 failed Fiber。启动结算后会移除临时 exporter。
|
|
149
|
+
|
|
150
|
+
包导出 `StartupCompositionDiagnostic`、`StartupPluginState` 和 `StartupServiceState`,供消费者按名引用。释放前,`composition` 捕获最多 256 个配置插件条目和 256 个缺失服务观测,并记录省略数量。条目包含模块、可取得的包版本、状态和 Loader 来源 URL,不含配置值。已注册提供者包含其状态及作用域是否与消费者一致。提供者列表为空表示归属未知:被禁用或失败的插件可能从未注册服务。Loader 来源不代表最后修改该条目的 overlay。元数据查询失败时版本标为未知;快照失败保留原始启动错误。
|
|
147
151
|
|
|
148
152
|
### Helper 行为
|
|
149
153
|
|
package/lib/index.js
CHANGED
|
@@ -2,20 +2,104 @@ import { createRequire, isBuiltin } from "node:module";
|
|
|
2
2
|
import { fileURLToPath, pathToFileURL } from "node:url";
|
|
3
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
|
+
import { Context, Service } from "@deepseek-ai/cordis";
|
|
5
6
|
import { basename, dirname, extname, isAbsolute, join, relative, resolve, sep, win32 } from "node:path";
|
|
6
7
|
import * as yaml from "js-yaml";
|
|
7
8
|
import { load } from "js-yaml";
|
|
8
|
-
import { Context, Service } from "@deepseek-ai/cordis";
|
|
9
9
|
import Loader, { EntryGroup, EntryTree, ModuleLoader, isJsExpr } from "@deepseek-ai/cordis-plugin-loader";
|
|
10
10
|
import { access, constants, mkdir, readFile, realpath, rename, writeFile } from "node:fs/promises";
|
|
11
11
|
import { setTimeout as setTimeout$1 } from "node:timers/promises";
|
|
12
12
|
import Group from "@deepseek-ai/cordis-plugin-group";
|
|
13
13
|
import { dshHomePath, resolveDshHome } from "@deepseek-ai/dsh-home-paths";
|
|
14
14
|
import { createLaunchEnvironmentSnapshot } from "@deepseek-ai/dsh-launch-environment";
|
|
15
|
+
import { INSTALLATION_OWNED_PROFILE_TUPLES, PROFILE_TEMPLATES, RETIRED_BUNDLES } from "@deepseek-ai/dsh-official-bundles";
|
|
15
16
|
import semver, { parse } from "semver";
|
|
16
17
|
import { withFileLock, writeFileAtomic } from "@deepseek-ai/dsh-atomic-write";
|
|
17
18
|
import { getEnvironmentData, setEnvironmentData } from "node:worker_threads";
|
|
18
19
|
import { imports } from "resolve.exports";
|
|
20
|
+
//#region lib/types/startup-diagnostics.js
|
|
21
|
+
/** Configuration-free snapshots captured before a failed startup disposes its plugins. */
|
|
22
|
+
function stateName(state) {
|
|
23
|
+
return {
|
|
24
|
+
0: "pending",
|
|
25
|
+
1: "loading",
|
|
26
|
+
2: "active",
|
|
27
|
+
3: "failed",
|
|
28
|
+
4: "disposed",
|
|
29
|
+
5: "unloading"
|
|
30
|
+
}[state];
|
|
31
|
+
}
|
|
32
|
+
function pluginState(ctx, entry) {
|
|
33
|
+
let state;
|
|
34
|
+
try {
|
|
35
|
+
state = entry.disabled ? "disabled" : entry.fiber === void 0 ? "failed" : stateName(entry.fiber.state);
|
|
36
|
+
} catch (_error) {
|
|
37
|
+
state = "failed";
|
|
38
|
+
}
|
|
39
|
+
let version = "unknown";
|
|
40
|
+
const source = entry.parent.tree.ctx.baseUrl;
|
|
41
|
+
try {
|
|
42
|
+
if (source !== void 0) version = ctx.get("pluginPackages")?.packageOf(entry.options.name, source)?.version ?? "unknown";
|
|
43
|
+
} catch (_error) {}
|
|
44
|
+
const fiber = entry.fiber;
|
|
45
|
+
return {
|
|
46
|
+
id: entry.id,
|
|
47
|
+
module: entry.options.name,
|
|
48
|
+
version,
|
|
49
|
+
state,
|
|
50
|
+
source: source ?? "unknown",
|
|
51
|
+
missing: state === "pending" && fiber !== void 0 ? Object.keys(fiber.inject).filter((name) => fiber.ctx.get(name) === void 0) : []
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Capture Loader state and registered service ownership before teardown.
|
|
56
|
+
* Providers that never registered cannot be inferred from their package names.
|
|
57
|
+
* @param ctx - Live application context with its Loader still mounted.
|
|
58
|
+
* @returns At most 256 plugin rows and 256 missing-service observations, with omission counts.
|
|
59
|
+
*/
|
|
60
|
+
function captureStartupComposition(ctx) {
|
|
61
|
+
const rows = [...ctx.loader.entries()].map((entry) => ({
|
|
62
|
+
entry,
|
|
63
|
+
state: pluginState(ctx, entry)
|
|
64
|
+
}));
|
|
65
|
+
rows.sort((a, b) => Number(a.state.state === "active") - Number(b.state.state === "active"));
|
|
66
|
+
const services = [];
|
|
67
|
+
let omittedServices = 0;
|
|
68
|
+
const store = ctx.reflect.store;
|
|
69
|
+
for (const { entry, state } of rows) {
|
|
70
|
+
const fiber = entry.fiber;
|
|
71
|
+
if (fiber === void 0) continue;
|
|
72
|
+
for (const service of state.missing) {
|
|
73
|
+
if (services.length === 256) {
|
|
74
|
+
omittedServices++;
|
|
75
|
+
continue;
|
|
76
|
+
}
|
|
77
|
+
const scope = fiber.ctx[Context.isolate][service];
|
|
78
|
+
const providers = [];
|
|
79
|
+
for (const key of Object.getOwnPropertySymbols(store)) {
|
|
80
|
+
const impl = store[key];
|
|
81
|
+
if (impl?.name !== service) continue;
|
|
82
|
+
providers.push({
|
|
83
|
+
entry: impl.fiber.entry?.id ?? "unknown",
|
|
84
|
+
state: stateName(impl.fiber.state),
|
|
85
|
+
visibility: key === scope ? "same-scope" : "other-scope"
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
services.push({
|
|
89
|
+
consumer: state.id,
|
|
90
|
+
service,
|
|
91
|
+
providers
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
return {
|
|
96
|
+
plugins: rows.slice(0, 256).map((row) => row.state),
|
|
97
|
+
services,
|
|
98
|
+
omittedPlugins: Math.max(0, rows.length - 256),
|
|
99
|
+
omittedServices
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
//#endregion
|
|
19
103
|
//#region ../../../vendor/include/src/index.ts
|
|
20
104
|
const JsExpr = new yaml.Type("tag:yaml.org,2002:js", {
|
|
21
105
|
kind: "scalar",
|
|
@@ -248,6 +332,44 @@ var Include = class extends EntryTree {
|
|
|
248
332
|
}
|
|
249
333
|
};
|
|
250
334
|
//#endregion
|
|
335
|
+
//#region lib/types/bundle-platform.js
|
|
336
|
+
/** Host operating-system admission for optional bundle layers. */
|
|
337
|
+
const NODE_PLATFORMS = Object.freeze([
|
|
338
|
+
"aix",
|
|
339
|
+
"android",
|
|
340
|
+
"darwin",
|
|
341
|
+
"freebsd",
|
|
342
|
+
"haiku",
|
|
343
|
+
"linux",
|
|
344
|
+
"openbsd",
|
|
345
|
+
"sunos",
|
|
346
|
+
"win32",
|
|
347
|
+
"cygwin",
|
|
348
|
+
"netbsd"
|
|
349
|
+
]);
|
|
350
|
+
/** A valid bundle declaration excludes the operating system running DSH. */
|
|
351
|
+
var UnsupportedBundlePlatformError = class extends Error {
|
|
352
|
+
/**
|
|
353
|
+
* @param platforms Node platform names supported by the bundle.
|
|
354
|
+
* @param platform Operating system of the DSH Host.
|
|
355
|
+
*/
|
|
356
|
+
constructor(platforms, platform) {
|
|
357
|
+
super(`Bundle supports Host platforms ${platforms.join(", ")}; the DSH Host is running ${platform}`);
|
|
358
|
+
this.name = "UnsupportedBundlePlatformError";
|
|
359
|
+
}
|
|
360
|
+
};
|
|
361
|
+
/**
|
|
362
|
+
* Validate package metadata and reject an unsupported Host before selecting or composing a bundle.
|
|
363
|
+
* @param platforms The optional `dsh.bundle.platforms` field read from package.json.
|
|
364
|
+
* @param platform Operating system of the DSH Host, from Node's `process.platform`.
|
|
365
|
+
* @throws When the declaration is malformed or excludes the Host; omission allows every platform.
|
|
366
|
+
*/
|
|
367
|
+
function assertBundlePlatform(platforms, platform) {
|
|
368
|
+
if (platforms === void 0) return;
|
|
369
|
+
if (!Array.isArray(platforms) || platforms.length === 0 || !platforms.every((value) => typeof value === "string" && NODE_PLATFORMS.includes(value))) throw new Error("dsh.bundle.platforms must be a nonempty list of Node platform names");
|
|
370
|
+
if (!platforms.includes(platform)) throw new UnsupportedBundlePlatformError(platforms, platform);
|
|
371
|
+
}
|
|
372
|
+
//#endregion
|
|
251
373
|
//#region lib/types/plugin-compatibility.js
|
|
252
374
|
/** Evaluate plugin dsh requirements (`engines.dsh`, else dsh peers) without importing plugin code. */
|
|
253
375
|
function objectOf$1(value, field) {
|
|
@@ -547,49 +669,6 @@ function resolveProfileDir(name, home = resolveDshHome()) {
|
|
|
547
669
|
if (name === "" || name.includes("/") || name.includes("\\") || name === "." || name === ".." || name === "node_modules") throw new Error(`dsh: invalid profile name ${JSON.stringify(name)}`);
|
|
548
670
|
return join(home, PROFILES_DIR, name);
|
|
549
671
|
}
|
|
550
|
-
/** The shipped profile templates auto-initialized on first use, by name. */
|
|
551
|
-
const PROFILE_TEMPLATES = {
|
|
552
|
-
acp: { bundles: ["@deepseek-ai/dsh-base", "@deepseek-ai/dsh-acp-app"] },
|
|
553
|
-
web: { bundles: ["@deepseek-ai/dsh-base", "@deepseek-ai/dsh-web-app"] },
|
|
554
|
-
headless: { bundles: ["@deepseek-ai/dsh-base", "@deepseek-ai/dsh-headless"] },
|
|
555
|
-
sdk: { bundles: ["@deepseek-ai/dsh-base", "@deepseek-ai/dsh-sdk-app"] },
|
|
556
|
-
"sdk-minimal": { bundles: ["@deepseek-ai/dsh-sdk-minimal"] }
|
|
557
|
-
};
|
|
558
|
-
/** Installation-owned bundle tuples normalized to the shipped template. */
|
|
559
|
-
const INSTALLATION_OWNED_PROFILE_TUPLES = { headless: [
|
|
560
|
-
"@deepseek-ai/dsh-base",
|
|
561
|
-
"@deepseek-ai/dsh-web-app",
|
|
562
|
-
"@deepseek-ai/dsh-headless"
|
|
563
|
-
] };
|
|
564
|
-
/**
|
|
565
|
-
* Bundles an earlier release shipped and the installation no longer carries;
|
|
566
|
-
* {@link loadProfileDirectory} removes them from the profile's bundle list.
|
|
567
|
-
*/
|
|
568
|
-
const RETIRED_BUNDLES = new Set(["@deepseek-ai/dsh-experimental-schedule-bundle"]);
|
|
569
|
-
/** The bundle list a `dsh plugin` init uses for a name with no shipped template. */
|
|
570
|
-
const DEFAULT_PROFILE_BUNDLES = ["@deepseek-ai/dsh-base"];
|
|
571
|
-
/**
|
|
572
|
-
* The bundles the dsh installation ships for a person to switch on: each a
|
|
573
|
-
* runtime dependency of the installation that declares `dsh.bundle.patch`,
|
|
574
|
-
* an `icon`, and `./locale/*.json` display metadata, selected by no shipped
|
|
575
|
-
* template, and offered switched off by the plugin manager
|
|
576
|
-
* ([rationale](../../../../.agents/notes/implemented/process/2026-09-15-shipped-optional-bundles.md),
|
|
577
|
-
* [admission](../../../../.agents/notes/implemented/architecture/2026-09-21-experimental-capabilities-as-optional-bundles.md)).
|
|
578
|
-
*/
|
|
579
|
-
const OPTIONAL_BUNDLES = [
|
|
580
|
-
"@deepseek-ai/dsh-experimental-session-search",
|
|
581
|
-
"@deepseek-ai/dsh-experimental-ralph-bundle",
|
|
582
|
-
"@deepseek-ai/dsh-experimental-terminal-bundle",
|
|
583
|
-
"@deepseek-ai/dsh-experimental-badge-skill-bundle",
|
|
584
|
-
"@deepseek-ai/dsh-experimental-session-titles-bundle",
|
|
585
|
-
"@deepseek-ai/dsh-experimental-agent-team-profile",
|
|
586
|
-
"@deepseek-ai/dsh-experimental-voice-input-bundle",
|
|
587
|
-
"@deepseek-ai/dsh-experimental-cot-translation-bundle",
|
|
588
|
-
"@deepseek-ai/dsh-experimental-auto-review",
|
|
589
|
-
"@deepseek-ai/dsh-experimental-inspector-profile",
|
|
590
|
-
"@deepseek-ai/dsh-experimental-plugin-market-bundle",
|
|
591
|
-
"@deepseek-ai/dsh-experimental-tool-worktree"
|
|
592
|
-
];
|
|
593
672
|
const PROFILE_PATCH_TEMPLATE = `# Your patch layer for this dsh profile, applied after every bundle layer:
|
|
594
673
|
# a top-level YAML array of loader patch entries (id-targeted config
|
|
595
674
|
# overrides, disables, and insert lists; \`!!js\` expressions allowed).
|
|
@@ -710,7 +789,11 @@ function readPackageManifest(anchor) {
|
|
|
710
789
|
}
|
|
711
790
|
/** Return dependency names that may be imported by a loader-visible plugin. */
|
|
712
791
|
function profileDependencyNames(manifest) {
|
|
713
|
-
return [
|
|
792
|
+
return [
|
|
793
|
+
...Object.keys(manifest.dependencies ?? {}),
|
|
794
|
+
...Object.keys(manifest.peerDependencies ?? {}),
|
|
795
|
+
...Object.keys(manifest.optionalDependencies ?? {})
|
|
796
|
+
];
|
|
714
797
|
}
|
|
715
798
|
/** Resolve the installation packages that the runtime resolver supplies to every profile. */
|
|
716
799
|
function collectInstallationScopePackages(installAnchor, skippedBundles) {
|
|
@@ -1004,7 +1087,8 @@ function resolveBundleDir(binName, packageName, installAnchor, profileDir) {
|
|
|
1004
1087
|
* the shared Harness home. This is used by application-owned profiles whose
|
|
1005
1088
|
* package project and lifecycle belong to that application.
|
|
1006
1089
|
* Retired bundles are removed from the stored bundle list first, rewriting the
|
|
1007
|
-
* manifest when it listed one. Unreadable bundles, and bundles whose own dsh requirements
|
|
1090
|
+
* manifest when it listed one. Unreadable bundles, unsupported Host platforms, and bundles whose own dsh requirements
|
|
1091
|
+
* the profile does not exempt are skipped
|
|
1008
1092
|
* without changing the manifest and listed in `skippedBundles`; nothing is printed.
|
|
1009
1093
|
* @param binName - the diagnostic prefix on thrown errors.
|
|
1010
1094
|
* @param dir - absolute profile package directory.
|
|
@@ -1022,6 +1106,7 @@ function loadProfileDirectory(binName, dir, installAnchor, options = {}) {
|
|
|
1022
1106
|
const bundleManifest = readProfileManifest(binName, packageDir);
|
|
1023
1107
|
const bundle = bundleManifest.dsh?.bundle;
|
|
1024
1108
|
if (bundle === void 0) throw new Error(`${binName}: profile bundle ${JSON.stringify(packageName)} declares no dsh.bundle in its package.json`);
|
|
1109
|
+
assertBundlePlatform(bundle.platforms, process.platform);
|
|
1025
1110
|
const issue = evaluatePluginCompatibility(bundleManifest, exemptions);
|
|
1026
1111
|
if (issue !== void 0 && !issue.exempted) throw new Error(pluginCompatibilityWarning(issue));
|
|
1027
1112
|
const patchPaths = bundlePatchPaths(packageDir, bundle);
|
|
@@ -1051,8 +1136,8 @@ function loadProfileDirectory(binName, dir, installAnchor, options = {}) {
|
|
|
1051
1136
|
}
|
|
1052
1137
|
/**
|
|
1053
1138
|
* Load a profile: resolve every `dsh.profile.bundles` entry to its patch
|
|
1054
|
-
* layer and parse the profile's own patch file. Unreadable
|
|
1055
|
-
* are skipped and listed in `skippedBundles`; profile manifest and user patch errors still throw.
|
|
1139
|
+
* layer and parse the profile's own patch file. Unreadable bundles, unsupported Host platforms,
|
|
1140
|
+
* and incompatible bundles are skipped and listed in `skippedBundles`; profile manifest and user patch errors still throw.
|
|
1056
1141
|
* @param binName - the diagnostic prefix on thrown errors.
|
|
1057
1142
|
* @param name - the profile name.
|
|
1058
1143
|
* @param installAnchor - absolute path of the dsh app's package.json (first resolution anchor).
|
|
@@ -1205,6 +1290,8 @@ function writeProfileBundles(profileDir, manifest, bundles) {
|
|
|
1205
1290
|
* template entries retain their order and duplicates. New bundle dependencies activate automatically.
|
|
1206
1291
|
* @param options - location, inventory captured before pnpm, and whether explicitly disabled bundles remain disabled.
|
|
1207
1292
|
* @returns updated inventory and newly added ordinary dependencies for caller-owned warnings.
|
|
1293
|
+
* @throws If a new selection has invalid platform metadata or excludes the Host. Installed dependencies
|
|
1294
|
+
* remain; no bundle selection changes are written.
|
|
1208
1295
|
*/
|
|
1209
1296
|
function reconcileProfilePlugins(options) {
|
|
1210
1297
|
const after = readProfilePlugins(options);
|
|
@@ -1214,7 +1301,10 @@ function reconcileProfilePlugins(options) {
|
|
|
1214
1301
|
const disabled = new Set(options.preserveDisabled ? options.before.dependencies.filter((dependency) => dependency.bundle && !dependency.enabled).map((dependency) => dependency.name) : []);
|
|
1215
1302
|
const previous = after.manifest.dsh?.profile?.bundles ?? [];
|
|
1216
1303
|
const bundles = previous.filter((name) => !(beforeNames.has(name) || afterNames.has(name)) || bundleNames.has(name));
|
|
1217
|
-
for (const dependency of after.dependencies) if (dependency.bundle && !disabled.has(dependency.name) && !bundles.includes(dependency.name))
|
|
1304
|
+
for (const dependency of after.dependencies) if (dependency.bundle && !disabled.has(dependency.name) && !bundles.includes(dependency.name)) {
|
|
1305
|
+
assertBundlePlatform(bundleManifest(options, dependency.name)?.dsh?.bundle?.platforms, process.platform);
|
|
1306
|
+
bundles.push(dependency.name);
|
|
1307
|
+
}
|
|
1218
1308
|
return {
|
|
1219
1309
|
plugins: {
|
|
1220
1310
|
manifest: bundles.length !== previous.length || bundles.some((name, index) => name !== previous[index]) ? writeProfileBundles(options.profileDir, after.manifest, bundles) : after.manifest,
|
|
@@ -1785,7 +1875,7 @@ function internalModules() {
|
|
|
1785
1875
|
const esmResolve = addon.requireBuiltin("internal/modules/esm/resolve");
|
|
1786
1876
|
const esm = esmModule.getOrInitializeCascadedLoader();
|
|
1787
1877
|
const modern = "getOrCreateModuleJob" in esm;
|
|
1788
|
-
/* v8 ignore start -- the supported Node
|
|
1878
|
+
/* v8 ignore start -- the supported Node 24/26 matrix validates each available Internal interface */
|
|
1789
1879
|
if (typeof esm.resolveSync !== "function" || typeof Reflect.get(esm, modern ? "getOrCreateModuleJob" : "getModuleJobForImport") !== "function" || !modern && typeof Reflect.get(esm, "resolve") !== "function" || typeof cjsModule.Module._resolveFilename !== "function" || typeof cjsHelpers.getCjsConditions !== "function" || typeof esmUtils.getDefaultConditions !== "function" || typeof esmResolve.defaultResolve !== "function") throw new Error("profile resolution: unsupported Node module loader");
|
|
1790
1880
|
/* v8 ignore stop */
|
|
1791
1881
|
return {
|
|
@@ -1861,7 +1951,7 @@ function installRuntimeInterception(resolution) {
|
|
|
1861
1951
|
let expected;
|
|
1862
1952
|
try {
|
|
1863
1953
|
expected = adapted(target.specifier, target.parentURL, attributes);
|
|
1864
|
-
/* v8 ignore next --
|
|
1954
|
+
/* v8 ignore next -- the current loader resolves synchronously; the private interface also permits Promise results */
|
|
1865
1955
|
if (expected instanceof Promise) expected = expected.catch(restoreImporter);
|
|
1866
1956
|
} catch (error) {
|
|
1867
1957
|
return restoreImporter(error);
|
|
@@ -1890,7 +1980,7 @@ function installRuntimeInterception(resolution) {
|
|
|
1890
1980
|
} catch (error) {
|
|
1891
1981
|
return restoreImporter(error);
|
|
1892
1982
|
}
|
|
1893
|
-
/* v8 ignore next --
|
|
1983
|
+
/* v8 ignore next -- the current loader resolves synchronously; the private interface also permits Promise results */
|
|
1894
1984
|
if (result instanceof Promise) return result.catch(restoreImporter);
|
|
1895
1985
|
if (cacheable) state.esm = result;
|
|
1896
1986
|
return result;
|
|
@@ -1912,12 +2002,12 @@ function installRuntimeInterception(resolution) {
|
|
|
1912
2002
|
};
|
|
1913
2003
|
return (request, parent, attributes) => {
|
|
1914
2004
|
const result = adapted(request, parent, attributes);
|
|
1915
|
-
/* v8 ignore next --
|
|
2005
|
+
/* v8 ignore next -- the current loader resolves synchronously; the private interface also permits Promise results */
|
|
1916
2006
|
return result instanceof Promise ? result.then((resolved) => relocate(resolved, parent)) : relocate(result, parent);
|
|
1917
2007
|
};
|
|
1918
2008
|
};
|
|
1919
2009
|
let restoreEsm;
|
|
1920
|
-
/* v8 ignore else -- CI coverage runs Node 24 v2; the Node
|
|
2010
|
+
/* v8 ignore else -- CI coverage runs Node 24 v2; the Node 24.0 matrix exercises the v1 adapter */
|
|
1921
2011
|
if (modern) {
|
|
1922
2012
|
const loader = esm;
|
|
1923
2013
|
const original = Reflect.get(loader, "resolveSync");
|
|
@@ -2401,42 +2491,6 @@ function prepareProfilePatches(ctx, patches, parentURL, binName = "dsh") {
|
|
|
2401
2491
|
return rows.length === 0 ? [] : [{ insert: rows }];
|
|
2402
2492
|
}
|
|
2403
2493
|
//#endregion
|
|
2404
|
-
//#region lib/types/official-bundle-packages.js
|
|
2405
|
-
/** Package admission shared by offline catalog generation and release ordering. */
|
|
2406
|
-
/** Public DSH release members available through the ordinary on-demand bundle installer. */
|
|
2407
|
-
const ON_DEMAND_BUNDLES = ["@deepseek-ai/dsh-subagent-claude-code", "@deepseek-ai/dsh-subagent-codex"];
|
|
2408
|
-
//#endregion
|
|
2409
|
-
//#region lib/types/official-bundles.generated.js
|
|
2410
|
-
/** Generated offline Official bundle metadata. Run pnpm gen-official-bundle-catalog; do not edit. */
|
|
2411
|
-
/** Official on-demand entries, independent of installed packages and registry availability. */
|
|
2412
|
-
const OFFICIAL_ON_DEMAND_CATALOG = [{
|
|
2413
|
-
packageName: "@deepseek-ai/dsh-subagent-claude-code",
|
|
2414
|
-
meta: {
|
|
2415
|
-
title: {
|
|
2416
|
-
"en": "Claude Code subagent",
|
|
2417
|
-
"zh": "Claude Code 子智能体"
|
|
2418
|
-
},
|
|
2419
|
-
description: {
|
|
2420
|
-
"en": "Delegate one task to Claude Code using its native authentication and settings.",
|
|
2421
|
-
"zh": "使用 Claude Code 原生认证和设置委派单个任务。"
|
|
2422
|
-
},
|
|
2423
|
-
icon: "data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMzYiIGhlaWdodD0iMzYiIHZpZXdCb3g9IjAgMCAzNiAzNiIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48cmVjdCB4PSIxNC45ODkzIiB5PSIxNS4xODc3IiB3aWR0aD0iMTIuMjM2NSIgaGVpZ2h0PSIxMi4yMzY1IiByeD0iMiIgZmlsbD0idXJsKCNkc2hfcGx1Z2luX2FydF9SMGEpIiBmaWxsLW9wYWNpdHk9IjAuOCI+PC9yZWN0PjxyZWN0IHg9IjguODcxMDkiIHk9IjkuMDY5NyIgd2lkdGg9IjEyLjIzNjUiIGhlaWdodD0iMTIuMjM2NSIgcng9IjIiIGZpbGw9InVybCgjZHNoX3BsdWdpbl9hcnRfUjBiKSIgZmlsbC1vcGFjaXR5PSIwLjgiPjwvcmVjdD48ZGVmcz48bGluZWFyR3JhZGllbnQgaWQ9ImRzaF9wbHVnaW5fYXJ0X1IwYSIgeDE9IjIxLjEwNzUiIHkxPSIxNS4xODc3IiB4Mj0iMjEuMTA3NSIgeTI9IjI3LjQyNDMiIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIj48c3RvcCBzdG9wLWNvbG9yPSIjNDVFN0E0Ij48L3N0b3A+PHN0b3Agb2Zmc2V0PSIxIiBzdG9wLWNvbG9yPSIjMDU5MDlEIj48L3N0b3A+PC9saW5lYXJHcmFkaWVudD48bGluZWFyR3JhZGllbnQgaWQ9ImRzaF9wbHVnaW5fYXJ0X1IwYiIgeDE9IjE0Ljk4OTQiIHkxPSI5LjA2OTciIHgyPSIxNC45ODk0IiB5Mj0iMjEuMzA2MyIgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiPjxzdG9wIHN0b3AtY29sb3I9IiM2OUI5RkYiPjwvc3RvcD48c3RvcCBvZmZzZXQ9IjEiIHN0b3AtY29sb3I9IiMzMjRERTIiPjwvc3RvcD48L2xpbmVhckdyYWRpZW50PjwvZGVmcz48L3N2Zz4K"
|
|
2424
|
-
}
|
|
2425
|
-
}, {
|
|
2426
|
-
packageName: "@deepseek-ai/dsh-subagent-codex",
|
|
2427
|
-
meta: {
|
|
2428
|
-
title: {
|
|
2429
|
-
"en": "Codex subagent",
|
|
2430
|
-
"zh": "Codex 子智能体"
|
|
2431
|
-
},
|
|
2432
|
-
description: {
|
|
2433
|
-
"en": "Delegate one task to Codex using its native authentication and settings.",
|
|
2434
|
-
"zh": "使用 Codex 原生认证和设置委派单个任务。"
|
|
2435
|
-
},
|
|
2436
|
-
icon: "data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMzYiIGhlaWdodD0iMzYiIHZpZXdCb3g9IjAgMCAzNiAzNiIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48cmVjdCB4PSIxNC45ODkzIiB5PSIxNS4xODc3IiB3aWR0aD0iMTIuMjM2NSIgaGVpZ2h0PSIxMi4yMzY1IiByeD0iMiIgZmlsbD0idXJsKCNkc2hfcGx1Z2luX2FydF9SMGEpIiBmaWxsLW9wYWNpdHk9IjAuOCI+PC9yZWN0PjxyZWN0IHg9IjguODcxMDkiIHk9IjkuMDY5NyIgd2lkdGg9IjEyLjIzNjUiIGhlaWdodD0iMTIuMjM2NSIgcng9IjIiIGZpbGw9InVybCgjZHNoX3BsdWdpbl9hcnRfUjBiKSIgZmlsbC1vcGFjaXR5PSIwLjgiPjwvcmVjdD48ZGVmcz48bGluZWFyR3JhZGllbnQgaWQ9ImRzaF9wbHVnaW5fYXJ0X1IwYSIgeDE9IjIxLjEwNzUiIHkxPSIxNS4xODc3IiB4Mj0iMjEuMTA3NSIgeTI9IjI3LjQyNDMiIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIj48c3RvcCBzdG9wLWNvbG9yPSIjNDVFN0E0Ij48L3N0b3A+PHN0b3Agb2Zmc2V0PSIxIiBzdG9wLWNvbG9yPSIjMDU5MDlEIj48L3N0b3A+PC9saW5lYXJHcmFkaWVudD48bGluZWFyR3JhZGllbnQgaWQ9ImRzaF9wbHVnaW5fYXJ0X1IwYiIgeDE9IjE0Ljk4OTQiIHkxPSI5LjA2OTciIHgyPSIxNC45ODk0IiB5Mj0iMjEuMzA2MyIgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiPjxzdG9wIHN0b3AtY29sb3I9IiM2OUI5RkYiPjwvc3RvcD48c3RvcCBvZmZzZXQ9IjEiIHN0b3AtY29sb3I9IiMzMjRERTIiPjwvc3RvcD48L2xpbmVhckdyYWRpZW50PjwvZGVmcz48L3N2Zz4K"
|
|
2437
|
-
}
|
|
2438
|
-
}];
|
|
2439
|
-
//#endregion
|
|
2440
2494
|
//#region lib/types/config-schema/native.js
|
|
2441
2495
|
/** Identity checks at the plugin-export and lazy-builder boundaries. */
|
|
2442
2496
|
/**
|
|
@@ -4269,6 +4323,8 @@ const FIBER_DISPOSED = 4;
|
|
|
4269
4323
|
*/
|
|
4270
4324
|
const requiredStartupEntryIds = new Set([
|
|
4271
4325
|
"agent-loop",
|
|
4326
|
+
"tool-executor-native",
|
|
4327
|
+
"tool-executor-ptc",
|
|
4272
4328
|
"webserver",
|
|
4273
4329
|
"web-runtime",
|
|
4274
4330
|
"modules",
|
|
@@ -4298,6 +4354,8 @@ function formatActivationError(error, stacks = true) {
|
|
|
4298
4354
|
/** Startup audit failure with non-enumerable metadata and original failures as its cause. */
|
|
4299
4355
|
var StartupError = class extends Error {
|
|
4300
4356
|
entries;
|
|
4357
|
+
/** Plugin states captured before disposal, excluding configuration values. */
|
|
4358
|
+
composition;
|
|
4301
4359
|
/** Root configuration and startup logs, attached by boot after disposal. */
|
|
4302
4360
|
startup;
|
|
4303
4361
|
/**
|
|
@@ -4310,7 +4368,8 @@ var StartupError = class extends Error {
|
|
|
4310
4368
|
this.entries = entries;
|
|
4311
4369
|
Object.defineProperties(this, {
|
|
4312
4370
|
entries: { enumerable: false },
|
|
4313
|
-
startup: { enumerable: false }
|
|
4371
|
+
startup: { enumerable: false },
|
|
4372
|
+
composition: { enumerable: false }
|
|
4314
4373
|
});
|
|
4315
4374
|
}
|
|
4316
4375
|
};
|
|
@@ -4541,6 +4600,11 @@ async function boot(binName, absoluteConfigPath, patches, prepare, bareModuleBas
|
|
|
4541
4600
|
await auditStartupEntries(ctx, binName);
|
|
4542
4601
|
return ctx;
|
|
4543
4602
|
} catch (cause) {
|
|
4603
|
+
if (cause instanceof StartupError) try {
|
|
4604
|
+
cause.composition = captureStartupComposition(ctx);
|
|
4605
|
+
} catch (error) {
|
|
4606
|
+
ctx.logger.warn("Startup composition diagnostic unavailable", error);
|
|
4607
|
+
}
|
|
4544
4608
|
await ctx.fiber.dispose();
|
|
4545
4609
|
if (cause instanceof StartupError) {
|
|
4546
4610
|
cause.startup = {
|
|
@@ -4563,4 +4627,4 @@ async function boot(binName, absoluteConfigPath, patches, prepare, bareModuleBas
|
|
|
4563
4627
|
}
|
|
4564
4628
|
}
|
|
4565
4629
|
//#endregion
|
|
4566
|
-
export {
|
|
4630
|
+
export { FAIL_LOUD_RELEASE_TIMEOUT_MS, LOADER_EXPRESSION_SCHEMA, PROFILES_DIR, PROFILE_COMPATIBILITY_FILENAME, PROFILE_PATCH_FILENAME, PluginPackages, ProfileRuntimeResolution, ResolutionRestartRequired, StartupError, UnsupportedBundlePlatformError, assertBundlePlatform, auditStartupEntries, boot, bundlePatchFiles, bundlePatchPaths, composeEntries, createConfigProjector, createRuntimeResolution, evaluatePluginCompatibility, generateConfigSchema, getDshRuntimeVersion, initProfile, installFailLoud, isNativeConfigSchema, loadEnv, loadLayeredEnv, loadOptionalPatches, loadOverlayPatches, loadProfile, loadProfileDirectory, mountRootInclude, pluginCompatibilityWarning, prepareProfileEntries, prepareProfilePatches, readBundlePatches, readPluginMeta, readProfileCompatibility, readProfileManifest, readProfilePatches, readProfilePlugins, readProfileVersionExemptions, recomposeProfile, reconcileProfilePatches, reconcileProfilePlugins, removeLinkProjections, renderConfigDump, reportSkippedBundles, resolveBundleDir, resolveConfigPath, resolvePluginResource, resolveProfileDir, resolveTelemetryPatch, sanitizeProfile, setProfileVersionExemption, validatePluginVersionExemption, writeProfileBundles, writeProfileManifest };
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/** Host operating-system admission for optional bundle layers. */
|
|
2
|
+
/** A valid bundle declaration excludes the operating system running DSH. */
|
|
3
|
+
export declare class UnsupportedBundlePlatformError extends Error {
|
|
4
|
+
/**
|
|
5
|
+
* @param platforms Node platform names supported by the bundle.
|
|
6
|
+
* @param platform Operating system of the DSH Host.
|
|
7
|
+
*/
|
|
8
|
+
constructor(platforms: readonly string[], platform: string);
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Validate package metadata and reject an unsupported Host before selecting or composing a bundle.
|
|
12
|
+
* @param platforms The optional `dsh.bundle.platforms` field read from package.json.
|
|
13
|
+
* @param platform Operating system of the DSH Host, from Node's `process.platform`.
|
|
14
|
+
* @throws When the declaration is malformed or excludes the Host; omission allows every platform.
|
|
15
|
+
*/
|
|
16
|
+
export declare function assertBundlePlatform(platforms: unknown, platform: string): void;
|
|
17
|
+
//# sourceMappingURL=bundle-platform.d.ts.map
|
package/lib/types/index.d.ts
CHANGED
|
@@ -5,6 +5,8 @@
|
|
|
5
5
|
* config expressions, and drive the Cordis Loader against a leaf `cordis.yml` until the tree settles.
|
|
6
6
|
* @module @deepseek-ai/dsh-app-boot
|
|
7
7
|
*/
|
|
8
|
+
import { type StartupCompositionDiagnostic } from './startup-diagnostics.ts';
|
|
9
|
+
export type { StartupCompositionDiagnostic, StartupPluginState, StartupServiceState } from './startup-diagnostics.ts';
|
|
8
10
|
import { Context, type FiberState } from '@deepseek-ai/cordis';
|
|
9
11
|
import { type Entry } from '@deepseek-ai/cordis-plugin-loader';
|
|
10
12
|
import { type PatchOptions } from '@deepseek-ai/cordis-plugin-include';
|
|
@@ -13,10 +15,9 @@ import { type LaunchEnvironmentSnapshot } from '@deepseek-ai/dsh-launch-environm
|
|
|
13
15
|
export { readBundlePatches, readProfilePatches, resolveTelemetryPatch, type ProfileContext, type ProfilePnpmInvocation } from './profile-context.ts';
|
|
14
16
|
export { sanitizeProfile } from './profile-sanitize.ts';
|
|
15
17
|
export { getDshRuntimeVersion, evaluatePluginCompatibility, pluginCompatibilityWarning, type PluginCompatibility } from './plugin-compatibility.ts';
|
|
16
|
-
export { PROFILE_COMPATIBILITY_FILENAME, readProfileCompatibility, readProfileVersionExemptions, setProfileVersionExemption, type ProfileCompatibility, } from './profile-compatibility.ts';
|
|
18
|
+
export { PROFILE_COMPATIBILITY_FILENAME, readProfileCompatibility, readProfileVersionExemptions, setProfileVersionExemption, validatePluginVersionExemption, type ProfileCompatibility, } from './profile-compatibility.ts';
|
|
17
19
|
export { prepareProfileEntries, prepareProfilePatches } from './compatibility-preflight.ts';
|
|
18
20
|
export { readPluginMeta, resolvePluginResource } from './package-meta.ts';
|
|
19
|
-
export { ON_DEMAND_BUNDLES, OFFICIAL_ON_DEMAND_CATALOG, type OfficialBundleCatalogEntry } from './official-bundles.ts';
|
|
20
21
|
export { generateConfigSchema, type ConfigSchemaDump, type NativeConfigSchema } from './config-schema/index.ts';
|
|
21
22
|
export { createConfigProjector, LOADER_EXPRESSION_SCHEMA, type ConfigProjection } from './config-schema/projector.ts';
|
|
22
23
|
export { isNativeConfigSchema } from './config-schema/native.ts';
|
|
@@ -35,7 +36,8 @@ declare module '@deepseek-ai/cordis' {
|
|
|
35
36
|
'app-boot/config-reload'(): void;
|
|
36
37
|
}
|
|
37
38
|
}
|
|
38
|
-
export {
|
|
39
|
+
export { assertBundlePlatform, UnsupportedBundlePlatformError } from './bundle-platform.ts';
|
|
40
|
+
export { composeEntries, createRuntimeResolution, ProfileRuntimeResolution, bundlePatchFiles, bundlePatchPaths, initProfile, removeLinkProjections, loadProfile, loadProfileDirectory, PROFILE_PATCH_FILENAME, PROFILES_DIR, readProfileManifest, reportSkippedBundles, resolveBundleDir, resolveProfileDir, writeProfileManifest, type Profile, type ProfileLayer, type SkippedBundle, type ProfileManifest, type LinkedRoot, type RuntimeResolutionOptions, type RuntimeResolutionEntry, type RuntimeResolution, } from './profile.ts';
|
|
39
41
|
export { PluginPackages, type PluginPackage, type PluginPackagesConfig, } from './profile-resolution/service.ts';
|
|
40
42
|
export { ResolutionRestartRequired } from './profile-resolution/resolver.ts';
|
|
41
43
|
/**
|
|
@@ -285,6 +287,8 @@ interface StartupLogRecord {
|
|
|
285
287
|
/** Startup audit failure with non-enumerable metadata and original failures as its cause. */
|
|
286
288
|
export declare class StartupError extends Error {
|
|
287
289
|
readonly entries: readonly StartupEntryDiagnostic[];
|
|
290
|
+
/** Plugin states captured before disposal, excluding configuration values. */
|
|
291
|
+
composition?: StartupCompositionDiagnostic;
|
|
288
292
|
/** Root configuration and startup logs, attached by boot after disposal. */
|
|
289
293
|
startup?: {
|
|
290
294
|
configurationPath: string;
|
|
@@ -52,6 +52,8 @@ export declare function writeProfileBundles(profileDir: string, manifest: Profil
|
|
|
52
52
|
* template entries retain their order and duplicates. New bundle dependencies activate automatically.
|
|
53
53
|
* @param options - location, inventory captured before pnpm, and whether explicitly disabled bundles remain disabled.
|
|
54
54
|
* @returns updated inventory and newly added ordinary dependencies for caller-owned warnings.
|
|
55
|
+
* @throws If a new selection has invalid platform metadata or excludes the Host. Installed dependencies
|
|
56
|
+
* remain; no bundle selection changes are written.
|
|
55
57
|
*/
|
|
56
58
|
export declare function reconcileProfilePlugins(options: ProfilePluginLocation & {
|
|
57
59
|
readonly before: ProfilePluginInventory;
|
package/lib/types/profile.d.ts
CHANGED
|
@@ -27,11 +27,6 @@ import type { DshBundleManifest, DshPackageManifest } from '@deepseek-ai/dsh-pac
|
|
|
27
27
|
export declare const PROFILES_DIR = "profiles";
|
|
28
28
|
/** The user patch layer inside a profile directory (hot-reloaded on long-lived surfaces). */
|
|
29
29
|
export declare const PROFILE_PATCH_FILENAME = "cordis.patch.yml";
|
|
30
|
-
/** Installation-owned defaults used when a shipped profile is first opened. */
|
|
31
|
-
export interface ProfileTemplate {
|
|
32
|
-
/** Ordered bundle layer list. */
|
|
33
|
-
bundles: readonly string[];
|
|
34
|
-
}
|
|
35
30
|
/** Package metadata accepted by the profile reader; local profiles need no published identity. */
|
|
36
31
|
export type ProfileManifest = Partial<DshPackageManifest>;
|
|
37
32
|
/**
|
|
@@ -132,19 +127,6 @@ export interface RuntimeResolution {
|
|
|
132
127
|
* @returns the absolute profile directory (which may not exist yet).
|
|
133
128
|
*/
|
|
134
129
|
export declare function resolveProfileDir(name: string, home?: string): string;
|
|
135
|
-
/** The shipped profile templates auto-initialized on first use, by name. */
|
|
136
|
-
export declare const PROFILE_TEMPLATES: Record<string, ProfileTemplate>;
|
|
137
|
-
/** The bundle list a `dsh plugin` init uses for a name with no shipped template. */
|
|
138
|
-
export declare const DEFAULT_PROFILE_BUNDLES: readonly string[];
|
|
139
|
-
/**
|
|
140
|
-
* The bundles the dsh installation ships for a person to switch on: each a
|
|
141
|
-
* runtime dependency of the installation that declares `dsh.bundle.patch`,
|
|
142
|
-
* an `icon`, and `./locale/*.json` display metadata, selected by no shipped
|
|
143
|
-
* template, and offered switched off by the plugin manager
|
|
144
|
-
* ([rationale](../../../../.agents/notes/implemented/process/2026-09-15-shipped-optional-bundles.md),
|
|
145
|
-
* [admission](../../../../.agents/notes/implemented/architecture/2026-09-21-experimental-capabilities-as-optional-bundles.md)).
|
|
146
|
-
*/
|
|
147
|
-
export declare const OPTIONAL_BUNDLES: readonly string[];
|
|
148
130
|
/**
|
|
149
131
|
* Initialize a profile directory: manifest, empty user patch layer, and the
|
|
150
132
|
* pnpm settings out-of-tree plugins need. Existing files are never touched,
|
|
@@ -237,7 +219,8 @@ export declare function resolveBundleDir(binName: string, packageName: string, i
|
|
|
237
219
|
* the shared Harness home. This is used by application-owned profiles whose
|
|
238
220
|
* package project and lifecycle belong to that application.
|
|
239
221
|
* 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 requirements
|
|
222
|
+
* manifest when it listed one. Unreadable bundles, unsupported Host platforms, and bundles whose own dsh requirements
|
|
223
|
+
* the profile does not exempt are skipped
|
|
241
224
|
* without changing the manifest and listed in `skippedBundles`; nothing is printed.
|
|
242
225
|
* @param binName - the diagnostic prefix on thrown errors.
|
|
243
226
|
* @param dir - absolute profile package directory.
|
|
@@ -250,8 +233,8 @@ export declare function loadProfileDirectory(binName: string, dir: string, insta
|
|
|
250
233
|
}): Profile;
|
|
251
234
|
/**
|
|
252
235
|
* Load a profile: resolve every `dsh.profile.bundles` entry to its patch
|
|
253
|
-
* layer and parse the profile's own patch file. Unreadable
|
|
254
|
-
* are skipped and listed in `skippedBundles`; profile manifest and user patch errors still throw.
|
|
236
|
+
* layer and parse the profile's own patch file. Unreadable bundles, unsupported Host platforms,
|
|
237
|
+
* and incompatible bundles are skipped and listed in `skippedBundles`; profile manifest and user patch errors still throw.
|
|
255
238
|
* @param binName - the diagnostic prefix on thrown errors.
|
|
256
239
|
* @param name - the profile name.
|
|
257
240
|
* @param installAnchor - absolute path of the dsh app's package.json (first resolution anchor).
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/** Configuration-free snapshots captured before a failed startup disposes its plugins. */
|
|
2
|
+
import { Context } from '@deepseek-ai/cordis';
|
|
3
|
+
/** One configured entry at the time startup failed. */
|
|
4
|
+
export interface StartupPluginState {
|
|
5
|
+
readonly id: string;
|
|
6
|
+
readonly module: string;
|
|
7
|
+
readonly version: string;
|
|
8
|
+
readonly state: 'disabled' | 'active' | 'pending' | 'failed' | 'disposed' | 'loading' | 'unloading';
|
|
9
|
+
/** Loader source URL; individual overlay ownership may be unavailable. */
|
|
10
|
+
readonly source: string;
|
|
11
|
+
readonly missing: readonly string[];
|
|
12
|
+
}
|
|
13
|
+
/** Observed registrations for one service missing from a consumer. */
|
|
14
|
+
export interface StartupServiceState {
|
|
15
|
+
readonly consumer: string;
|
|
16
|
+
readonly service: string;
|
|
17
|
+
/** Empty means no registration was observed, not that no configured plugin can provide it. */
|
|
18
|
+
readonly providers: readonly {
|
|
19
|
+
readonly entry: string;
|
|
20
|
+
readonly state: string;
|
|
21
|
+
readonly visibility: 'same-scope' | 'other-scope';
|
|
22
|
+
}[];
|
|
23
|
+
}
|
|
24
|
+
/** Bounded startup state without plugin config, service values, or logger arguments. */
|
|
25
|
+
export interface StartupCompositionDiagnostic {
|
|
26
|
+
readonly plugins: readonly StartupPluginState[];
|
|
27
|
+
readonly services: readonly StartupServiceState[];
|
|
28
|
+
readonly omittedPlugins: number;
|
|
29
|
+
readonly omittedServices: number;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Capture Loader state and registered service ownership before teardown.
|
|
33
|
+
* Providers that never registered cannot be inferred from their package names.
|
|
34
|
+
* @param ctx - Live application context with its Loader still mounted.
|
|
35
|
+
* @returns At most 256 plugin rows and 256 missing-service observations, with omission counts.
|
|
36
|
+
*/
|
|
37
|
+
export declare function captureStartupComposition(ctx: Context): StartupCompositionDiagnostic;
|
|
38
|
+
//# sourceMappingURL=startup-diagnostics.d.ts.map
|
|
@@ -569,7 +569,7 @@ function internalModules() {
|
|
|
569
569
|
const esmResolve = addon.requireBuiltin("internal/modules/esm/resolve");
|
|
570
570
|
const esm = esmModule.getOrInitializeCascadedLoader();
|
|
571
571
|
const modern = "getOrCreateModuleJob" in esm;
|
|
572
|
-
/* v8 ignore start -- the supported Node
|
|
572
|
+
/* v8 ignore start -- the supported Node 24/26 matrix validates each available Internal interface */
|
|
573
573
|
if (typeof esm.resolveSync !== "function" || typeof Reflect.get(esm, modern ? "getOrCreateModuleJob" : "getModuleJobForImport") !== "function" || !modern && typeof Reflect.get(esm, "resolve") !== "function" || typeof cjsModule.Module._resolveFilename !== "function" || typeof cjsHelpers.getCjsConditions !== "function" || typeof esmUtils.getDefaultConditions !== "function" || typeof esmResolve.defaultResolve !== "function") throw new Error("profile resolution: unsupported Node module loader");
|
|
574
574
|
/* v8 ignore stop */
|
|
575
575
|
return {
|
|
@@ -645,7 +645,7 @@ function installRuntimeInterception(resolution) {
|
|
|
645
645
|
let expected;
|
|
646
646
|
try {
|
|
647
647
|
expected = adapted(target.specifier, target.parentURL, attributes);
|
|
648
|
-
/* v8 ignore next --
|
|
648
|
+
/* v8 ignore next -- the current loader resolves synchronously; the private interface also permits Promise results */
|
|
649
649
|
if (expected instanceof Promise) expected = expected.catch(restoreImporter);
|
|
650
650
|
} catch (error) {
|
|
651
651
|
return restoreImporter(error);
|
|
@@ -674,7 +674,7 @@ function installRuntimeInterception(resolution) {
|
|
|
674
674
|
} catch (error) {
|
|
675
675
|
return restoreImporter(error);
|
|
676
676
|
}
|
|
677
|
-
/* v8 ignore next --
|
|
677
|
+
/* v8 ignore next -- the current loader resolves synchronously; the private interface also permits Promise results */
|
|
678
678
|
if (result instanceof Promise) return result.catch(restoreImporter);
|
|
679
679
|
if (cacheable) state.esm = result;
|
|
680
680
|
return result;
|
|
@@ -696,12 +696,12 @@ function installRuntimeInterception(resolution) {
|
|
|
696
696
|
};
|
|
697
697
|
return (request, parent, attributes) => {
|
|
698
698
|
const result = adapted(request, parent, attributes);
|
|
699
|
-
/* v8 ignore next --
|
|
699
|
+
/* v8 ignore next -- the current loader resolves synchronously; the private interface also permits Promise results */
|
|
700
700
|
return result instanceof Promise ? result.then((resolved) => relocate(resolved, parent)) : relocate(result, parent);
|
|
701
701
|
};
|
|
702
702
|
};
|
|
703
703
|
let restoreEsm;
|
|
704
|
-
/* v8 ignore else -- CI coverage runs Node 24 v2; the Node
|
|
704
|
+
/* v8 ignore else -- CI coverage runs Node 24 v2; the Node 24.0 matrix exercises the v1 adapter */
|
|
705
705
|
if (modern) {
|
|
706
706
|
const loader = esm;
|
|
707
707
|
const original = Reflect.get(loader, "resolveSync");
|
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.
|
|
4
|
+
"version": "0.2.2-alpha.2",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
7
7
|
},
|
|
@@ -32,8 +32,9 @@
|
|
|
32
32
|
],
|
|
33
33
|
"license": "MIT",
|
|
34
34
|
"dependencies": {
|
|
35
|
-
"@deepseek-ai/dsh-atomic-write": "0.2.
|
|
36
|
-
"@deepseek-ai/dsh-
|
|
35
|
+
"@deepseek-ai/dsh-atomic-write": "0.2.2-alpha.2",
|
|
36
|
+
"@deepseek-ai/dsh-official-bundles": "0.2.2-alpha.2",
|
|
37
|
+
"@deepseek-ai/dsh-package-manifest": "0.2.2-alpha.2",
|
|
37
38
|
"@eslint-community/regexpp": "^4.12.2",
|
|
38
39
|
"ajv": "^8.20.0",
|
|
39
40
|
"js-yaml": "^4.3.2",
|
|
@@ -42,24 +43,24 @@
|
|
|
42
43
|
"semver": "^7.8.5"
|
|
43
44
|
},
|
|
44
45
|
"peerDependencies": {
|
|
45
|
-
"@deepseek-ai/cordis-plugin-group": "~1.0.
|
|
46
|
-
"@deepseek-ai/cordis-plugin-include": "~1.0.
|
|
47
|
-
"@deepseek-ai/cordis-plugin-loader": "~1.0.
|
|
48
|
-
"@deepseek-ai/dsh-launch-environment": "0.2.
|
|
49
|
-
"@deepseek-ai/dsh-home-paths": "0.2.
|
|
50
|
-
"@deepseek-ai/cordis": "~4.0.
|
|
46
|
+
"@deepseek-ai/cordis-plugin-group": "~1.0.6-alpha.1",
|
|
47
|
+
"@deepseek-ai/cordis-plugin-include": "~1.0.11-alpha.1",
|
|
48
|
+
"@deepseek-ai/cordis-plugin-loader": "~1.0.7-alpha.1",
|
|
49
|
+
"@deepseek-ai/dsh-launch-environment": "0.2.2-alpha.2",
|
|
50
|
+
"@deepseek-ai/dsh-home-paths": "0.2.2-alpha.2",
|
|
51
|
+
"@deepseek-ai/cordis": "~4.0.6-alpha.1"
|
|
51
52
|
},
|
|
52
53
|
"devDependencies": {
|
|
53
|
-
"@deepseek-ai/schemastery": "~3.18.
|
|
54
|
-
"@deepseek-ai/cordis-plugin-group": "~1.0.
|
|
55
|
-
"@deepseek-ai/cordis-plugin-include": "~1.0.
|
|
56
|
-
"@deepseek-ai/cordis-plugin-loader": "~1.0.
|
|
57
|
-
"@deepseek-ai/cordis-plugin-timer": "~1.1.
|
|
58
|
-
"@deepseek-ai/dsh-launch-environment": "0.2.
|
|
59
|
-
"@deepseek-ai/dsh-home-paths": "0.2.
|
|
60
|
-
"@deepseek-ai/dsh-system-prompt": "0.2.
|
|
54
|
+
"@deepseek-ai/schemastery": "~3.18.6-alpha.1",
|
|
55
|
+
"@deepseek-ai/cordis-plugin-group": "~1.0.6-alpha.1",
|
|
56
|
+
"@deepseek-ai/cordis-plugin-include": "~1.0.11-alpha.1",
|
|
57
|
+
"@deepseek-ai/cordis-plugin-loader": "~1.0.7-alpha.1",
|
|
58
|
+
"@deepseek-ai/cordis-plugin-timer": "~1.1.8-alpha.1",
|
|
59
|
+
"@deepseek-ai/dsh-launch-environment": "0.2.2-alpha.2",
|
|
60
|
+
"@deepseek-ai/dsh-home-paths": "0.2.2-alpha.2",
|
|
61
|
+
"@deepseek-ai/dsh-system-prompt": "0.2.2-alpha.2",
|
|
61
62
|
"@types/js-yaml": "^4.0.9",
|
|
62
63
|
"@types/semver": "^7.8.0",
|
|
63
|
-
"@deepseek-ai/cordis": "~4.0.
|
|
64
|
+
"@deepseek-ai/cordis": "~4.0.6-alpha.1"
|
|
64
65
|
}
|
|
65
66
|
}
|
|
@@ -1,4 +0,0 @@
|
|
|
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
|
|
@@ -1,12 +0,0 @@
|
|
|
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
|
|
@@ -1,5 +0,0 @@
|
|
|
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
|