@deepseek-ai/dsh-client-ui-settings-general 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/client/ui-settings-general/README.md
5
- README.md: c59b77617cfd5848553ba340e97bafe37b7b2a2f
6
- README.zh.md: ea4896284b677a7b430cceb949b53aa6e3a5a242
5
+ README.md: 1d231c2c1de2d8870c6f16e0d993b2387c876e4d
6
+ README.zh.md: 13fe7b9f4a58f0f8836437485333127e76e2410e
package/README.md CHANGED
@@ -1,18 +1,91 @@
1
+ ---
2
+ description: "Settings shell, ownerless copy, and durable product-onboarding namespace for the dsh web client: the General section, trigger chrome, and onboarding ledger projection."
3
+ kind: "package-reference"
4
+ ---
5
+
1
6
  # @deepseek-ai/dsh-client-ui-settings-general
2
7
 
3
8
  English | [中文](README.zh.md)
4
9
 
5
- Settings shell, ownerless copy, and durable product-onboarding namespace. It occupies `sidebar.settings` with the trigger chrome and modal settings panel, projects the `settings.section` ledger into the navigation and the `settings.onboarding` ledger into one mounted step at a time, and registers everything on the Settings pages that belongs to no single feature — the trigger/header/close chrome content, the local configuration-file action, the General section and its `settings.general.item` slot, and the `settings` dictionaries. The slot types it renders into belong to ui-settings, the settings domain base; only the shell's own contract types live here, because they reference ui-sidebar's slot type and the base layer must depend on no `ui-*` package. Feature-owned rows (Permission, Language, Appearance), sections (Models), and conditional onboarding steps stay with their feature packages.
10
+ ## Summary
11
+
12
+ `dsh-client-ui-settings-general` is the settings shell of the dsh web client: the Settings panel opens from the sidebar's bottom control, a connection-failure indicator beside that control offers immediate recovery, the navigation is built from the sections features contribute, and first-run users are walked through one onboarding step at a time. It also registers everything on the Settings pages that belongs to no single feature: the trigger/header/close chrome content, the local configuration-file action, the General section and its `settings.general.item` slot, and the `settings` dictionaries. Feature-owned rows (Permission, Language, Appearance), sections (Models), and conditional onboarding steps stay with their feature packages; the shell itself ships no onboarding copy of its own.
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
+ Users reach the shell through the sidebar's bottom Settings control; feature plugins contribute their pages and onboarding steps through the slot ledgers this shell projects. After a Host connection failure, a pale-yellow **Disconnected** action appears to the right of Settings. Automatic recovery shows **Connecting** with one to three dots advancing every 500ms. Hover or keyboard focus changes either yellow label to **Reconnect now** without changing its background; press feedback stays within the warning palette, and selecting it starts retry 1 immediately. Recovery changes the region to pale-green **Connected** for two seconds before it disappears. The icon, left-aligned text origin, height, and width remain fixed across every visible state. Initial startup and uninterrupted healthy operation remain silent. The shell renders the modal panel, the navigation built from `settings.section` entries, and exactly one mounted onboarding step at a time.
29
+
30
+ ### The General section
31
+
32
+ The General section holds rows registered into `settings.general.item` by feature packages — it has no built-in rows. Feature plugins own the row copy and behavior; the shell only provides the section and its slot. The Appearance row, for example, lives in ui-theme.
33
+
34
+ ### Opening the configuration file
35
+
36
+ On a loopback browser, the shell renders **Open configuration file** only when the Host confirms that a provider-owned local document can be prepared. The action opens that document in the native text editor (bypassing the browser file association on macOS). Remote browsers never register the action and never issue the privileged settings read.
37
+
38
+ ### Onboarding steps
39
+
40
+ The onboarding ledger projects in ascending order and mounts exactly one step at a time. Registrants own durable completion, capability readiness, copy, mutations, and their visible wrapper, so independently registered flows cannot stack and the shell does not become a second configuration fact source. Visible steps own their dialog chrome and app-root `inert` lifecycle.
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
+ The shell owns the chrome and the projections; every piece of content and copy belongs to a registrant.
51
+
52
+ ### Ledger projections
6
53
 
7
- The shell ships no onboarding copy of its own all text arrives from registrants. Nav labels may be locale-following thunks, so the nav projection resolves them through `resolveSlotLabel` and re-renders on the section ledger bump or the locale revision (an optional `ctx.get('locale')` read; no hard locale dependency). The onboarding ledger projects in ascending order and mounts exactly one step at a time. Visible steps own their dialog chrome and app-root `inert` lifecycle; a mounted step still resolving private facts renders null, so nothing paints or blocks while it decides. The active registrant receives its id, `complete()`, and an `openSection(id)` callback; completing or skipping transfers ownership to the next entry. Registrants own durable completion, capability readiness, copy, mutations, and their visible wrapper, so independently registered flows cannot stack and the shell does not become a second configuration fact source.
54
+ The navigation is a projection of the `settings.section` ledger; nav labels may be locale-following thunks, resolved through `resolveSlotLabel` and re-rendered on the section ledger bump or the locale revision (an optional `ctx.get('locale')` read; no hard locale dependency). The onboarding ledger projects in ascending order; the active registrant receives its id, `complete()`, and an `openSection(id)` callback, and completing or skipping transfers ownership to the next entry.
8
55
 
9
- A loopback browser loads the provider's `hasDocument` capability through `settings.describe` and renders **Open configuration file** only when the Host confirms that a provider-owned local document can be prepared. The action sends the pathless, loopback-only `settings.openDocument` request; the Host resolves the provider path again, materializes an absent document, and hands it to a native text editor (`open -t` on macOS, bypassing a browser file association; the desktop file association on Linux and Windows; Windows association after `wslpath -w` translation on WSL). Open failures keep the action available and render a localized error. Reopening the dialog or reconnecting refreshes availability after a transient read failure or Host topology change. Remote browsers never register the action and never issue the privileged settings read.
56
+ ### Connection recovery
10
57
 
11
- The Host half registers `ui-onboarding` in the user-settings seam. The welcome step contributed by `ui-settings-models` reads and writes its `welcomeNoticeVersion` through the existing public settings boundary; the shell itself remains policy-free.
58
+ The shell is an explicit recovery consumer, so it injects Connection directly rather than adding lifecycle controls to `ctx.remote`. Its private hooks compartment binds `ctx.connection.state`, while the component receives only the selected state and an injected callback for `ctx.connection.reconnect()`. `ConnectionIndicator` owns the inline presentation and receives all visible and accessible copy from the `settings` locale namespace; the shell owns the two-second recovered-state timer.
12
59
 
60
+ ### Document availability
61
+
62
+ On a loopback page, the Client loads the provider's `hasDocument` capability through `settings/describe` and renders **Open configuration file** only when the Host confirms that a provider-owned local document can be prepared. The action calls the pathless, browser-authenticated `settings/openSettingsDocument` Remote; the Host resolves the provider path again, materializes an absent document, and hands it to a native text editor (`open -t` on macOS, bypassing a browser file association; the desktop file association on Linux and Windows; Windows association after `wslpath -w` translation on WSL). Open failures keep the action available and render a localized error. Reopening the dialog or reconnecting refreshes availability after a transient read failure or Host topology change. Non-loopback pages retain the Client policy that withholds this native action and its settings read.
63
+
64
+ ### Host half
65
+
66
+ The Host half registers `ui-onboarding` in the user-settings seam. The welcome step contributed by ui-settings-models reads and writes its `welcomeNoticeVersion` through the existing public settings boundary; the shell itself remains policy-free.
67
+
68
+ </details>
69
+
70
+ -----
71
+
72
+ <a id="further-exploration"></a>
73
+ ## Further Exploration
74
+
75
+ These pages cover the settings surface family and the composition model.
76
+
77
+ - [ui-settings](../ui-settings/README.md) — the domain base whose slot types and scope service this shell builds on.
78
+ - [ui-sidebar](../ui-sidebar/README.md) — the sidebar shell hosting the `sidebar.settings` seat.
79
+ - [ui-settings-models](../ui-settings-models/README.md) — the feature package contributing the DeepSeek onboarding step.
80
+ - [settings](../../settings/README.md) — the durable user-settings seam and its file provider.
81
+ - [Slot system standard](../../../.agents/notes/implemented/architecture/2026-07-22-slot-type-chain-implementation.md) — the composition model behind the ledgers.
82
+
83
+ -----
84
+
85
+ <a id="model-experience"></a>
13
86
  ## Model Experience
14
87
 
15
- None, as the plugin renders browser settings UI; nothing here reaches a model request.
88
+ None, as the package is a browser-side UI plugin layer that registers nothing model-facing.
16
89
 
17
90
  #### KV Cache effect
18
91
 
@@ -20,4 +93,19 @@ None; this package neither assembles nor sends a provider request.
20
93
 
21
94
  ## Known Limitations and Deferred Work
22
95
 
23
- - The General section has no built-in rows; each row appears only when its owning feature plugin is mounted.
96
+ <a id="known-limitations-and-deferred-work"></a>
97
+
98
+
99
+ These limits define what the shell itself provides versus what features must supply; they are current package constraints.
100
+
101
+ - **The General section has no built-in rows** — each row appears only when its owning feature plugin is mounted; the shell cannot fill the section alone.
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,23 +1,111 @@
1
+ ---
2
+ description: "dsh Web 客户端的设置外壳、无特定功能归属文案与持久化产品引导命名空间:「通用」分区、触发控件界面框架与引导账本投影。"
3
+ kind: "package-reference"
4
+ ---
5
+
1
6
  # @deepseek-ai/dsh-client-ui-settings-general
2
7
 
3
8
  [English](README.md) | 中文
4
9
 
5
- 设置外壳、无特定功能归属文案与持久化产品引导 namespace。它以触发控件和模态设置面板占用 `sidebar.settings`,把 `settings.section` 账本投影成导航、把 `settings.onboarding` 账本投影成每次只挂载一个步骤的引导流程,并在设置页面上注册所有不属于单一功能的内容:触发器、标题栏与关闭控件内容、本地配置文件操作,「通用」分区及其 `settings.general.item` slot,以及 `settings` 字典。它渲染进的那些 slot 类型归 ui-settings——设置领域底座——所有;只有外壳自身的契约类型放在这里,因为它们引用 ui-sidebar 的 slot 类型,而底座不得依赖任何 `ui-*` 包。归具体功能所有的行(「权限」、「语言」、「外观」)、分区(「模型」)和条件式首次使用引导步骤仍由各自的功能包提供。
10
+ ## 概述
11
+
12
+ `dsh-client-ui-settings-general` 是 dsh Web 客户端的设置外壳:Settings 面板从侧边栏底部的控件打开,该控件旁的连接故障指示器提供即时恢复操作;导航由各功能贡献的分区构建;首次运行的用户一次只走一个引导步骤。它还注册设置页面上所有不属于单一功能的内容:触发器、标题栏与关闭控件界面框架、「本地配置文件」操作、「通用」分区及其 `settings.general.item` slot,以及 `settings` 字典。归具体功能所有的行(「权限」、「语言」、「外观」)、分区(「模型」)与条件式首次使用引导步骤仍由各自的功能包提供;外壳本身不自带任何引导文案。
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
+ 用户通过侧边栏底部的 Settings 控件进入外壳;功能插件通过本外壳所投影的 slot 账本贡献自己的页面与引导步骤。Host 连接失败后,浅黄色的**连接异常**操作会出现在 Settings 右侧;自动恢复期间显示**连接中**,其后一至三个点每 500ms 前进一次。鼠标悬浮或键盘聚焦任一黄色状态时,只有文案变为**立即重连**,背景保持不变;按压反馈留在黄色色阶内,选中后立即从 retry 1 开始。恢复后该区域变为浅绿色的**连接成功**,驻留 2 秒再消失。所有可见状态的文字都左对齐,且图标、文字起点、高度和宽度保持固定。首次启动与未曾中断的健康连接保持静默。外壳渲染模态面板、由 `settings.section` 条目构建的导航,以及每次只挂载一个的引导步骤。
29
+
30
+ ### 「通用」分区
31
+
32
+ 「通用」分区承载由功能包注册进 `settings.general.item` 的行——它没有内置行。功能插件拥有行文案与行为;外壳只提供分区及其 slot。例如「外观」行位于 ui-theme。
33
+
34
+ ### 打开配置文件
35
+
36
+ 在回环浏览器上,只有当宿主确认可准备好一份由提供方持有的本地文档时,外壳才渲染**打开配置文件**。该操作会在原生文本编辑器中打开该文档(macOS 上绕过浏览器文件关联)。远程浏览器从不注册该操作,也从不发起这项特权设置读取。
37
+
38
+ ### 引导步骤
39
+
40
+ 引导账本按升序投影,每次只挂载一个步骤。注册方持有持久化完成状态、能力就绪状态、文案、变更操作与可见包装,因此独立注册的流程无法堆叠,外壳也不会成为第二个配置事实来源。可见步骤自行持有弹窗框架与应用根节点 `inert` 生命周期。
41
+
42
+ -----
43
+
44
+ <a id="understand-the-implementation"></a>
45
+ ## 理解实现
46
+
47
+ <details>
48
+ <summary>实现细节——点击展开</summary>
49
+
50
+ 外壳拥有界面框架与投影;每段内容与文案都属于某个注册方。
51
+
52
+ ### 账本投影
6
53
 
7
- 外壳不自带引导文案:所有文本都来自注册方。导航 label 可以是跟随语言的 thunk,因此导航投影经 `resolveSlotLabel` 解析,并在分区账本更新或 locale revision 变化时重新渲染(`ctx.get('locale')` 可选读取,无硬 locale 依赖)。首次使用引导记录按升序投影,每次只挂载一个步骤;可见步骤自行持有弹窗框架和应用根节点 `inert` 生命周期。已挂载但仍在判定私有事实的步骤渲染 null,因此判定期间不绘制也不阻塞任何内容。当前注册方会收到该条目的 id、`complete()` `openSection(id)` 回调;完成或跳过当前步骤后,所有权转交给下一项。持久化完成状态、能力就绪状态、文案、变更操作以及可见包装均由注册方持有,因此独立注册的流程无法堆叠,外壳也不会成为第二个配置事实来源。
54
+ 导航是 `settings.section` 账本的投影;导航 label 可以是跟随语言的 thunk,经 `resolveSlotLabel` 解析,并在分区账本更新或 locale revision 变化时重新渲染(`ctx.get('locale')` 可选读取,无硬 locale 依赖)。引导账本按升序投影;当前注册方会收到该条目的 id、`complete()` `openSection(id)` 回调,完成或跳过当前步骤后,所有权转交给下一项。
8
55
 
9
- 回环浏览器通过 `settings.describe` 加载提供方的 `hasDocument` 能力,且只有在 Host 确认可准备好一份由提供方持有的本地文档时才渲染**打开配置文件**。该操作发送无路径参数且仅限回环访问的 `settings.openDocument` 请求;Host 会再次解析提供方路径、在文档缺失时将其创建出来,并交给原生文本编辑器(macOS 上使用 `open -t`,绕过浏览器文件关联;Linux 和 Windows 上使用桌面文件关联;WSL 上经 `wslpath -w` 转换后使用 Windows 文件关联)。打开失败时该操作仍可使用,并渲染本地化错误。临时读取失败或 Host 拓扑变化后,重新打开对话框或重新连接会刷新可用性。远程浏览器从不注册该操作,也从不发起这项特权设置读取。
56
+ ### 连接恢复
57
+
58
+ 外壳是明确的恢复功能消费方,因此直接注入 Connection,而不把生命周期控制放进 `ctx.remote`。它的私有 hooks compartment 绑定 `ctx.connection.state`,组件只接收选出的状态与调用 `ctx.connection.reconnect()` 的注入回调。`ConnectionIndicator` 拥有内联展示并从 `settings` locale namespace 接收全部可见与无障碍文案;2 秒恢复状态计时器归外壳所有。
59
+
60
+ ### 文档可用性
61
+
62
+ 在 loopback 页面上,Client 通过 `settings/describe` 加载提供方的 `hasDocument` 能力,且只有在 Host 确认可准备好一份由提供方持有的本地文档时才渲染配置文件操作。该操作调用无路径参数且经浏览器认证的 `settings/openSettingsDocument` Remote;Host 会再次解析提供方路径、在文档缺失时将其创建出来,并交给原生文本编辑器(macOS 上使用 `open -t`,绕过浏览器文件关联;Linux 和 Windows 上使用桌面文件关联;WSL 上经 `wslpath -w` 转换后使用 Windows 文件关联)。打开失败时该操作仍可使用,并渲染本地化错误。临时读取失败或 Host 拓扑变化后,重新打开对话框或重新连接会刷新可用性。非 loopback 页面保留 Client 策略,不提供该原生操作及其 settings 读取。
63
+
64
+ ### 宿主端
10
65
 
11
66
  宿主端在用户设置 seam 中注册 `ui-onboarding`。`ui-settings-models` 提供的欢迎步骤通过既有公开 settings 边界读写其中的 `welcomeNoticeVersion`;外壳本身仍不持有产品策略。
12
67
 
68
+ </details>
69
+
70
+ -----
71
+
72
+ <a id="further-exploration"></a>
73
+ ## 进一步探索
74
+
75
+ 以下页面覆盖设置界面家族与组合模型。
76
+
77
+ - [ui-settings](../ui-settings/README.zh.md)——本外壳所依赖 slot 类型与 scope 服务所在的领域底座。
78
+ - [ui-sidebar](../ui-sidebar/README.zh.md)——承载 `sidebar.settings` 席位的侧边栏外壳。
79
+ - [ui-settings-models](../ui-settings-models/README.zh.md)——贡献 DeepSeek 引导步骤的功能包。
80
+ - [settings](../../settings/README.zh.md)——持久化用户设置 seam 及其文件提供方。
81
+ - [slot 系统标准](../../../.agents/notes/implemented/architecture/2026-07-22-slot-type-chain-implementation.zh.md)——账本背后的组合模型。
82
+
83
+ -----
84
+
85
+ <a id="model-experience"></a>
13
86
  ## 模型体验
14
87
 
15
- 无。该插件渲染浏览器设置 UI;这里没有任何内容进入模型请求。
88
+ 无。该包是浏览器端 UI 插件层,不注册任何面向模型的内容。
16
89
 
17
90
  #### KV Cache 影响
18
91
 
19
92
  无;该包既不组装也不发送提供方请求。
20
93
 
21
- ## 已知限制与暂缓事项
94
+ ## 已知限制与延期工作
95
+
96
+ <a id="known-limitations-and-deferred-work"></a>
97
+
98
+
99
+ 这些限制说明外壳自身提供什么、功能包必须提供什么;它们是当前包约束。
100
+
101
+ - **「通用」分区没有内置行**:每一行仅在其所属功能插件挂载时出现;外壳单独无法填满该分区。
102
+
103
+ <a id="dev-note"></a>
104
+ ### 开发备注
105
+
106
+ <details>
107
+ <summary>维护者的工作上下文——点击展开</summary>
108
+
109
+ 无。
22
110
 
23
- - 「通用」分区没有内置行;每一行仅在其所属功能插件挂载时出现。
111
+ </details>
package/lib/client.js CHANGED
@@ -8,7 +8,7 @@ window.__ModuleLoader__.load({
8
8
  let react_jsx_runtime = require("react/jsx-runtime");
9
9
  let react = require("react");
10
10
  let _deepseek_ai_dsh_client_ui_primitives = require("@deepseek-ai/dsh-client-ui-primitives");
11
- let _deepseek_ai_dsh_client_runtime_client = require("@deepseek-ai/dsh-client-runtime/client");
11
+ let _deepseek_ai_dsh_client_store = require("@deepseek-ai/dsh-client-store");
12
12
  //#region ../../../node_modules/.pnpm/clsx@2.1.1/node_modules/clsx/dist/clsx.mjs
13
13
  function r(e) {
14
14
  var t, f, n = "";
@@ -25,7 +25,7 @@ window.__ModuleLoader__.load({
25
25
  }
26
26
  //#endregion
27
27
  //#region \0dsh-css:/home/runner/work/deepseek-harness/deepseek-harness/packages/client/ui-settings-general/src/client/SettingsRoot.module.css.mjs
28
- const css$3 = ".VOzbGW_trigger{box-sizing:border-box;cursor:pointer;width:calc(100% + 4px);height:42px;color:var(--dsw-alias-label-primary);background:0 0;border:none;border-radius:12px;flex:none;align-items:center;gap:8px;margin:4px -2px;padding:0 10px 0 8px;font-family:inherit;font-size:14px;line-height:22px;display:flex;overflow:hidden}.VOzbGW_trigger:hover{background:var(--dsw-alias-interactive-bg-hover)}.VOzbGW_trigger.VOzbGW_rail{border-radius:50%;justify-content:center;gap:0;width:36px;height:36px;margin:8px 0 10px;padding:0}.VOzbGW_triggerLabel{white-space:nowrap;overflow:hidden}.VOzbGW_overlay{z-index:1000;justify-content:center;align-items:center;display:flex;position:fixed;inset:0}.VOzbGW_mask{background:var(--dsw-alias-bg-mask-1);backdrop-filter:var(--dsw-mask-blur);position:absolute;inset:0}.VOzbGW_panel{z-index:1;background:var(--dsw-alias-bg-layer-2);width:800px;max-width:calc(100vw - 48px);height:min(800px,100vh - 48px);box-shadow:var(--dsw-shadow-lv3);--dsh-scrollbar-thumb:var(--dsw-alias-scrollbar-bg-l2);--dsh-scrollbar-thumb-hover:var(--dsw-alias-scrollbar-hover-l2);border-radius:24px;display:flex;position:relative;overflow:hidden}.VOzbGW_nav{box-sizing:border-box;flex-direction:column;flex:none;gap:18px;width:188px;padding:22px 12px 0;display:flex}.VOzbGW_navTitle{color:var(--dsw-alias-label-primary);padding:0 12px;font-size:16px;font-weight:500;line-height:24px}.VOzbGW_navList{flex-direction:column;gap:4px;display:flex}.VOzbGW_navCell{box-sizing:border-box;cursor:pointer;height:40px;color:var(--dsw-alias-label-primary);text-align:left;background:0 0;border:none;border-radius:12px;align-items:center;gap:8px;padding:9px 16px 9px 12px;font-family:inherit;font-size:14px;font-weight:400;line-height:22px;display:flex}.VOzbGW_navCell:hover{background:var(--dsw-specific-sidebar-nav-item-hover)}.VOzbGW_navCell.VOzbGW_active{background:var(--dsw-specific-sidebar-nav-item-active)}.VOzbGW_navIcon{flex:none}.VOzbGW_navLabel{white-space:nowrap;text-overflow:ellipsis;flex:1;min-width:0;overflow:hidden}.VOzbGW_content{flex-direction:column;flex:1;min-width:0;display:flex}.VOzbGW_header{box-sizing:border-box;flex:none;justify-content:space-between;align-items:flex-start;gap:8px;height:54px;padding:20px 14px 8px 10px;display:flex}.VOzbGW_actions{justify-content:flex-end;align-items:center;gap:8px;min-width:0;margin-left:auto;display:flex}.VOzbGW_close{cursor:pointer;width:28px;height:28px;color:var(--dsw-alias-label-primary);background:0 0;border:none;border-radius:28px;justify-content:center;align-items:center;padding:0;display:inline-flex}.VOzbGW_close:hover{background:var(--dsw-alias-interactive-bg-hover)}.VOzbGW_options{flex:1;min-height:0;padding:0 24px 24px;overflow-y:auto}.VOzbGW_hiddenLabel{clip:rect(0 0 0 0);white-space:nowrap;width:1px;height:1px;position:absolute;overflow:hidden}";
28
+ const css$3 = ".VOzbGW_triggerRow{flex:none;align-items:center;gap:8px;width:calc(100% + 4px);margin:4px -2px;display:flex}.VOzbGW_triggerRow.VOzbGW_railRow{width:36px;margin:8px 0 10px}.VOzbGW_trigger{box-sizing:border-box;cursor:pointer;width:auto;min-width:0;height:42px;color:var(--dsw-alias-label-primary);background:0 0;border:none;border-radius:12px;flex:1;align-items:center;gap:8px;margin:0;padding:0 10px 0 8px;font-family:inherit;font-size:14px;line-height:22px;display:flex;overflow:hidden}.VOzbGW_trigger:hover{background:var(--dsw-alias-interactive-bg-hover)}.VOzbGW_trigger.VOzbGW_rail{border-radius:50%;flex:none;justify-content:center;gap:0;width:36px;height:36px;margin:0;padding:0}.VOzbGW_triggerLabel{white-space:nowrap;overflow:hidden}.VOzbGW_overlay{z-index:1000;justify-content:center;align-items:center;display:flex;position:fixed;inset:0}.VOzbGW_mask{background:var(--dsw-alias-bg-mask-1);backdrop-filter:var(--dsw-mask-blur);position:absolute;inset:0}.VOzbGW_panel{z-index:1;background:var(--dsw-alias-bg-layer-2);width:800px;max-width:calc(100vw - 48px);height:min(800px,100vh - 48px);box-shadow:var(--dsw-shadow-lv3);--dsh-scrollbar-thumb:var(--dsw-alias-scrollbar-bg-l2);--dsh-scrollbar-thumb-hover:var(--dsw-alias-scrollbar-hover-l2);border-radius:24px;display:flex;position:relative;overflow:hidden}.VOzbGW_nav{box-sizing:border-box;flex-direction:column;flex:none;gap:18px;width:188px;padding:22px 12px 0;display:flex}.VOzbGW_navTitle{color:var(--dsw-alias-label-primary);padding:0 12px;font-size:16px;font-weight:500;line-height:24px}.VOzbGW_navList{flex-direction:column;gap:4px;display:flex}.VOzbGW_navCell{box-sizing:border-box;cursor:pointer;height:40px;color:var(--dsw-alias-label-primary);text-align:left;background:0 0;border:none;border-radius:12px;align-items:center;gap:8px;padding:9px 16px 9px 12px;font-family:inherit;font-size:14px;font-weight:400;line-height:22px;display:flex}.VOzbGW_navCell:hover{background:var(--dsw-specific-sidebar-nav-item-hover)}.VOzbGW_navCell.VOzbGW_active{background:var(--dsw-specific-sidebar-nav-item-active)}.VOzbGW_navIcon{flex:none}.VOzbGW_navLabel{white-space:nowrap;text-overflow:ellipsis;flex:1;min-width:0;overflow:hidden}.VOzbGW_content{flex-direction:column;flex:1;min-width:0;display:flex}.VOzbGW_header{box-sizing:border-box;flex:none;justify-content:space-between;align-items:flex-start;gap:8px;height:54px;padding:20px 14px 8px 10px;display:flex}.VOzbGW_actions{justify-content:flex-end;align-items:center;gap:8px;min-width:0;margin-left:auto;display:flex}.VOzbGW_close{cursor:pointer;width:28px;height:28px;color:var(--dsw-alias-label-primary);background:0 0;border:none;border-radius:28px;justify-content:center;align-items:center;padding:0;display:inline-flex}.VOzbGW_close:hover{background:var(--dsw-alias-interactive-bg-hover)}.VOzbGW_options{flex:1;min-height:0;padding:0 24px 24px;overflow-y:auto}.VOzbGW_hiddenLabel{clip:rect(0 0 0 0);white-space:nowrap;width:1px;height:1px;position:absolute;overflow:hidden}";
29
29
  const tagId$3 = "@deepseek-ai/dsh-client-ui-settings-general/SettingsRoot.module.css";
30
30
  if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$3) + "]") === null) {
31
31
  const tag = document.createElement("style");
@@ -52,8 +52,10 @@ window.__ModuleLoader__.load({
52
52
  "overlay": "VOzbGW_overlay",
53
53
  "panel": "VOzbGW_panel",
54
54
  "rail": "VOzbGW_rail",
55
+ "railRow": "VOzbGW_railRow",
55
56
  "trigger": "VOzbGW_trigger",
56
- "triggerLabel": "VOzbGW_triggerLabel"
57
+ "triggerLabel": "VOzbGW_triggerLabel",
58
+ "triggerRow": "VOzbGW_triggerRow"
57
59
  };
58
60
  //#endregion
59
61
  //#region lib/types/client/SettingsRoot.js
@@ -69,6 +71,7 @@ window.__ModuleLoader__.load({
69
71
  * sessions-derived empty-Hero fact is active. Visible dialog chrome belongs
70
72
  * to the step, so a mounted-but-deciding step paints nothing here.
71
73
  */
74
+ const RECOVERY_CONFIRMATION_MS = 2e3;
72
75
  /** Nav glyph by section id; unknown ids fall back to the settings gear. */
73
76
  function navIcon(id) {
74
77
  if (id === "models") return (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconDataOutline16, {
@@ -173,19 +176,28 @@ window.__ModuleLoader__.load({
173
176
  * @returns the settings shell element tree.
174
177
  */
175
178
  function SettingsRoot(props) {
176
- const { wide, useSections, useOnboardingSteps, useSessions, renderSlot } = props;
179
+ const { wide, reconnect, useConnectionState, useSections, useOnboardingSteps, useSessions, renderSlot, t } = props;
177
180
  const [open, setOpen] = (0, react.useState)(false);
178
181
  const [activeId, setActiveId] = (0, react.useState)(void 0);
179
182
  const [completedOnboarding, setCompletedOnboarding] = (0, react.useState)(() => /* @__PURE__ */ new Set());
183
+ const [showRecovery, setShowRecovery] = (0, react.useState)(false);
184
+ const triggerButton = (0, react.useRef)(null);
185
+ const wasOpen = (0, react.useRef)(open);
180
186
  const close = (0, react.useCallback)(() => {
181
187
  setOpen(false);
182
188
  setActiveId(void 0);
183
189
  }, []);
190
+ (0, react.useEffect)(() => {
191
+ if (wasOpen.current && !open) triggerButton.current?.focus();
192
+ wasOpen.current = open;
193
+ }, [open]);
184
194
  const openSection = (0, react.useCallback)((id) => {
185
195
  setActiveId(id);
186
196
  setOpen(true);
187
197
  }, []);
188
198
  const rows = useSections((s) => s);
199
+ const connectionState = useConnectionState((state) => state);
200
+ const previousConnectionState = (0, react.useRef)(connectionState);
189
201
  const onboardingSteps = useOnboardingSteps((s) => s);
190
202
  const onboardingActive = useSessions((state) => state.phase === "ready" && (state.current === void 0 || state.byId[state.current]?.blank === true));
191
203
  const onboardingStep = onboardingActive ? onboardingSteps.find((step) => !completedOnboarding.has(step.id)) : void 0;
@@ -193,22 +205,55 @@ window.__ModuleLoader__.load({
193
205
  if (onboardingActive) return;
194
206
  setCompletedOnboarding(/* @__PURE__ */ new Set());
195
207
  }, [onboardingActive]);
208
+ (0, react.useLayoutEffect)(() => {
209
+ const previous = previousConnectionState.current;
210
+ previousConnectionState.current = connectionState;
211
+ if (connectionState !== "connected") {
212
+ setShowRecovery(false);
213
+ return;
214
+ }
215
+ if (previous !== "disconnected" && previous !== "connecting") return;
216
+ setShowRecovery(true);
217
+ const timeout = window.setTimeout(() => {
218
+ setShowRecovery(false);
219
+ }, RECOVERY_CONFIRMATION_MS);
220
+ return () => {
221
+ window.clearTimeout(timeout);
222
+ };
223
+ }, [connectionState]);
196
224
  const completeOnboardingStep = (0, react.useCallback)((id) => {
197
225
  setCompletedOnboarding((previous) => {
198
226
  if (previous.has(id)) return previous;
199
227
  return new Set([...previous, id]);
200
228
  });
201
229
  }, []);
230
+ let connectionIndicator;
231
+ if (connectionState === "disconnected") connectionIndicator = "disconnected";
232
+ else if (connectionState === "connecting") connectionIndicator = "connecting";
233
+ else if (showRecovery) connectionIndicator = "recovered";
202
234
  return (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
203
- (0, react_jsx_runtime.jsx)("button", {
204
- type: "button",
205
- className: clsx(SettingsRoot_module_css_default.trigger, !wide && SettingsRoot_module_css_default.rail),
206
- "aria-haspopup": "dialog",
207
- "aria-expanded": open,
208
- onClick: () => {
209
- setOpen(true);
210
- },
211
- children: renderSlot("settings.trigger", { wide })
235
+ (0, react_jsx_runtime.jsxs)("div", {
236
+ className: clsx(SettingsRoot_module_css_default.triggerRow, !wide && SettingsRoot_module_css_default.railRow),
237
+ children: [(0, react_jsx_runtime.jsx)("button", {
238
+ ref: triggerButton,
239
+ type: "button",
240
+ className: clsx(SettingsRoot_module_css_default.trigger, !wide && SettingsRoot_module_css_default.rail),
241
+ "aria-haspopup": "dialog",
242
+ "aria-expanded": open,
243
+ onClick: () => {
244
+ setOpen(true);
245
+ },
246
+ children: renderSlot("settings.trigger", { wide })
247
+ }), (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.ConnectionIndicator, {
248
+ state: wide ? connectionIndicator : void 0,
249
+ disconnectedLabel: t("connection.error"),
250
+ reconnectLabel: t("connection.retry"),
251
+ connectingLabel: t("connection.connecting"),
252
+ recoveredLabel: t("connection.connected"),
253
+ reconnectActionLabel: t("connection.reconnect"),
254
+ restartActionLabel: t("connection.restart"),
255
+ onReconnect: reconnect
256
+ })]
212
257
  }),
213
258
  open && (0, react_jsx_runtime.jsx)(SettingsPanel, {
214
259
  rows,
@@ -347,26 +392,24 @@ window.__ModuleLoader__.load({
347
392
  //#endregion
348
393
  //#region lib/types/client/settings-document-store.js
349
394
  /** State owner for the optional local settings-document action. */
350
- function messageOf(error) {
351
- return error instanceof Error ? error.message : String(error);
352
- }
353
395
  /** Derives local-document availability from the shared mirror and invokes the pathless Host-owned open operation. */
354
396
  var SettingsDocumentStore = class {
355
- api;
397
+ ctx;
356
398
  describeFace;
357
399
  /** uSES-safe state source shared by the registered header action. */
358
- store = (0, _deepseek_ai_dsh_client_runtime_client.createSnapshotStore)({
400
+ store = (0, _deepseek_ai_dsh_client_store.createSnapshotStore)({
359
401
  status: "idle",
360
402
  opening: false,
361
403
  error: null
362
404
  });
363
405
  following;
364
406
  /**
365
- * @param api - loopback settings wire face that opens the provider document.
407
+ * @param ctx - the plugin's context, whose loopback `remote.settings`
408
+ * namespace opens the provider document.
366
409
  * @param describeFace - the shared mirror's describe face (`hasDocument` source).
367
410
  */
368
- constructor(api, describeFace) {
369
- this.api = api;
411
+ constructor(ctx, describeFace) {
412
+ this.ctx = ctx;
370
413
  this.describeFace = describeFace;
371
414
  }
372
415
  /**
@@ -397,12 +440,13 @@ window.__ModuleLoader__.load({
397
440
  state.error = null;
398
441
  });
399
442
  try {
400
- const response = await this.api.settings.openDocument({});
401
- if (!response.result.ok) throw new Error(response.result.error.message);
402
- } catch (error) {
403
- this.store.update((state) => {
404
- state.error = messageOf(error);
405
- });
443
+ const result = await this.ctx.remote.settings.openSettingsDocument();
444
+ if (!result.ok) {
445
+ const { message } = result.error;
446
+ this.store.update((state) => {
447
+ state.error = message;
448
+ });
449
+ }
406
450
  } finally {
407
451
  this.store.update((state) => {
408
452
  state.opening = false;
@@ -440,7 +484,13 @@ window.__ModuleLoader__.load({
440
484
  "close": "关闭",
441
485
  "openDocument": "打开配置文件",
442
486
  "openDocument.error": "无法打开配置文件",
443
- "general.nav": "通用设置"
487
+ "general.nav": "通用设置",
488
+ "connection.error": "连接异常",
489
+ "connection.retry": "立即重连",
490
+ "connection.connecting": "连接中",
491
+ "connection.connected": "连接成功",
492
+ "connection.reconnect": "连接异常,点击立即重连",
493
+ "connection.restart": "连接中,点击立即重连"
444
494
  };
445
495
  /** English dictionary, checked complete against the zh key set. */
446
496
  const en = {
@@ -449,7 +499,13 @@ window.__ModuleLoader__.load({
449
499
  "close": "Close",
450
500
  "openDocument": "Open configuration file",
451
501
  "openDocument.error": "Could not open configuration file",
452
- "general.nav": "General"
502
+ "general.nav": "General",
503
+ "connection.error": "Disconnected",
504
+ "connection.retry": "Reconnect now",
505
+ "connection.connecting": "Connecting",
506
+ "connection.connected": "Connected",
507
+ "connection.reconnect": "Disconnected, reconnect now",
508
+ "connection.restart": "Connecting, restart now"
453
509
  };
454
510
  //#endregion
455
511
  //#region lib/types/client/index.js
@@ -464,6 +520,8 @@ window.__ModuleLoader__.load({
464
520
  "slots",
465
521
  "locale",
466
522
  "connection",
523
+ "remote",
524
+ "remote.settings",
467
525
  "settingsScope"
468
526
  ];
469
527
  /**
@@ -476,9 +534,9 @@ window.__ModuleLoader__.load({
476
534
  zh,
477
535
  en
478
536
  }), "ui-settings-general: dictionaries");
479
- const t = ctx.locale.bind(NS);
480
537
  const connection = ctx.get("connection");
481
- const documentController = connection.isLoopback ? new SettingsDocumentStore(connection.api, ctx.settingsScope.describe()) : void 0;
538
+ const t = ctx.locale.bind(NS);
539
+ const documentController = ctx.remote.$host.isLoopback ? new SettingsDocumentStore(ctx, ctx.settingsScope.describe()) : void 0;
482
540
  const documentInjected = documentController === void 0 ? void 0 : () => ({
483
541
  controller: documentController,
484
542
  hooks: { snapshot: documentController.store }
@@ -491,50 +549,57 @@ window.__ModuleLoader__.load({
491
549
  let rows = [];
492
550
  let onboardingVersion = -1;
493
551
  let onboardingSteps = [];
494
- const shellInjected = () => ({ hooks: {
495
- sections: {
496
- getSnapshot: () => {
497
- const version = ctx.slots.getVersion("settings.section");
498
- const revision = ctx.locale.getSnapshot().revision;
499
- if (version !== rowsVersion || revision !== rowsRevision) {
500
- rowsVersion = version;
501
- rowsRevision = revision;
502
- rows = ctx.slots.entries("settings.section").map((e) => ({
503
- /* v8 ignore next -- list-slot registration requires id (SlotCore rejects an entry without one) */
504
- id: e.options.id ?? "",
505
- order: e.options.order ?? 0,
506
- label: (0, _deepseek_ai_dsh_client_ui_slots.resolveSlotLabel)(e.options.label) ?? ""
507
- })).sort((a, b) => a.order - b.order);
508
- }
509
- return rows;
510
- },
511
- subscribe: (listener) => {
512
- const offLedger = ctx.slots.subscribe("settings.section", listener);
513
- const offLocale = ctx.locale.subscribe(listener);
514
- return () => {
515
- offLedger();
516
- offLocale();
517
- };
518
- }
552
+ const shellInjected = () => ({
553
+ reconnect: () => {
554
+ connection.reconnect();
519
555
  },
520
- onboardingSteps: {
521
- getSnapshot: () => {
522
- const version = ctx.slots.getVersion("settings.onboarding");
523
- if (version !== onboardingVersion) {
524
- onboardingVersion = version;
525
- onboardingSteps = ctx.slots.entries("settings.onboarding").map((e) => ({
526
- /* v8 ignore next -- list-slot registration requires id */
527
- id: e.options.id ?? "",
528
- order: e.options.order ?? 0
529
- })).sort((a, b) => a.order - b.order);
556
+ hooks: {
557
+ connectionState: connection.state,
558
+ sections: {
559
+ getSnapshot: () => {
560
+ const version = ctx.slots.getVersion("settings.section");
561
+ const revision = ctx.locale.getSnapshot().revision;
562
+ if (version !== rowsVersion || revision !== rowsRevision) {
563
+ rowsVersion = version;
564
+ rowsRevision = revision;
565
+ rows = ctx.slots.entries("settings.section").map((e) => ({
566
+ /* v8 ignore next -- list-slot registration requires id (SlotCore rejects an entry without one) */
567
+ id: e.options.id ?? "",
568
+ order: e.options.order ?? 0,
569
+ label: (0, _deepseek_ai_dsh_client_ui_slots.resolveSlotLabel)(e.options.label) ?? ""
570
+ })).sort((a, b) => a.order - b.order);
571
+ }
572
+ return rows;
573
+ },
574
+ subscribe: (listener) => {
575
+ const offLedger = ctx.slots.subscribe("settings.section", listener);
576
+ const offLocale = ctx.locale.subscribe(listener);
577
+ return () => {
578
+ offLedger();
579
+ offLocale();
580
+ };
530
581
  }
531
- return onboardingSteps;
532
582
  },
533
- subscribe: (listener) => ctx.slots.subscribe("settings.onboarding", listener)
583
+ onboardingSteps: {
584
+ getSnapshot: () => {
585
+ const version = ctx.slots.getVersion("settings.onboarding");
586
+ if (version !== onboardingVersion) {
587
+ onboardingVersion = version;
588
+ onboardingSteps = ctx.slots.entries("settings.onboarding").map((e) => ({
589
+ /* v8 ignore next -- list-slot registration requires id */
590
+ id: e.options.id ?? "",
591
+ order: e.options.order ?? 0
592
+ })).sort((a, b) => a.order - b.order);
593
+ }
594
+ return onboardingSteps;
595
+ },
596
+ subscribe: (listener) => ctx.slots.subscribe("settings.onboarding", listener)
597
+ }
534
598
  }
535
- } });
599
+ });
536
600
  ctx.slots.inject("sidebar.settings", () => ctx.slots.register({
537
601
  name: "sidebar.settings",
602
+ locale: NS,
538
603
  children: {
539
604
  "settings.trigger": {
540
605
  kind: "single",
package/lib/index.js CHANGED
@@ -1,5 +1,4 @@
1
1
  import z from "@deepseek-ai/schemastery";
2
- import { settingsNamespace } from "@deepseek-ai/dsh-settings";
3
2
  //#region lib/types/index.js
4
3
  /** Host loader entry for the browser implementation exported from `./client`. */
5
4
  /** Durable settings namespace for product-wide GUI onboarding facts. */
@@ -8,7 +7,7 @@ const OnboardingSettingsSchema = z.object({ welcomeNoticeVersion: z.string() });
8
7
  /** Register the durable GUI-onboarding section when a settings provider exists. */
9
8
  function apply(ctx) {
10
9
  ctx.inject(["settings"], (settingsCtx) => {
11
- settingsCtx.settings.register(settingsNamespace(ONBOARDING_SETTINGS_NAMESPACE), OnboardingSettingsSchema);
10
+ settingsCtx.settings.register(ONBOARDING_SETTINGS_NAMESPACE, OnboardingSettingsSchema);
12
11
  });
13
12
  }
14
13
  //#endregion
@@ -7,7 +7,7 @@
7
7
  * Feature-owned rows and sections stay with their features.
8
8
  * Export discipline: packages/client/AGENTS.md.
9
9
  */
10
- import type { ClientContext } from '@deepseek-ai/dsh-client-runtime/client';
10
+ import type { Context as ClientContext } from '@deepseek-ai/cordis';
11
11
  import { type SettingsKey } from './locales.ts';
12
12
  export type { CloseLabelProps, HeaderContentProps, TriggerContentProps, } from './chrome.tsx';
13
13
  export type { GeneralSectionComponentProps, } from './GeneralSection.tsx';
@@ -7,6 +7,12 @@ export declare const zh: {
7
7
  openDocument: string;
8
8
  'openDocument.error': string;
9
9
  'general.nav': string;
10
+ 'connection.error': string;
11
+ 'connection.retry': string;
12
+ 'connection.connecting': string;
13
+ 'connection.connected': string;
14
+ 'connection.reconnect': string;
15
+ 'connection.restart': string;
10
16
  };
11
17
  /** The settings namespace key union. */
12
18
  export type SettingsKey = keyof typeof zh;
@@ -18,5 +24,11 @@ export declare const en: {
18
24
  openDocument: string;
19
25
  'openDocument.error': string;
20
26
  'general.nav': string;
27
+ 'connection.error': string;
28
+ 'connection.retry': string;
29
+ 'connection.connecting': string;
30
+ 'connection.connected': string;
31
+ 'connection.reconnect': string;
32
+ 'connection.restart': string;
21
33
  };
22
34
  //# sourceMappingURL=locales.d.ts.map
@@ -1,6 +1,6 @@
1
1
  /** State owner for the optional local settings-document action. */
2
- import type { IApiClient } from '@deepseek-ai/dsh-api-remotes/client';
3
- import { type SnapshotStore } from '@deepseek-ai/dsh-client-runtime/client';
2
+ import type { Context as ClientContext } from '@deepseek-ai/cordis';
3
+ import { type SnapshotStore } from '@deepseek-ai/dsh-client-store';
4
4
  import type { SettingsDescribeFace } from '@deepseek-ai/dsh-client-ui-settings/client';
5
5
  /** Browser state of the Host-owned settings document. */
6
6
  export interface SettingsDocumentState {
@@ -13,16 +13,17 @@ export interface SettingsDocumentState {
13
13
  }
14
14
  /** Derives local-document availability from the shared mirror and invokes the pathless Host-owned open operation. */
15
15
  export declare class SettingsDocumentStore {
16
- private readonly api;
16
+ private readonly ctx;
17
17
  private readonly describeFace;
18
18
  /** uSES-safe state source shared by the registered header action. */
19
19
  readonly store: SnapshotStore<SettingsDocumentState>;
20
20
  private following;
21
21
  /**
22
- * @param api - loopback settings wire face that opens the provider document.
22
+ * @param ctx - the plugin's context, whose loopback `remote.settings`
23
+ * namespace opens the provider document.
23
24
  * @param describeFace - the shared mirror's describe face (`hasDocument` source).
24
25
  */
25
- constructor(api: Pick<IApiClient, 'settings'>, describeFace: SettingsDescribeFace);
26
+ constructor(ctx: ClientContext, describeFace: SettingsDescribeFace);
26
27
  /**
27
28
  * Begin following the mirror (idempotent) and reflect whether the current
28
29
  * provider owns a local document.
@@ -6,7 +6,8 @@
6
6
  * reference graph closes a cycle through ui-sidebar → ui-layout → ui-theme.
7
7
  * The settings SLOT types (what registrants contribute) stay in ui-settings.
8
8
  */
9
- import type { HostObservable, InjectFace, PropsRenderSlots, PropsRuntime } from '@deepseek-ai/dsh-client-ui-slots';
9
+ import type { ConnectionState } from '@deepseek-ai/dsh-client-connection/client';
10
+ import type { HostObservable, InjectFace, PropsLocale, PropsRenderSlots, PropsRuntime } from '@deepseek-ai/dsh-client-ui-slots';
10
11
  /** One nav row projected from a settings.section registration's options. */
11
12
  export interface SettingsSectionRow {
12
13
  id: string;
@@ -20,11 +21,15 @@ export interface SettingsOnboardingStep {
20
21
  }
21
22
  /**
22
23
  * Registrant-private injected share of the settings shell (assembled in
23
- * apply): the ledger's nav-row projection as a hooks-compartment source —
24
- * the shell reads no locale state and subscribes through the bound hook.
24
+ * apply): connection state and ledger projections arrive as hook-compartment
25
+ * sources, while the reconnect command remains a plain callback.
25
26
  */
26
27
  export type SettingsRootInjected = {
28
+ /** Request a fresh logical generation and physical WebSocket immediately. */
29
+ reconnect: () => void;
27
30
  hooks: {
31
+ /** Connection-owned state for the current Host connection. */
32
+ connectionState: HostObservable<ConnectionState | undefined>;
28
33
  /** settings.section ledger projected into ordered nav rows. */
29
34
  sections: HostObservable<readonly SettingsSectionRow[]>;
30
35
  /** settings.onboarding ledger projected into coordinator order. */
@@ -37,5 +42,5 @@ export type SettingsRootInjected = {
37
42
  * (hooks compartment bound to useSections). No store is registered — modal
38
43
  * open state and active section id are component-local viewing state.
39
44
  */
40
- export type SettingsRootComponentProps = PropsRuntime<'sidebar.settings'> & PropsRenderSlots<'settings.trigger' | 'settings.header' | 'settings.action' | 'settings.close' | 'settings.section' | 'settings.onboarding'> & InjectFace<SettingsRootInjected>;
45
+ export type SettingsRootComponentProps = PropsRuntime<'sidebar.settings'> & PropsRenderSlots<'settings.trigger' | 'settings.header' | 'settings.action' | 'settings.close' | 'settings.section' | 'settings.onboarding'> & InjectFace<SettingsRootInjected> & PropsLocale<'settings'>;
41
46
  //# sourceMappingURL=shell-contract.d.ts.map
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@deepseek-ai/dsh-client-ui-settings-general",
3
3
  "description": "Settings ownerless-copy and product onboarding plugin: the General section, shell trigger/header chrome content, settings dictionaries, and the versioned welcome notice",
4
- "version": "0.1.1-rc.2",
4
+ "version": "0.1.2-alpha.2",
5
5
  "publishConfig": {
6
6
  "access": "public"
7
7
  },
@@ -32,7 +32,6 @@
32
32
  "dsh": {
33
33
  "client": {
34
34
  "inject": [
35
- "@deepseek-ai/dsh-client-runtime",
36
35
  "@deepseek-ai/dsh-client-ui-settings",
37
36
  "@deepseek-ai/dsh-client-locale",
38
37
  "@deepseek-ai/dsh-client-connection",
@@ -45,34 +44,28 @@
45
44
  "license": "MIT",
46
45
  "dependencies": {
47
46
  "clsx": "^2.0.0",
48
- "@deepseek-ai/schemastery": "^3.18.1"
47
+ "@deepseek-ai/schemastery": "^3.18.2"
49
48
  },
50
49
  "peerDependencies": {
51
- "@deepseek-ai/dsh-api-remotes": "^0.1.1-rc.2",
52
- "@deepseek-ai/dsh-client-connection": "^0.1.1-rc.2",
53
- "@deepseek-ai/dsh-client-locale": "^0.1.1-rc.2",
54
- "@deepseek-ai/dsh-client-runtime": "^0.1.1-rc.2",
55
- "@deepseek-ai/dsh-client-ui-settings": "^0.1.1-rc.2",
56
- "@deepseek-ai/dsh-invariants": "^0.1.1-rc.2",
57
- "@deepseek-ai/dsh-client-ui-sidebar": "^0.1.1-rc.2",
58
- "@deepseek-ai/cordis": "^4.0.1",
59
- "@deepseek-ai/dsh-settings": "^0.1.1-rc.2"
50
+ "@deepseek-ai/cordis": "^4.0.2"
60
51
  },
61
52
  "devDependencies": {
62
53
  "@types/react": "~18.3.1",
63
54
  "react": "^18.2.0",
64
- "@deepseek-ai/dsh-api-remotes": "^0.1.1-rc.2",
65
- "@deepseek-ai/dsh-client-connection": "^0.1.1-rc.2",
66
- "@deepseek-ai/dsh-client-locale": "^0.1.1-rc.2",
67
- "@deepseek-ai/dsh-client-runtime": "^0.1.1-rc.2",
68
- "@deepseek-ai/dsh-client-test-runtime": "^0.1.1-rc.2",
69
- "@deepseek-ai/dsh-client-ui-primitives": "^0.1.1-rc.2",
70
- "@deepseek-ai/dsh-client-ui-settings": "^0.1.1-rc.2",
71
- "@deepseek-ai/dsh-invariants": "^0.1.1-rc.2",
72
- "@deepseek-ai/dsh-client-ui-slots": "^0.1.1-rc.2",
73
- "@deepseek-ai/cordis": "^4.0.1",
74
- "@deepseek-ai/dsh-settings": "^0.1.1-rc.2",
75
- "@deepseek-ai/dsh-client-ui-sidebar": "^0.1.1-rc.2"
55
+ "@deepseek-ai/dsh-api-remotes": "^0.1.2-alpha.2",
56
+ "@deepseek-ai/dsh-client-connection": "^0.1.2-alpha.2",
57
+ "@deepseek-ai/dsh-client-locale": "^0.1.2-alpha.2",
58
+ "@deepseek-ai/dsh-client-store": "^0.1.2-alpha.2",
59
+ "@deepseek-ai/dsh-client-test-runtime": "^0.1.2-alpha.2",
60
+ "@deepseek-ai/dsh-client-ui-primitives": "^0.1.2-alpha.2",
61
+ "@deepseek-ai/dsh-client-ui-settings": "^0.1.2-alpha.2",
62
+ "@deepseek-ai/dsh-client-ui-sidebar": "^0.1.2-alpha.2",
63
+ "@deepseek-ai/dsh-client-ui-slots": "^0.1.2-alpha.2",
64
+ "@deepseek-ai/dsh-invariants": "^0.1.2-alpha.2",
65
+ "@deepseek-ai/cordis": "^4.0.2",
66
+ "@deepseek-ai/dsh-client-ui-renderer": "^0.1.2-alpha.2",
67
+ "@deepseek-ai/dsh-client-ui-session": "^0.1.2-alpha.2",
68
+ "@deepseek-ai/dsh-settings": "^0.1.2-alpha.2"
76
69
  },
77
70
  "files": [
78
71
  "lib/index.js",