@deepseek-ai/dsh-client-ui-settings-general 0.1.6-alpha.1 → 0.1.7-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/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: af68c42ad111f74e68037436e18a5be57195a64b
6
- README.zh.md: f929df66a13cde7beb63721922f2a3f4aa90ba43
5
+ README.md: 266fe837899f13d33e7a098b901cc34402da765e
6
+ README.zh.md: 09570948b89089dda33d6705e4f17c7cd2f8481c
package/README.md CHANGED
@@ -9,7 +9,7 @@ English | [中文](README.zh.md)
9
9
 
10
10
  ## Summary
11
11
 
12
- Use this package to give the dsh web client a Settings panel, connection-recovery control, feature-contributed navigation, and sequential first-run onboarding. Users can open it from the sidebar, retry a failed connection immediately, and access a local configuration file when the Host makes one available on a loopback browser. Feature packages supply their own settings rows, sections, and onboarding steps; this package supplies their shared presentation and does not add onboarding copy or built-in General rows.
12
+ Use this package to give the dsh web client a Settings panel, connection-recovery control, feature-contributed navigation, and sequential first-run onboarding. Users can open it from the sidebar, retry a failed connection immediately, and access a local configuration file when the Host makes one available on a loopback browser. Feature packages supply their own settings rows, sections, and onboarding steps; this package supplies their shared presentation and the Developer tools switch without adding onboarding copy.
13
13
 
14
14
  ## Table of Contents
15
15
 
@@ -22,14 +22,24 @@ Use this package to give the dsh web client a Settings panel, connection-recover
22
22
 
23
23
  -----
24
24
 
25
+ The Settings panel uses a shared 760 × 500 layout, bounded by the viewport. Longer sections scroll inside the content column; the Account entry uses the account icon.
26
+
25
27
  <a id="use-this-package"></a>
26
28
  ## Use this package
27
29
 
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. In both the expanded sidebar and collapsed rail, the control exposes the localized Settings label as its accessible name. A pale-yellow **Disconnected** action beside Settings indicates browser offline suspension; its permanent retry glyph marks the retry action, which the Chinese outage copy also names (连接异常,刷新重试). Every recovery attempt shows a spinner beside **Reconnecting** with one to three dots advancing every 500ms, and an attempt stays visible for at least 800ms so brief retries do not flicker. Selecting either yellow state starts an immediate retry; press feedback stays within the warning palette. Recovery changes the region to pale-green **Connected** for two seconds from the moment the green pill becomes visible. The pill fades in on appearance, fades out over 150ms on removal, and sizes to its current label. 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.
30
+ 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. In both the expanded sidebar and collapsed rail, the control exposes the localized Settings label as its accessible name. A pale-yellow **Disconnected** action beside Settings indicates browser offline suspension; its permanent retry glyph marks the retry action, which the Chinese outage copy also names (连接异常,刷新重试). Every recovery attempt shows the shared ongoing loader beside **Reconnecting** with one to three dots advancing every 500ms, and an attempt stays visible for at least 800ms so brief retries do not flicker. Selecting either yellow state starts an immediate retry; press feedback stays within the warning palette. Recovery changes the region to pale-green **Connected** for two seconds from the moment the green pill becomes visible. The pill fades in on appearance, fades out over 150ms on removal, and sizes to its current label. 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.
31
+
32
+ When the section navigation exceeds the panel's available height, the list scrolls independently of the settings content and keeps the Settings title fixed.
33
+
34
+ In Desktop, the account-row update control shows availability, progress, verification, readiness, and persistent retry feedback. The preload carries semantic phase, version, progress, and classified failures; the component resolves every visible and accessible string from the active `settings` locale, including after an in-application language change. Selecting an available update starts downloading; installation requires a separate shell-owned confirmation. A collapsed sidebar shows the same status as a dot on its top expand button. Connection feedback takes priority except during shell-reported installation, when the expected backend disconnect must not hide update status. Failure restores connection feedback. Both controls share one carrier subscription; browser code cannot choose packages or authorize installation. [Desktop updates](../../../apps/desktop/README.md) owns the release workflow.
29
35
 
30
36
  ### The General section
31
37
 
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.
38
+ The current release version appears at the bottom of General Settings in Web and Desktop, using the build’s `DSH_CLIENT_VERSION` metadata and the active language. Partial builds without version metadata omit the row.
39
+
40
+ The Developer tools switch controls the shared preference described by [ui-settings](../ui-settings/README.md#use-this-package). It is available in both Web and desktop, follows accepted changes immediately, and disables duplicate input while a write settles. A failed write displays localized retry guidance.
41
+
42
+ The General section holds the built-in Developer tools and Current version rows alongside rows registered into `settings.general.item` by feature packages. Each registrant owns its row copy and behavior. The Appearance row, for example, lives in ui-theme.
33
43
 
34
44
  ### Opening the configuration file
35
45
 
@@ -44,10 +54,12 @@ The onboarding ledger projects in ascending order and mounts exactly one step at
44
54
  <a id="understand-the-implementation"></a>
45
55
  ## Understand the implementation
46
56
 
57
+ The shell declares settings.launcher for an account-owned sidebar menu and retains the Settings button as its fallback. Closing the dialog returns focus to the active launcher.
58
+
47
59
  <details>
48
60
  <summary>Implementation internals — click to expand</summary>
49
61
 
50
- The shell owns the chrome and the projections; every piece of content and copy belongs to a registrant.
62
+ The shell owns the chrome and the projections; it contributes the Developer tools and Current version rows, while feature registrants own their additional content and copy.
51
63
 
52
64
  ### Ledger projections
53
65
 
@@ -63,7 +75,7 @@ On a loopback page, the Client loads the provider's `hasDocument` capability thr
63
75
 
64
76
  ### Host half
65
77
 
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.
78
+ The Host half declares `welcomeNoticeVersion` as a volatile field of the `ui-settings-general` entry Config. 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
79
 
68
80
  </details>
69
81
 
@@ -98,7 +110,8 @@ None; this package neither assembles nor sends a provider request.
98
110
 
99
111
  These limits define what the shell itself provides versus what features must supply; they are current package constraints.
100
112
 
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.
113
+ - **Additional General rows require their feature plugins** — the shell supplies Developer tools and Current version; feature plugins supply the remaining preferences.
114
+ - **The Windows caption badge keeps a side-opening bubble** — `DesktopUpdateBadge` occupies `sidebar.toggle.badge` in the caption and requests `side="right"`, so the Desktop-owned menu text can cover its bubble while the sidebar is collapsed on Windows; the sidebar toggle and New Session bubbles open below the caption instead (#4688).
102
115
 
103
116
  <a id="dev-note"></a>
104
117
  ### Dev Note
package/README.zh.md CHANGED
@@ -9,7 +9,7 @@ kind: "package-reference"
9
9
 
10
10
  ## 概述
11
11
 
12
- 使用本包可为 dsh Web 客户端提供 Settings 面板、连接恢复控件、由功能包贡献的导航,以及依次进行的首次运行引导。用户可以从侧边栏打开面板、立即重试失败的连接,并在宿主为回环浏览器提供本地配置文件时访问该文件。各功能包提供自己的设置行、分区和引导步骤;本包提供共享的界面展示,但不添加引导文案或「通用」分区的内置行。
12
+ 使用本包可为 dsh Web 客户端提供 Settings 面板、连接恢复控件、由功能包贡献的导航,以及依次进行的首次运行引导。用户可以从侧边栏打开面板、立即重试失败的连接,并在宿主为回环浏览器提供本地配置文件时访问该文件。各功能包提供自己的设置行、分区和引导步骤;本包提供共享的界面展示和开发者工具开关,但不添加引导文案。
13
13
 
14
14
  ## 目录
15
15
 
@@ -22,14 +22,24 @@ kind: "package-reference"
22
22
 
23
23
  -----
24
24
 
25
+ 设置面板采用各页面共享的 760 × 500 布局,并受视口大小约束。较长的页面在内容栏内部滚动;账号入口使用账号图标。
26
+
25
27
  <a id="use-this-package"></a>
26
28
  ## 使用本包
27
29
 
28
- 用户通过侧边栏底部的 Settings 控件进入外壳;功能插件通过本外壳所投影的 slot 账本贡献自己的页面与引导步骤。在展开侧边栏和收起轨道中,该控件都会把本地化的 Settings 文案作为其可访问名称。Settings 右侧浅黄色的**连接异常**操作表示浏览器离线暂停;其常驻重试图形与中文文案「连接异常,刷新重试」都指明重试动作。每次恢复尝试都显示 spinner 加**重新连接中**,其后一至三个点每 500ms 前进一次,且每次尝试至少可见 800ms,短暂重试不会闪动。选中任一黄色状态都会立即发起重试;按压反馈留在黄色色阶内。恢复后该区域变为浅绿色的**连接成功**,从绿色药丸可见起驻留 2 秒再消失。药丸出现时淡入、移除时以 150ms 淡出,宽度随当前文案自适应。首次启动与未曾中断的健康连接保持静默。外壳渲染模态面板、由 `settings.section` 条目构建的导航,以及每次只挂载一个的引导步骤。
30
+ 用户通过侧边栏底部的 Settings 控件进入外壳;功能插件通过本外壳所投影的 slot 账本贡献自己的页面与引导步骤。在展开侧边栏和收起轨道中,该控件都会把本地化的 Settings 文案作为其可访问名称。Settings 右侧浅黄色的**连接异常**操作表示浏览器离线暂停;其常驻重试图形与中文文案「连接异常,刷新重试」都指明重试动作。每次恢复尝试都显示共享 ongoing loading 加**重新连接中**,其后一至三个点每 500ms 前进一次,且每次尝试至少可见 800ms,短暂重试不会闪动。选中任一黄色状态都会立即发起重试;按压反馈留在黄色色阶内。恢复后该区域变为浅绿色的**连接成功**,从绿色药丸可见起驻留 2 秒再消失。药丸出现时淡入、移除时以 150ms 淡出,宽度随当前文案自适应。首次启动与未曾中断的健康连接保持静默。外壳渲染模态面板、由 `settings.section` 条目构建的导航,以及每次只挂载一个的引导步骤。
31
+
32
+ 当分区导航超出面板可用高度时,列表独立于设置内容滚动,并保持「设置」标题固定。
33
+
34
+ 在 Desktop 中,账户行更新控件显示可用版本、进度、验证、就绪和持久重试反馈。预加载仅传递语义化阶段、版本、进度和失败类别;组件从当前 `settings` locale 解析全部可见与无障碍文案,并在应用内语言变化后同步更新。选择可用更新即开始下载;安装需要独立的壳拥有的确认。侧栏收起时,其顶部展开按钮以圆点显示相同状态。连接反馈通常优先展示,但壳报告正在安装时,预期的后端断开不能遮盖更新状态;失败后恢复连接反馈。两个控件共用一次载体订阅;浏览器代码不能选择安装包或授权安装。[Desktop 更新](../../../apps/desktop/README.zh.md)负责发布流程。
29
35
 
30
36
  ### 「通用」分区
31
37
 
32
- 「通用」分区承载由功能包注册进 `settings.general.item` 的行——它没有内置行。功能插件拥有行文案与行为;外壳只提供分区及其 slot。例如「外观」行位于 ui-theme。
38
+ Web 与桌面端的通用设置底部显示当前发布版本,使用构建注入的 `DSH_CLIENT_VERSION` 元数据和当前语言。缺少版本元数据的局部构建不显示该行。
39
+
40
+ 开发者工具开关控制 [ui-settings](../ui-settings/README.zh.md#use-this-package) 定义的共享偏好。Web 和桌面端均提供此开关,立即跟随已接受的变更,并在写入完成前禁用重复输入。写入失败时显示本地化的重试提示。
41
+
42
+ 「通用」分区承载内置的开发者工具行与当前版本行,以及功能包注册进 `settings.general.item` 的行。每个注册方拥有自己的行文案与行为。例如「外观」行位于 ui-theme。
33
43
 
34
44
  ### 打开配置文件
35
45
 
@@ -44,10 +54,12 @@ kind: "package-reference"
44
54
  <a id="understand-the-implementation"></a>
45
55
  ## 理解实现
46
56
 
57
+ 外壳声明 settings.launcher,供账号功能提供侧边栏菜单,并以设置按钮作为回退。关闭对话框后,焦点返回当前入口。
58
+
47
59
  <details>
48
60
  <summary>实现细节——点击展开</summary>
49
61
 
50
- 外壳拥有界面框架与投影;每段内容与文案都属于某个注册方。
62
+ 外壳拥有界面框架与投影,并提供开发者工具行与当前版本行;功能注册方拥有其余内容与文案。
51
63
 
52
64
  ### 账本投影
53
65
 
@@ -63,7 +75,7 @@ kind: "package-reference"
63
75
 
64
76
  ### 宿主端
65
77
 
66
- 宿主端在用户设置 seam 中注册 `ui-onboarding`。`ui-settings-models` 提供的欢迎步骤通过既有公开 settings 边界读写其中的 `welcomeNoticeVersion`;外壳本身仍不持有产品策略。
78
+ 宿主端在 `ui-settings-general` 条目的 Config 中把 `welcomeNoticeVersion` 声明为 volatile 字段。`ui-settings-models` 提供的欢迎步骤通过既有公开 settings 边界读写其中的 `welcomeNoticeVersion`;外壳本身仍不持有产品策略。
67
79
 
68
80
  </details>
69
81
 
@@ -98,7 +110,8 @@ kind: "package-reference"
98
110
 
99
111
  这些限制说明外壳自身提供什么、功能包必须提供什么;它们是当前包约束。
100
112
 
101
- - **「通用」分区没有内置行**:每一行仅在其所属功能插件挂载时出现;外壳单独无法填满该分区。
113
+ - **额外的通用设置行需要相应功能插件**:外壳提供开发者工具与当前版本;功能插件提供其他偏好。
114
+ - **Windows 顶栏徽标的气泡仍向右展开**:`DesktopUpdateBadge` 占用顶栏的 `sidebar.toggle.badge` 且请求 `side="right"`,侧栏收起时其气泡会被 Desktop 菜单文字遮挡;侧栏开关与新建会话的气泡则改在顶栏下方展开(#4688)。
102
115
 
103
116
  <a id="dev-note"></a>
104
117
  ### 开发备注
package/lib/client.js CHANGED
@@ -25,13 +25,13 @@ 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_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{corner-shape:round;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-elevation-prominent);--dsh-scrollbar-thumb:var(--dsw-alias-scrollbar-bg-l2);--dsh-scrollbar-thumb-hover:var(--dsw-alias-scrollbar-hover-l2);border-radius:32px;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
- const tagId$3 = "@deepseek-ai/dsh-client-ui-settings-general/SettingsRoot.module.css";
30
- if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$3) + "]") === null) {
28
+ const css$6 = ".VOzbGW_triggerRow{flex:none;align-items:center;gap:8px;width:calc(100% + 4px);margin:4px -2px;display:flex;position:relative}.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{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;width:800px;height:min(800px, calc(100vh - 2 * max(24px, var(--dsh-frame-top-clearance,24px))));background:var(--dsw-alias-bg-layer-2);max-width:calc(100vw - 48px);box-shadow:var(--dsw-elevation-prominent);--dsh-scrollbar-thumb:var(--dsw-alias-scrollbar-bg-l2);--dsh-scrollbar-thumb-hover:var(--dsw-alias-scrollbar-hover-l2);border-radius:32px;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;overflow-y:auto}.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}[data-platform=darwin] .VOzbGW_overlay{-webkit-app-region:no-drag}";
29
+ const tagId$6 = "@deepseek-ai/dsh-client-ui-settings-general/SettingsRoot.module.css";
30
+ if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$6) + "]") === null) {
31
31
  const tag = document.createElement("style");
32
32
  tag.dataset.plugin = "@deepseek-ai/dsh-client-ui-settings-general";
33
- tag.dataset.pluginCss = tagId$3;
34
- tag.textContent = css$3;
33
+ tag.dataset.pluginCss = tagId$6;
34
+ tag.textContent = css$6;
35
35
  document.head.appendChild(tag);
36
36
  }
37
37
  var SettingsRoot_module_css_default = {
@@ -58,10 +58,139 @@ window.__ModuleLoader__.load({
58
58
  "triggerRow": "VOzbGW_triggerRow"
59
59
  };
60
60
  //#endregion
61
+ //#region \0dsh-css:/home/runner/work/deepseek-harness/deepseek-harness/packages/client/ui-settings-general/src/client/DesktopUpdateIndicator.module.css.mjs
62
+ const css$5 = ".DOUpOa_indicator{border:1px solid color-mix(in srgb, var(--dsw-alias-brand-primary-new-colorprimary-new-color) 20%, transparent);color:var(--dsw-alias-brand-primary-new-colorprimary-new-color);background:color-mix(in srgb, var(--dsw-alias-brand-primary-new-colorprimary-new-color) 8%, transparent);font:inherit;white-space:nowrap;cursor:pointer;border-radius:6px;flex:none;align-items:center;gap:6px;margin-inline-end:4px;padding:1px 8px;font-size:12px;line-height:20px;display:inline-flex}.DOUpOa_indicator[data-error]{color:var(--dsw-alias-state-error-primary)}.DOUpOa_badge{inset-inline-end:2px;corner-shape:round;background:var(--dsw-alias-brand-primary-new-colorprimary-new-color);border-radius:50%;width:6px;height:6px;position:absolute;top:2px}.DOUpOa_badge[data-error],.DOUpOa_errorDot{background:var(--dsw-alias-state-error-primary)}.DOUpOa_errorDot{corner-shape:round;border-radius:50%;width:6px;height:6px}.DOUpOa_spinner{animation:1s linear infinite DOUpOa_spin}@keyframes DOUpOa_spin{to{transform:rotate(360deg)}}@media (prefers-reduced-motion:reduce){.DOUpOa_spinner{animation:none}}.DOUpOa_indicator[aria-disabled=true]{cursor:default}";
63
+ const tagId$5 = "@deepseek-ai/dsh-client-ui-settings-general/DesktopUpdateIndicator.module.css";
64
+ if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$5) + "]") === null) {
65
+ const tag = document.createElement("style");
66
+ tag.dataset.plugin = "@deepseek-ai/dsh-client-ui-settings-general";
67
+ tag.dataset.pluginCss = tagId$5;
68
+ tag.textContent = css$5;
69
+ document.head.appendChild(tag);
70
+ }
71
+ var DesktopUpdateIndicator_module_css_default = {
72
+ "badge": "DOUpOa_badge",
73
+ "errorDot": "DOUpOa_errorDot",
74
+ "indicator": "DOUpOa_indicator",
75
+ "spin": "DOUpOa_spin",
76
+ "spinner": "DOUpOa_spinner"
77
+ };
78
+ //#endregion
79
+ //#region lib/types/client/DesktopUpdateIndicator.js
80
+ /** Optional Electron status presentation; the native shell owns actions and Web owns visible copy. */
81
+ const BUSY_PHASES = new Set([
82
+ "checking",
83
+ "downloading",
84
+ "verifying",
85
+ "installing"
86
+ ]);
87
+ function updateCopy(state, t) {
88
+ const label = {
89
+ idle: "",
90
+ checking: t("desktop.update.checking"),
91
+ available: t("desktop.update.available"),
92
+ downloading: t("desktop.update.progress", { percent: state.percent ?? 0 }),
93
+ verifying: t("desktop.update.verifying"),
94
+ installing: t("desktop.update.installing"),
95
+ ready: t("desktop.update.ready"),
96
+ error: t("desktop.update.retry")
97
+ }[state.phase];
98
+ if (state.phase === "error") return {
99
+ label,
100
+ detail: {
101
+ check: t("desktop.update.checkFailed"),
102
+ "check-network": t("desktop.update.checkNetworkFailed"),
103
+ download: t("desktop.update.downloadFailed"),
104
+ "download-network": t("desktop.update.downloadNetworkFailed"),
105
+ install: t("desktop.update.installFailed"),
106
+ "install-network": t("desktop.update.installNetworkFailed"),
107
+ "stop-failed": t("desktop.update.stopFailed"),
108
+ "tasks-changed": t("desktop.update.tasksChanged"),
109
+ "tasks-unavailable": t("desktop.update.tasksUnavailable")
110
+ }[state.failure ?? "install"]
111
+ };
112
+ if (state.phase === "downloading" && state.version !== void 0) return {
113
+ label,
114
+ detail: t("desktop.update.downloadDetail", {
115
+ percent: state.percent ?? 0,
116
+ version: state.version
117
+ })
118
+ };
119
+ return {
120
+ label,
121
+ detail: state.version === void 0 ? label : t("desktop.update.versionDetail", {
122
+ label,
123
+ version: state.version
124
+ })
125
+ };
126
+ }
127
+ /**
128
+ * @param props - Connection priority, sidebar width, and localized bridge-failure copy.
129
+ * @returns Desktop-only status beside the account button, or nothing in browsers.
130
+ */
131
+ function DesktopUpdateIndicator({ wide, hidden, t, view, onOpen }) {
132
+ const { presentation: state, failed, opening } = view;
133
+ if (!wide || hidden || !failed && (state === void 0 || state.phase === "idle")) return null;
134
+ const retryLabel = t("desktop.update.retry");
135
+ const copy = state === void 0 ? {
136
+ label: retryLabel,
137
+ detail: retryLabel
138
+ } : updateCopy(state, t);
139
+ const label = failed ? retryLabel : copy.label;
140
+ const error = failed || state?.phase === "error";
141
+ const busy = opening || state !== void 0 && BUSY_PHASES.has(state.phase);
142
+ return (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Tooltip, {
143
+ label: failed ? retryLabel : copy.detail,
144
+ side: "top",
145
+ children: (0, react_jsx_runtime.jsxs)("button", {
146
+ type: "button",
147
+ className: DesktopUpdateIndicator_module_css_default.indicator,
148
+ "data-error": error || void 0,
149
+ "aria-label": label,
150
+ "aria-disabled": busy,
151
+ onClick: () => {
152
+ if (!busy) onOpen();
153
+ },
154
+ children: [error ? (0, react_jsx_runtime.jsx)("span", {
155
+ className: DesktopUpdateIndicator_module_css_default.errorDot,
156
+ "aria-hidden": "true"
157
+ }) : busy ? (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconLoadingOutlineRegular, {
158
+ className: DesktopUpdateIndicator_module_css_default.spinner,
159
+ size: 16
160
+ }) : (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconDownloadOutlineRegular, { size: 14 }), (0, react_jsx_runtime.jsx)("span", { children: label })]
161
+ })
162
+ });
163
+ }
164
+ /**
165
+ * @param props - Framework-bound carrier and connection state.
166
+ * @returns A non-interactive notification on the sidebar expand button.
167
+ */
168
+ function DesktopUpdateBadge({ useDesktopUpdate, useConnectionState, t }) {
169
+ const { presentation: state, failed } = useDesktopUpdate((value) => value);
170
+ const connection = useConnectionState((value) => value);
171
+ if ((connection === "disconnected" || connection === "connecting") && state?.phase !== "installing" || !failed && (state === void 0 || state.phase === "idle")) return null;
172
+ const retryLabel = t("desktop.update.retry");
173
+ const copy = state === void 0 ? {
174
+ label: retryLabel,
175
+ detail: retryLabel
176
+ } : updateCopy(state, t);
177
+ const label = failed ? retryLabel : copy.label;
178
+ return (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Tooltip, {
179
+ label: failed ? label : copy.detail,
180
+ side: "right",
181
+ children: (0, react_jsx_runtime.jsx)("span", {
182
+ role: "img",
183
+ "aria-label": label,
184
+ className: DesktopUpdateIndicator_module_css_default.badge,
185
+ "data-error": failed || state?.phase === "error" || void 0
186
+ })
187
+ });
188
+ }
189
+ //#endregion
61
190
  //#region lib/types/client/SettingsRoot.js
62
191
  /**
63
192
  * Settings shell root: the sidebar-foot trigger row plus the centered modal
64
- * panel (figma 501:29947, 1080x700) with the section nav rail. The shell is
193
+ * panel (figma 2552:26025, 760x500) with the section nav rail. The shell is
65
194
  * a pure composition face — slot-owned text (trigger label, panel title,
66
195
  * close label, sections) arrives from registrants through slots; accessible
67
196
  * names resolve from localized content (trigger: shell locale; dialog:
@@ -76,23 +205,27 @@ window.__ModuleLoader__.load({
76
205
  const CONNECTING_MIN_VISIBLE_MS = 800;
77
206
  /** Nav glyph by section id; unknown ids fall back to the settings gear. */
78
207
  function navIcon(id) {
79
- if (id === "models") return (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconDataOutline16, {
208
+ if (id === "account") return (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconUserOutlineMedium, {
209
+ className: SettingsRoot_module_css_default.navIcon,
210
+ size: 16
211
+ });
212
+ if (id === "models") return (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconDataOutlineMedium, {
80
213
  className: SettingsRoot_module_css_default.navIcon,
81
214
  size: 16
82
215
  });
83
- if (id === "agent-presets") return (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconAgentPresetOutline16, {
216
+ if (id === "agent-presets") return (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconAgentPresetOutlineMedium, {
84
217
  className: SettingsRoot_module_css_default.navIcon,
85
218
  size: 16
86
219
  });
87
- if (id === "plugins") return (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconPersonalizationOutline16, {
220
+ if (id === "plugins") return (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconPersonalizationOutlineMedium, {
88
221
  className: SettingsRoot_module_css_default.navIcon,
89
222
  size: 16
90
223
  });
91
- if (id === "archived-sessions") return (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconArchiveOutline20, {
224
+ if (id === "archived-sessions") return (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconArchiveOutlineMedium, {
92
225
  className: SettingsRoot_module_css_default.navIcon,
93
226
  size: 16
94
227
  });
95
- return (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconSettingsOutline16, {
228
+ return (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconSettingsOutlineMedium, {
96
229
  className: SettingsRoot_module_css_default.navIcon,
97
230
  size: 16
98
231
  });
@@ -163,7 +296,7 @@ window.__ModuleLoader__.load({
163
296
  type: "button",
164
297
  className: SettingsRoot_module_css_default.close,
165
298
  onClick: onClose,
166
- children: [(0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconCloseOutline16, { size: 14 }), (0, react_jsx_runtime.jsx)("span", {
299
+ children: [(0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconCloseOutlineRegular, { size: 14 }), (0, react_jsx_runtime.jsx)("span", {
167
300
  className: SettingsRoot_module_css_default.hiddenLabel,
168
301
  children: renderSlot("settings.close", {})
169
302
  })]
@@ -182,13 +315,15 @@ window.__ModuleLoader__.load({
182
315
  * @returns the settings shell element tree.
183
316
  */
184
317
  function SettingsRoot(props) {
185
- const { wide, reconnect, useConnectionState, useSections, useOnboardingSteps, useSessions, renderSlot, t } = props;
318
+ const { wide, reconnect, useConnectionState, useSections, useOnboardingSteps, useSessions, renderSlot, t, useDesktopUpdate, openDesktopUpdate } = props;
186
319
  const [open, setOpen] = (0, react.useState)(false);
187
320
  const [activeId, setActiveId] = (0, react.useState)(void 0);
321
+ const [requestedOnboarding, setRequestedOnboarding] = (0, react.useState)();
188
322
  const [completedOnboarding, setCompletedOnboarding] = (0, react.useState)(() => /* @__PURE__ */ new Set());
189
323
  const [showRecovery, setShowRecovery] = (0, react.useState)(false);
190
324
  const [holdConnecting, setHoldConnecting] = (0, react.useState)(false);
191
325
  const connectingShownAt = (0, react.useRef)(void 0);
326
+ const triggerRow = (0, react.useRef)(null);
192
327
  const triggerButton = (0, react.useRef)(null);
193
328
  const wasOpen = (0, react.useRef)(open);
194
329
  const close = (0, react.useCallback)(() => {
@@ -196,7 +331,7 @@ window.__ModuleLoader__.load({
196
331
  setActiveId(void 0);
197
332
  }, []);
198
333
  (0, react.useEffect)(() => {
199
- if (wasOpen.current && !open) triggerButton.current?.focus();
334
+ if (wasOpen.current && !open) triggerRow.current?.querySelector("button")?.focus();
200
335
  wasOpen.current = open;
201
336
  }, [open]);
202
337
  const openSection = (0, react.useCallback)((id) => {
@@ -204,11 +339,15 @@ window.__ModuleLoader__.load({
204
339
  setOpen(true);
205
340
  }, []);
206
341
  const rows = useSections((s) => s);
342
+ const desktopUpdate = useDesktopUpdate((state) => state);
207
343
  const connectionState = useConnectionState((state) => state);
208
344
  const previousConnectionState = (0, react.useRef)(connectionState);
209
345
  const onboardingSteps = useOnboardingSteps((s) => s);
210
- const onboardingActive = useSessions((state) => state.phase === "ready" && (state.current === void 0 || state.byId[state.current]?.blank === true));
211
- const onboardingStep = onboardingActive ? onboardingSteps.find((step) => !completedOnboarding.has(step.id)) : void 0;
346
+ const onboardingActive = useSessions((state) => {
347
+ const main = Object.values(state.byId).find((session) => (session.retainedBy.mainView ?? 0) > 0);
348
+ return state.phase === "ready" && (main === void 0 || main.blank);
349
+ });
350
+ const onboardingStep = requestedOnboarding !== void 0 ? onboardingSteps.find((step) => step.id === requestedOnboarding) : onboardingActive ? onboardingSteps.find((step) => !completedOnboarding.has(step.id)) : void 0;
212
351
  (0, react.useEffect)(() => {
213
352
  if (onboardingActive) return;
214
353
  setCompletedOnboarding(/* @__PURE__ */ new Set());
@@ -252,6 +391,7 @@ window.__ModuleLoader__.load({
252
391
  };
253
392
  }, [connectionState]);
254
393
  const completeOnboardingStep = (0, react.useCallback)((id) => {
394
+ setRequestedOnboarding(void 0);
255
395
  setCompletedOnboarding((previous) => {
256
396
  if (previous.has(id)) return previous;
257
397
  return new Set([...previous, id]);
@@ -263,27 +403,47 @@ window.__ModuleLoader__.load({
263
403
  else if (showRecovery) connectionIndicator = "recovered";
264
404
  return (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
265
405
  (0, react_jsx_runtime.jsxs)("div", {
406
+ ref: triggerRow,
266
407
  className: clsx(SettingsRoot_module_css_default.triggerRow, !wide && SettingsRoot_module_css_default.railRow),
267
- children: [(0, react_jsx_runtime.jsx)("button", {
268
- ref: triggerButton,
269
- type: "button",
270
- className: clsx(SettingsRoot_module_css_default.trigger, !wide && SettingsRoot_module_css_default.rail),
271
- "aria-label": t("trigger"),
272
- "aria-haspopup": "dialog",
273
- "aria-expanded": open,
274
- onClick: () => {
275
- setOpen(true);
276
- },
277
- children: renderSlot("settings.trigger", { wide })
278
- }), (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.ConnectionIndicator, {
279
- state: wide ? connectionIndicator : void 0,
280
- disconnectedLabel: t("connection.error"),
281
- connectingLabel: t("connection.connecting"),
282
- recoveredLabel: t("connection.connected"),
283
- reconnectActionLabel: t("connection.reconnect"),
284
- restartActionLabel: t("connection.restart"),
285
- onReconnect: reconnect
286
- })]
408
+ children: [
409
+ renderSlot("settings.launcher", {
410
+ wide,
411
+ openSettings: () => {
412
+ setOpen(true);
413
+ },
414
+ openOnboarding: (id) => {
415
+ setOpen(false);
416
+ setRequestedOnboarding(id);
417
+ }
418
+ }, { fallback: (0, react_jsx_runtime.jsx)("button", {
419
+ ref: triggerButton,
420
+ type: "button",
421
+ className: clsx(SettingsRoot_module_css_default.trigger, !wide && SettingsRoot_module_css_default.rail),
422
+ "aria-label": t("trigger"),
423
+ "aria-haspopup": "dialog",
424
+ "aria-expanded": open,
425
+ onClick: () => {
426
+ setOpen(true);
427
+ },
428
+ children: renderSlot("settings.trigger", { wide })
429
+ }) }),
430
+ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.ConnectionIndicator, {
431
+ state: wide && desktopUpdate.presentation?.phase !== "installing" ? connectionIndicator : void 0,
432
+ disconnectedLabel: t("connection.error"),
433
+ connectingLabel: t("connection.connecting"),
434
+ recoveredLabel: t("connection.connected"),
435
+ reconnectActionLabel: t("connection.reconnect"),
436
+ restartActionLabel: t("connection.restart"),
437
+ onReconnect: reconnect
438
+ }),
439
+ (0, react_jsx_runtime.jsx)(DesktopUpdateIndicator, {
440
+ wide,
441
+ hidden: connectionIndicator !== void 0 && desktopUpdate.presentation?.phase !== "installing",
442
+ t,
443
+ view: desktopUpdate,
444
+ onOpen: openDesktopUpdate
445
+ })
446
+ ]
287
447
  }),
288
448
  open && (0, react_jsx_runtime.jsx)(SettingsPanel, {
289
449
  rows,
@@ -294,6 +454,7 @@ window.__ModuleLoader__.load({
294
454
  }),
295
455
  onboardingStep !== void 0 && renderSlot("settings.onboarding", {
296
456
  stepId: onboardingStep.id,
457
+ explicit: requestedOnboarding !== void 0,
297
458
  complete: () => {
298
459
  completeOnboardingStep(onboardingStep.id);
299
460
  },
@@ -302,14 +463,84 @@ window.__ModuleLoader__.load({
302
463
  ] });
303
464
  }
304
465
  //#endregion
466
+ //#region lib/types/client/desktop-update-source.js
467
+ /** Client-owned observation of the optional Desktop preload. */
468
+ /** Owns one preload subscription across both sidebar locations. */
469
+ var DesktopUpdateSource = class {
470
+ bridge;
471
+ /** Framework-observed carrier status shared by both sidebar controls. */
472
+ store = (0, _deepseek_ai_dsh_client_store.createSnapshotStore)({
473
+ failed: false,
474
+ opening: false
475
+ });
476
+ live = true;
477
+ received = false;
478
+ unsubscribe;
479
+ /** @param bridge - Optional isolated Electron API, absent in ordinary browsers. */
480
+ constructor(bridge) {
481
+ this.bridge = bridge;
482
+ this.unsubscribe = bridge?.subscribe((presentation) => {
483
+ if (!this.live) return;
484
+ this.received = true;
485
+ this.store.set({
486
+ ...this.store.getSnapshot(),
487
+ presentation,
488
+ failed: false
489
+ });
490
+ });
491
+ bridge?.status().then((presentation) => {
492
+ if (this.live && !this.received) this.store.set({
493
+ ...this.store.getSnapshot(),
494
+ presentation
495
+ });
496
+ }, () => {
497
+ if (this.live && !this.received) this.store.set({
498
+ ...this.store.getSnapshot(),
499
+ failed: true
500
+ });
501
+ });
502
+ }
503
+ /** Invoke one user action; subsequent clicks join the shell-owned operation. */
504
+ open() {
505
+ if (!this.live || this.bridge === void 0) return;
506
+ const state = this.store.getSnapshot();
507
+ if (state.opening || state.presentation !== void 0 && [
508
+ "checking",
509
+ "downloading",
510
+ "verifying",
511
+ "installing"
512
+ ].includes(state.presentation.phase)) return;
513
+ this.store.set({
514
+ ...state,
515
+ opening: true
516
+ });
517
+ this.bridge.open().catch(() => {
518
+ if (this.live) this.store.set({
519
+ ...this.store.getSnapshot(),
520
+ failed: true
521
+ });
522
+ }).finally(() => {
523
+ if (this.live) this.store.set({
524
+ ...this.store.getSnapshot(),
525
+ opening: false
526
+ });
527
+ });
528
+ }
529
+ /** Detach the carrier and ignore any pending status or action completion. */
530
+ dispose() {
531
+ this.live = false;
532
+ this.unsubscribe?.();
533
+ }
534
+ };
535
+ //#endregion
305
536
  //#region \0dsh-css:/home/runner/work/deepseek-harness/deepseek-harness/packages/client/ui-settings-general/src/client/chrome.module.css.mjs
306
- const css$2 = ".UQsH_q_triggerLabel{white-space:nowrap;overflow:hidden}";
307
- const tagId$2 = "@deepseek-ai/dsh-client-ui-settings-general/chrome.module.css";
308
- if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$2) + "]") === null) {
537
+ const css$4 = ".UQsH_q_triggerLabel{white-space:nowrap;overflow:hidden}";
538
+ const tagId$4 = "@deepseek-ai/dsh-client-ui-settings-general/chrome.module.css";
539
+ if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$4) + "]") === null) {
309
540
  const tag = document.createElement("style");
310
541
  tag.dataset.plugin = "@deepseek-ai/dsh-client-ui-settings-general";
311
- tag.dataset.pluginCss = tagId$2;
312
- tag.textContent = css$2;
542
+ tag.dataset.pluginCss = tagId$4;
543
+ tag.textContent = css$4;
313
544
  document.head.appendChild(tag);
314
545
  }
315
546
  var chrome_module_css_default = { "triggerLabel": "UQsH_q_triggerLabel" };
@@ -327,7 +558,7 @@ window.__ModuleLoader__.load({
327
558
  * @returns the trigger content fragment.
328
559
  */
329
560
  function TriggerContent({ wide, t }) {
330
- return (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [wide ? (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconSettingsOutline16, { size: 16 }) : (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconSettingsOutline14, { size: 18 }), wide && (0, react_jsx_runtime.jsx)("span", {
561
+ return (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [(0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconSettingsOutlineMedium, { size: wide ? 16 : 18 }), wide && (0, react_jsx_runtime.jsx)("span", {
331
562
  className: chrome_module_css_default.triggerLabel,
332
563
  children: t("trigger")
333
564
  })] });
@@ -350,13 +581,13 @@ window.__ModuleLoader__.load({
350
581
  }
351
582
  //#endregion
352
583
  //#region \0dsh-css:/home/runner/work/deepseek-harness/deepseek-harness/packages/client/ui-settings-general/src/client/GeneralSection.module.css.mjs
353
- const css$1 = "._WvWnq_section{flex-direction:column;width:100%;display:flex}._WvWnq_section>[data-slot=\"settings.general.item\"]>:last-child{border-bottom:none}";
354
- const tagId$1 = "@deepseek-ai/dsh-client-ui-settings-general/GeneralSection.module.css";
355
- if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$1) + "]") === null) {
584
+ const css$3 = "._WvWnq_section{flex-direction:column;width:100%;display:flex}._WvWnq_section>[data-slot=\"settings.general.item\"]>:last-child{border-bottom:none}";
585
+ const tagId$3 = "@deepseek-ai/dsh-client-ui-settings-general/GeneralSection.module.css";
586
+ if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$3) + "]") === null) {
356
587
  const tag = document.createElement("style");
357
588
  tag.dataset.plugin = "@deepseek-ai/dsh-client-ui-settings-general";
358
- tag.dataset.pluginCss = tagId$1;
359
- tag.textContent = css$1;
589
+ tag.dataset.pluginCss = tagId$3;
590
+ tag.textContent = css$3;
360
591
  document.head.appendChild(tag);
361
592
  }
362
593
  var GeneralSection_module_css_default = { "section": "_WvWnq_section" };
@@ -374,6 +605,90 @@ window.__ModuleLoader__.load({
374
605
  });
375
606
  }
376
607
  //#endregion
608
+ //#region \0dsh-css:/home/runner/work/deepseek-harness/deepseek-harness/packages/client/ui-settings-general/src/client/CurrentVersionRow.module.css.mjs
609
+ const css$2 = ".yIbyla_row{color:var(--dsw-alias-label-primary);overflow-wrap:anywhere;padding:16px 0;font-size:14px;line-height:22px}";
610
+ const tagId$2 = "@deepseek-ai/dsh-client-ui-settings-general/CurrentVersionRow.module.css";
611
+ if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$2) + "]") === null) {
612
+ const tag = document.createElement("style");
613
+ tag.dataset.plugin = "@deepseek-ai/dsh-client-ui-settings-general";
614
+ tag.dataset.pluginCss = tagId$2;
615
+ tag.textContent = css$2;
616
+ document.head.appendChild(tag);
617
+ }
618
+ var CurrentVersionRow_module_css_default = { "row": "yIbyla_row" };
619
+ //#endregion
620
+ //#region lib/types/client/CurrentVersionRow.js
621
+ /**
622
+ * Render the version embedded by the client build; partial builds without metadata omit the row.
623
+ * @param props - runtime share and localized copy.
624
+ * @returns the current release label, or nothing when build metadata is absent.
625
+ */
626
+ function CurrentVersionRow({ t }) {
627
+ return (0, react_jsx_runtime.jsx)("div", {
628
+ className: CurrentVersionRow_module_css_default.row,
629
+ children: t("general.currentVersion", { version: "0.1.7-alpha.1" })
630
+ });
631
+ }
632
+ //#endregion
633
+ //#region \0dsh-css:/home/runner/work/deepseek-harness/deepseek-harness/packages/client/ui-settings-general/src/client/DeveloperToolsRow.module.css.mjs
634
+ const css$1 = ".Pt1bsG_row{border-bottom:.5px solid var(--dsw-alias-border-l2);justify-content:space-between;align-items:center;gap:24px;padding:16px 0;display:flex}.Pt1bsG_title{font-size:14px;line-height:20px}.Pt1bsG_description{color:var(--dsw-alias-label-secondary);margin-top:4px;font-size:12px;line-height:18px}";
635
+ const tagId$1 = "@deepseek-ai/dsh-client-ui-settings-general/DeveloperToolsRow.module.css";
636
+ if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$1) + "]") === null) {
637
+ const tag = document.createElement("style");
638
+ tag.dataset.plugin = "@deepseek-ai/dsh-client-ui-settings-general";
639
+ tag.dataset.pluginCss = tagId$1;
640
+ tag.textContent = css$1;
641
+ document.head.appendChild(tag);
642
+ }
643
+ var DeveloperToolsRow_module_css_default = {
644
+ "description": "Pt1bsG_description",
645
+ "row": "Pt1bsG_row",
646
+ "title": "Pt1bsG_title"
647
+ };
648
+ //#endregion
649
+ //#region lib/types/client/DeveloperToolsRow.js
650
+ /** General Settings control for shared developer-tool visibility and previews. */
651
+ /**
652
+ * Render the developer-tool toggle.
653
+ * @param props - accepted preference, writer and localized copy.
654
+ * @returns the General Settings row.
655
+ */
656
+ function DeveloperToolsRow({ useDeveloperTools, setEnabled, t }) {
657
+ const enabled = useDeveloperTools((value) => value);
658
+ const [busy, setBusy] = (0, react.useState)(false);
659
+ const [failed, setFailed] = (0, react.useState)(false);
660
+ return (0, react_jsx_runtime.jsxs)("div", {
661
+ className: DeveloperToolsRow_module_css_default.row,
662
+ children: [(0, react_jsx_runtime.jsxs)("div", { children: [
663
+ (0, react_jsx_runtime.jsx)("div", {
664
+ className: DeveloperToolsRow_module_css_default.title,
665
+ children: t("developerTools.title")
666
+ }),
667
+ (0, react_jsx_runtime.jsx)("div", {
668
+ className: DeveloperToolsRow_module_css_default.description,
669
+ children: t("developerTools.description")
670
+ }),
671
+ failed && (0, react_jsx_runtime.jsx)("div", {
672
+ role: "alert",
673
+ children: t("developerTools.error")
674
+ })
675
+ ] }), (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Switch, {
676
+ checked: enabled,
677
+ disabled: busy,
678
+ label: t("developerTools.title"),
679
+ onChange: (next) => {
680
+ setFailed(false);
681
+ setBusy(true);
682
+ setEnabled(next).catch(() => {
683
+ setFailed(true);
684
+ }).finally(() => {
685
+ setBusy(false);
686
+ });
687
+ }
688
+ })]
689
+ });
690
+ }
691
+ //#endregion
377
692
  //#region \0dsh-css:/home/runner/work/deepseek-harness/deepseek-harness/packages/client/ui-settings-general/src/client/SettingsDocumentAction.module.css.mjs
378
693
  const css = ".me01iq_action{align-items:center;gap:8px;min-width:0;display:flex}.me01iq_error{max-width:180px;color:var(--dsw-alias-state-error-primary);text-overflow:ellipsis;white-space:nowrap;font-size:12px;line-height:18px;overflow:hidden}";
379
694
  const tagId = "@deepseek-ai/dsh-client-ui-settings-general/SettingsDocumentAction.module.css";
@@ -510,11 +825,33 @@ window.__ModuleLoader__.load({
510
825
  /** Simplified Chinese dictionary (the key-set source of truth). */
511
826
  const zh = {
512
827
  "trigger": "设置",
828
+ "desktop.update.available": "新版本",
829
+ "desktop.update.checking": "正在检查更新…",
830
+ "desktop.update.progress": "{percent}%…",
831
+ "desktop.update.verifying": "正在校验更新文件…",
832
+ "desktop.update.installing": "正在准备重启…",
833
+ "desktop.update.ready": "安装并重启",
834
+ "desktop.update.retry": "重试更新",
835
+ "desktop.update.versionDetail": "{label} — V{version}",
836
+ "desktop.update.downloadDetail": "正在下载更新:{percent}%\n目标版本:V{version}",
837
+ "desktop.update.checkFailed": "检查更新失败,请稍后重试。",
838
+ "desktop.update.downloadFailed": "下载更新失败,请重试。",
839
+ "desktop.update.installFailed": "安装更新失败,请稍后重试。",
840
+ "desktop.update.checkNetworkFailed": "检查更新失败,请稍后重试。网络连接异常,请检查网络后重试。",
841
+ "desktop.update.downloadNetworkFailed": "下载更新失败,请重试。网络连接异常,请检查网络后重试。",
842
+ "desktop.update.installNetworkFailed": "安装更新失败,请稍后重试。网络连接异常,请检查网络后重试。",
843
+ "desktop.update.stopFailed": "未能安全停止任务,更新未安装。请稍后重试。",
844
+ "desktop.update.tasksChanged": "有新任务开始,请重新确认更新。",
845
+ "desktop.update.tasksUnavailable": "无法确认任务状态,请在工作区就绪后重试更新。",
513
846
  "title": "设置",
514
847
  "close": "关闭",
515
848
  "openDocument": "打开配置文件",
516
849
  "openDocument.error": "无法打开配置文件",
517
850
  "general.nav": "通用设置",
851
+ "general.currentVersion": "当前版本:{version}",
852
+ "developerTools.title": "开发者工具",
853
+ "developerTools.error": "保存失败,请重试",
854
+ "developerTools.description": "显示用于调试和排查问题的工具与信息",
518
855
  "connection.error": "连接异常,刷新重试",
519
856
  "connection.connecting": "重新连接中",
520
857
  "connection.connected": "连接成功",
@@ -524,11 +861,33 @@ window.__ModuleLoader__.load({
524
861
  /** English dictionary, checked complete against the zh key set. */
525
862
  const en = {
526
863
  "trigger": "Settings",
864
+ "desktop.update.available": "Update",
865
+ "desktop.update.checking": "Checking for updates…",
866
+ "desktop.update.progress": "{percent}%…",
867
+ "desktop.update.verifying": "Verifying update files…",
868
+ "desktop.update.installing": "Preparing to restart…",
869
+ "desktop.update.ready": "Install and Restart",
870
+ "desktop.update.retry": "Retry update",
871
+ "desktop.update.versionDetail": "{label} — V{version}",
872
+ "desktop.update.downloadDetail": "Downloading update: {percent}%\nTarget version: V{version}",
873
+ "desktop.update.checkFailed": "Could not check for updates. Please try again later.",
874
+ "desktop.update.downloadFailed": "Could not download the update. Please try again.",
875
+ "desktop.update.installFailed": "Could not install the update. Please try again later.",
876
+ "desktop.update.checkNetworkFailed": "Could not check for updates. Please try again later. The connection was interrupted. Check your network and try again.",
877
+ "desktop.update.downloadNetworkFailed": "Could not download the update. Please try again. The connection was interrupted. Check your network and try again.",
878
+ "desktop.update.installNetworkFailed": "Could not install the update. Please try again later. The connection was interrupted. Check your network and try again.",
879
+ "desktop.update.stopFailed": "Tasks could not be stopped safely. The update was not installed. Please try again later.",
880
+ "desktop.update.tasksChanged": "New tasks started. Review the update confirmation again.",
881
+ "desktop.update.tasksUnavailable": "Task status is unavailable. Try updating again when the workspace is ready.",
527
882
  "title": "Settings",
528
883
  "close": "Close",
529
884
  "openDocument": "Open configuration file",
530
885
  "openDocument.error": "Could not open configuration file",
531
886
  "general.nav": "General",
887
+ "general.currentVersion": "Current version: {version}",
888
+ "developerTools.title": "Developer tools",
889
+ "developerTools.error": "Could not save. Please try again.",
890
+ "developerTools.description": "Show tools and information for debugging and troubleshooting",
532
891
  "connection.error": "Disconnected",
533
892
  "connection.connecting": "Reconnecting",
534
893
  "connection.connected": "Connected",
@@ -550,7 +909,7 @@ window.__ModuleLoader__.load({
550
909
  "connection",
551
910
  "remote",
552
911
  "remote.settings",
553
- "settingsScope"
912
+ "configForms"
554
913
  ];
555
914
  /**
556
915
  * Register the `settings` dictionaries, the chrome content, and the General
@@ -558,13 +917,42 @@ window.__ModuleLoader__.load({
558
917
  * @param ctx - client root context.
559
918
  */
560
919
  function apply(ctx) {
920
+ ctx.slots.inject("settings.general.item", () => ctx.slots.register({
921
+ name: "settings.general.item",
922
+ id: "developer-tools",
923
+ order: 15,
924
+ locale: NS,
925
+ inject: () => ({
926
+ hooks: { developerTools: ctx.configForms.developerTools.enabled },
927
+ setEnabled: (enabled) => ctx.configForms.developerTools.setEnabled(enabled)
928
+ })
929
+ }, DeveloperToolsRow));
930
+ ctx.slots.inject("settings.general.item", () => ctx.slots.register({
931
+ name: "settings.general.item",
932
+ id: "current-version",
933
+ order: 100,
934
+ locale: NS
935
+ }, CurrentVersionRow));
561
936
  ctx.effect(() => ctx.locale.register(NS, {
562
937
  zh,
563
938
  en
564
939
  }), "ui-settings-general: dictionaries");
565
940
  const connection = ctx.get("connection");
941
+ const carrier = globalThis.dshDesktop;
942
+ const desktopUpdate = new DesktopUpdateSource(carrier?.protocolVersion === 1 ? carrier.updates : void 0);
943
+ ctx.effect(() => () => {
944
+ desktopUpdate.dispose();
945
+ }, "ui-settings-general: desktop update carrier");
946
+ ctx.slots.inject("sidebar.toggle.badge", () => ctx.slots.register({
947
+ name: "sidebar.toggle.badge",
948
+ locale: NS,
949
+ inject: () => ({ hooks: {
950
+ desktopUpdate: desktopUpdate.store,
951
+ connectionState: connection.state
952
+ } })
953
+ }, DesktopUpdateBadge));
566
954
  const t = ctx.locale.bind(NS);
567
- const documentController = ctx.remote.$host.isLoopback ? new SettingsDocumentStore(ctx, ctx.settingsScope.describe()) : void 0;
955
+ const documentController = ctx.remote.$host.isLoopback ? new SettingsDocumentStore(ctx, ctx.configForms.describe()) : void 0;
568
956
  const documentInjected = documentController === void 0 ? void 0 : () => ({
569
957
  controller: documentController,
570
958
  hooks: { snapshot: documentController.store }
@@ -578,10 +966,14 @@ window.__ModuleLoader__.load({
578
966
  let onboardingVersion = -1;
579
967
  let onboardingSteps = [];
580
968
  const shellInjected = () => ({
969
+ openDesktopUpdate: () => {
970
+ desktopUpdate.open();
971
+ },
581
972
  reconnect: () => {
582
973
  connection.reconnect();
583
974
  },
584
975
  hooks: {
976
+ desktopUpdate: desktopUpdate.store,
585
977
  connectionState: connection.state,
586
978
  sections: {
587
979
  getSnapshot: () => {
@@ -629,6 +1021,10 @@ window.__ModuleLoader__.load({
629
1021
  name: "sidebar.settings",
630
1022
  locale: NS,
631
1023
  children: {
1024
+ "settings.launcher": {
1025
+ kind: "single",
1026
+ scope: "root"
1027
+ },
632
1028
  "settings.trigger": {
633
1029
  kind: "single",
634
1030
  scope: "root"
package/lib/index.js CHANGED
@@ -1,14 +1,14 @@
1
1
  import z from "@deepseek-ai/schemastery";
2
2
  //#region lib/types/index.js
3
- /** Host loader entry for the browser implementation exported from `./client`. */
4
- /** Durable settings namespace for product-wide GUI onboarding facts. */
5
- const ONBOARDING_SETTINGS_NAMESPACE = "ui-onboarding";
6
- const OnboardingSettingsSchema = z.object({ welcomeNoticeVersion: z.string() });
7
- /** Register the durable GUI-onboarding section when a settings provider exists. */
3
+ /** Live welcome preference. */
4
+ const Config = z.object({ welcomeNoticeVersion: z.string().volatile() });
5
+ /** The browser consumes the configuration form projection.
6
+ * @param ctx Plugin context used for optional settings presentation.
7
+ */
8
8
  function apply(ctx) {
9
- ctx.inject(["settings"], (settingsCtx) => {
10
- settingsCtx.settings.register(ONBOARDING_SETTINGS_NAMESPACE, OnboardingSettingsSchema);
9
+ ctx.inject(["settings"], (child) => {
10
+ child.effect(() => child.settings.configure({ auto: false }, ctx.fiber));
11
11
  });
12
12
  }
13
13
  //#endregion
14
- export { apply };
14
+ export { Config, apply };
@@ -0,0 +1,9 @@
1
+ /** Installed release version in General Settings for Web and Desktop. */
2
+ import type { PropsLocale, PropsRuntime } from '@deepseek-ai/dsh-client-ui-slots';
3
+ /**
4
+ * Render the version embedded by the client build; partial builds without metadata omit the row.
5
+ * @param props - runtime share and localized copy.
6
+ * @returns the current release label, or nothing when build metadata is absent.
7
+ */
8
+ export declare function CurrentVersionRow({ t }: PropsRuntime<'settings.general.item'> & PropsLocale<'settings'>): import("react").JSX.Element | null;
9
+ //# sourceMappingURL=CurrentVersionRow.d.ts.map
@@ -0,0 +1,23 @@
1
+ import type { InjectFace, PropsLocale, PropsRuntime } from '@deepseek-ai/dsh-client-ui-slots';
2
+ import type { DesktopUpdateView } from '../types.ts';
3
+ import type { SettingsRootInjected } from './shell-contract.ts';
4
+ type SettingsTranslate = PropsLocale<'settings'>['t'];
5
+ /**
6
+ * @param props - Connection priority, sidebar width, and localized bridge-failure copy.
7
+ * @returns Desktop-only status beside the account button, or nothing in browsers.
8
+ */
9
+ export declare function DesktopUpdateIndicator({ wide, hidden, t, view, onOpen }: {
10
+ wide: boolean;
11
+ hidden: boolean;
12
+ t: SettingsTranslate;
13
+ view: DesktopUpdateView;
14
+ onOpen: () => void;
15
+ }): import("react").JSX.Element | null;
16
+ type BadgeProps = PropsRuntime<'sidebar.toggle.badge'> & PropsLocale<'settings'> & Pick<InjectFace<SettingsRootInjected>, 'useDesktopUpdate' | 'useConnectionState'>;
17
+ /**
18
+ * @param props - Framework-bound carrier and connection state.
19
+ * @returns A non-interactive notification on the sidebar expand button.
20
+ */
21
+ export declare function DesktopUpdateBadge({ useDesktopUpdate, useConnectionState, t }: BadgeProps): import("react").JSX.Element | null;
22
+ export {};
23
+ //# sourceMappingURL=DesktopUpdateIndicator.d.ts.map
@@ -0,0 +1,16 @@
1
+ import type { ObservableSnapshot } from '@deepseek-ai/dsh-client-store';
2
+ import type { InjectFace, PropsLocale, PropsRuntime } from '@deepseek-ai/dsh-client-ui-slots';
3
+ /** Accepted setting and ordered mutation supplied by the settings owner. */
4
+ export interface DeveloperToolsRowInjected {
5
+ hooks: {
6
+ developerTools: ObservableSnapshot<boolean>;
7
+ };
8
+ setEnabled(enabled: boolean): Promise<void>;
9
+ }
10
+ /**
11
+ * Render the developer-tool toggle.
12
+ * @param props - accepted preference, writer and localized copy.
13
+ * @returns the General Settings row.
14
+ */
15
+ export declare function DeveloperToolsRow({ useDeveloperTools, setEnabled, t }: PropsRuntime<'settings.general.item'> & PropsLocale<'settings'> & InjectFace<DeveloperToolsRowInjected>): import("react").JSX.Element;
16
+ //# sourceMappingURL=DeveloperToolsRow.d.ts.map
@@ -0,0 +1,17 @@
1
+ import type { DesktopUpdateBridge, DesktopUpdateView } from '../types.ts';
2
+ /** Owns one preload subscription across both sidebar locations. */
3
+ export declare class DesktopUpdateSource {
4
+ private readonly bridge;
5
+ /** Framework-observed carrier status shared by both sidebar controls. */
6
+ readonly store: import("@deepseek-ai/dsh-client-store").SnapshotStore<DesktopUpdateView>;
7
+ private live;
8
+ private received;
9
+ private readonly unsubscribe;
10
+ /** @param bridge - Optional isolated Electron API, absent in ordinary browsers. */
11
+ constructor(bridge: DesktopUpdateBridge | undefined);
12
+ /** Invoke one user action; subsequent clicks join the shell-owned operation. */
13
+ open(): void;
14
+ /** Detach the carrier and ignore any pending status or action completion. */
15
+ dispose(): void;
16
+ }
17
+ //# sourceMappingURL=desktop-update-source.d.ts.map
@@ -2,11 +2,33 @@
2
2
  /** Simplified Chinese dictionary (the key-set source of truth). */
3
3
  export declare const zh: {
4
4
  trigger: string;
5
+ 'desktop.update.available': string;
6
+ 'desktop.update.checking': string;
7
+ 'desktop.update.progress': string;
8
+ 'desktop.update.verifying': string;
9
+ 'desktop.update.installing': string;
10
+ 'desktop.update.ready': string;
11
+ 'desktop.update.retry': string;
12
+ 'desktop.update.versionDetail': string;
13
+ 'desktop.update.downloadDetail': string;
14
+ 'desktop.update.checkFailed': string;
15
+ 'desktop.update.downloadFailed': string;
16
+ 'desktop.update.installFailed': string;
17
+ 'desktop.update.checkNetworkFailed': string;
18
+ 'desktop.update.downloadNetworkFailed': string;
19
+ 'desktop.update.installNetworkFailed': string;
20
+ 'desktop.update.stopFailed': string;
21
+ 'desktop.update.tasksChanged': string;
22
+ 'desktop.update.tasksUnavailable': string;
5
23
  title: string;
6
24
  close: string;
7
25
  openDocument: string;
8
26
  'openDocument.error': string;
9
27
  'general.nav': string;
28
+ 'general.currentVersion': string;
29
+ 'developerTools.title': string;
30
+ 'developerTools.error': string;
31
+ 'developerTools.description': string;
10
32
  'connection.error': string;
11
33
  'connection.connecting': string;
12
34
  'connection.connected': string;
@@ -18,11 +40,33 @@ export type SettingsKey = keyof typeof zh;
18
40
  /** English dictionary, checked complete against the zh key set. */
19
41
  export declare const en: {
20
42
  trigger: string;
43
+ 'desktop.update.available': string;
44
+ 'desktop.update.checking': string;
45
+ 'desktop.update.progress': string;
46
+ 'desktop.update.verifying': string;
47
+ 'desktop.update.installing': string;
48
+ 'desktop.update.ready': string;
49
+ 'desktop.update.retry': string;
50
+ 'desktop.update.versionDetail': string;
51
+ 'desktop.update.downloadDetail': string;
52
+ 'desktop.update.checkFailed': string;
53
+ 'desktop.update.downloadFailed': string;
54
+ 'desktop.update.installFailed': string;
55
+ 'desktop.update.checkNetworkFailed': string;
56
+ 'desktop.update.downloadNetworkFailed': string;
57
+ 'desktop.update.installNetworkFailed': string;
58
+ 'desktop.update.stopFailed': string;
59
+ 'desktop.update.tasksChanged': string;
60
+ 'desktop.update.tasksUnavailable': string;
21
61
  title: string;
22
62
  close: string;
23
63
  openDocument: string;
24
64
  'openDocument.error': string;
25
65
  'general.nav': string;
66
+ 'general.currentVersion': string;
67
+ 'developerTools.title': string;
68
+ 'developerTools.error': string;
69
+ 'developerTools.description': string;
26
70
  'connection.error': string;
27
71
  'connection.connecting': string;
28
72
  'connection.connected': string;
@@ -8,6 +8,7 @@
8
8
  */
9
9
  import type { ConnectionState } from '@deepseek-ai/dsh-client-connection/client';
10
10
  import type { HostObservable, InjectFace, PropsLocale, PropsRenderSlots, PropsRuntime } from '@deepseek-ai/dsh-client-ui-slots';
11
+ import type { DesktopUpdateView } from '../types.ts';
11
12
  /** One nav row projected from a settings.section registration's options. */
12
13
  export interface SettingsSectionRow {
13
14
  id: string;
@@ -25,9 +26,13 @@ export interface SettingsOnboardingStep {
25
26
  * sources, while the reconnect command remains a plain callback.
26
27
  */
27
28
  export type SettingsRootInjected = {
29
+ /** Request the current shell-owned update action. */
30
+ openDesktopUpdate: () => void;
28
31
  /** Request a fresh logical generation and physical WebSocket immediately. */
29
32
  reconnect: () => void;
30
33
  hooks: {
34
+ /** Shared Electron status for both sidebar locations. */
35
+ desktopUpdate: HostObservable<DesktopUpdateView>;
31
36
  /** Connection-owned state for the current Host connection. */
32
37
  connectionState: HostObservable<ConnectionState | undefined>;
33
38
  /** settings.section ledger projected into ordered nav rows. */
@@ -42,5 +47,5 @@ export type SettingsRootInjected = {
42
47
  * (hooks compartment bound to useSections). No store is registered — modal
43
48
  * open state and active section id are component-local viewing state.
44
49
  */
45
- export type SettingsRootComponentProps = PropsRuntime<'sidebar.settings'> & PropsRenderSlots<'settings.trigger' | 'settings.header' | 'settings.action' | 'settings.close' | 'settings.section' | 'settings.onboarding'> & InjectFace<SettingsRootInjected> & PropsLocale<'settings'>;
50
+ export type SettingsRootComponentProps = PropsRuntime<'sidebar.settings'> & PropsRenderSlots<'settings.launcher' | 'settings.trigger' | 'settings.header' | 'settings.action' | 'settings.close' | 'settings.section' | 'settings.onboarding'> & InjectFace<SettingsRootInjected> & PropsLocale<'settings'>;
46
51
  //# sourceMappingURL=shell-contract.d.ts.map
@@ -1,5 +1,18 @@
1
- /** Host loader entry for the browser implementation exported from `./client`. */
2
- import type { Context } from '@deepseek-ai/cordis';
3
- /** Register the durable GUI-onboarding section when a settings provider exists. */
1
+ import type { Volatile, Context } from '@deepseek-ai/cordis';
2
+ import z from '@deepseek-ai/schemastery';
3
+ /** Runtime preferences projected to the browser. */
4
+ export interface Config {
5
+ /** Last acknowledged welcome notice version. */
6
+ welcomeNoticeVersion: Volatile<string | undefined>;
7
+ }
8
+ /** Live welcome preference. */
9
+ export declare const Config: z<Schemastery.ObjectS<NoInfer<{
10
+ welcomeNoticeVersion: z<string, string, "volatile">;
11
+ }>>, Schemastery.ObjectT<NoInfer<{
12
+ welcomeNoticeVersion: z<string, string, "volatile">;
13
+ }>>, "plain">;
14
+ /** The browser consumes the configuration form projection.
15
+ * @param ctx Plugin context used for optional settings presentation.
16
+ */
4
17
  export declare function apply(ctx: Context): void;
5
18
  //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1,23 @@
1
+ /** Type-only Electron update declarations shared by the settings UI and Desktop compatibility checks. */
2
+ /** Classified failure copy selected by the Web locale without exposing raw updater diagnostics. */
3
+ export type DesktopUpdateFailureKind = 'check' | 'check-network' | 'download' | 'download-network' | 'install' | 'install-network' | 'stop-failed' | 'tasks-changed' | 'tasks-unavailable';
4
+ /** Public semantic preload fields consumed by the settings row. */
5
+ export interface DesktopUpdatePresentation {
6
+ readonly phase: 'idle' | 'checking' | 'available' | 'downloading' | 'verifying' | 'installing' | 'ready' | 'error';
7
+ readonly version?: string;
8
+ readonly percent?: number;
9
+ readonly failure?: DesktopUpdateFailureKind;
10
+ }
11
+ /** Optional carrier API; it cannot select artifacts or authorize installation. */
12
+ export interface DesktopUpdateBridge {
13
+ status(): Promise<DesktopUpdatePresentation>;
14
+ open(): Promise<void>;
15
+ subscribe(listener: (state: DesktopUpdatePresentation) => void): () => void;
16
+ }
17
+ /** Shared carrier status for the account row and collapsed sidebar badge. */
18
+ export interface DesktopUpdateView {
19
+ readonly presentation?: DesktopUpdatePresentation;
20
+ readonly failed: boolean;
21
+ readonly opening: boolean;
22
+ }
23
+ //# sourceMappingURL=types.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.6-alpha.1",
4
+ "version": "0.1.7-alpha.1",
5
5
  "publishConfig": {
6
6
  "access": "public"
7
7
  },
@@ -22,6 +22,9 @@
22
22
  "types": "./lib/types/client/index.d.ts",
23
23
  "default": "./lib/client.js"
24
24
  },
25
+ "./types": {
26
+ "types": "./lib/types/types.d.ts"
27
+ },
25
28
  "./src/*": "./src/*",
26
29
  "./package.json": "./package.json"
27
30
  },
@@ -39,29 +42,29 @@
39
42
  },
40
43
  "license": "MIT",
41
44
  "dependencies": {
42
- "@deepseek-ai/schemastery": "^3.18.2"
45
+ "@deepseek-ai/schemastery": "^3.18.3"
43
46
  },
44
47
  "peerDependencies": {
45
- "@deepseek-ai/cordis": "^4.0.2"
48
+ "@deepseek-ai/cordis": "^4.0.3"
46
49
  },
47
50
  "devDependencies": {
48
51
  "@types/react": "~18.3.1",
49
52
  "clsx": "^2.0.0",
50
53
  "react": "^18.2.0",
51
- "@deepseek-ai/cordis": "^4.0.2",
52
- "@deepseek-ai/dsh-api-remotes": "^0.1.6-alpha.1",
53
- "@deepseek-ai/dsh-client-connection": "^0.1.6-alpha.1",
54
- "@deepseek-ai/dsh-client-locale": "^0.1.6-alpha.1",
55
- "@deepseek-ai/dsh-client-store": "^0.1.6-alpha.1",
56
- "@deepseek-ai/dsh-client-ui-primitives": "^0.1.6-alpha.1",
57
- "@deepseek-ai/dsh-client-ui-renderer": "^0.1.6-alpha.1",
58
- "@deepseek-ai/dsh-client-ui-session": "^0.1.6-alpha.1",
59
- "@deepseek-ai/dsh-client-ui-sidebar": "^0.1.6-alpha.1",
60
- "@deepseek-ai/dsh-client-ui-slots": "^0.1.6-alpha.1",
61
- "@deepseek-ai/dsh-remote-mock": "^0.1.6-alpha.1",
62
- "@deepseek-ai/dsh-settings": "^0.1.6-alpha.1",
63
- "@deepseek-ai/dsh-client-test-runtime": "^0.1.6-alpha.1",
64
- "@deepseek-ai/dsh-client-ui-settings": "^0.1.6-alpha.1"
54
+ "@deepseek-ai/cordis": "^4.0.3",
55
+ "@deepseek-ai/dsh-api-remotes": "^0.1.7-alpha.1",
56
+ "@deepseek-ai/dsh-client-connection": "^0.1.7-alpha.1",
57
+ "@deepseek-ai/dsh-client-locale": "^0.1.7-alpha.1",
58
+ "@deepseek-ai/dsh-client-store": "^0.1.7-alpha.1",
59
+ "@deepseek-ai/dsh-client-test-runtime": "^0.1.7-alpha.1",
60
+ "@deepseek-ai/dsh-client-ui-primitives": "^0.1.7-alpha.1",
61
+ "@deepseek-ai/dsh-client-ui-renderer": "^0.1.7-alpha.1",
62
+ "@deepseek-ai/dsh-client-ui-settings": "^0.1.7-alpha.1",
63
+ "@deepseek-ai/dsh-client-ui-session": "^0.1.7-alpha.1",
64
+ "@deepseek-ai/dsh-client-ui-sidebar": "^0.1.7-alpha.1",
65
+ "@deepseek-ai/dsh-client-ui-slots": "^0.1.7-alpha.1",
66
+ "@deepseek-ai/dsh-remote-mock": "^0.1.7-alpha.1",
67
+ "@deepseek-ai/dsh-settings": "^0.1.7-alpha.1"
65
68
  },
66
69
  "files": [
67
70
  "lib/index.js",