@deepseek-ai/dsh-client-ui-settings 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/README.md
5
- README.md: 760b4a4567481b561ce319926149815119018177
6
- README.zh.md: f8e2128d734b650b7cd7a10c180f90ea01b77ab5
5
+ README.md: 67b094993acbff92917594aafd0731818b5daa1b
6
+ README.zh.md: eec972705e9113594b06aca0ee5b8b149b5c62ca
package/README.md CHANGED
@@ -1,5 +1,5 @@
1
1
  ---
2
- description: "Settings domain base plugin: the settings-namespace scope service, schema service, and the canonical settings slot-type contract for the dsh web client."
2
+ description: "Settings domain base plugin: shared configuration forms, schema service, and the canonical settings slot-type contract for the dsh web client."
3
3
  kind: "package-reference"
4
4
  ---
5
5
 
@@ -27,23 +27,31 @@ This package lets web-client features expose editable preferences backed by the
27
27
 
28
28
  Feature plugins use this package to store and edit their preferences without re-implementing transport or schema handling. Mount it once per composition; it injects the `remote` service with its `settings` namespace and owns the single `settings.describe` reader in the browser.
29
29
 
30
- ### Binding a namespace
30
+ ### Configuration forms
31
31
 
32
- A feature calls `ctx.settingsScope.bind(spec)` with a per-namespace spec and gets a scope derived from the shared document mirror. The scope snapshot carries the resolved section, composition `base`, raw `user`, revision, writability, and host/memory mode; a field is overridden when it is present in `user`, even when its value equals `base`, and `unset` clears that override. Writes go through the scope: `set` and `unset` submit one operation, while `mutate` submits several ordered operations atomically. Each write is fenced by the namespace revision as `expectedRevision`, so a concurrent write from another surface is refused instead of silently overwritten. A staged editor can supply the revision where its draft began as a fixed fence; otherwise the scope uses the latest queued or mirrored revision.
32
+ `ctx.configForms.developerTools` owns the shared Web and desktop preference `ui-settings.enabled`, defaulting to `true`. Its `enabled` observable publishes accepted choices and `setEnabled` uses the same ordered settings writes. Desktop and loopback Web persist to the Host document; remote Web keeps this choice in one browser-local observable until reload without issuing Host writes. This controls presentation and HTML preview permissions, not Host authorization or Session recording. Host-backed clients keep developer features disabled until the first accepted schema-resolved value arrives; missing or failed initial responses do not enable them. Later refreshes retain the last accepted choice.
33
+
34
+ Feature adapters use `ctx.configForms.get(entryId)` to obtain accepted values and a write queue shared by every editor of that Host entry. Snapshots contain resolved `value`, inherited `base`, raw `user`, revision, writability, and persistence mode. `set` and `unset` submit one operation; `mutate` submits one atomic operation list. Staged editors pass the revision read before editing; conflicts preserve their drafts. Unsetting removes the override and restores inheritance.
35
+
36
+ ### Following served namespaces
37
+
38
+ A page that edits a namespace another plugin owns registers through `ctx.configForms.whileServed(namespaces, register)`: `register` runs once any listed namespace is in the shared mirror, receives the set of namespaces the Host serves, and returns the registration's disposer, which runs when none of them is served any more or when the disposer `whileServed` returns runs. The caller owns that returned disposer and wraps it in `ctx.effect`; unlike `get`, the service registers nothing on the caller's context. A deployment that never composed the owner therefore shows no trace of the page, and a namespace the Host stops serving withdraws it. The four official pages on the Plugins page ride it, one companion package each.
33
39
 
34
40
  ### Filling the settings slots
35
41
 
36
- A settings surface registers into the slot types this package declares. The shell (`sidebar.settings` occupant, navigation, chrome) lives in ui-settings-general; feature pages register `settings.section` contributions; the Plugins section hosts `settings.plugins.tab` pages; onboarding steps register `settings.onboarding`. Cross-namespace surfaces (schema introspection, the served-namespace directory, `hasDocument`) read the same mirror through `ctx.settingsScope.describe()`.
42
+ A settings surface registers into the slot types this package declares. The shell (`sidebar.settings` occupant, navigation, chrome) lives in ui-settings-general; feature pages register `settings.section` contributions; the Plugins section hosts `settings.plugins.tab` pages; onboarding steps register `settings.onboarding`. Cross-namespace surfaces (schema introspection, the served-namespace directory, `hasDocument`) read the same mirror through `ctx.configForms.describe()`.
37
43
 
38
44
  ### Observable success and failures
39
45
 
40
- A bound scope reflects the current document revision immediately; a committed write folds its answer back into the mirror with no re-read. A rejected or failed latest write triggers one mirror recovery read; a superseded write leaves recovery to its successor. Without a `decode` in the spec, a section that is not a plain object or fails schema rehydration publishes no value, so a row renders its own absent state instead of a half-decoded one.
46
+ A committed write folds its answer into the shared mirror. Refused writes refresh the latest Host values. Browser validation uses the serialized Config schema; the Host validates complete configuration, including checks that cannot be serialized.
41
47
 
42
48
  -----
43
49
 
44
50
  <a id="understand-the-implementation"></a>
45
51
  ## Understand the implementation
46
52
 
53
+ The optional settings.launcher contribution receives wide and openSettings to supply a sidebar account menu; the shell retains its plain Settings trigger when no launcher is registered.
54
+
47
55
  <details>
48
56
  <summary>Implementation internals — click to expand</summary>
49
57
 
@@ -51,15 +59,15 @@ The package realizes one ownership rule: the browser keeps one shared mirror of
51
59
 
52
60
  ### The describe mirror
53
61
 
54
- The plugin injects `remote` with its `settings` namespace, resolves Host persistence once from the fixed `remote.$host` facts, and owns the one `settings.describe` reader in the browser: a shared mirror refreshed on every forwarded `settings/document-updated` event and on `connection/reset` (the first connection included, closing the window where a commit lands between the eager read and the SSE subscription). Cross-namespace surfaces read it through `ctx.settingsScope.describe()`, a read/fold face (`getSnapshot`/`subscribe`/`ensure`, plus `acceptView` folding a write answer in).
62
+ The Host Config of the `ui-settings` entry declares the default-on `enabled` preference. The Client plugin injects `remote` with its `settings` namespace, resolves Host persistence once from the fixed `remote.$host` facts, and owns the one `settings.describe` reader in the browser: a shared mirror refreshed on every forwarded `settings/document-updated` event and on `connection/reset` (the first connection included, closing the window where a commit lands between the eager read and the SSE subscription). Cross-namespace surfaces read it through `ctx.configForms.describe()`, a read/fold face (`getSnapshot`/`subscribe`/`ensure`, plus `acceptView` folding a write answer in).
55
63
 
56
- ### Scope derivation
64
+ ### Shared entry writes
57
65
 
58
- `ctx.settingsScope.bind(spec)` returns a per-namespace scope derived from the mirror on the caller's context: the scope's disposer belongs to the calling fiber, binding adds no wire read, and a row's activation never blocks on the settings transport. Writes stay per-scope: `set` and `unset` are single-operation forms of `mutate`, which copies and queues several ordered field operations behind one namespace revision as `expectedRevision`. A committed mutation folds its answer in, a rejected or failed latest mutation triggers one recovery read, and a superseded one leaves recovery to its successor. The cold-boot read count is pinned by `../../../apps/web/tests/startup-rpc-budget.e2e.ts`; a new direct `settings.describe` caller in client code is a regression against it.
66
+ The provider owns one controller per Host entry, including its subscription and write queue; repeated `get(entryId)` calls return the same form. Consumers release their own view subscriptions. No caller-scoped configuration binding is created. The startup RPC budget covers the shared describe reader.
59
67
 
60
68
  ### Schema service
61
69
 
62
- `ctx.settingsSchema` performs synchronous schema rehydration, validation, and immutable path editing for settings plugins. Without a `decode` in the spec, a section that is not a plain object, fails its rehydrated schema, or carries a schema envelope this client cannot rehydrate publishes no value at all.
70
+ `ctx.settingsSchema` rehydrates schemas, validates drafts, and edits nested values. Invalid wire values do not replace accepted values.
63
71
 
64
72
  </details>
65
73
 
@@ -71,7 +79,8 @@ The plugin injects `remote` with its `settings` namespace, resolves Host persist
71
79
  These pages cover the settings surface family and the durable seam behind it.
72
80
 
73
81
  - [ui-settings-general](../ui-settings-general/README.md) — the settings shell: trigger chrome, navigation, General section, onboarding projection.
74
- - [ui-settings-plugins](../ui-settings-plugins/README.md) — the Plugins section and its configurable host-plane cards.
82
+ - [ui-settings-plugins](../ui-settings-plugins/README.md) — the Built-in plugins section shell around the inventory tab.
83
+ - [ui-settings-shell](../ui-settings-shell/README.md), [ui-settings-agent-loop](../ui-settings-agent-loop/README.md), [ui-settings-subagent](../ui-settings-subagent/README.md), [ui-settings-web-search](../ui-settings-web-search/README.md) — the official configuration pages on the Plugins page, each following its namespaces through `whileServed`.
75
84
  - [ui-settings-models](../ui-settings-models/README.md) — the Models page and DeepSeek onboarding over this base.
76
85
  - [settings](../../settings/README.md) — the durable user-settings seam and its file provider.
77
86
  - [ui-sidebar](../ui-sidebar/README.md) — the sidebar shell whose bottom seat hosts the settings trigger.
@@ -94,7 +103,7 @@ None; this package neither assembles nor sends a provider request.
94
103
 
95
104
  These limits define where the settings transport cannot reach; they are current package constraints.
96
105
 
97
- - **Non-loopback pages get no durable settings** — this Client keeps Host persistence disabled there, so a scope starts `unavailable` and never crosses the wire; every row it backs is inert even though Connection authentication covers the API.
106
+ - **Non-loopback pages get no durable settings** — this Client keeps Host persistence disabled there, so a form starts `unavailable` and never crosses the wire; form writes are inert even though Connection authentication covers the API. The shared Developer tools preference instead provides browser-local changes.
98
107
 
99
108
  <a id="dev-note"></a>
100
109
  ### Dev Note
package/README.zh.md CHANGED
@@ -1,5 +1,5 @@
1
1
  ---
2
- description: "设置领域底座插件:设置命名空间 scope 服务、schema 服务,以及 dsh Web 客户端的规范设置 slot 类型约定。"
2
+ description: "设置领域底座插件:共享配置表单、schema 服务,以及 dsh Web 客户端的规范设置 slot 类型约定。"
3
3
  kind: "package-reference"
4
4
  ---
5
5
 
@@ -27,23 +27,31 @@ kind: "package-reference"
27
27
 
28
28
  功能插件用本包存储与编辑自己的偏好设置,而无需重新实现传输层或 schema 处理。每个组合挂载一次即可;它注入 `remote` 服务及其 `settings` 命名空间,并持有浏览器中唯一的 `settings.describe` 读取方。
29
29
 
30
- ### 绑定命名空间
30
+ ### 配置表单
31
31
 
32
- 功能调用 `ctx.settingsScope.bind(spec)` 并传入按命名空间的 spec,得到一个由共享文档镜像派生的 scope。scope 快照携带解析后的分区、组合 `base`、原始 `user`、revision、可写性以及 host/内存模式;字段只要出现在 `user` 中即视为覆盖,即使其值与 `base` 相等,`unset` 会清除该覆盖。写入经 scope 进行:`set` 与 `unset` 提交一个操作,`mutate` 则原子提交多个有序操作。每次写入都以命名空间 revision 作为 `expectedRevision` 围栏,因此来自另一界面的并发写入会被拒绝,而不是被静默覆盖。暂存编辑器可以把开始草拟时读取的 revision 作为固定围栏传入;否则 scope 使用最新排队或镜像 revision。
32
+ `ctx.configForms.developerTools` 管理 Web 和桌面端共享的偏好 `ui-settings.enabled`,默认为 `true`。其 `enabled` 可观察值发布已接受的选择,`setEnabled` 使用相同的有序设置写入。桌面端和回环 Web 将设置持久化到 Host 文档;远程 Web 将此选择保存在单个浏览器本地可观察值中,刷新后重置,不发送 Host 写入。此设置控制界面展示和 HTML 预览权限,不控制 Host 授权或 Session 记录。 使用 Host 偏好的客户端在首个经过 schema 解析并接受的值到达前保持开发者功能关闭;首次响应缺失或失败不会启用它们。后续刷新保留已接受的选择。
33
+
34
+ 功能适配器使用 `ctx.configForms.get(entryId)` 获取该 Host 条目所有编辑器共享的已接受值和写入队列。快照包含解析后的 `value`、继承 `base`、原始 `user`、修订号、可写性和持久化模式。`set` 与 `unset` 提交单个操作,`mutate` 提交一个原子操作列表。暂存编辑器传入编辑前读取的修订号;冲突时保留草稿。清除操作移除覆盖并恢复继承。
35
+
36
+ ### 跟随被服务的命名空间
37
+
38
+ 编辑另一个插件所拥有命名空间的页面通过 `ctx.configForms.whileServed(namespaces, register)` 注册:只要所列命名空间中的任一个进入共享镜像,`register` 就运行一次,收到 Host 当前服务的命名空间集合,并返回该注册的 disposer;当它们全都不再被服务,或 `whileServed` 返回的 disposer 被调用时,这个 disposer 就运行。调用方持有返回的 disposer 并把它包进 `ctx.effect`;与 `get` 不同,服务不会在调用方的 context 上注册任何东西。因此从未组合过所有者的部署看不到该页面的任何痕迹,Host 停止服务的命名空间会撤下它。插件页上的四个官方页面各自通过一个伴生包走这条路径。
33
39
 
34
40
  ### 填充设置 slot
35
41
 
36
- 设置界面会注册进本包声明的 slot 类型。外壳(`sidebar.settings` 占位方、导航、界面框架)位于 ui-settings-general;功能页面注册 `settings.section` 贡献;「插件」分区承载 `settings.plugins.tab` 页面;首次使用引导步骤注册 `settings.onboarding`。跨命名空间的表面(schema 内省、已服务命名空间目录、`hasDocument`)通过 `ctx.settingsScope.describe()` 读同一面镜像。
42
+ 设置界面会注册进本包声明的 slot 类型。外壳(`sidebar.settings` 占位方、导航、界面框架)位于 ui-settings-general;功能页面注册 `settings.section` 贡献;「插件」分区承载 `settings.plugins.tab` 页面;首次使用引导步骤注册 `settings.onboarding`。跨命名空间的表面(schema 内省、已服务命名空间目录、`hasDocument`)通过 `ctx.configForms.describe()` 读同一面镜像。
37
43
 
38
44
  ### 可观察的成功与失败
39
45
 
40
- 绑定后的 scope 会立即反映当前文档 revision;提交成功的写入把应答折回镜像、不再重读。被拒绝或失败的最新写入触发一次镜像恢复读取;被取代的写入把恢复留给后继者。若 spec 未提供 `decode`,则分区不是普通对象或未通过 schema 重建时一律不发布任何值,于是行渲染自己的缺失状态,而不是一份半解码的值。
46
+ 已提交的写入将应答合入共享镜像。被拒绝的写入刷新最新 Host 值。浏览器使用序列化的 Config schema 校验;Host 校验完整配置,包括无法序列化的检查。
41
47
 
42
48
  -----
43
49
 
44
50
  <a id="understand-the-implementation"></a>
45
51
  ## 理解实现
46
52
 
53
+ 可选的 settings.launcher 贡献接收 wide 和 openSettings,以提供侧边栏账号菜单;未注册时,外壳保留普通设置按钮。
54
+
47
55
  <details>
48
56
  <summary>实现细节——点击展开</summary>
49
57
 
@@ -51,15 +59,15 @@ kind: "package-reference"
51
59
 
52
60
  ### Describe 镜像
53
61
 
54
- 插件注入 `remote` 及其 `settings` 命名空间,从固定的 `remote.$host` 事实一次性解析 Host 持久化模式,并持有浏览器中唯一的 `settings.describe` 读取方:一面共享镜像,在每次转发的 `settings/document-updated` 事件与 `connection/reset` 时刷新(首次连接也包含在内,关闭「提交落在急切读取与 SSE 订阅之间」的窗口)。跨命名空间表面通过 `ctx.settingsScope.describe()` 读它,这是一个读取/折叠面(`getSnapshot`/`subscribe`/`ensure`,另有把写应答折入的 `acceptView`)。
62
+ `ui-settings` 条目的 Host Config 声明默认开启的 `enabled` 偏好。Client 插件注入 `remote` 及其 `settings` 命名空间,从固定的 `remote.$host` 事实一次性解析 Host 持久化模式,并持有浏览器中唯一的 `settings.describe` 读取方:一面共享镜像,在每次转发的 `settings/document-updated` 事件与 `connection/reset` 时刷新(首次连接也包含在内,关闭「提交落在急切读取与 SSE 订阅之间」的窗口)。跨命名空间表面通过 `ctx.configForms.describe()` 读它,这是一个读取/折叠面(`getSnapshot`/`subscribe`/`ensure`,另有把写应答折入的 `acceptView`)。
55
63
 
56
- ### Scope 派生
64
+ ### 共享条目写入
57
65
 
58
- `ctx.settingsScope.bind(spec)` 在调用方的 context 上返回一个由镜像派生的按命名空间 scope:scope 的 disposer 归调用方 fiber 所有,绑定不新增任何线路读取,某一行的激活绝不会阻塞在设置传输层上。写入仍归各 scope:`set` 与 `unset` 是 `mutate` 的单操作形式,后者会复制操作列表,并把多个有序字段操作排在同一个作为 `expectedRevision` 的命名空间 revision 之后。提交成功的 mutation 把应答折回镜像,被拒绝或失败的最新 mutation 触发一次恢复读取,被取代的 mutation 把恢复留给后继者。冷启动读取次数由 `../../../apps/web/tests/startup-rpc-budget.e2e.ts` 钉住;客户端代码中新增直连 `settings.describe` 调用即是对它的回归。
66
+ 提供者为每个 Host 条目持有一个控制器,包括其订阅和写入队列;重复调用 `get(entryId)` 返回同一表单。消费者释放自己的视图订阅。不创建调用方作用域的配置绑定。启动 RPC 预算覆盖共享的 describe 读取。
59
67
 
60
68
  ### Schema 服务
61
69
 
62
- `ctx.settingsSchema` 为设置插件执行同步 schema 重建、校验与不可变路径编辑。若 spec 未提供 `decode`,则分区不是普通对象、未通过其重建后的 schema 校验、或携带本客户端无法重建的 schema 信封时,一律不发布任何值。
70
+ `ctx.settingsSchema` 重建 schema、校验草稿并编辑嵌套值。无效的线路值不会替换已接受值。
63
71
 
64
72
  </details>
65
73
 
@@ -71,7 +79,8 @@ kind: "package-reference"
71
79
  以下页面覆盖设置界面家族及其背后的持久化 seam。
72
80
 
73
81
  - [ui-settings-general](../ui-settings-general/README.zh.md)——设置外壳:触发控件、导航、「通用」分区、引导投影。
74
- - [ui-settings-plugins](../ui-settings-plugins/README.zh.md)——「插件」分区及其可配置宿主平面卡片。
82
+ - [ui-settings-plugins](../ui-settings-plugins/README.zh.md)——围绕清单标签页的「内置插件」分区壳。
83
+ - [ui-settings-shell](../ui-settings-shell/README.zh.md)、[ui-settings-agent-loop](../ui-settings-agent-loop/README.zh.md)、[ui-settings-subagent](../ui-settings-subagent/README.zh.md)、[ui-settings-web-search](../ui-settings-web-search/README.zh.md)——插件页上的官方配置页,各自通过 `whileServed` 跟随其命名空间。
75
84
  - [ui-settings-models](../ui-settings-models/README.zh.md)——建立在本底座之上的 Models 页面与 DeepSeek 引导。
76
85
  - [settings](../../settings/README.zh.md)——持久化用户设置 seam 及其文件提供方。
77
86
  - [ui-sidebar](../ui-sidebar/README.zh.md)——底部席位承载设置触发控件的侧边栏外壳。
@@ -94,7 +103,7 @@ kind: "package-reference"
94
103
 
95
104
  这些限制说明设置传输层够不到的地方;它们是当前包约束。
96
105
 
97
- - **非 loopback 页面没有持久化设置**:本 Client 在那里禁用 Host 持久化,因此 scope 以 `unavailable` 起步且从不跨线路;尽管 Connection 认证覆盖 API,它支撑的每一行仍在那里无效。
106
+ - **非 loopback 页面没有持久化设置**:本 Client 在那里禁用 Host 持久化,因此 表单以 `unavailable` 起步且从不跨线路;尽管 Connection 认证覆盖 API,表单写入仍在那里无效。共享的开发者工具偏好单独提供浏览器本地变更。
98
107
 
99
108
  <a id="dev-note"></a>
100
109
  ### 开发备注