@prettier-ai/dsh-client-ui-settings-plugin-inventory 0.1.2-alpha.1

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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 DeepSeek
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,6 @@
1
+ # Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each
2
+ # side as of the last confirmed-consistent state. Both languages carry equal authority;
3
+ # after editing either side, bring the other along and re-record with:
4
+ # pnpm run verify-translation-pairing --write packages/client/ui-settings-plugin-inventory/README.md
5
+ README.md: c44e150e528f20349429f9a49d416367f1ca3c41
6
+ README.zh.md: ae2e2cd1105464f0fb262a07e96b66082a6e7166
package/README.md ADDED
@@ -0,0 +1,99 @@
1
+ ---
2
+ description: "Read-only Cordis Loader inventory tab in Web Plugins settings for the dsh web client: searchable plugin catalog with enablement state and configuration."
3
+ kind: "package-reference"
4
+ ---
5
+
6
+ # @deepseek-ai/dsh-client-ui-settings-plugin-inventory
7
+
8
+ English | [中文](README.zh.md)
9
+
10
+ ## Summary
11
+
12
+ `dsh-client-ui-settings-plugin-inventory` contributes the read-only **Plugin list** tab to the Web Settings Plugins section. The tab lazily calls `ctx.remote.pluginInventory.list()` the first time it is selected and renders a searchable two-column catalog of compact disclosure cards: each collapsed card shows the short module name, an effective-enablement tag, and (for enabled entries) a colored root-fiber status dot; expanding a card reveals the Loader-tree entry id, effective configuration, and Cordis status. Loading, empty, no-match, and generic failure states stay local to the mounted component, and a failed read can be retried without exposing transport details.
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
+ Open the Plugins section in Settings and select the **Plugin list** tab to inspect the Host's plugin inventory. The tab reads no Remote during plugin activation — selecting it for the first time mounts the component and lazily calls `ctx.remote.pluginInventory.list()` through `api-remotes`.
29
+
30
+ ### Reading a card
31
+
32
+ Each collapsed card uses the short module name as its title and a small effective-enablement tag; enabled entries also show a colored root-fiber status dot. Expanding one card reveals its Loader-tree entry id, followed by the effective configuration and, for enabled entries, Cordis status; disabled entries omit the redundant unmounted runtime state. Search filters the catalog by name and entry id.
33
+
34
+ ### Retrying a failed read
35
+
36
+ A failed read renders a generic failure state inside the tab; retrying re-runs the lazy `list()` call without exposing transport details.
37
+
38
+ -----
39
+
40
+ <a id="understand-the-implementation"></a>
41
+ ## Understand the implementation
42
+
43
+ <details>
44
+ <summary>Implementation internals — click to expand</summary>
45
+
46
+ The tab is a read-only projection of a Host-owned snapshot; it performs no Remote read during plugin activation and takes the snapshot on first selection.
47
+
48
+ ### Registration
49
+
50
+ The browser plugin registers one localized `settings.plugins.tab` contribution with id `all`; the Plugins section owns the navigation entry and tab chrome. Registration uses `ctx.slots.inject()`, so it follows late tab declaration, redeclaration, locale changes, and teardown without importing the section owner.
51
+
52
+ ### Rendering
53
+
54
+ The entry id remains the React key, disclosure identity, detail value, and an additional search target; it is never classified by string shape.
55
+
56
+ </details>
57
+
58
+ -----
59
+
60
+ <a id="further-exploration"></a>
61
+ ## Further Exploration
62
+
63
+ These pages cover the settings section, the remote call, and the Host-side projection.
64
+
65
+ - [ui-settings-plugins](../ui-settings-plugins/README.md) — the Plugins section this tab registers into.
66
+ - [ui-settings](../ui-settings/README.md) — the domain base declaring `settings.plugins.tab`.
67
+ - [api-remotes](../../api/remotes/README.md) — the Remote BFF surface behind `pluginInventory.list()`.
68
+ - [plugin-inventory](../../host/plugin-inventory/README.md) — the Host-side read-only Loader projection this tab renders.
69
+
70
+ -----
71
+
72
+ <a id="model-experience"></a>
73
+ ## Model Experience
74
+
75
+ None, as the package is a browser-side inventory projection that registers nothing model-facing.
76
+
77
+ #### KV Cache effect
78
+
79
+ None; this package neither assembles nor sends a provider request.
80
+
81
+ ## Known Limitations and Deferred Work
82
+
83
+ <a id="known-limitations-and-deferred-work"></a>
84
+
85
+
86
+ These limits define the freshness and reach of the inventory view; they are current package constraints.
87
+
88
+ - **One snapshot per Settings mount or retry** — the tab does not subscribe to Loader changes or automatically refetch after reconnect; switching tabs preserves the current snapshot, while reopening Settings obtains a new one.
89
+ - **Read-only Loader view** — local search does not add provenance, current-browser activation diagnosis, grouping by source, or plugin mutation controls.
90
+
91
+ <a id="dev-note"></a>
92
+ ### Dev Note
93
+
94
+ <details>
95
+ <summary>Working context for maintainers — click to expand</summary>
96
+
97
+ None.
98
+
99
+ </details>
package/README.zh.md ADDED
@@ -0,0 +1,99 @@
1
+ ---
2
+ description: "dsh Web 客户端设置中的只读 Cordis Loader 清单标签页:可搜索的插件目录,含启停状态与配置。"
3
+ kind: "package-reference"
4
+ ---
5
+
6
+ # @deepseek-ai/dsh-client-ui-settings-plugin-inventory
7
+
8
+ [English](README.md) | 中文
9
+
10
+ ## 概述
11
+
12
+ `dsh-client-ui-settings-plugin-inventory` 向 Web 设置的「插件」分区贡献只读的**插件列表**标签页。该标签页在首次被选择时懒调用 `ctx.remote.pluginInventory.list()`,并以可搜索的双列紧凑折叠卡片展示清单:每张收起的卡片显示模块短名称、有效启停标签,以及(对已启用条目)彩色根 fiber 状态圆点;展开卡片会显示 Loader 树条目 id、有效配置与 Cordis 状态。加载、空结果、无匹配与通用失败状态只属于已挂载组件,读取失败后可以重试,且不会暴露传输细节。
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
+ 打开设置中的「插件」分区并选择**插件列表**标签页,即可查看宿主的插件清单。插件激活期间不会读取 Remote——首次选择该标签页时才挂载组件,并通过 `api-remotes` 懒调用 `ctx.remote.pluginInventory.list()`。
29
+
30
+ ### 阅读卡片
31
+
32
+ 每张收起的卡片使用模块短名称作为标题,并以小标签表示有效启停状态;已启用的条目还会显示彩色根 fiber 状态圆点。展开卡片后会直接展示 Loader 树条目 id、有效配置,已启用条目还会显示 Cordis 状态;已停用条目省略重复的「未挂载」运行状态。搜索按名称与条目 id 过滤目录。
33
+
34
+ ### 重试失败的读取
35
+
36
+ 读取失败会在标签页内渲染通用失败状态;重试会重新执行懒 `list()` 调用,且不会暴露传输细节。
37
+
38
+ -----
39
+
40
+ <a id="understand-the-implementation"></a>
41
+ ## 理解实现
42
+
43
+ <details>
44
+ <summary>实现细节——点击展开</summary>
45
+
46
+ 该标签页是宿主拥有快照的只读投影;插件激活期间不执行任何 Remote 读取,首次选择时才取快照。
47
+
48
+ ### 注册
49
+
50
+ 浏览器插件注册一个 id 为 `all` 的本地化 `settings.plugins.tab` 贡献;「插件」分区拥有导航入口与标签栏。注册使用 `ctx.slots.inject()`,因此能跟随标签 slot 的延迟声明、重新声明、本地化变化与 teardown,而无需 import 分区拥有方。
51
+
52
+ ### 渲染
53
+
54
+ 条目 id 仍作为 React key、展开标识、详情值与额外的搜索目标;代码不按字符串形状对它分类。
55
+
56
+ </details>
57
+
58
+ -----
59
+
60
+ <a id="further-exploration"></a>
61
+ ## 进一步探索
62
+
63
+ 以下页面覆盖设置分区、Remote 调用与宿主侧投影。
64
+
65
+ - [ui-settings-plugins](../ui-settings-plugins/README.zh.md)——本标签页注册进的「插件」分区。
66
+ - [ui-settings](../ui-settings/README.zh.md)——声明 `settings.plugins.tab` 的领域底座。
67
+ - [api-remotes](../../api/remotes/README.zh.md)——`pluginInventory.list()` 背后的 Remote BFF 表面。
68
+ - [plugin-inventory](../../host/plugin-inventory/README.zh.md)——本标签页所渲染的宿主侧只读 Loader 投影。
69
+
70
+ -----
71
+
72
+ <a id="model-experience"></a>
73
+ ## 模型体验
74
+
75
+ 无。该包是浏览器端清单投影,不注册任何面向模型的内容。
76
+
77
+ #### KV Cache 影响
78
+
79
+ 无;该包既不组装也不发送提供方请求。
80
+
81
+ ## 已知限制与延期工作
82
+
83
+ <a id="known-limitations-and-deferred-work"></a>
84
+
85
+
86
+ 这些限制定义清单视图的新鲜度与触达范围;它们是当前包约束。
87
+
88
+ - **每次 Settings 挂载或重试只读取一份快照**:标签页不订阅 Loader 变化,也不会在重连后自动重新读取;切换标签页会保留当前快照,重新打开 Settings 则会取得新快照。
89
+ - **只读 Loader 视图**:本地搜索不会额外引入来源、按来源分组、当前浏览器激活诊断或插件修改控件。
90
+
91
+ <a id="dev-note"></a>
92
+ ### 开发备注
93
+
94
+ <details>
95
+ <summary>维护者的工作上下文——点击展开</summary>
96
+
97
+ 无。
98
+
99
+ </details>
package/lib/client.js ADDED
@@ -0,0 +1,302 @@
1
+ window.__ModuleLoader__.load({
2
+ id: "@prettier-ai/dsh-client-ui-settings-plugin-inventory",
3
+ factory: (require) => {
4
+ var module = { exports: {} };
5
+ var exports = module.exports;
6
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
7
+ let react_jsx_runtime = require("react/jsx-runtime");
8
+ let react = require("react");
9
+ let _prettier_ai_dsh_client_ui_primitives = require("@prettier-ai/dsh-client-ui-primitives");
10
+ //#region \0dsh-css:/home/runner/work/dsh-publisher/dsh-publisher/upstream/packages/client/ui-settings-plugin-inventory/src/client/PluginInventorySettingsTab.module.css.mjs
11
+ const css = "._4AfKUq_section{width:100%;max-width:760px;color:var(--dsw-alias-label-primary);flex-direction:column;gap:14px;display:flex}._4AfKUq_catalogHeading h3,._4AfKUq_status,._4AfKUq_failure p{margin:0}._4AfKUq_status,._4AfKUq_failure{color:var(--dsw-alias-label-tertiary);font-size:13px;line-height:20px}._4AfKUq_failure{color:var(--dsw-alias-state-error-primary);align-items:center;gap:10px;display:flex}._4AfKUq_failure button{border:1px solid var(--dsw-alias-border-l2);color:var(--dsw-alias-label-primary);font:inherit;cursor:pointer;background:0 0;border-radius:6px;padding:4px 10px}._4AfKUq_catalog{flex-direction:column;gap:12px;display:flex}._4AfKUq_search{width:100%;color:var(--dsw-alias-label-tertiary);align-items:center;display:flex;position:relative}._4AfKUq_search>svg{pointer-events:none;position:absolute;left:12px}._4AfKUq_search input{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-1);width:100%;height:36px;color:var(--dsw-alias-label-primary);font:inherit;border-radius:8px;outline:none;padding:0 34px 0 36px;font-size:13px}._4AfKUq_search input::placeholder{color:var(--dsw-alias-label-tertiary)}._4AfKUq_search input:focus-visible{border-color:var(--dsw-alias-state-business-primary);box-shadow:0 0 0 2px color-mix(in srgb, var(--dsw-alias-state-business-primary) 18%, transparent)}._4AfKUq_catalogHeading{align-items:baseline;gap:7px;padding:0 2px;display:flex}._4AfKUq_catalogHeading h3{font-size:13px;font-weight:600;line-height:20px}._4AfKUq_catalogHeading span{color:var(--dsw-alias-label-tertiary);font-variant-numeric:tabular-nums;font-size:12px;line-height:18px}._4AfKUq_cards{grid-template-columns:repeat(2,minmax(0,1fr));align-items:start;gap:10px;margin:0;padding:0;list-style:none;display:grid}._4AfKUq_card{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-3);border-radius:10px;min-width:0;overflow:hidden}._4AfKUq_card[data-open=true]{border-color:var(--dsw-alias-border-l1);box-shadow:var(--dsw-shadow-lv1)}._4AfKUq_cardContent{box-sizing:border-box;width:100%;min-height:52px;color:inherit;font:inherit;text-align:left;cursor:pointer;background:0 0;border:0;justify-content:space-between;align-items:center;gap:12px;padding:12px 14px;display:flex}._4AfKUq_cardContent:hover,._4AfKUq_card[data-open=true]>._4AfKUq_cardContent{background:var(--dsw-alias-interactive-bg-hover)}._4AfKUq_cardContent:focus-visible{outline:2px solid var(--dsw-alias-state-business-primary);outline-offset:-2px}._4AfKUq_cardTitle{text-overflow:ellipsis;white-space:nowrap;min-width:0;font-size:14px;font-weight:600;line-height:20px;overflow:hidden}._4AfKUq_cardTrailing{color:var(--dsw-alias-label-tertiary);flex:none;align-items:center;gap:7px;display:inline-flex}._4AfKUq_statusDot{background:var(--dsw-alias-label-tertiary);border-radius:999px;flex:none;width:7px;height:7px;display:inline-block}._4AfKUq_statusDot[data-phase=active]{background:var(--dsw-alias-state-success-primary)}._4AfKUq_statusDot[data-phase=failed]{background:var(--dsw-alias-state-error-primary)}._4AfKUq_statusDot[data-phase=loading]{background:var(--dsw-alias-state-business-primary)}._4AfKUq_configTag{background:var(--dsw-alias-bg-layer-1);min-height:20px;color:var(--dsw-alias-label-secondary);white-space:nowrap;border-radius:5px;align-items:center;padding:1px 6px;font-size:11px;line-height:16px;display:inline-flex}._4AfKUq_configTag[data-enabled=true]{background:color-mix(in srgb, var(--dsw-alias-state-success-primary) 10%, transparent);color:var(--dsw-alias-state-success-primary)}._4AfKUq_chevron{color:var(--dsw-alias-label-tertiary);flex:none}._4AfKUq_card[data-open=true] ._4AfKUq_chevron{transform:rotate(180deg)}._4AfKUq_cardDetails{border-top:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-module-platform);padding:10px 14px 12px}._4AfKUq_entryValue{overflow-wrap:anywhere;color:var(--dsw-alias-label-primary);font-family:var(--ds-font-family-code);font-size:12px;line-height:18px;display:block}._4AfKUq_details{grid-template-columns:76px minmax(0,1fr);gap:6px 10px;margin:8px 0 0;display:grid}._4AfKUq_details div{display:contents}._4AfKUq_details dt{color:var(--dsw-alias-label-tertiary);font-size:11px;line-height:17px}._4AfKUq_details dd{overflow-wrap:anywhere;min-width:0;color:var(--dsw-alias-label-secondary);margin:0;font-size:12px;line-height:17px}._4AfKUq_visuallyHidden{clip:rect(0 0 0 0);clip-path:inset(50%);white-space:nowrap;width:1px;height:1px;position:absolute;overflow:hidden}@media (prefers-reduced-motion:no-preference){._4AfKUq_chevron{transition:transform .14s var(--ds-ease-in-out)}}@media (width<=680px){._4AfKUq_cards{grid-template-columns:minmax(0,1fr)}}";
12
+ const tagId = "@prettier-ai/dsh-client-ui-settings-plugin-inventory/PluginInventorySettingsTab.module.css";
13
+ if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId) + "]") === null) {
14
+ const tag = document.createElement("style");
15
+ tag.dataset.plugin = "@prettier-ai/dsh-client-ui-settings-plugin-inventory";
16
+ tag.dataset.pluginCss = tagId;
17
+ tag.textContent = css;
18
+ document.head.appendChild(tag);
19
+ }
20
+ var PluginInventorySettingsTab_module_css_default = {
21
+ "card": "_4AfKUq_card",
22
+ "cardContent": "_4AfKUq_cardContent",
23
+ "cardDetails": "_4AfKUq_cardDetails",
24
+ "cardTitle": "_4AfKUq_cardTitle",
25
+ "cardTrailing": "_4AfKUq_cardTrailing",
26
+ "cards": "_4AfKUq_cards",
27
+ "catalog": "_4AfKUq_catalog",
28
+ "catalogHeading": "_4AfKUq_catalogHeading",
29
+ "chevron": "_4AfKUq_chevron",
30
+ "configTag": "_4AfKUq_configTag",
31
+ "details": "_4AfKUq_details",
32
+ "entryValue": "_4AfKUq_entryValue",
33
+ "failure": "_4AfKUq_failure",
34
+ "search": "_4AfKUq_search",
35
+ "section": "_4AfKUq_section",
36
+ "status": "_4AfKUq_status",
37
+ "statusDot": "_4AfKUq_statusDot",
38
+ "visuallyHidden": "_4AfKUq_visuallyHidden"
39
+ };
40
+ //#endregion
41
+ //#region lib/types/client/PluginInventorySettingsTab.js
42
+ const PHASE_KEYS = {
43
+ pending: "pending",
44
+ loading: "loadingPhase",
45
+ active: "active",
46
+ failed: "failed",
47
+ unloading: "unloading"
48
+ };
49
+ /** Localized accessible label for one root Fiber phase. */
50
+ function phaseLabel(phase, t) {
51
+ return phase === null ? t("unobserved") : t(PHASE_KEYS[phase]);
52
+ }
53
+ /** Compact a module specifier without guessing whether its Loader id was generated. */
54
+ function moduleShortName(moduleName) {
55
+ return (moduleName.startsWith("@") ? moduleName.slice(moduleName.indexOf("/") + 1) : moduleName).replace(/^cordis:/, "").replace(/^cordis-plugin-/, "").replace(/^dsh-(?:host-|client-)?/, "");
56
+ }
57
+ /** Whether an inventory row matches the local catalog query. */
58
+ function matches(entry, normalizedQuery) {
59
+ if (normalizedQuery.length === 0) return true;
60
+ return [entry.moduleName, entry.entryId].some((value) => value.toLocaleLowerCase().includes(normalizedQuery));
61
+ }
62
+ /** Render the read-only current Loader inventory. */
63
+ function PluginInventorySettingsTab({ list, t }) {
64
+ const catalogId = (0, react.useId)();
65
+ const [request, setRequest] = (0, react.useState)(0);
66
+ const [query, setQuery] = (0, react.useState)("");
67
+ const [expanded, setExpanded] = (0, react.useState)(null);
68
+ const [state, setState] = (0, react.useState)({ status: "loading" });
69
+ (0, react.useEffect)(() => {
70
+ let current = true;
71
+ Promise.resolve().then(() => list()).then((snapshot) => {
72
+ if (current) setState({
73
+ status: "ready",
74
+ snapshot
75
+ });
76
+ }, () => {
77
+ if (current) setState({ status: "error" });
78
+ });
79
+ return () => {
80
+ current = false;
81
+ };
82
+ }, [list, request]);
83
+ const normalizedQuery = query.trim().toLocaleLowerCase();
84
+ const filteredEntries = (0, react.useMemo)(() => state.status === "ready" ? state.snapshot.entries.filter((entry) => matches(entry, normalizedQuery)) : [], [normalizedQuery, state]);
85
+ (0, react.useEffect)(() => {
86
+ if (expanded !== null && !filteredEntries.some((entry) => entry.entryId === expanded)) setExpanded(null);
87
+ }, [expanded, filteredEntries]);
88
+ const retry = () => {
89
+ setState({ status: "loading" });
90
+ setRequest((value) => value + 1);
91
+ };
92
+ return (0, react_jsx_runtime.jsxs)("div", {
93
+ className: PluginInventorySettingsTab_module_css_default.section,
94
+ "aria-busy": state.status === "loading",
95
+ children: [
96
+ state.status === "loading" ? (0, react_jsx_runtime.jsx)("p", {
97
+ className: PluginInventorySettingsTab_module_css_default.status,
98
+ children: t("loading")
99
+ }) : null,
100
+ state.status === "error" ? (0, react_jsx_runtime.jsxs)("div", {
101
+ className: PluginInventorySettingsTab_module_css_default.failure,
102
+ children: [(0, react_jsx_runtime.jsx)("p", {
103
+ role: "alert",
104
+ children: t("error")
105
+ }), (0, react_jsx_runtime.jsx)("button", {
106
+ type: "button",
107
+ onClick: retry,
108
+ children: t("retry")
109
+ })]
110
+ }) : null,
111
+ state.status === "ready" ? (0, react_jsx_runtime.jsxs)("div", {
112
+ className: PluginInventorySettingsTab_module_css_default.catalog,
113
+ children: [
114
+ (0, react_jsx_runtime.jsxs)("label", {
115
+ className: PluginInventorySettingsTab_module_css_default.search,
116
+ children: [
117
+ (0, react_jsx_runtime.jsx)(_prettier_ai_dsh_client_ui_primitives.IconSearchOutline16, { "aria-hidden": "true" }),
118
+ (0, react_jsx_runtime.jsx)("span", {
119
+ className: PluginInventorySettingsTab_module_css_default.visuallyHidden,
120
+ children: t("search")
121
+ }),
122
+ (0, react_jsx_runtime.jsx)("input", {
123
+ type: "search",
124
+ value: query,
125
+ placeholder: t("search"),
126
+ "aria-label": t("search"),
127
+ onChange: (event) => {
128
+ setQuery(event.currentTarget.value);
129
+ }
130
+ })
131
+ ]
132
+ }),
133
+ (0, react_jsx_runtime.jsxs)("div", {
134
+ className: PluginInventorySettingsTab_module_css_default.catalogHeading,
135
+ children: [(0, react_jsx_runtime.jsx)("h3", { children: t("catalog") }), (0, react_jsx_runtime.jsx)("span", {
136
+ "data-plugin-count": filteredEntries.length,
137
+ children: filteredEntries.length
138
+ })]
139
+ }),
140
+ state.snapshot.entries.length === 0 ? (0, react_jsx_runtime.jsx)("p", {
141
+ className: PluginInventorySettingsTab_module_css_default.status,
142
+ children: t("empty")
143
+ }) : null,
144
+ state.snapshot.entries.length > 0 && filteredEntries.length === 0 ? (0, react_jsx_runtime.jsx)("p", {
145
+ className: PluginInventorySettingsTab_module_css_default.status,
146
+ children: t("emptySearch")
147
+ }) : null,
148
+ filteredEntries.length > 0 ? (0, react_jsx_runtime.jsx)("ul", {
149
+ className: PluginInventorySettingsTab_module_css_default.cards,
150
+ children: filteredEntries.map((entry) => {
151
+ const status = phaseLabel(entry.fiberPhase, t);
152
+ const title = moduleShortName(entry.moduleName);
153
+ const configuration = t(entry.enabled ? "enabledTag" : "disabledTag");
154
+ const open = expanded === entry.entryId;
155
+ const detailId = `${catalogId}-details-${encodeURIComponent(entry.entryId)}`;
156
+ return (0, react_jsx_runtime.jsxs)("li", {
157
+ className: PluginInventorySettingsTab_module_css_default.card,
158
+ "data-plugin-entry": entry.entryId,
159
+ "data-open": open ? "true" : void 0,
160
+ children: [(0, react_jsx_runtime.jsxs)("button", {
161
+ className: PluginInventorySettingsTab_module_css_default.cardContent,
162
+ type: "button",
163
+ "aria-expanded": open,
164
+ "aria-controls": detailId,
165
+ "aria-label": entry.enabled ? `${title}, ${status}, ${configuration}` : `${title}, ${configuration}`,
166
+ onClick: () => {
167
+ setExpanded((current) => current === entry.entryId ? null : entry.entryId);
168
+ },
169
+ children: [(0, react_jsx_runtime.jsx)("strong", {
170
+ className: PluginInventorySettingsTab_module_css_default.cardTitle,
171
+ title: entry.moduleName,
172
+ children: title
173
+ }), (0, react_jsx_runtime.jsxs)("span", {
174
+ className: PluginInventorySettingsTab_module_css_default.cardTrailing,
175
+ children: [
176
+ entry.enabled ? (0, react_jsx_runtime.jsx)("span", {
177
+ className: PluginInventorySettingsTab_module_css_default.statusDot,
178
+ "data-phase": entry.fiberPhase ?? "unobserved",
179
+ role: "img",
180
+ "aria-label": status,
181
+ title: status
182
+ }) : null,
183
+ (0, react_jsx_runtime.jsx)("span", {
184
+ className: PluginInventorySettingsTab_module_css_default.configTag,
185
+ "data-enabled": entry.enabled ? "true" : "false",
186
+ children: configuration
187
+ }),
188
+ (0, react_jsx_runtime.jsx)(_prettier_ai_dsh_client_ui_primitives.IconChevronDownOutline14, {
189
+ className: PluginInventorySettingsTab_module_css_default.chevron,
190
+ size: 12,
191
+ "aria-hidden": "true"
192
+ })
193
+ ]
194
+ })]
195
+ }), open ? (0, react_jsx_runtime.jsxs)("div", {
196
+ className: PluginInventorySettingsTab_module_css_default.cardDetails,
197
+ id: detailId,
198
+ children: [(0, react_jsx_runtime.jsx)("code", {
199
+ className: PluginInventorySettingsTab_module_css_default.entryValue,
200
+ "data-loader-entry": true,
201
+ children: entry.entryId
202
+ }), (0, react_jsx_runtime.jsxs)("dl", {
203
+ className: PluginInventorySettingsTab_module_css_default.details,
204
+ children: [(0, react_jsx_runtime.jsxs)("div", { children: [(0, react_jsx_runtime.jsx)("dt", { children: t("configuration") }), (0, react_jsx_runtime.jsx)("dd", { children: configuration })] }), entry.enabled ? (0, react_jsx_runtime.jsxs)("div", { children: [(0, react_jsx_runtime.jsx)("dt", { children: t("cordis") }), (0, react_jsx_runtime.jsx)("dd", { children: status })] }) : null]
205
+ })]
206
+ }) : null]
207
+ }, entry.entryId);
208
+ })
209
+ }) : null
210
+ ]
211
+ }) : null
212
+ ]
213
+ });
214
+ }
215
+ //#endregion
216
+ //#region lib/types/client/locales.js
217
+ /** Copy dictionaries for the plugin inventory Settings section. */
218
+ /** Simplified Chinese dictionary and key source of truth. */
219
+ const zh = {
220
+ tab: "插件列表",
221
+ loading: "正在读取插件…",
222
+ error: "暂时无法读取插件。",
223
+ retry: "重试",
224
+ search: "搜索插件",
225
+ catalog: "插件列表",
226
+ empty: "暂无插件。",
227
+ emptySearch: "没有匹配的插件。",
228
+ enabledTag: "已启用",
229
+ disabledTag: "已停用",
230
+ configuration: "配置状态",
231
+ cordis: "Cordis 状态",
232
+ unobserved: "未挂载",
233
+ pending: "等待依赖",
234
+ loadingPhase: "加载中",
235
+ active: "已挂载",
236
+ failed: "挂载失败",
237
+ unloading: "卸载中"
238
+ };
239
+ /** English dictionary checked against the Chinese key set. */
240
+ const en = {
241
+ tab: "Plugin list",
242
+ loading: "Reading plugins…",
243
+ error: "Plugins are temporarily unavailable.",
244
+ retry: "Retry",
245
+ search: "Search plugins",
246
+ catalog: "Plugin list",
247
+ empty: "No plugins are available.",
248
+ emptySearch: "No matching plugins.",
249
+ enabledTag: "Enabled",
250
+ disabledTag: "Disabled",
251
+ configuration: "Configuration",
252
+ cordis: "Cordis status",
253
+ unobserved: "Not mounted",
254
+ pending: "Waiting for dependencies",
255
+ loadingPhase: "Loading",
256
+ active: "Mounted",
257
+ failed: "Mount failed",
258
+ unloading: "Unloading"
259
+ };
260
+ //#endregion
261
+ //#region lib/types/client/index.js
262
+ /** Read-only Host plugin inventory registered into Web Settings. */
263
+ /** Dictionary namespace owned by this plugin. */
264
+ const NS = "settings.pluginInventory";
265
+ /** Services required by the Settings registration and generated Remote face. */
266
+ const inject = [
267
+ "slots",
268
+ "locale",
269
+ "remote",
270
+ "remote.pluginInventory"
271
+ ];
272
+ /** Contribute the lazy inventory tab to the Plugins settings section. */
273
+ function apply(ctx) {
274
+ ctx.effect(() => ctx.locale.register(NS, {
275
+ zh,
276
+ en
277
+ }), "ui-settings-plugin-inventory: dictionaries");
278
+ const t = ctx.locale.bind(NS);
279
+ const list = async () => {
280
+ const result = await ctx.remote.pluginInventory.list();
281
+ if (!result.ok) throw new Error(`pluginInventory.list failed: ${result.error.code}: ${result.error.message}`);
282
+ return result.value;
283
+ };
284
+ const injected = () => ({ list });
285
+ ctx.slots.inject("settings.plugins.tab", () => ctx.slots.register({
286
+ name: "settings.plugins.tab",
287
+ id: "all",
288
+ order: 10,
289
+ label: () => t("tab"),
290
+ locale: NS,
291
+ inject: injected
292
+ }, PluginInventorySettingsTab));
293
+ }
294
+ //#endregion
295
+ exports.NS = NS;
296
+ exports.apply = apply;
297
+ exports.inject = inject;
298
+ return module.exports;
299
+ }
300
+ });
301
+
302
+ //# sourceMappingURL=client.js.map
package/lib/index.js ADDED
@@ -0,0 +1,6 @@
1
+ //#region lib/types/index.js
2
+ /** Host loader entry for the inventory-tab browser implementation exported from `./client`. */
3
+ /** Host plugin body — no host-side behavior for the plugin inventory tab. */
4
+ function apply() {}
5
+ //#endregion
6
+ export { apply };
@@ -0,0 +1,13 @@
1
+ //#region lib/types/invariant.js
2
+ /** Package-owned invariant companion. @module @prettier-ai/dsh-client-ui-settings-plugin-inventory/invariant */
3
+ const PACKAGE_NAME = "@prettier-ai/dsh-client-ui-settings-plugin-inventory";
4
+ /** Cordis companion plugin name. */
5
+ const name = "client-ui-settings-plugin-inventory-invariant";
6
+ /** Service required before the companion can reserve package ownership. */
7
+ const inject = ["invariants"];
8
+ /** No runtime invariant: this package owns a read-only Settings contribution. */
9
+ const install = () => {};
10
+ /** Register this package's invariant companion. */
11
+ const apply = (ctx) => Promise.resolve(ctx.invariants.register(PACKAGE_NAME, install));
12
+ //#endregion
13
+ export { apply, inject, name };
@@ -0,0 +1,13 @@
1
+ import { type ReactNode } from 'react';
2
+ import type { PluginInventorySnapshot } from '@prettier-ai/dsh-api-remotes/client';
3
+ import type { InjectFace, PropsLocale, PropsRuntime } from '@prettier-ai/dsh-client-ui-slots';
4
+ /** Registration-side Remote face used by the section. */
5
+ export interface PluginInventorySettingsTabInjected {
6
+ /** Read a current Host inventory snapshot. */
7
+ list: () => Promise<PluginInventorySnapshot>;
8
+ }
9
+ /** Full component props assembled by the Settings slot renderer. */
10
+ export type PluginInventorySettingsTabProps = PropsRuntime<'settings.plugins.tab'> & PropsLocale<'settings.pluginInventory'> & InjectFace<PluginInventorySettingsTabInjected>;
11
+ /** Render the read-only current Loader inventory. */
12
+ export declare function PluginInventorySettingsTab({ list, t }: PluginInventorySettingsTabProps): ReactNode;
13
+ //# sourceMappingURL=PluginInventorySettingsTab.d.ts.map
@@ -0,0 +1,18 @@
1
+ /** Read-only Host plugin inventory registered into Web Settings. */
2
+ import type { Context as ClientContext } from '@prettier-ai/cordis';
3
+ import { type PluginInventoryLocaleKey } from './locales.ts';
4
+ export type { PluginInventorySettingsTabInjected, PluginInventorySettingsTabProps } from './PluginInventorySettingsTab.tsx';
5
+ export type { PluginInventoryLocaleKey } from './locales.ts';
6
+ declare module '@prettier-ai/dsh-client-ui-slots' {
7
+ interface LocaleNamespaceMap {
8
+ /** Read-only Host plugin inventory copy. */
9
+ 'settings.pluginInventory': PluginInventoryLocaleKey;
10
+ }
11
+ }
12
+ /** Dictionary namespace owned by this plugin. */
13
+ export declare const NS = "settings.pluginInventory";
14
+ /** Services required by the Settings registration and generated Remote face. */
15
+ export declare const inject: string[];
16
+ /** Contribute the lazy inventory tab to the Plugins settings section. */
17
+ export declare function apply(ctx: ClientContext): void;
18
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1,46 @@
1
+ /** Copy dictionaries for the plugin inventory Settings section. */
2
+ /** Simplified Chinese dictionary and key source of truth. */
3
+ export declare const zh: {
4
+ tab: string;
5
+ loading: string;
6
+ error: string;
7
+ retry: string;
8
+ search: string;
9
+ catalog: string;
10
+ empty: string;
11
+ emptySearch: string;
12
+ enabledTag: string;
13
+ disabledTag: string;
14
+ configuration: string;
15
+ cordis: string;
16
+ unobserved: string;
17
+ pending: string;
18
+ loadingPhase: string;
19
+ active: string;
20
+ failed: string;
21
+ unloading: string;
22
+ };
23
+ /** Plugin inventory locale key union. */
24
+ export type PluginInventoryLocaleKey = keyof typeof zh;
25
+ /** English dictionary checked against the Chinese key set. */
26
+ export declare const en: {
27
+ tab: string;
28
+ loading: string;
29
+ error: string;
30
+ retry: string;
31
+ search: string;
32
+ catalog: string;
33
+ empty: string;
34
+ emptySearch: string;
35
+ enabledTag: string;
36
+ disabledTag: string;
37
+ configuration: string;
38
+ cordis: string;
39
+ unobserved: string;
40
+ pending: string;
41
+ loadingPhase: string;
42
+ active: string;
43
+ failed: string;
44
+ unloading: string;
45
+ };
46
+ //# sourceMappingURL=locales.d.ts.map
@@ -0,0 +1,4 @@
1
+ /** Host loader entry for the inventory-tab browser implementation exported from `./client`. */
2
+ /** Host plugin body — no host-side behavior for the plugin inventory tab. */
3
+ export declare function apply(): void;
4
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1,9 @@
1
+ /** Package-owned invariant companion. @module @prettier-ai/dsh-client-ui-settings-plugin-inventory/invariant */
2
+ import type { Context } from '@prettier-ai/cordis';
3
+ /** Cordis companion plugin name. */
4
+ export declare const name = "client-ui-settings-plugin-inventory-invariant";
5
+ /** Service required before the companion can reserve package ownership. */
6
+ export declare const inject: string[];
7
+ /** Register this package's invariant companion. */
8
+ export declare const apply: (ctx: Context) => Promise<() => void>;
9
+ //# sourceMappingURL=invariant.d.ts.map
package/package.json ADDED
@@ -0,0 +1,76 @@
1
+ {
2
+ "name": "@prettier-ai/dsh-client-ui-settings-plugin-inventory",
3
+ "description": "Read-only Cordis Loader inventory tab in Web Plugins settings",
4
+ "version": "0.1.2-alpha.1",
5
+ "publishConfig": {
6
+ "access": "public"
7
+ },
8
+ "repository": {
9
+ "type": "git",
10
+ "url": "git+https://github.com/deepseek-ai/deepseek-harness.git",
11
+ "directory": "packages/client/ui-settings-plugin-inventory"
12
+ },
13
+ "type": "module",
14
+ "main": "lib/index.js",
15
+ "types": "lib/types/index.d.ts",
16
+ "exports": {
17
+ ".": {
18
+ "types": "./lib/types/index.d.ts",
19
+ "default": "./lib/index.js"
20
+ },
21
+ "./invariant": {
22
+ "types": "./lib/types/invariant.d.ts",
23
+ "default": "./lib/invariant.js"
24
+ },
25
+ "./client": {
26
+ "types": "./lib/types/client/index.d.ts",
27
+ "default": "./lib/client.js"
28
+ },
29
+ "./src/*": "./src/*",
30
+ "./package.json": "./package.json"
31
+ },
32
+ "dsh": {
33
+ "client": {
34
+ "inject": [
35
+ "@prettier-ai/dsh-api-remotes",
36
+ "@prettier-ai/dsh-client-ui-settings",
37
+ "@prettier-ai/dsh-client-locale"
38
+ ],
39
+ "platform": "web"
40
+ }
41
+ },
42
+ "license": "MIT",
43
+ "peerDependencies": {
44
+ "@prettier-ai/dsh-client-ui-settings": "^0.1.2-alpha.1",
45
+ "@prettier-ai/dsh-invariants": "^0.1.2-alpha.1",
46
+ "@prettier-ai/cordis": "^4.0.1",
47
+ "@prettier-ai/dsh-client-ui-renderer": "^0.1.2-alpha.1",
48
+ "@prettier-ai/dsh-client-locale": "^0.1.2-alpha.1",
49
+ "@prettier-ai/dsh-api-remotes": "^0.1.2-alpha.1"
50
+ },
51
+ "devDependencies": {
52
+ "@testing-library/react": "^16.1.0",
53
+ "@types/react": "~18.3.1",
54
+ "react": "^18.2.0",
55
+ "react-dom": "^18.2.0",
56
+ "@prettier-ai/dsh-api-remotes": "^0.1.2-alpha.1",
57
+ "@prettier-ai/dsh-client-test-runtime": "^0.1.2-alpha.1",
58
+ "@prettier-ai/dsh-client-locale": "^0.1.2-alpha.1",
59
+ "@prettier-ai/dsh-client-ui-primitives": "^0.1.2-alpha.1",
60
+ "@prettier-ai/dsh-client-ui-settings": "^0.1.2-alpha.1",
61
+ "@prettier-ai/dsh-client-ui-slots": "^0.1.2-alpha.1",
62
+ "@prettier-ai/dsh-invariants": "^0.1.2-alpha.1",
63
+ "@prettier-ai/cordis": "^4.0.1",
64
+ "@prettier-ai/dsh-client-ui-renderer": "^0.1.2-alpha.1"
65
+ },
66
+ "files": [
67
+ "lib/index.js",
68
+ "lib/invariant.js",
69
+ "lib/client.js",
70
+ "lib/types/**/*.d.ts"
71
+ ],
72
+ "scripts": {
73
+ "bundle": "tsdown",
74
+ "watch": "tsdown --watch"
75
+ }
76
+ }