@deepseek-ai/dsh-client-ui-settings-plugins 0.1.0-rc.3 → 0.1.0-rc.7
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 +2 -2
- package/README.md +5 -5
- package/README.zh.md +5 -5
- package/lib/client.js +149 -39
- package/lib/invariant.js +2 -2
- package/lib/types/client/ConfigurablePluginsTab.d.ts +16 -9
- package/lib/types/client/index.d.ts +2 -1
- package/lib/types/client/slot-contract.d.ts +13 -10
- package/lib/types/client/tab-store.d.ts +74 -0
- package/package.json +21 -21
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/client/ui-settings-plugins/README.md
|
|
5
|
-
README.md:
|
|
6
|
-
README.zh.md:
|
|
5
|
+
README.md: 92ba426b6bee3ae73e184dfcfd418e889bd47086
|
|
6
|
+
README.zh.md: dc319ea9f128016b6df821575cb4d75740f04579
|
package/README.md
CHANGED
|
@@ -6,13 +6,13 @@ The **Plugins** settings section and its **Plugin configuration** tab. The secti
|
|
|
6
6
|
|
|
7
7
|
## What appears here
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
The configurable tab reads which settings namespaces the Host serves and dispatches one slot key per namespace, so what renders is the intersection of two ledgers: the namespaces a live Host plugin registered, and the cards registered under those keys. A served namespace no card claims renders nothing — another surface owns it, or this deployment ships no browser half for it — and a card whose namespace this deployment does not serve is never dispatched, so an uncomposed plugin leaves no trace and does not hold the tab back from its empty line. The empty line waits for the Host's first answer, so an unanswered read never reads as "this deployment configures no plugin". Cards appear in the order they registered, which is stable for the cards one package installs together and not stable across plugins: apply order between packages is unconstrained.
|
|
10
10
|
|
|
11
|
-
The
|
|
11
|
+
The cards this package ships cover the shell executor (`bash`), the agent loop's tool-call parallelism (`agent-loop`), and the DeepSeek search provider (`web-search-deepseek`).
|
|
12
12
|
|
|
13
13
|
## Extension point
|
|
14
14
|
|
|
15
|
-
The section declares `settings.plugins.tab`, a root list slot whose labels become ordered tabs. It keeps a tab mounted after its first selection, so local drafts and read-only snapshots survive tab switches. The package registers its own `configurable` contribution, which declares the nested `settings.plugin.item`
|
|
15
|
+
The section declares `settings.plugins.tab`, a root list slot whose labels become ordered tabs. It keeps a tab mounted after its first selection, so local drafts and read-only snapshots survive tab switches. The package registers its own `configurable` contribution, which declares the nested `settings.plugin.item` slot — keyed on the settings namespace a card edits. A plugin that ships a browser half registers its own card under its own namespace and owns every part of it: chrome, controls, and copy. Keying on the namespace is what lets a plugin distributed outside this repository appear here — it registers the namespace on the Host and the card in the browser, and the tab pairs the two without learning what the namespace means. Tabs follow the contribution's `order`; cards follow registration order.
|
|
16
16
|
|
|
17
17
|
## Writes
|
|
18
18
|
|
|
@@ -35,6 +35,6 @@ None; this package neither assembles nor sends a provider request.
|
|
|
35
35
|
## Known Limitations and Deferred Work
|
|
36
36
|
|
|
37
37
|
- **Only host-plane plugins appear** — a plugin an agent preset mounts carries its configuration inline in that preset's `agent.cordis.yml` and cannot register a settings namespace at all (a second session mounting the same preset would fail on a duplicate registration), so this section lists nothing for it. Editing those values remains the preset editor's job.
|
|
38
|
-
- **
|
|
38
|
+
- **A card still needs a browser bundle** — the browser half must be a `dsh.client` package built in the client module system's lazy-CJS factory format, and the `clientBundle` preset that emits it lives in `packages/client/tsdown.client.ts` rather than a published package, so a plugin outside this repository has to reproduce that build itself. The bundle-purity gate also forbids importing this package's card chrome or form model as values, so such a card owns its own staging and revision fencing.
|
|
39
|
+
- **The served namespaces re-read on two signals only** — the wire announces settings-document commits and connection resets, not registrations, so a namespace whose owner registers after the tab's read joins the list on the next document commit or reconnect.
|
|
39
40
|
- **The shell card follows the composed executor** — the POSIX and PowerShell executor families share the `bash` namespace because a host composes exactly one of them, so the served schema differs by platform (PowerShell adds `pwshPath`) even though the card edits the same two fields on both, and a deployment composing neither shows no card.
|
|
40
|
-
- **The empty line counts registered cards, not visible ones** — a card whose namespace this deployment does not expose renders nothing, but still counts, so a deployment that exposes none shows an empty list rather than the empty line. The count is also read once, because the renderer caches a root entry's inject face; a card registered later does not raise it.
|
package/README.zh.md
CHANGED
|
@@ -6,13 +6,13 @@
|
|
|
6
6
|
|
|
7
7
|
## 这里会出现什么
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
“插件配置”标签页读取 Host 服务了哪些 settings 命名空间,并为每个命名空间派发一个 slot 键,因此渲染出来的是两份账本的交集:存活 Host 插件注册的命名空间,以及注册在这些键上的卡片。被服务却无人认领的命名空间什么都不渲染——它归别的界面所有,或本部署没有为它提供浏览器半侧;而命名空间未被本部署服务的卡片根本不会被派发,因此未组装的插件不留任何痕迹,也不会挡住那行空态文案。空态文案要等 Host 的第一次答复,因此一次尚未答复的读取绝不会被读成“本部署没有可配置的插件”。卡片按自身注册的顺序出现;对同一个包一起安装的卡片这是稳定的,对跨插件的卡片则不稳定:包与包之间的 apply 顺序是无约束的。
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
本包自带的卡片覆盖 shell 执行器(`bash`)、agent 循环的工具调用并行度(`agent-loop`)以及 DeepSeek 搜索提供方(`web-search-deepseek`)。
|
|
12
12
|
|
|
13
13
|
## 扩展点
|
|
14
14
|
|
|
15
|
-
本分区声明根级列表 slot `settings.plugins.tab`,其标签会成为有序标签页。某个标签页首次被选择后会保持挂载,因此本地草稿与只读快照在切换标签页时不会丢失。本包注册自己的 `configurable` 贡献,由它声明嵌套的 `settings.plugin.item`
|
|
15
|
+
本分区声明根级列表 slot `settings.plugins.tab`,其标签会成为有序标签页。某个标签页首次被选择后会保持挂载,因此本地草稿与只读快照在切换标签页时不会丢失。本包注册自己的 `configurable` 贡献,由它声明嵌套的 `settings.plugin.item` slot——以卡片所编辑的 settings 命名空间为键。带浏览器半侧的插件把自己的卡片注册在自己的命名空间上,并拥有它的全部:外观、控件与文案。以命名空间为键,正是在本仓库之外分发的插件能出现在这里的原因——它在 Host 上注册命名空间、在浏览器里注册卡片,由标签页把两者配对,而无需知道命名空间意味着什么。标签页遵循贡献的 `order`;卡片遵循注册顺序。
|
|
16
16
|
|
|
17
17
|
## 写入
|
|
18
18
|
|
|
@@ -35,6 +35,6 @@
|
|
|
35
35
|
## 已知限制与暂缓事项
|
|
36
36
|
|
|
37
37
|
- **只有宿主平面的插件会出现**——由 agent preset 挂载的插件把配置内联在该 preset 的 `agent.cordis.yml` 中,且根本无法注册 settings 命名空间(同一 preset 挂载第二个会话时会因重复注册而失败),因此本分区不会列出它。编辑那些值仍是 preset 编辑器的职责。
|
|
38
|
-
-
|
|
38
|
+
- **卡片仍然需要一份浏览器 bundle**——浏览器半侧必须是按客户端模块系统的 lazy-CJS factory 格式构建的 `dsh.client` 包,而产出它的 `clientBundle` 预设位于 `packages/client/tsdown.client.ts`,并非已发布的包,因此本仓库之外的插件得自行复刻该构建。bundle 纯净度门禁同时禁止以值的形式导入本包的卡片外观与表单模型,所以这样的卡片要自行拥有暂存与 revision 设栅。
|
|
39
|
+
- **被服务的命名空间只在两种信号上重读**——协议通告的是 settings 文档提交与连接重置,而非注册行为,因此在标签页读取之后才被其拥有方注册的命名空间,要等下一次文档提交或重连才会加入列表。
|
|
39
40
|
- **shell 卡片跟随被组装的执行器**——POSIX 与 PowerShell 两个执行器家族共用 `bash` 命名空间,因为一个宿主只组装其中之一,所以被服务的 schema 随平台不同(PowerShell 多出 `pwshPath`),尽管卡片在两者下编辑的都是同样两个字段;而两者都不组装的部署不会显示这张卡片。
|
|
40
|
-
- **空态数的是已注册卡片,不是可见卡片**——命名空间未被本部署暴露的卡片什么都不渲染,但仍计入数量,因此一个都不暴露的部署看到的是空列表而非那行空态文案。该计数还只读取一次,因为渲染器会缓存根级 entry 的 inject face;之后注册的卡片不会让它变大。
|
package/lib/client.js
CHANGED
|
@@ -20,17 +20,17 @@ window.__ModuleLoader__.load({
|
|
|
20
20
|
document.head.appendChild(tag);
|
|
21
21
|
}
|
|
22
22
|
var fields_module_css_default = {
|
|
23
|
+
"input": "At1oFq_input",
|
|
24
|
+
"field": "At1oFq_field",
|
|
25
|
+
"head": "At1oFq_head",
|
|
23
26
|
"label": "At1oFq_label",
|
|
24
|
-
"badge": "At1oFq_badge",
|
|
25
|
-
"reset": "At1oFq_reset",
|
|
26
|
-
"invalid": "At1oFq_invalid",
|
|
27
27
|
"inputInvalid": "At1oFq_inputInvalid",
|
|
28
|
-
"
|
|
28
|
+
"invalid": "At1oFq_invalid",
|
|
29
29
|
"badges": "At1oFq_badges",
|
|
30
|
-
"
|
|
31
|
-
"
|
|
32
|
-
"
|
|
33
|
-
"
|
|
30
|
+
"badgeMuted": "At1oFq_badgeMuted",
|
|
31
|
+
"badge": "At1oFq_badge",
|
|
32
|
+
"hint": "At1oFq_hint",
|
|
33
|
+
"reset": "At1oFq_reset"
|
|
34
34
|
};
|
|
35
35
|
//#endregion
|
|
36
36
|
//#region lib/types/client/fields.js
|
|
@@ -162,21 +162,21 @@ window.__ModuleLoader__.load({
|
|
|
162
162
|
document.head.appendChild(tag);
|
|
163
163
|
}
|
|
164
164
|
var PluginCard_module_css_default = {
|
|
165
|
-
"
|
|
165
|
+
"discard": "YyYd_a_discard",
|
|
166
166
|
"header": "YyYd_a_header",
|
|
167
|
-
"chevron": "YyYd_a_chevron",
|
|
168
|
-
"readOnly": "YyYd_a_readOnly",
|
|
169
167
|
"pending": "YyYd_a_pending",
|
|
170
|
-
"
|
|
171
|
-
"cardOpen": "YyYd_a_cardOpen",
|
|
168
|
+
"name": "YyYd_a_name",
|
|
172
169
|
"body": "YyYd_a_body",
|
|
173
|
-
"card": "YyYd_a_card",
|
|
174
|
-
"footer": "YyYd_a_footer",
|
|
175
|
-
"chevronOpen": "YyYd_a_chevronOpen",
|
|
176
|
-
"save": "YyYd_a_save",
|
|
177
170
|
"failed": "YyYd_a_failed",
|
|
171
|
+
"save": "YyYd_a_save",
|
|
172
|
+
"chevronOpen": "YyYd_a_chevronOpen",
|
|
173
|
+
"chevron": "YyYd_a_chevron",
|
|
174
|
+
"cardOpen": "YyYd_a_cardOpen",
|
|
175
|
+
"readOnly": "YyYd_a_readOnly",
|
|
178
176
|
"description": "YyYd_a_description",
|
|
179
|
-
"
|
|
177
|
+
"card": "YyYd_a_card",
|
|
178
|
+
"headText": "YyYd_a_headText",
|
|
179
|
+
"footer": "YyYd_a_footer"
|
|
180
180
|
};
|
|
181
181
|
//#endregion
|
|
182
182
|
//#region lib/types/client/PluginCard.js
|
|
@@ -371,26 +371,41 @@ window.__ModuleLoader__.load({
|
|
|
371
371
|
document.head.appendChild(tag);
|
|
372
372
|
}
|
|
373
373
|
var PluginsSettingsSection_module_css_default = {
|
|
374
|
-
"
|
|
375
|
-
"panel": "pbvGtq_panel",
|
|
376
|
-
"heading": "pbvGtq_heading",
|
|
377
|
-
"tab": "pbvGtq_tab",
|
|
374
|
+
"tabs": "pbvGtq_tabs",
|
|
378
375
|
"cards": "pbvGtq_cards",
|
|
379
|
-
"
|
|
376
|
+
"tab": "pbvGtq_tab",
|
|
377
|
+
"heading": "pbvGtq_heading",
|
|
380
378
|
"intro": "pbvGtq_intro",
|
|
381
|
-
"
|
|
379
|
+
"empty": "pbvGtq_empty",
|
|
380
|
+
"section": "pbvGtq_section",
|
|
381
|
+
"panel": "pbvGtq_panel"
|
|
382
382
|
};
|
|
383
383
|
//#endregion
|
|
384
384
|
//#region lib/types/client/ConfigurablePluginsTab.js
|
|
385
|
-
/**
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
385
|
+
/**
|
|
386
|
+
* Configurable Host plugins contributed to the shared Plugins section.
|
|
387
|
+
*
|
|
388
|
+
* The tab enumerates settings namespaces but never interprets one — a card
|
|
389
|
+
* arrives through `settings.plugin.item` keyed by the namespace it edits, so a
|
|
390
|
+
* plugin that ships a browser half owns its own card and this tab only decides
|
|
391
|
+
* which keys to dispatch.
|
|
392
|
+
*/
|
|
393
|
+
/**
|
|
394
|
+
* Render cards registered by plugins that expose editable settings.
|
|
395
|
+
* @param props - locale copy, slot rendering, and the namespaces to dispatch.
|
|
396
|
+
* @returns the card list, or the empty line once the Host has answered.
|
|
397
|
+
*/
|
|
398
|
+
function ConfigurablePluginsTab(props) {
|
|
399
|
+
const { t, renderSlot } = props;
|
|
400
|
+
const { loaded, namespaces } = props.useConfigurablePlugins((snapshot) => snapshot);
|
|
401
|
+
if (namespaces.length > 0) return (0, react_jsx_runtime.jsx)("ul", {
|
|
391
402
|
className: PluginsSettingsSection_module_css_default.cards,
|
|
392
|
-
children: renderSlot("settings.plugin.item", {})
|
|
403
|
+
children: namespaces.map((ns) => (0, react_jsx_runtime.jsx)(react.Fragment, { children: renderSlot("settings.plugin.item", {}, { entryKey: ns }) }, ns))
|
|
393
404
|
});
|
|
405
|
+
return loaded ? (0, react_jsx_runtime.jsx)("p", {
|
|
406
|
+
className: PluginsSettingsSection_module_css_default.empty,
|
|
407
|
+
children: t("empty")
|
|
408
|
+
}) : null;
|
|
394
409
|
}
|
|
395
410
|
//#endregion
|
|
396
411
|
//#region lib/types/client/PluginsSettingsSection.js
|
|
@@ -893,6 +908,90 @@ window.__ModuleLoader__.load({
|
|
|
893
908
|
}
|
|
894
909
|
};
|
|
895
910
|
//#endregion
|
|
911
|
+
//#region lib/types/client/tab-store.js
|
|
912
|
+
/**
|
|
913
|
+
* The configurable-plugins tab's card list.
|
|
914
|
+
*
|
|
915
|
+
* The tab dispatches its slot by settings namespace, so what it renders is
|
|
916
|
+
* the intersection of two ledgers: the namespaces the Host serves and the
|
|
917
|
+
* cards registered into `settings.plugin.item`. A served namespace no card
|
|
918
|
+
* claims renders nothing — another surface owns it, or this deployment ships
|
|
919
|
+
* no browser half for it — and a card whose namespace the Host does not serve
|
|
920
|
+
* is never dispatched, so a plugin this deployment did not compose leaves no
|
|
921
|
+
* trace and does not count toward the empty line.
|
|
922
|
+
*/
|
|
923
|
+
/** Reads the served namespaces and pairs them with the cards that claim them. */
|
|
924
|
+
var ConfigurablePluginsTabController = class {
|
|
925
|
+
api;
|
|
926
|
+
entries;
|
|
927
|
+
store = (0, _deepseek_ai_dsh_client_runtime_client.createSnapshotStore)({
|
|
928
|
+
loaded: false,
|
|
929
|
+
namespaces: []
|
|
930
|
+
});
|
|
931
|
+
/** Last Host answer; kept so a slot mutation republishes without a wire read. */
|
|
932
|
+
served = [];
|
|
933
|
+
loaded = false;
|
|
934
|
+
generation = 0;
|
|
935
|
+
disposed = false;
|
|
936
|
+
/**
|
|
937
|
+
* @param api - settings wire face.
|
|
938
|
+
* @param entries - reads the cards currently registered into the section's slot.
|
|
939
|
+
*/
|
|
940
|
+
constructor(api, entries) {
|
|
941
|
+
this.api = api;
|
|
942
|
+
this.entries = entries;
|
|
943
|
+
}
|
|
944
|
+
/** Opaque read of {@link disposed}: control flow cannot narrow it across awaits. */
|
|
945
|
+
isDisposed() {
|
|
946
|
+
return this.disposed;
|
|
947
|
+
}
|
|
948
|
+
/**
|
|
949
|
+
* Re-read the served namespaces from the Host and republish.
|
|
950
|
+
* @returns settlement after the read, or immediately once disposed.
|
|
951
|
+
*/
|
|
952
|
+
async load() {
|
|
953
|
+
if (this.isDisposed()) return;
|
|
954
|
+
const generation = ++this.generation;
|
|
955
|
+
let response;
|
|
956
|
+
try {
|
|
957
|
+
response = await this.api.settings.describe({});
|
|
958
|
+
} catch (_settingsReadFailure) {
|
|
959
|
+
return;
|
|
960
|
+
}
|
|
961
|
+
if (this.isDisposed() || generation !== this.generation || !response.result.ok) return;
|
|
962
|
+
this.served = response.result.value.namespaces.map((view) => view.ns);
|
|
963
|
+
this.loaded = true;
|
|
964
|
+
this.publish();
|
|
965
|
+
}
|
|
966
|
+
/** Republish after the slot ledger changed; a card registered late joins here. */
|
|
967
|
+
refresh() {
|
|
968
|
+
if (this.disposed) return;
|
|
969
|
+
this.publish();
|
|
970
|
+
}
|
|
971
|
+
/** Stop publishing; an in-flight read settles without touching the store. */
|
|
972
|
+
dispose() {
|
|
973
|
+
this.disposed = true;
|
|
974
|
+
this.generation += 1;
|
|
975
|
+
}
|
|
976
|
+
/**
|
|
977
|
+
* Build the face the tab's slot registration injects.
|
|
978
|
+
* @returns the tab's snapshot source.
|
|
979
|
+
*/
|
|
980
|
+
inject() {
|
|
981
|
+
return { hooks: { configurablePlugins: this.store } };
|
|
982
|
+
}
|
|
983
|
+
publish() {
|
|
984
|
+
const served = new Set(this.served);
|
|
985
|
+
const namespaces = this.entries().flatMap((entry) => entry.options.key !== void 0 && served.has(entry.options.key) ? [entry.options.key] : []);
|
|
986
|
+
const previous = this.store.getSnapshot();
|
|
987
|
+
if (previous.loaded === this.loaded && previous.namespaces.length === namespaces.length && previous.namespaces.every((ns, index) => ns === namespaces[index])) return;
|
|
988
|
+
this.store.set({
|
|
989
|
+
loaded: this.loaded,
|
|
990
|
+
namespaces
|
|
991
|
+
});
|
|
992
|
+
}
|
|
993
|
+
};
|
|
994
|
+
//#endregion
|
|
896
995
|
//#region lib/types/client/web-search-card-controller.js
|
|
897
996
|
/**
|
|
898
997
|
* The web-search card's staged form over the `web-search-deepseek` settings
|
|
@@ -1155,6 +1254,20 @@ window.__ModuleLoader__.load({
|
|
|
1155
1254
|
ctx.effect(() => ctx.remote.$on("credentials/updated", (ref) => {
|
|
1156
1255
|
webSearch.refreshCredential(ref);
|
|
1157
1256
|
}), "ui-settings-plugins: credential invalidations");
|
|
1257
|
+
const configurable = new ConfigurablePluginsTabController(api, () => ctx.slots.entries("settings.plugin.item"));
|
|
1258
|
+
ctx.effect(() => () => {
|
|
1259
|
+
configurable.dispose();
|
|
1260
|
+
}, "ui-settings-plugins: tab directory");
|
|
1261
|
+
ctx.effect(() => ctx.remote.$on("settings/document-updated", () => {
|
|
1262
|
+
configurable.load();
|
|
1263
|
+
}), "ui-settings-plugins: served-namespace invalidations");
|
|
1264
|
+
ctx.effect(() => ctx.on("connection/reset", () => {
|
|
1265
|
+
configurable.load();
|
|
1266
|
+
}), "ui-settings-plugins: served-namespace reconnect");
|
|
1267
|
+
ctx.effect(() => ctx.slots.subscribe("settings.plugin.item", () => {
|
|
1268
|
+
configurable.refresh();
|
|
1269
|
+
}), "ui-settings-plugins: card ledger");
|
|
1270
|
+
configurable.load();
|
|
1158
1271
|
let tabsVersion = -1;
|
|
1159
1272
|
let tabsRevision = -1;
|
|
1160
1273
|
let tabs = [];
|
|
@@ -1201,31 +1314,28 @@ window.__ModuleLoader__.load({
|
|
|
1201
1314
|
order: 0,
|
|
1202
1315
|
label: () => t("configurableTab"),
|
|
1203
1316
|
locale: NS,
|
|
1204
|
-
inject: () =>
|
|
1317
|
+
inject: () => configurable.inject(),
|
|
1205
1318
|
children: { "settings.plugin.item": {
|
|
1206
|
-
kind: "
|
|
1319
|
+
kind: "keyed",
|
|
1207
1320
|
scope: "root"
|
|
1208
1321
|
} }
|
|
1209
1322
|
}, ConfigurablePluginsTab));
|
|
1210
1323
|
ctx.slots.inject("settings.plugin.item", function* () {
|
|
1211
1324
|
yield ctx.slots.register({
|
|
1212
1325
|
name: "settings.plugin.item",
|
|
1213
|
-
|
|
1214
|
-
order: 0,
|
|
1326
|
+
key: SHELL_NS,
|
|
1215
1327
|
locale: NS,
|
|
1216
1328
|
inject: () => bash.inject()
|
|
1217
1329
|
}, BashCard);
|
|
1218
1330
|
yield ctx.slots.register({
|
|
1219
1331
|
name: "settings.plugin.item",
|
|
1220
|
-
|
|
1221
|
-
order: 10,
|
|
1332
|
+
key: AGENT_LOOP_NS,
|
|
1222
1333
|
locale: NS,
|
|
1223
1334
|
inject: () => agentLoop.inject()
|
|
1224
1335
|
}, AgentLoopCard);
|
|
1225
1336
|
yield ctx.slots.register({
|
|
1226
1337
|
name: "settings.plugin.item",
|
|
1227
|
-
|
|
1228
|
-
order: 20,
|
|
1338
|
+
key: WEB_SEARCH_NS,
|
|
1229
1339
|
locale: NS,
|
|
1230
1340
|
inject: () => webSearch.inject()
|
|
1231
1341
|
}, WebSearchCard);
|
package/lib/invariant.js
CHANGED
|
@@ -10,8 +10,8 @@ const name = "client-ui-settings-plugins-invariant";
|
|
|
10
10
|
const inject = ["invariants"];
|
|
11
11
|
/**
|
|
12
12
|
* No runtime invariant: this is a browser-side settings surface whose node half owns no event
|
|
13
|
-
* stream or mutable runtime data; the layering
|
|
14
|
-
*
|
|
13
|
+
* stream or mutable runtime data; the layering and write refusals are Host contracts covered by
|
|
14
|
+
* the owning plugins and the api-proxy.
|
|
15
15
|
*/
|
|
16
16
|
const install = () => {};
|
|
17
17
|
/**
|
|
@@ -1,12 +1,19 @@
|
|
|
1
|
-
/**
|
|
1
|
+
/**
|
|
2
|
+
* Configurable Host plugins contributed to the shared Plugins section.
|
|
3
|
+
*
|
|
4
|
+
* The tab enumerates settings namespaces but never interprets one — a card
|
|
5
|
+
* arrives through `settings.plugin.item` keyed by the namespace it edits, so a
|
|
6
|
+
* plugin that ships a browser half owns its own card and this tab only decides
|
|
7
|
+
* which keys to dispatch.
|
|
8
|
+
*/
|
|
2
9
|
import type { InjectFace, PropsLocale, PropsRenderSlots, PropsRuntime } from '@deepseek-ai/dsh-client-ui-slots';
|
|
3
|
-
|
|
4
|
-
export interface ConfigurablePluginsTabInjected {
|
|
5
|
-
/** How many cards the slot ledger held when the tab registration mounted. */
|
|
6
|
-
cardCount: number;
|
|
7
|
-
}
|
|
10
|
+
import type { ConfigurablePluginsTabFace } from './tab-store.ts';
|
|
8
11
|
/** Props the renderer binds for the configurable tab. */
|
|
9
|
-
export type ConfigurablePluginsTabProps = PropsRuntime<'settings.plugins.tab'> & PropsLocale<'settings.plugins'> & PropsRenderSlots<'settings.plugin.item'> & InjectFace<
|
|
10
|
-
/**
|
|
11
|
-
|
|
12
|
+
export type ConfigurablePluginsTabProps = PropsRuntime<'settings.plugins.tab'> & PropsLocale<'settings.plugins'> & PropsRenderSlots<'settings.plugin.item'> & InjectFace<ConfigurablePluginsTabFace>;
|
|
13
|
+
/**
|
|
14
|
+
* Render cards registered by plugins that expose editable settings.
|
|
15
|
+
* @param props - locale copy, slot rendering, and the namespaces to dispatch.
|
|
16
|
+
* @returns the card list, or the empty line once the Host has answered.
|
|
17
|
+
*/
|
|
18
|
+
export declare function ConfigurablePluginsTab(props: ConfigurablePluginsTabProps): import("react").JSX.Element | null;
|
|
12
19
|
//# sourceMappingURL=ConfigurablePluginsTab.d.ts.map
|
|
@@ -10,7 +10,8 @@
|
|
|
10
10
|
*/
|
|
11
11
|
import type { ClientContext } from '@deepseek-ai/dsh-client-runtime/client';
|
|
12
12
|
export type { PluginsSettingsSectionInjected, PluginsSettingsSectionProps } from './PluginsSettingsSection.tsx';
|
|
13
|
-
export type {
|
|
13
|
+
export type { ConfigurablePluginsTabProps } from './ConfigurablePluginsTab.tsx';
|
|
14
|
+
export type { ConfigurablePluginsTabFace, ConfigurablePluginsTabState } from './tab-store.ts';
|
|
14
15
|
export type { PluginCardProps } from './PluginCard.tsx';
|
|
15
16
|
export type { SettingsPluginItemOwnerProps } from './slot-contract.ts';
|
|
16
17
|
export type { FieldProps } from './fields.tsx';
|
|
@@ -1,20 +1,23 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* The `settings.plugin.item` slot type — one plugin's card inside the
|
|
3
|
-
*
|
|
4
|
-
* A card draws its own internals; the
|
|
5
|
-
*
|
|
2
|
+
* The `settings.plugin.item` slot type — one plugin's card inside the
|
|
3
|
+
* configurable-plugins tab, keyed by the settings namespace the card edits.
|
|
4
|
+
* Options: `key` (the namespace). A card draws its own internals; the tab only
|
|
5
|
+
* decides which namespaces to dispatch and stacks what comes back.
|
|
6
6
|
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
7
|
+
* Keying on the namespace is what lets a plugin distributed outside this
|
|
8
|
+
* repository contribute a card: it registers its own settings namespace on the
|
|
9
|
+
* Host and its own card under that key in the browser, and the tab pairs the
|
|
10
|
+
* two without ever learning what the namespace means.
|
|
11
|
+
*
|
|
12
|
+
* TYPE HOME RATIONALE: the tab declares this slot at runtime, and a plugin
|
|
13
|
+
* registering its own card already depends on this package for the slot's
|
|
14
|
+
* declaration. The type therefore lives with its declarer.
|
|
12
15
|
*/
|
|
13
16
|
declare module '@deepseek-ai/dsh-client-ui-slots' {
|
|
14
17
|
interface SlotMap {
|
|
15
18
|
/** One plugin's card inside the plugin configuration section (see module JSDoc). */
|
|
16
19
|
'settings.plugin.item': {
|
|
17
|
-
kind: '
|
|
20
|
+
kind: 'keyed';
|
|
18
21
|
scope: 'root';
|
|
19
22
|
owner: SettingsPluginItemOwnerProps;
|
|
20
23
|
};
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The configurable-plugins tab's card list.
|
|
3
|
+
*
|
|
4
|
+
* The tab dispatches its slot by settings namespace, so what it renders is
|
|
5
|
+
* the intersection of two ledgers: the namespaces the Host serves and the
|
|
6
|
+
* cards registered into `settings.plugin.item`. A served namespace no card
|
|
7
|
+
* claims renders nothing — another surface owns it, or this deployment ships
|
|
8
|
+
* no browser half for it — and a card whose namespace the Host does not serve
|
|
9
|
+
* is never dispatched, so a plugin this deployment did not compose leaves no
|
|
10
|
+
* trace and does not count toward the empty line.
|
|
11
|
+
*/
|
|
12
|
+
import type { IApiClient } from '@deepseek-ai/dsh-client-connection/client';
|
|
13
|
+
import type { StoredEntry } from '@deepseek-ai/dsh-client-ui-slots';
|
|
14
|
+
import { type SnapshotStore } from '@deepseek-ai/dsh-client-runtime/client';
|
|
15
|
+
/** What the section renders. */
|
|
16
|
+
export interface ConfigurablePluginsTabState {
|
|
17
|
+
/**
|
|
18
|
+
* Whether the Host has answered once. The empty line waits for it: an
|
|
19
|
+
* unanswered read is not the same statement as "this deployment configures
|
|
20
|
+
* no plugin", and saying the second while the first is true would flash a
|
|
21
|
+
* wrong answer on every open.
|
|
22
|
+
*/
|
|
23
|
+
loaded: boolean;
|
|
24
|
+
/**
|
|
25
|
+
* Namespaces to dispatch, in the order their cards registered, narrowed to
|
|
26
|
+
* those the Host serves. Card registration order rather than the Host's
|
|
27
|
+
* description order: the latter follows plugin activation, which async
|
|
28
|
+
* settings injection can reorder between boots, and a settings page whose
|
|
29
|
+
* cards move between visits is worse than one whose order a registrant
|
|
30
|
+
* chose.
|
|
31
|
+
*/
|
|
32
|
+
namespaces: string[];
|
|
33
|
+
}
|
|
34
|
+
/** The registration-side face the tab's slot entry injects. */
|
|
35
|
+
export interface ConfigurablePluginsTabFace {
|
|
36
|
+
hooks: {
|
|
37
|
+
/** Section snapshot bound by the renderer as usePluginConfigSection. */
|
|
38
|
+
configurablePlugins: SnapshotStore<ConfigurablePluginsTabState>;
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
/** Reads the served namespaces and pairs them with the cards that claim them. */
|
|
42
|
+
export declare class ConfigurablePluginsTabController {
|
|
43
|
+
private readonly api;
|
|
44
|
+
private readonly entries;
|
|
45
|
+
private readonly store;
|
|
46
|
+
/** Last Host answer; kept so a slot mutation republishes without a wire read. */
|
|
47
|
+
private served;
|
|
48
|
+
private loaded;
|
|
49
|
+
private generation;
|
|
50
|
+
private disposed;
|
|
51
|
+
/**
|
|
52
|
+
* @param api - settings wire face.
|
|
53
|
+
* @param entries - reads the cards currently registered into the section's slot.
|
|
54
|
+
*/
|
|
55
|
+
constructor(api: Pick<IApiClient, 'settings'>, entries: () => readonly StoredEntry[]);
|
|
56
|
+
/** Opaque read of {@link disposed}: control flow cannot narrow it across awaits. */
|
|
57
|
+
private isDisposed;
|
|
58
|
+
/**
|
|
59
|
+
* Re-read the served namespaces from the Host and republish.
|
|
60
|
+
* @returns settlement after the read, or immediately once disposed.
|
|
61
|
+
*/
|
|
62
|
+
load(): Promise<void>;
|
|
63
|
+
/** Republish after the slot ledger changed; a card registered late joins here. */
|
|
64
|
+
refresh(): void;
|
|
65
|
+
/** Stop publishing; an in-flight read settles without touching the store. */
|
|
66
|
+
dispose(): void;
|
|
67
|
+
/**
|
|
68
|
+
* Build the face the tab's slot registration injects.
|
|
69
|
+
* @returns the tab's snapshot source.
|
|
70
|
+
*/
|
|
71
|
+
inject(): ConfigurablePluginsTabFace;
|
|
72
|
+
private publish;
|
|
73
|
+
}
|
|
74
|
+
//# sourceMappingURL=tab-store.d.ts.map
|
package/package.json
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@deepseek-ai/dsh-client-ui-settings-plugins",
|
|
3
3
|
"description": "Plugins settings section with feature-owned tabs and configurable host-plane plugin cards",
|
|
4
|
-
"version": "0.1.0-rc.
|
|
4
|
+
"version": "0.1.0-rc.7",
|
|
5
5
|
"publishConfig": {
|
|
6
|
-
"access": "
|
|
6
|
+
"access": "public"
|
|
7
7
|
},
|
|
8
8
|
"repository": {
|
|
9
9
|
"type": "git",
|
|
@@ -45,30 +45,30 @@
|
|
|
45
45
|
"peerDependencies": {
|
|
46
46
|
"react": "^18.2.0",
|
|
47
47
|
"@deepseek-ai/cordis": "^4.0.1",
|
|
48
|
-
"@deepseek-ai/dsh-api-remotes": "^0.1.0-rc.
|
|
49
|
-
"@deepseek-ai/dsh-client-connection": "^0.1.0-rc.
|
|
50
|
-
"@deepseek-ai/dsh-client-locale": "^0.1.0-rc.
|
|
51
|
-
"@deepseek-ai/dsh-client-runtime": "^0.1.0-rc.
|
|
52
|
-
"@deepseek-ai/dsh-client-ui-primitives": "^0.1.0-rc.
|
|
53
|
-
"@deepseek-ai/dsh-client-ui-
|
|
54
|
-
"@deepseek-ai/dsh-client-ui-
|
|
55
|
-
"@deepseek-ai/dsh-invariants": "^0.1.0-rc.
|
|
56
|
-
"@deepseek-ai/dsh-client-web-react": "^0.1.0-rc.
|
|
48
|
+
"@deepseek-ai/dsh-api-remotes": "^0.1.0-rc.7",
|
|
49
|
+
"@deepseek-ai/dsh-client-connection": "^0.1.0-rc.7",
|
|
50
|
+
"@deepseek-ai/dsh-client-locale": "^0.1.0-rc.7",
|
|
51
|
+
"@deepseek-ai/dsh-client-runtime": "^0.1.0-rc.7",
|
|
52
|
+
"@deepseek-ai/dsh-client-ui-primitives": "^0.1.0-rc.7",
|
|
53
|
+
"@deepseek-ai/dsh-client-ui-settings": "^0.1.0-rc.7",
|
|
54
|
+
"@deepseek-ai/dsh-client-ui-slots": "^0.1.0-rc.7",
|
|
55
|
+
"@deepseek-ai/dsh-invariants": "^0.1.0-rc.7",
|
|
56
|
+
"@deepseek-ai/dsh-client-web-react": "^0.1.0-rc.7"
|
|
57
57
|
},
|
|
58
58
|
"devDependencies": {
|
|
59
59
|
"@types/react": "~18.3.1",
|
|
60
60
|
"react": "^18.2.0",
|
|
61
61
|
"@deepseek-ai/cordis": "^4.0.1",
|
|
62
|
-
"@deepseek-ai/dsh-api-remotes": "^0.1.0-rc.
|
|
63
|
-
"@deepseek-ai/dsh-client-
|
|
64
|
-
"@deepseek-ai/dsh-client-locale": "^0.1.0-rc.
|
|
65
|
-
"@deepseek-ai/dsh-client-
|
|
66
|
-
"@deepseek-ai/dsh-client-test-runtime": "^0.1.0-rc.
|
|
67
|
-
"@deepseek-ai/dsh-client-ui-primitives": "^0.1.0-rc.
|
|
68
|
-
"@deepseek-ai/dsh-client-ui-
|
|
69
|
-
"@deepseek-ai/dsh-client-web-react": "^0.1.0-rc.
|
|
70
|
-
"@deepseek-ai/dsh-client-ui-
|
|
71
|
-
"@deepseek-ai/dsh-invariants": "^0.1.0-rc.
|
|
62
|
+
"@deepseek-ai/dsh-api-remotes": "^0.1.0-rc.7",
|
|
63
|
+
"@deepseek-ai/dsh-client-runtime": "^0.1.0-rc.7",
|
|
64
|
+
"@deepseek-ai/dsh-client-locale": "^0.1.0-rc.7",
|
|
65
|
+
"@deepseek-ai/dsh-client-connection": "^0.1.0-rc.7",
|
|
66
|
+
"@deepseek-ai/dsh-client-test-runtime": "^0.1.0-rc.7",
|
|
67
|
+
"@deepseek-ai/dsh-client-ui-primitives": "^0.1.0-rc.7",
|
|
68
|
+
"@deepseek-ai/dsh-client-ui-settings": "^0.1.0-rc.7",
|
|
69
|
+
"@deepseek-ai/dsh-client-web-react": "^0.1.0-rc.7",
|
|
70
|
+
"@deepseek-ai/dsh-client-ui-slots": "^0.1.0-rc.7",
|
|
71
|
+
"@deepseek-ai/dsh-invariants": "^0.1.0-rc.7"
|
|
72
72
|
},
|
|
73
73
|
"files": [
|
|
74
74
|
"lib/index.js",
|