@deepseek-ai/dsh-app-boot 0.2.1-rc.5 → 0.2.2-alpha.3
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 +1002 -253
- 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
|
|