@deepseek-ai/dsh-host-plugin-inventory 0.1.1-rc.2 → 0.1.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 CHANGED
@@ -2,5 +2,5 @@
2
2
  # side as of the last confirmed-consistent state. Both languages carry equal authority;
3
3
  # after editing either side, bring the other along and re-record with:
4
4
  # pnpm run verify-translation-pairing --write packages/host/plugin-inventory/README.md
5
- README.md: a91c02df5e7a57db89c9a63af6c4355573b843da
6
- README.zh.md: 786dfa8261c25bb838f6b8df88ae388bf78d764c
5
+ README.md: f8be329198fd1ffe078b4f821ffc568700ec3f19
6
+ README.zh.md: 8291a1cb4b27cce9efad22a85eaaaf0dadea10dc
package/README.md CHANGED
@@ -1,22 +1,111 @@
1
+ ---
2
+ description: "Read-only projection of the current Cordis Loader plugin state with each agent preset's composition beside it: the pluginInventory service and its pluginInventory/list Remote for web GUI host clients."
3
+ kind: "package-reference"
4
+ ---
5
+
1
6
  # @deepseek-ai/dsh-host-plugin-inventory
2
7
 
3
8
  English | [中文](README.zh.md)
4
9
 
5
- Read-only Host projection of the current Cordis Loader tree. `PluginInventoryGateway` registers the `pluginInventory` service and publishes one generated direct Remote, `pluginInventory/list`. Every call reads `ctx.loader.entries()` directly, skips structural group rows, and returns the remaining entries in Loader order with only their Loader entry id, module specifier, effective enablement, and current root Fiber phase.
10
+ ## Summary
11
+
12
+ Clients and settings pages can show what is currently composed in the host: calling `pluginInventory/list` returns the current non-group Loader entries in Loader order — entry id, module specifier, effective enablement, and root Fiber phase (`pending`, `loading`, `active`, `failed`, or `unloading`, or `null` when an entry has no live root Fiber). When an agent-preset roster is composed, the snapshot also carries one group per preset — id, trust, display name, default marking, health, and flattened composition rows — because a deployment that mounts the roster runs its model-facing plugins there rather than on the Loader's own entries. The snapshot is point-in-time: the Loader is the sole lifecycle authority, and this package owns no cache, history, provenance model, event stream, or mutation path. Client packages consume the Remote through the explicit [`api-remotes`](../../api/remotes/README.md) assembly rather than importing the Host implementation.
13
+
14
+ ## Table of Contents
15
+
16
+ - [Use this package](#use-this-package)
17
+ - [Understand the implementation](#understand-the-implementation)
18
+ - [Further Exploration](#further-exploration)
19
+ - [Model Experience](#model-experience)
20
+ - [Known Limitations and Deferred Work](#known-limitations-and-deferred-work)
21
+ - [Dev Note](#dev-note)
22
+
23
+ -----
24
+
25
+ <a id="use-this-package"></a>
26
+ ## Use this package
27
+
28
+ Call `pluginInventory/list` when a client or settings page needs to show what is currently composed in the host — which plugins are loaded, enabled, and alive, and what each agent preset would give a session. The Remote is the only entry point: the service is Remote-only and deliberately declares no same-process Cordis `Context` merge.
29
+
30
+ ### What a snapshot contains
31
+
32
+ Each row is one non-group Loader entry: its entry id, the exact module specifier, the effective enablement (including disabled ancestor groups), and the current root Fiber phase. `pending` means the entry waits to load, `loading` that it is being read, `active` that it is running, `failed` that its fiber rejected, and `unloading` that it is being torn down; `null` means no live root Fiber exists at all. Structural group rows are skipped.
33
+
34
+ ### Per-preset compositions
35
+
36
+ With a roster composed, `agentPresets` carries one group per preset in roster order: its id, whether the deployment ships it or the user owns it (`trust`, which clients use to localize shipped names), published display name, whether a session naming no preset composes it, and flattened plugin rows — entry id (null when the file row declares none), module specifier, effective enablement, the row's own `!!js` disabled expression when it carries one, and a root-fiber phase when the composition is live. A preset some session already composed answers from its newest standing generation — even when its file has since broken, because the mount is what those sessions run; one never composed since boot answers from its composition file with disabled gates evaluated against the Loader context, and reading never mounts a preset. `conditional` enablement marks a gate the Host could not evaluate, and a broken preset nothing composed stays listed with its reason and no rows. Without a roster the field is absent.
37
+
38
+ ### What you can and cannot do with it
39
+
40
+ The inventory is a snapshot for display and diagnostics: a client can render the roster, flag failed entries, and detect changes by comparing snapshots. It cannot enable, disable, add, or remove plugins, and it carries no history — a fiber that already failed and was removed is absent. Because the service reads the Loader on every call, the answer always reflects the current composition rather than a cached view.
41
+
42
+ -----
43
+
44
+ <a id="understand-the-implementation"></a>
45
+ ## Understand the implementation
46
+
47
+ <details>
48
+ <summary>Implementation internals — click to expand</summary>
49
+
50
+ ### Design concept
6
51
 
7
- The phase is `pending`, `loading`, `active`, `failed`, or `unloading`; it is `null` when the entry has no live root Fiber. The snapshot is intentionally point-in-time: Loader remains the sole lifecycle authority, while this package owns no cache, history, provenance model, event stream, or mutation path. Its public payload types live under `./types`, and Typert generates the Host and Client Remote artifacts exposed by `./typert` and `./remote`.
52
+ The gateway is a direct projection with no second lifecycle truth: every `list()` call reads `ctx.loader.entries()` and maps each non-group entry to its public row. Cordis's internal plugin/status events already maintain `Entry.fiber` and `Fiber.state`, so a cache would only add another lifecycle truth to keep synchronized. The agent-preset roster is an optional peer resolved per call through `ctx.get('agentPresets')`: its `compositionInventory()` owns every preset read, and this package only maps root-fiber states onto the public phase vocabulary.
8
53
 
9
- The service is Remote-only and deliberately declares no same-process Cordis `Context` merge. Client packages consume it through the explicit [`api-remotes`](../../api/remotes/README.md) assembly rather than importing the Host implementation.
54
+ ### The phase mapping
10
55
 
56
+ Fiber states map onto the public phase vocabulary, with `disposed` folding into `null` — an entry whose fiber is gone has no live root to report. The phase therefore never distinguishes why no live root exists: the entry may never have started, or its fiber may already have been disposed.
57
+
58
+ ### Source map
59
+
60
+ | File | Role |
61
+ |---|---|
62
+ | [`src/index.ts`](src/index.ts) | `PluginInventoryGateway`: the `pluginInventory` Remote service and the Loader projection |
63
+ | [`src/types.ts`](src/types.ts) | Public payload types: `PluginInventoryEntry`, `PluginInventorySnapshot`, `PluginFiberPhase` |
64
+ | [`src/invariant.ts`](src/invariant.ts) | Invariant companion (no runtime invariant; every snapshot projects Loader-owned state) |
65
+
66
+ Typert generates the Host and Client Remote artifacts exposed by `./typert` and `./remote`.
67
+
68
+ </details>
69
+
70
+ -----
71
+
72
+ <a id="further-exploration"></a>
73
+ ## Further Exploration
74
+
75
+ Read these when the inventory contract is not enough: how the Remote reaches clients, then the Loader it projects and the surface that renders it.
76
+
77
+ - [Remote assembly](../../api/remotes/README.md) — how clients consume `pluginInventory/list` without importing the Host implementation.
78
+ - [Cordis plugin loader](../../../vendor/loader/README.md) — the Loader whose entries this package projects.
79
+ - [Plugin inventory settings surface](../../client/ui-settings-plugin-inventory/README.md) — the browser-side projection that renders the inventory.
80
+
81
+ -----
82
+
83
+ <a id="model-experience"></a>
11
84
  ## Model Experience
12
85
 
13
- None, as this Host-only inventory projection registers no prompt, tool, message, or provider request.
86
+ None, as the host-side read-only Loader projection registers nothing model-facing.
14
87
 
15
88
  #### KV Cache effect
16
89
 
17
- None; this package never assembles model input.
90
+ None; this package neither assembles nor sends a provider request.
18
91
 
19
92
  ## Known Limitations and Deferred Work
20
93
 
94
+ <a id="known-limitations-and-deferred-work"></a>
95
+
96
+
97
+ These limits define what a point-in-time inventory cannot tell a client. They are current package constraints, not a task backlog.
98
+
21
99
  - **Point-in-time state only** — the result contains no durable failure history or subscription; a missing root Fiber is reported as `null`, regardless of why no live root exists.
22
- - **No provenance or mutation** — the service does not identify which bundle, profile, or override introduced an entry, and it cannot enable, disable, add, or remove plugins.
100
+ - **No provenance or mutation** — the service does not identify which bundle, profile, or override introduced an entry, and it cannot enable, disable, add, or remove plugins in either plane.
101
+ - **Presets appear only with a roster** — a deployment without `dsh-agent-presets` serves Loader entries alone; the `agentPresets` field is absent rather than empty.
102
+
103
+ <a id="dev-note"></a>
104
+ ### Dev Note
105
+
106
+ <details>
107
+ <summary>Working context for maintainers — click to expand</summary>
108
+
109
+ None.
110
+
111
+ </details>
package/README.zh.md CHANGED
@@ -1,22 +1,111 @@
1
+ ---
2
+ description: "当前 Cordis Loader 插件状态的只读投影,并附带每个 Agent 预设的组合:面向 web GUI 宿主客户端的 pluginInventory 服务及其 pluginInventory/list Remote。"
3
+ kind: "package-reference"
4
+ ---
5
+
1
6
  # @deepseek-ai/dsh-host-plugin-inventory
2
7
 
3
8
  [English](README.md) | 中文
4
9
 
5
- 当前 Cordis Loader 树的只读 Host 投影。`PluginInventoryGateway` 注册 `pluginInventory` 服务,并发布一个由 Typert 生成的直接 Remote:`pluginInventory/list`。每次调用都直接读取 `ctx.loader.entries()`,跳过结构性的 group 行,再按 Loader 顺序返回其余条目,并且只包含 Loader 条目 id、模块标识、有效启用状态与当前根 Fiber 阶段。
10
+ ## 概述
11
+
12
+ 客户端与设置页可以展示宿主当前组合了什么:调用 `pluginInventory/list` 即按 Loader 顺序返回当前的非组条目——条目 id、模块标识、有效启用状态与根 Fiber 阶段(`pending`、`loading`、`active`、`failed` 或 `unloading`;条目没有存活根 Fiber 时为 `null`)。当部署组合了 Agent 预设 roster 时,快照还携带每个预设一组——id、trust、显示名、默认标记、健康状态与压平后的组合行——因为挂载 roster 的部署把模型侧插件运行在预设组合里,而不是 Loader 自己的条目上。该快照只表示调用当下:Loader 是唯一的生命周期权威,本包不拥有缓存、历史、来源模型、事件流或修改路径。Client 包通过显式的 [`api-remotes`](../../api/remotes/README.zh.md) 组合消费这个 Remote,而不导入 Host 实现。
13
+
14
+ ## 目录
15
+
16
+ - [使用本包](#use-this-package)
17
+ - [理解实现](#understand-the-implementation)
18
+ - [进一步探索](#further-exploration)
19
+ - [模型体验](#model-experience)
20
+ - [已知限制与延期工作](#known-limitations-and-deferred-work)
21
+ - [开发备注](#dev-note)
22
+
23
+ -----
24
+
25
+ <a id="use-this-package"></a>
26
+ ## 使用本包
27
+
28
+ 当客户端或设置页需要展示宿主当前组合了什么——哪些插件已加载、已启用、是否存活,以及每个 Agent 预设会给会话什么——时调用 `pluginInventory/list`。Remote 是唯一入口:该服务仅供 Remote 使用,刻意不声明同进程 Cordis `Context` merge。
29
+
30
+ ### 快照包含什么
31
+
32
+ 每一行是一个非组 Loader 条目:其条目 id、精确模块标识、有效启用状态(含被禁用的祖先组)与当前根 Fiber 阶段。`pending` 表示条目等待加载,`loading` 表示正在读取,`active` 表示正在运行,`failed` 表示其 fiber 被拒绝,`unloading` 表示正在拆除;`null` 表示完全不存在存活的根 Fiber。结构性的 group 行会被跳过。
33
+
34
+ ### 每个预设的组合
35
+
36
+ 组合了 roster 时,`agentPresets` 按 roster 顺序携带每个预设一组:其 id、随部署内置还是用户自建(`trust`,客户端据此本地化内置预设名)、发布的显示名、未指名预设的会话是否组合它,以及压平后的插件行——条目 id(文件行未声明时为 null)、模块标识、有效启用状态、行自带的 `!!js` disabled 表达式(如有),以及组合存活时的根 Fiber 阶段。已有会话组合过的预设由其最新 standing 世代作答——即使其文件事后损坏也是如此,因为挂载才是这些会话实际运行的组合;开机以来从未被组合的预设由其组合文件作答,disabled 门用 Loader 上下文求值,且读取从不挂载预设。`conditional` 表示宿主无法求值的门;无人组合的坏预设保留在列表中,携带原因且没有行。没有 roster 时该字段缺席。
37
+
38
+ ### 你能用它做什么、不能做什么
39
+
40
+ 该清单是供展示与诊断的快照:客户端可以渲染名单、标出失败条目,并通过比较快照检测变化。它不能启用、停用、添加或移除插件,也不携带历史——已经失败并被移除的 fiber 缺席。由于服务每次调用都读取 Loader,答案总是反映当前组合,而不是缓存视图。
41
+
42
+ -----
43
+
44
+ <a id="understand-the-implementation"></a>
45
+ ## 理解实现
46
+
47
+ <details>
48
+ <summary>实现细节——点击展开</summary>
49
+
50
+ ### 设计理念
6
51
 
7
- 阶段为 `pending`、`loading`、`active`、`failed` 或 `unloading`;条目没有存活的根 Fiber 时则为 `null`。该快照刻意只表示调用当下:Loader 仍是唯一的生命周期权威,本包不拥有缓存、历史、来源模型、事件流或修改路径。公开 payload 类型位于 `./types`,Typert 生成由 `./typert` 与 `./remote` 导出的 Host 和 Client Remote 产物。
52
+ 网关是一层没有第二个生命周期真源的直接投影:每次 `list()` 调用都读取 `ctx.loader.entries()`,并把每个非组条目映射为公共行。Cordis 内部的 plugin/status 事件已经维护了 `Entry.fiber` 与 `Fiber.state`,因此再加缓存只会多出一个需要同步的生命周期真源。Agent 预设 roster 是每次调用经 `ctx.get('agentPresets')` 解析的可选伙伴:所有预设读取都由它的 `compositionInventory()` 负责,本包只把根 Fiber 状态映射到公共阶段词汇。
8
53
 
9
- 该服务仅供 Remote 使用,刻意不声明同进程 Cordis `Context` merge。Client 包通过显式的 [`api-remotes`](../../api/remotes/README.zh.md) 组合消费它,而不导入 Host 实现。
54
+ ### 阶段映射
10
55
 
56
+ Fiber 状态映射到公共阶段词汇,其中 `disposed` 折叠为 `null`——fiber 已消失的条目没有可报告的存活根。因此阶段从不区分为什么没有存活根:条目可能从未启动,也可能其 fiber 已被释放。
57
+
58
+ ### 源码地图
59
+
60
+ | 文件 | 职责 |
61
+ |---|---|
62
+ | [`src/index.ts`](src/index.ts) | `PluginInventoryGateway`:`pluginInventory` Remote 服务与 Loader 投影 |
63
+ | [`src/types.ts`](src/types.ts) | 公共 payload 类型:`PluginInventoryEntry`、`PluginInventorySnapshot`、`PluginFiberPhase` |
64
+ | [`src/invariant.ts`](src/invariant.ts) | 不变式伴生插件(无运行时不变式;每个快照都投影 Loader 持有的状态) |
65
+
66
+ Typert 生成由 `./typert` 与 `./remote` 导出的 Host 和 Client Remote 产物。
67
+
68
+ </details>
69
+
70
+ -----
71
+
72
+ <a id="further-exploration"></a>
73
+ ## 进一步探索
74
+
75
+ 当清单约定不够用时阅读以下内容:先看 Remote 如何到达客户端,再看它所投影的 Loader 与渲染它的界面。
76
+
77
+ - [Remote 组合](../../api/remotes/README.zh.md)——客户端如何在不导入 Host 实现的情况下消费 `pluginInventory/list`。
78
+ - [Cordis 插件 loader](../../../vendor/loader/README.md)——本包所投影条目的那个 Loader。
79
+ - [插件清单设置界面](../../client/ui-settings-plugin-inventory/README.zh.md)——渲染该清单的浏览器侧投影。
80
+
81
+ -----
82
+
83
+ <a id="model-experience"></a>
11
84
  ## 模型体验
12
85
 
13
- 无,因为这个仅限 Host 的清单投影不注册提示词、工具、消息或提供方请求。
86
+ 无。这个仅限 Host 的只读 Loader 投影不注册任何面向模型的内容。
14
87
 
15
88
  #### KV Cache 影响
16
89
 
17
- 无;本包从不组装模型输入。
90
+ 无;该包既不组装也不发送提供方请求。
91
+
92
+ ## 已知限制与延期工作
93
+
94
+ <a id="known-limitations-and-deferred-work"></a>
95
+
96
+
97
+ 这些限制说明一个点时刻清单无法告诉客户端什么。它们是当前包约束,不是任务积压。
98
+
99
+ - **仅表示调用当下**——结果不包含持久的失败历史或订阅;只要不存在存活的根 Fiber,就会报告 `null`,而不区分其原因。
100
+ - **无来源与修改能力**——服务不识别条目由哪个 bundle、profile 或 override 引入,也不能在任一平面启用、停用、添加或移除插件。
101
+ - **预设仅随 roster 出现**——未装 `dsh-agent-presets` 的部署只提供 Loader 条目;`agentPresets` 字段缺席而非为空。
102
+
103
+ <a id="dev-note"></a>
104
+ ### 开发备注
105
+
106
+ <details>
107
+ <summary>维护者的工作上下文——点击展开</summary>
18
108
 
19
- ## 已知限制与暂缓事项
109
+ 无。
20
110
 
21
- - **仅表示调用当下** —— 结果不包含持久的失败历史或订阅;只要不存在存活的根 Fiber,就会报告 `null`,而不区分其原因。
22
- - **无来源与修改能力** —— 服务不识别条目由哪个 bundle、profile 或 override 引入,也不能启用、停用、添加或移除插件。
111
+ </details>
package/lib/index.js CHANGED
@@ -97,9 +97,15 @@ let PluginInventoryGateway = (() => {
97
97
  * Read the Loader directly on every call. Cordis's internal plugin/status
98
98
  * events already maintain Entry.fiber and Fiber.state, so a second cache
99
99
  * would only add another lifecycle truth to keep synchronized.
100
- * @returns Current non-group Loader entries in Loader order.
100
+ *
101
+ * When an agent-preset roster is composed, the snapshot also carries each
102
+ * preset's composition rows, because those rows — not the Loader's own
103
+ * entries — are where a deployment that mounts the roster runs its
104
+ * model-facing plugins.
105
+ * @returns Current non-group Loader entries in Loader order, with per-preset
106
+ * compositions when a roster is composed.
101
107
  */
102
- list() {
108
+ async list() {
103
109
  const entries = [];
104
110
  for (const entry of this.ctx.loader.entries()) {
105
111
  if (entry.options.group) continue;
@@ -110,7 +116,18 @@ let PluginInventoryGateway = (() => {
110
116
  fiberPhase: entry.fiber === void 0 ? null : FIBER_PHASE[entry.fiber.state]
111
117
  });
112
118
  }
113
- return { entries };
119
+ const presets = this.ctx.get("agentPresets");
120
+ if (presets === void 0) return { entries };
121
+ return {
122
+ entries,
123
+ agentPresets: (await presets.compositionInventory()).map((composition) => ({
124
+ ...composition,
125
+ rows: composition.rows.map(({ fiberState, ...row }) => ({
126
+ ...row,
127
+ fiberPhase: fiberState === void 0 ? null : FIBER_PHASE[fiberState]
128
+ }))
129
+ }))
130
+ };
114
131
  }
115
132
  };
116
133
  })();
@@ -6,8 +6,22 @@ const _deepseek_ai_dsh_host_plugin_inventory_pluginInventory_list_result$schema
6
6
  'entryId': z.intersection(z.string(), z.unknown()).readonly(),
7
7
  'moduleName': z.string().readonly(),
8
8
  'enabled': z.boolean().readonly(),
9
- 'fiberPhase': z.union([z.literal(null), z.literal("failed"), z.literal("pending"), z.literal("active"), z.literal("loading"), z.literal("unloading")]).readonly(),
9
+ 'fiberPhase': z.union([z.literal(null), z.literal("pending"), z.literal("active"), z.literal("failed"), z.literal("loading"), z.literal("unloading")]).readonly(),
10
10
  })).readonly(),
11
+ 'agentPresets': z.array(z.object({
12
+ 'id': z.string().readonly(),
13
+ 'trust': z.union([z.literal("system"), z.literal("user")]).readonly(),
14
+ 'name': z.string().readonly().optional(),
15
+ 'isDefault': z.boolean().readonly(),
16
+ 'broken': z.string().readonly().optional(),
17
+ 'rows': z.array(z.object({
18
+ 'entryId': z.union([z.literal(null), z.string()]).readonly(),
19
+ 'moduleName': z.string().readonly(),
20
+ 'enabled': z.union([z.literal(false), z.literal(true), z.literal("conditional")]).readonly(),
21
+ 'condition': z.string().readonly().optional(),
22
+ 'fiberPhase': z.union([z.literal(null), z.literal("pending"), z.literal("active"), z.literal("failed"), z.literal("loading"), z.literal("unloading")]).readonly(),
23
+ })).readonly(),
24
+ })).readonly().optional(),
11
25
  })
12
26
 
13
27
  export const TYPERT = {
@@ -29,7 +43,7 @@ export const TYPERT = {
29
43
  typeSymbol: '@deepseek-ai/dsh-host-plugin-inventory/types#PluginInventorySnapshot',
30
44
  schema: _deepseek_ai_dsh_host_plugin_inventory_pluginInventory_list_result$schema,
31
45
  },
32
- sourceLocation: {"file":"packages/host/plugin-inventory/src/index.ts","line":57,"column":3},
46
+ sourceLocation: {"file":"packages/host/plugin-inventory/src/index.ts","line":66,"column":9},
33
47
  },
34
48
  ],
35
49
  model: {
@@ -6,8 +6,22 @@ const _deepseek_ai_dsh_host_plugin_inventory_pluginInventory_list_result$schema
6
6
  'entryId': z.intersection(z.string(), z.unknown()).readonly(),
7
7
  'moduleName': z.string().readonly(),
8
8
  'enabled': z.boolean().readonly(),
9
- 'fiberPhase': z.union([z.literal(null), z.literal("failed"), z.literal("pending"), z.literal("active"), z.literal("loading"), z.literal("unloading")]).readonly(),
9
+ 'fiberPhase': z.union([z.literal(null), z.literal("pending"), z.literal("active"), z.literal("failed"), z.literal("loading"), z.literal("unloading")]).readonly(),
10
10
  })).readonly(),
11
+ 'agentPresets': z.array(z.object({
12
+ 'id': z.string().readonly(),
13
+ 'trust': z.union([z.literal("system"), z.literal("user")]).readonly(),
14
+ 'name': z.string().readonly().optional(),
15
+ 'isDefault': z.boolean().readonly(),
16
+ 'broken': z.string().readonly().optional(),
17
+ 'rows': z.array(z.object({
18
+ 'entryId': z.union([z.literal(null), z.string()]).readonly(),
19
+ 'moduleName': z.string().readonly(),
20
+ 'enabled': z.union([z.literal(false), z.literal(true), z.literal("conditional")]).readonly(),
21
+ 'condition': z.string().readonly().optional(),
22
+ 'fiberPhase': z.union([z.literal(null), z.literal("pending"), z.literal("active"), z.literal("failed"), z.literal("loading"), z.literal("unloading")]).readonly(),
23
+ })).readonly(),
24
+ })).readonly().optional(),
11
25
  })
12
26
 
13
27
  export const TYPERT_REMOTE = {
@@ -26,7 +40,7 @@ export const TYPERT_REMOTE = {
26
40
  typeSymbol: '@deepseek-ai/dsh-host-plugin-inventory/types#PluginInventorySnapshot',
27
41
  schema: _deepseek_ai_dsh_host_plugin_inventory_pluginInventory_list_result$schema,
28
42
  },
29
- sourceLocation: {"file":"packages/host/plugin-inventory/src/index.ts","line":57,"column":3},
43
+ sourceLocation: {"file":"packages/host/plugin-inventory/src/index.ts","line":66,"column":9},
30
44
  },
31
45
  ],
32
46
  }
@@ -11,9 +11,15 @@ export declare class PluginInventoryGateway extends TypertRemoteService {
11
11
  * Read the Loader directly on every call. Cordis's internal plugin/status
12
12
  * events already maintain Entry.fiber and Fiber.state, so a second cache
13
13
  * would only add another lifecycle truth to keep synchronized.
14
- * @returns Current non-group Loader entries in Loader order.
14
+ *
15
+ * When an agent-preset roster is composed, the snapshot also carries each
16
+ * preset's composition rows, because those rows — not the Loader's own
17
+ * entries — are where a deployment that mounts the roster runs its
18
+ * model-facing plugins.
19
+ * @returns Current non-group Loader entries in Loader order, with per-preset
20
+ * compositions when a roster is composed.
15
21
  */
16
- list(): PluginInventorySnapshot;
22
+ list(): Promise<PluginInventorySnapshot>;
17
23
  }
18
24
  export default PluginInventoryGateway;
19
25
  //# sourceMappingURL=index.d.ts.map
@@ -77,9 +77,15 @@ let PluginInventoryGateway = (() => {
77
77
  * Read the Loader directly on every call. Cordis's internal plugin/status
78
78
  * events already maintain Entry.fiber and Fiber.state, so a second cache
79
79
  * would only add another lifecycle truth to keep synchronized.
80
- * @returns Current non-group Loader entries in Loader order.
80
+ *
81
+ * When an agent-preset roster is composed, the snapshot also carries each
82
+ * preset's composition rows, because those rows — not the Loader's own
83
+ * entries — are where a deployment that mounts the roster runs its
84
+ * model-facing plugins.
85
+ * @returns Current non-group Loader entries in Loader order, with per-preset
86
+ * compositions when a roster is composed.
81
87
  */
82
- list() {
88
+ async list() {
83
89
  const entries = [];
84
90
  for (const entry of this.ctx.loader.entries()) {
85
91
  if (entry.options.group)
@@ -91,7 +97,17 @@ let PluginInventoryGateway = (() => {
91
97
  fiberPhase: entry.fiber === undefined ? null : FIBER_PHASE[entry.fiber.state],
92
98
  });
93
99
  }
94
- return { entries };
100
+ const presets = this.ctx.get('agentPresets');
101
+ if (presets === undefined)
102
+ return { entries };
103
+ const agentPresets = (await presets.compositionInventory()).map(composition => ({
104
+ ...composition,
105
+ rows: composition.rows.map(({ fiberState, ...row }) => ({
106
+ ...row,
107
+ fiberPhase: fiberState === undefined ? null : FIBER_PHASE[fiberState],
108
+ })),
109
+ }));
110
+ return { entries, agentPresets };
95
111
  }
96
112
  };
97
113
  })();
@@ -12,8 +12,47 @@ export interface PluginInventoryEntry {
12
12
  readonly enabled: boolean;
13
13
  readonly fiberPhase: PluginFiberPhase;
14
14
  }
15
+ /** Effective enablement of one preset composition row. */
16
+ export type PresetPluginEnablement = boolean | 'conditional';
17
+ /** One plugin row an agent preset's composition names. */
18
+ export interface AgentPresetPluginRow {
19
+ /** Composition row id, or null when the row declares none. */
20
+ readonly entryId: string | null;
21
+ /** Module specifier the row names. */
22
+ readonly moduleName: string;
23
+ /**
24
+ * Effective enablement, including disabled ancestor groups. `'conditional'`
25
+ * marks a `!!js` disabled expression on a composition no session has
26
+ * mounted, which only a Loader context can decide.
27
+ */
28
+ readonly enabled: PresetPluginEnablement;
29
+ /** The row's own `!!js` disabled expression, when it carries one. */
30
+ readonly condition?: string;
31
+ /** Root-fiber phase when the composition is live; null otherwise. */
32
+ readonly fiberPhase: PluginFiberPhase;
33
+ }
34
+ /** One agent preset's identity and flattened composition in the inventory. */
35
+ export interface AgentPresetPluginGroup {
36
+ /** Stable preset id. */
37
+ readonly id: string;
38
+ /** Whether the deployment ships the preset or the user owns it. */
39
+ readonly trust: 'system' | 'user';
40
+ /** Display name the preset published; a reader falls back to the id. */
41
+ readonly name?: string;
42
+ /** Whether a session naming no preset composes this one. */
43
+ readonly isDefault: boolean;
44
+ /** Why this preset's composition cannot be read; absent when rows answer. */
45
+ readonly broken?: string;
46
+ /** Plugin rows in composition order; empty when the preset is broken. */
47
+ readonly rows: readonly AgentPresetPluginRow[];
48
+ }
15
49
  /** Point-in-time inventory returned by the plugin inventory Remote. */
16
50
  export interface PluginInventorySnapshot {
17
51
  readonly entries: readonly PluginInventoryEntry[];
52
+ /**
53
+ * Per-preset compositions, present only when an agent-preset roster is
54
+ * composed in this deployment.
55
+ */
56
+ readonly agentPresets?: readonly AgentPresetPluginGroup[];
18
57
  }
19
58
  //# sourceMappingURL=types.d.ts.map
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@deepseek-ai/dsh-host-plugin-inventory",
3
3
  "description": "Read-only Remote projection of current Cordis Loader plugin state",
4
- "version": "0.1.1-rc.2",
4
+ "version": "0.1.2-alpha.2",
5
5
  "publishConfig": {
6
6
  "access": "public"
7
7
  },
@@ -52,17 +52,24 @@
52
52
  "zod": "^4.4.3"
53
53
  },
54
54
  "peerDependencies": {
55
- "@deepseek-ai/cordis-plugin-loader": "^1.0.2",
56
- "@deepseek-ai/dsh-brand": "^0.1.1-rc.2",
57
- "@deepseek-ai/dsh-invariants": "^0.1.1-rc.2",
58
- "@deepseek-ai/dsh-typert-protocol": "^0.1.1-rc.2",
59
- "@deepseek-ai/cordis": "^4.0.1"
55
+ "@deepseek-ai/cordis-plugin-loader": "^1.0.3",
56
+ "@deepseek-ai/dsh-agent-presets": "^0.1.2-alpha.2",
57
+ "@deepseek-ai/dsh-brand": "^0.1.2-alpha.2",
58
+ "@deepseek-ai/dsh-invariants": "^0.1.2-alpha.2",
59
+ "@deepseek-ai/dsh-typert-protocol": "^0.1.2-alpha.2",
60
+ "@deepseek-ai/cordis": "^4.0.2"
61
+ },
62
+ "peerDependenciesMeta": {
63
+ "@deepseek-ai/dsh-agent-presets": {
64
+ "optional": true
65
+ }
60
66
  },
61
67
  "devDependencies": {
62
- "@deepseek-ai/cordis-plugin-loader": "^1.0.2",
63
- "@deepseek-ai/dsh-brand": "^0.1.1-rc.2",
64
- "@deepseek-ai/dsh-invariants": "^0.1.1-rc.2",
65
- "@deepseek-ai/dsh-typert-protocol": "^0.1.1-rc.2",
66
- "@deepseek-ai/cordis": "^4.0.1"
68
+ "@deepseek-ai/cordis-plugin-loader": "^1.0.3",
69
+ "@deepseek-ai/dsh-agent-presets": "^0.1.2-alpha.2",
70
+ "@deepseek-ai/dsh-brand": "^0.1.2-alpha.2",
71
+ "@deepseek-ai/dsh-invariants": "^0.1.2-alpha.2",
72
+ "@deepseek-ai/dsh-typert-protocol": "^0.1.2-alpha.2",
73
+ "@deepseek-ai/cordis": "^4.0.2"
67
74
  }
68
75
  }