@deepseek-ai/dsh-client-ui-settings-models 0.2.1-alpha.2 → 0.2.1-alpha.3

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
@@ -18,11 +18,11 @@
18
18
  en: db5aaf7f702e1f0c
19
19
  zh: 409a78c14fb2b6e3
20
20
  /deepseek-ai-dsh-client-ui-settings-models/use-this-package/api-keys:
21
- en: c2f2a5c06ef20d5b
22
- zh: 49a7eb0b66b4ed53
21
+ en: f4817eb2e3537ed9
22
+ zh: e589c193fa85473f
23
23
  /deepseek-ai-dsh-client-ui-settings-models/use-this-package/editing-a-provider:
24
- en: ec0ba62a4e7185b4
25
- zh: 37d1e1e7a3817d12
24
+ en: eac663a25c60adf9
25
+ zh: 24450ef377a79e01
26
26
  /deepseek-ai-dsh-client-ui-settings-models/use-this-package/adding-and-deleting-providers:
27
27
  en: 9d533c65c82cd4a4
28
28
  zh: 0a5da334e127c035
@@ -30,8 +30,8 @@
30
30
  en: 589397a35f82244e
31
31
  zh: 342fbceee2c173a2
32
32
  /deepseek-ai-dsh-client-ui-settings-models/use-this-package/extension-slots:
33
- en: 65e9d8822b67b6c2
34
- zh: 7e83be9defda28ee
33
+ en: 79f8f80bdaba73cd
34
+ zh: f4d7496b293fbf81
35
35
  /deepseek-ai-dsh-client-ui-settings-models/understand-the-implementation:
36
36
  en: a87afbec5e339b36
37
37
  zh: 6348c81af7e650e1
@@ -42,8 +42,8 @@
42
42
  en: 6e04c00818f014cd
43
43
  zh: 2d57f8d8944e67ed
44
44
  /deepseek-ai-dsh-client-ui-settings-models/understand-the-implementation/onboarding-coordinator:
45
- en: 46dea666dffe8813
46
- zh: 6f56fdc365fa3642
45
+ en: dc515a31212e477a
46
+ zh: 770ba77cd9a69f73
47
47
  /deepseek-ai-dsh-client-ui-settings-models/further-exploration:
48
48
  en: 20abd8b98b6c20e2
49
49
  zh: 6dfda7955ce5f33f
package/README.md CHANGED
@@ -41,13 +41,19 @@ Host configuration `credentialOnboarding` defaults to `true`. The Electron prelo
41
41
 
42
42
  ### API keys
43
43
 
44
- API-key inputs start empty and use `autocomplete="new-password"` to ask browsers not to autofill saved login passwords.
44
+ API-key inputs start empty and use `autocomplete="new-password"` to ask browsers not to autofill saved login passwords. A nonempty draft has the same eye control as masked conversation text: **Show secret** reveals the current input and **Hide secret** masks it. Changing or clearing the input masks it again. Stored credentials are never read into the input.
45
45
 
46
- The primary field on an editor card is a single **API key** input — the page never asks for an environment-variable name. A typed key stores write-only through `credentials.set` under the profile's reference, deriving `<ROUTE>_API_KEY` when the profile has none, and the pi-ai profile records that derivation as `apiKeyEnv`, so `cordis.patch.yml` never carries a key value. Leaving a new pi-ai provider's key blank saves a reference-free profile and preserves provider-native authentication (for example the Bedrock credential chain or Vertex ADC). A row labels API-key state with a green solid dot only when a referenced credential is confirmed configured, and with a red solid dot only when a named reference is confirmed missing. A successful Apply emits a local accessible status message without echoing secret material.
46
+ The primary field on an editor card is a single **API key** input — the page never asks for an environment-variable name. A typed key stores write-only through `credentials.set` under the profile's reference, deriving `<ROUTE>_API_KEY` when the profile has none, and the pi-ai profile records that derivation as `apiKeyEnv`, so `cordis.patch.yml` never carries a key value. Leaving a new pi-ai provider's key blank saves a reference-free profile and preserves provider-native authentication (for example the Bedrock credential chain or Vertex ADC). The field's placeholder and help tooltip use the profile's `apiKeyEnv` when it has one; otherwise they use the credential variables of the route's `nativeAuth`, excluding `baseURLEnv` address variables, in lookup order, as the configurable-provider directory reports them. These display hints omit references containing `oauth` (case-insensitively), and describe saved credentials followed by the displayed environment fallbacks. This presentation filter does not change the [credential resolution order](../../../docs/subsystems/credentials.md#resolution), the adapter's complete environment list, or an explicit reference. A filtered explicit reference still has a usable key input with the plain placeholder and no tooltip. A native route that has no key authentication omits the key field and authentication help entirely; an explicit reference still enables the field. A profile without a reference on a route without `nativeAuth`, such as a hand-declared route, shows the plain key placeholder and no tooltip. A row labels API-key state with a green solid dot only when a referenced credential is confirmed configured, and with a red solid dot only when a named reference is confirmed missing. A successful Apply emits a local accessible status message without echoing secret material.
47
+
48
+ The editor uses redacted `CredentialInfo` to choose the saved-credential placeholder or environment detection, without displaying a credential-source label. Refreshing the snapshot updates an open editor without a separate probe. The hint never receives a credential value or changes field writability.
47
49
 
48
50
  ### Editing a provider
49
51
 
50
- The collapsed 自定义设置 fold carries the curated extras: `baseURL` for both families (the deepseek placeholder shows the public endpoint), each adapter's model catalog, and the **display name** and **API protocol** of a pi-ai route the adapter does not ship. Profile `headers` remain deployment configuration in `cordis.patch.yml` or Cordis config and have no Models-page editor. The Provider ID stays fixed: it is the settings key, the name every other namespace and every logged session references, and the stem of a credential reference the page cannot read back to move. Reasoning effort is deliberately not among the editable fields: it is a per-model capability, so a provider-scoped control could only be set to a value some models reject. Each model row edits `id`, optional display `name`, optional `contextWindow`/`maxTokens`, and input types; unrelated model fields survive edits.
52
+ A blank key field offers a saved credential when one is detected, with no status text below the input; otherwise it offers environment authentication. Redacted `credentials.describe` checks distinguish a detected environment reference, no detected variables, and an unconfirmed read. A missing-variable hint uses the warning color and names the first variable to configure. A detected environment reference uses green. Address configuration variables do not count as credentials. Hidden authentication references still participate in detection; a generic detected hint keeps their names hidden. Detection does not validate credentials, test a connection, or inspect provider-managed files such as AWS profiles and Google application-default credentials. A nonempty input shows no authentication status text. The page reads native variable names as well as named references, in batches of at most 64, and never reads their values into the Client.
53
+
54
+ An endpoint without a fixed catalog default shows the provider's `baseURLEnv` configuration names below the input. A profile endpoint remains the first placeholder choice.
55
+
56
+ The collapsed 自定义设置 fold carries the curated extras: `baseURL` for both families (the placeholder shows the endpoint the profile resolves to, the public endpoint for deepseek, else the `defaultBaseURL` the configurable-provider directory reports for a pi-ai catalog route), each adapter's model catalog, and the **display name** and **API protocol** of a pi-ai route the adapter does not ship. Profile `headers` remain deployment configuration in `cordis.patch.yml` or Cordis config and have no Models-page editor. The Provider ID stays fixed: it is the settings key, the name every other namespace and every logged session references, and the stem of a credential reference the page cannot read back to move. Reasoning effort is deliberately not among the editable fields: it is a per-model capability, so a provider-scoped control could only be set to a value some models reject. Each model row edits `id`, optional display `name`, optional `contextWindow`/`maxTokens`, and input types; unrelated model fields survive edits.
51
57
 
52
58
  The DeepSeek card edits the `llm-deepseek` endpoint, credentials, and model catalog. It uses Messages, with the default endpoint placeholder `https://api.deepseek.com/anthropic`.
53
59
 
@@ -65,7 +71,7 @@ After the versioned notice step completes, the DeepSeek step projects first-run
65
71
 
66
72
  The section declares two seats for plugins distributed outside this repository, typed in [`src/client/slot-contract.ts`](src/client/slot-contract.ts) and exported from `./client`. `settings.models.provider-card` (keyed) renders inside every card that shows a directory row — a saved row's card, its first-run setup posture, and the add-provider draft — dispatched with `entryKey = settingsNs` and owner props carrying the row's `ConfigurableProviderView`, its configured state, and its confirmed api-key credential state, so one registration under an adapter family's namespace receives every card of that family, hand-declared routes included; the hand-declared draft card has no directory row yet and dispatches nothing until saved. `settings.models.footer` (list) renders after the rows and the add controls. A registrant activates through `ctx.slots.inject` with a type-only import of this package's `/client` entry; without registrants both seats render nothing.
67
73
 
68
- The Models page includes **DeepSeek Account** (`deepseek-account`, **DeepSeek 账号** in Chinese). Its editor exposes the shared DeepSeek model catalog without API-key or base-URL inputs, and saves that catalog under the account route's own settings section (`llm-deepseek-account` by default), so an account edit never rewrites the `llm-deepseek` section the official route reads. The account row is hidden when its available model catalog is empty, including before sign-in and after sign-out; it returns when account models become available.
74
+ The Models page includes **DeepSeek Account** (`deepseek-account`, **DeepSeek 账号** in Chinese). The row shows a **Signed in** status and offers no editor: the account listing supplies its models, and [model overrides](../../llm/llm-deepseek-account/README.md#use-this-package) live in `cordis.patch.yml`. The account row is hidden when its available model catalog is empty, including before sign-in and after sign-out; it returns when account models become available.
69
75
 
70
76
  -----
71
77
 
@@ -89,7 +95,7 @@ Concurrent `ModelsSettingsStore.load()` callers resolve after the current refres
89
95
 
90
96
  ### Onboarding coordinator
91
97
 
92
- The notice step owns its exact copy in `src/client/locales.ts` and its acknowledgement version in `src/onboarding-copy.ts`; on loopback it compares and writes `ui-settings-general.welcomeNoticeVersion` through the shared configuration form, and only an explicit Continue records the current version. Users who acknowledged an earlier version see the current notice again. A non-loopback browser cannot use that Host-only namespace, so acknowledgement is process-local and the notice returns after reload. The DeepSeek step targets `deepseek-official` in `llm-deepseek` and renders the existing `ProviderEditor` in credential-only mode inside the shared onboarding modal; `credentials.set` stays the only secret write, and no provider settings are changed.
98
+ The notice step owns its exact copy in `src/client/locales.ts` and its acknowledgement version in `src/onboarding-copy.ts`. Authenticated browsers compare and write `ui-settings-general.welcomeNoticeVersion` through the shared configuration form; only an explicit Continue records the current version, and an unavailable namespace or a refused write leaves the notice unacknowledged. Users who acknowledged an earlier version see the current notice again. The DeepSeek step targets `deepseek-official` in `llm-deepseek` and renders the existing `ProviderEditor` in credential-only mode inside the shared onboarding modal; `credentials.set` stays the only secret write, and no provider settings are changed.
93
99
 
94
100
  </details>
95
101
 
package/README.zh.md CHANGED
@@ -41,13 +41,19 @@ Host 配置 `credentialOnboarding` 默认为 `true`。Electron preload 标记会
41
41
 
42
42
  ### API 密钥
43
43
 
44
- API 密钥输入框初始为空,并通过 `autocomplete="new-password"` 请求浏览器不要自动填入已保存的登录密码。
44
+ API 密钥输入框初始为空,并通过 `autocomplete="new-password"` 请求浏览器不要自动填入已保存的登录密码。输入非空时,显示与会话密钥遮罩一致的眼睛按钮:**显示密钥**展示当前输入,**隐藏密钥**重新遮住输入。修改或清空输入后会重新遮住密钥。已保存凭据从不读入输入框。
45
45
 
46
- 编辑卡片上的主字段是单独一个 **API 密钥**输入框——页面从不询问环境变量名。键入的密钥经 `credentials.set` 以**只写**方式存入 profile 的引用之下,profile 没有引用时便派生 `<ROUTE>_API_KEY`,pi-ai profile 会把这次派生记录为 `apiKeyEnv`,因此 `cordis.patch.yml` 从不携带密钥值。为新的 pi-ai 提供商留空密钥会保存一个不带引用的 profile,从而保留提供商原生认证(例如 Bedrock 凭据链或 Vertex ADC)。只有确认引用的凭据已配置时,行才会以绿色实心点标示 API 密钥状态;只有确认具名引用缺失时,才会以红色实心点标示。「应用」成功后会发出本地无障碍状态消息,且绝不回显任何机密内容。
46
+ 编辑卡片上的主字段是单独一个 **API 密钥**输入框——页面从不询问环境变量名。键入的密钥经 `credentials.set` 以**只写**方式存入 profile 的引用之下,profile 没有引用时便派生 `<ROUTE>_API_KEY`,pi-ai profile 会把这次派生记录为 `apiKeyEnv`,因此 `cordis.patch.yml` 从不携带密钥值。为新的 pi-ai 提供商留空密钥会保存一个不带引用的 profile,从而保留提供商原生认证(例如 Bedrock 凭据链或 Vertex ADC)。profile 有 `apiKeyEnv` 时,字段的占位文字与帮助提示采用该引用;否则按查找顺序采用可配置提供商目录为该路由报告的 `nativeAuth` 凭据变量,并排除 `baseURLEnv` 地址变量。这些显示提示会忽略包含 `oauth` 的引用(不区分大小写),并说明优先使用已保存凭据,其后为显示的环境后备。这项显示过滤不改变[凭据解析顺序](../../../docs/subsystems/credentials.zh.md#resolution)、适配器的完整环境变量列表或显式引用。被过滤的显式引用仍有可用的密钥输入框,使用普通占位文字且不显示帮助提示。没有密钥认证的原生路由不显示密钥字段及认证帮助;显式引用仍会启用该字段。路由没有 `nativeAuth`(例如手动声明的路由)且 profile 没有引用时,显示普通的密钥占位文字,且不显示帮助提示。只有确认引用的凭据已配置时,行才会以绿色实心点标示 API 密钥状态;只有确认具名引用缺失时,才会以红色实心点标示。「应用」成功后会发出本地无障碍状态消息,且绝不回显任何机密内容。
47
+
48
+ 编辑器使用脱敏 `CredentialInfo` 选择已保存凭据的占位文字或环境检测,不显示凭据来源标签。快照刷新会更新打开的编辑器,无需单独探测。提示从不接收凭据值,也不改变字段的可写性。
47
49
 
48
50
  ### 编辑提供商
49
51
 
50
- 收起的「自定义设置」折叠区承载精选的额外字段:两个家族都有 `baseURL`(deepseek 的占位符显示公共端点)、各适配器自己的模型目录,以及适配器未提供的 pi-ai 路由的**显示名称**与 **API 协议**。Profile `headers` 仍是 `cordis.patch.yml` 或 Cordis 配置中的部署配置,Models 页面不提供编辑器。Provider ID 保持固定:它是 settings 的键、其他每个 namespace 与每一条已记录会话引用的名字,也是页面读不回、因而搬不走的凭据引用词干。推理等级刻意不在可编辑字段之列:它是按模型的能力,提供商级的控件只可能被设成某些模型会拒绝的值。每个模型行可编辑 `id`、可选显示 `name`、可选 `contextWindow`/`maxTokens` 和输入类型;无关的模型字段在编辑后仍会保留。
52
+ 密钥字段留空时,已检测到已保存凭据则提示使用该凭据,输入框下方不显示状态文字;否则提示使用环境认证。脱敏的 `credentials.describe` 检查区分已检测到环境引用、未检测到变量和读取状态未确认。缺少变量时使用黄色提示,并列出应配置的首个变量名。已检测到环境引用时使用绿色。地址配置变量不计作凭据。隐藏的认证引用仍参与检测;使用不含变量名的通用检测提示。检测不验证凭据、不测试连接,也不检查 AWS profile 或 Google 应用默认凭据等提供商管理的文件。输入非空时,不显示认证状态文字。页面读取原生变量名和具名引用,每批最多 64 项,不将变量值读入 Client。
53
+
54
+ 目录未提供固定默认端点时,输入框下方显示提供方的 `baseURLEnv` 配置变量名。Profile 中的端点仍是占位符的首选。
55
+
56
+ 收起的「自定义设置」折叠区承载精选的额外字段:两个家族都有 `baseURL`(占位符显示 profile 解析出的端点,deepseek 即公共端点;没有时显示可配置提供商目录为 pi-ai 内置路由报告的 `defaultBaseURL`)、各适配器自己的模型目录,以及适配器未提供的 pi-ai 路由的**显示名称**与 **API 协议**。Profile `headers` 仍是 `cordis.patch.yml` 或 Cordis 配置中的部署配置,Models 页面不提供编辑器。Provider ID 保持固定:它是 settings 的键、其他每个 namespace 与每一条已记录会话引用的名字,也是页面读不回、因而搬不走的凭据引用词干。推理等级刻意不在可编辑字段之列:它是按模型的能力,提供商级的控件只可能被设成某些模型会拒绝的值。每个模型行可编辑 `id`、可选显示 `name`、可选 `contextWindow`/`maxTokens` 和输入类型;无关的模型字段在编辑后仍会保留。
51
57
 
52
58
  `llm-deepseek` 的 DeepSeek 卡片编辑端点、凭据和模型目录。它使用 Messages,默认端点占位符为 `https://api.deepseek.com/anthropic`。
53
59
 
@@ -65,7 +71,7 @@ API 密钥输入框初始为空,并通过 `autocomplete="new-password"` 请求
65
71
 
66
72
  本分区为仓库外分发的插件声明两个席位,类型定义在 [`src/client/slot-contract.ts`](src/client/slot-contract.ts) 并从 `./client` 导出。`settings.models.provider-card`(keyed)渲染在每张展示目录行的卡片内部——已保存行的卡片、其首次运行 setup 形态、以及「添加提供商」草稿卡——以 `entryKey = settingsNs` 分发,owner props 携带该行的 `ConfigurableProviderView`、其 configured 状态与已确认的 api-key 凭据状态,因此以某适配器家族的 namespace 注册一次即可收到该家族的全部卡片,含手工声明的路由;手工声明的草稿卡尚无目录行,保存之前不分发。`settings.models.footer`(list)渲染在行列表与新增控件之后。注册方通过 `ctx.slots.inject` 激活,并以 type-only import 引入本包 `/client` 入口;没有注册方时两个席位均不渲染任何内容。
67
73
 
68
- Models 页面包含 **DeepSeek 账号**(`deepseek-account`,英文为 **DeepSeek Account**)。其编辑器展示共享的 DeepSeek 模型目录,不提供 API Key 或 Base URL 输入框;目录保存到账号路由自己的设置段(默认为 `llm-deepseek-account`),因此账号侧的编辑不会改写 official 路由读取的 `llm-deepseek` 段。账号可用模型目录为空时隐藏账号行,包括登录前和退登后;账号模型恢复可用时重新显示。
74
+ Models 页面包含 **DeepSeek 账号**(`deepseek-account`,英文为 **DeepSeek Account**)。该行显示 **已登录** 状态,不提供编辑器:模型来自账号的模型列表,[模型覆盖](../../llm/llm-deepseek-account/README.zh.md#use-this-package)写在 `cordis.patch.yml` 中。账号可用模型目录为空时隐藏账号行,包括登录前和退登后;账号模型恢复可用时重新显示。
69
75
 
70
76
  -----
71
77
 
@@ -89,7 +95,7 @@ Models 页面包含 **DeepSeek 账号**(`deepseek-account`,英文为 **DeepS
89
95
 
90
96
  ### 引导协调器
91
97
 
92
- 预览版说明在 `src/client/locales.ts` 中持有精确文案,并在 `src/onboarding-copy.ts` 中持有确认版本;回环时它通过既有 settings API 比较并写入 `ui-settings-general.welcomeNoticeVersion`,且只有显式点击「继续」才会记录当前版本。已确认旧版的用户会再次看到当前说明。非回环浏览器无法使用这个仅限宿主的 namespace,因此确认只保留在进程内,刷新后说明会再次出现。DeepSeek 步骤面向 `llm-deepseek` 中的 `deepseek-official`,在共享引导模态框内以仅凭据模式渲染既有 `ProviderEditor`;`credentials.set` 仍是唯一的机密写入,且不改变任何提供商设置。
98
+ 预览版说明在 `src/client/locales.ts` 中持有精确文案,并在 `src/onboarding-copy.ts` 中持有确认版本。认证浏览器通过共享配置表单比较并写入 `ui-settings-general.welcomeNoticeVersion`;只有显式点击「继续」才会记录当前版本;命名空间不可用或写入被拒时,声明保持未确认状态。已确认旧版的用户会再次看到当前说明。DeepSeek 步骤面向 `llm-deepseek` 中的 `deepseek-official`,在共享引导模态框内以仅凭据模式渲染既有 `ProviderEditor`;`credentials.set` 仍是唯一的机密写入,且不改变任何提供商设置。
93
99
 
94
100
  </details>
95
101
 
package/lib/client.js CHANGED
@@ -55,7 +55,7 @@ window.__ModuleLoader__.load({
55
55
  }
56
56
  //#endregion
57
57
  //#region \0dsh-css:/home/runner/work/deepseek-harness/deepseek-harness/packages/client/ui-settings-models/src/client/ModelsSection.module.css.mjs
58
- const css$3 = ".zGbnIq_section{max-width:720px;color:var(--dsw-alias-label-primary);flex-direction:column;gap:12px;display:flex}.zGbnIq_title{color:var(--dsw-alias-label-primary);margin:0;font-size:16px;font-weight:500;line-height:24px}.zGbnIq_intro{color:var(--dsw-alias-label-tertiary);margin:0;font-size:14px;line-height:22px}.zGbnIq_notice{color:var(--dsw-alias-state-warn-label);margin:0;font-size:12px;line-height:18px}.zGbnIq_savedNotice{color:var(--dsw-alias-state-success-primary);margin:0;font-size:12px;line-height:18px}.zGbnIq_rows{flex-direction:column;gap:8px;margin:12px 0 0;padding:0;list-style:none;display:flex}.zGbnIq_rowCard{border:.5px solid var(--dsw-alias-settings-card-stroke);background:var(--dsw-alias-settings-card-fill);border-radius:var(--dsw-radius-xl);flex-direction:column;gap:12px;padding:12px 14px;display:flex}.zGbnIq_rowHead{align-items:center;gap:10px;display:flex}.zGbnIq_rowIdentity{align-items:center;gap:6px;min-width:0;display:inline-flex}.zGbnIq_rowName{color:var(--dsw-alias-label-primary);font-size:14px;font-weight:500;line-height:22px}.zGbnIq_rowTag{border:.5px solid var(--dsw-alias-border-l3);border-radius:var(--dsw-radius-xs);color:var(--dsw-alias-label-secondary);flex:none;padding:1px 6px;font-size:11px;line-height:16px}.zGbnIq_credentialDot{box-sizing:border-box;corner-shape:round;border-radius:50%;flex:none;width:8px;height:8px;display:inline-block}.zGbnIq_credentialDotConfigured{background:var(--dsw-alias-state-success-primary)}.zGbnIq_credentialDotMissing{background:var(--dsw-alias-state-error-primary)}.zGbnIq_rowActions{align-items:center;gap:4px;margin-left:auto;display:inline-flex}.zGbnIq_primaryButton,.zGbnIq_secondaryButton,.zGbnIq_addButton{box-sizing:border-box;border-radius:var(--dsw-radius-md);height:36px;font:inherit;cursor:pointer;border:none;justify-content:center;align-items:center;gap:4px;padding:0 14px;font-size:14px;line-height:22px;display:inline-flex}.zGbnIq_primaryButton{background:var(--dsw-alias-button-primary-fill);color:var(--dsw-alias-label-primary-foreground)}.zGbnIq_primaryButton:hover:not(:disabled){background:var(--dsw-alias-button-primary-hover)}.zGbnIq_secondaryButton,.zGbnIq_addButton{border:.5px solid var(--dsw-alias-border-l3);color:var(--dsw-alias-label-primary);background:0 0}.zGbnIq_secondaryButton:hover:not(:disabled),.zGbnIq_addButton:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover)}.zGbnIq_secondaryButton:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover-solid)}.zGbnIq_dangerButton{box-sizing:border-box;border-radius:var(--dsw-radius-md);height:36px;color:var(--dsw-alias-state-error-primary);font:inherit;cursor:pointer;background:0 0;border:none;justify-content:center;align-items:center;padding:0 14px;font-size:14px;line-height:22px;display:inline-flex}.zGbnIq_dangerButton:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover-danger)}.zGbnIq_rowActions .zGbnIq_secondaryButton,.zGbnIq_rowActions .zGbnIq_dangerButton{border-radius:var(--dsw-radius-sm);height:28px;padding:0 10px;font-size:12px;line-height:18px}.zGbnIq_primaryButton:disabled,.zGbnIq_secondaryButton:disabled,.zGbnIq_dangerButton:disabled,.zGbnIq_addButton:disabled,.zGbnIq_linkButton:disabled,.zGbnIq_addModelButton:disabled{opacity:.4;cursor:default}.zGbnIq_primaryButton:focus-visible,.zGbnIq_secondaryButton:focus-visible,.zGbnIq_dangerButton:focus-visible,.zGbnIq_addButton:focus-visible,.zGbnIq_linkButton:focus-visible,.zGbnIq_addModelButton:focus-visible,.zGbnIq_iconButton:focus-visible,.zGbnIq_customizedSummary:focus-visible{box-shadow:0 0 0 2px var(--dsw-focus-ring-color,var(--dsw-alias-state-business-primary));outline:none}.zGbnIq_editor{border-radius:var(--dsw-radius-lg);background:var(--dsw-alias-bg-module-platform);flex-direction:column;gap:14px;padding:14px 16px;display:flex}.zGbnIq_editorHeader{align-items:baseline;gap:8px;display:flex}.zGbnIq_editorTitle{color:var(--dsw-alias-label-primary);font-size:14px;font-weight:500;line-height:22px}.zGbnIq_editorRoute{color:var(--dsw-alias-label-tertiary);font-size:12px;line-height:18px}.zGbnIq_field{flex-direction:column;gap:6px;display:flex}.zGbnIq_fieldLabel{color:var(--dsw-alias-label-secondary);align-items:center;gap:10px;font-size:12px;font-weight:500;line-height:18px;display:inline-flex}.zGbnIq_linkButton{box-sizing:border-box;border-radius:var(--dsw-radius-sm);height:28px;color:var(--dsw-alias-label-tertiary);font:inherit;cursor:pointer;background:0 0;border:none;align-items:center;padding:0 10px;font-size:12px;line-height:18px;display:inline-flex}.zGbnIq_linkButton:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-secondary)}.zGbnIq_advancedHint{color:var(--dsw-alias-label-tertiary);margin:0;font-size:12px;line-height:18px}.zGbnIq_editorActions{justify-content:flex-end;gap:8px;display:flex}.zGbnIq_addBlock{flex-direction:column;gap:12px;display:flex}.zGbnIq_addActions{display:flex}.zGbnIq_addButton{border:1px dashed var(--dsw-alias-border-l3);border-radius:var(--dsw-radius-lg);flex:1 1 0;gap:6px;min-width:180px;height:44px}.zGbnIq_addModes{flex-direction:column;align-items:flex-start;gap:8px;display:flex}.zGbnIq_addPanel{flex-direction:column;gap:14px;display:flex}.zGbnIq_addPanel[hidden]{display:none}.zGbnIq_addCard,.zGbnIq_setupCard{border-radius:var(--dsw-radius-lg);background:var(--dsw-alias-bg-module-platform);flex-direction:column;gap:14px;padding:14px 16px;list-style:none;display:flex}.zGbnIq_addCard .zGbnIq_editor,.zGbnIq_setupCard .zGbnIq_editor{background:0 0;padding:0}.zGbnIq_customized{border-top:.5px solid var(--dsw-alias-border-l2);padding-top:10px}.zGbnIq_customizedSummary{border-radius:var(--dsw-radius-sm);cursor:pointer;width:fit-content;color:var(--dsw-alias-label-secondary);align-items:center;gap:6px;margin-left:-4px;padding:2px 4px;font-size:12px;font-weight:500;line-height:18px;list-style:none;display:flex}.zGbnIq_customizedSummary::-webkit-details-marker{display:none}.zGbnIq_customizedSummary:before{content:\"\";border-bottom:1.5px solid;border-right:1.5px solid;width:5px;height:5px;transition:transform .12s;transform:rotate(-45deg)translate(-1px,-1px)}.zGbnIq_customized[open]>.zGbnIq_customizedSummary:before{transform:rotate(45deg)translate(-1px,-1px)}.zGbnIq_customizedSummary:hover{color:var(--dsw-alias-label-primary)}.zGbnIq_customizedBody{flex-direction:column;gap:12px;padding-top:12px;display:flex}.zGbnIq_modelCatalog{border-top:.5px solid var(--dsw-alias-border-l2);flex-direction:column;gap:10px;padding-top:12px;display:flex}.zGbnIq_modelCatalogHeading{flex-direction:column;gap:2px;display:flex}.zGbnIq_modelCatalogTitle{color:var(--dsw-alias-label-secondary);font-size:12px;font-weight:500;line-height:18px}.zGbnIq_modelCatalogMeta,.zGbnIq_modelEmpty{color:var(--dsw-alias-label-tertiary);margin:0;font-size:12px;line-height:18px}.zGbnIq_modelList{flex-direction:column;gap:8px;display:flex}.zGbnIq_modelListHead{justify-content:space-between;align-items:flex-start;gap:12px;display:flex}.zGbnIq_modelEntry{border:.5px solid var(--dsw-alias-border-l4);border-radius:var(--dsw-radius-lg);padding:6px}.zGbnIq_modelRow{grid-template-columns:minmax(0,1.4fr) minmax(0,1fr) auto auto;align-items:center;gap:6px;display:grid}.zGbnIq_iconButton{box-sizing:border-box;border-radius:var(--dsw-radius-sm);width:28px;height:28px;color:var(--dsw-alias-label-tertiary);cursor:pointer;background:0 0;border:none;justify-content:center;align-items:center;display:inline-flex}.zGbnIq_iconButton:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary)}.zGbnIq_iconButton:disabled{cursor:default;opacity:.4}.zGbnIq_iconButtonDanger:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover-danger);color:var(--dsw-alias-state-error-primary)}.zGbnIq_modelAdvanced{grid-template-columns:repeat(2,minmax(0,1fr));gap:8px;padding:8px 4px 2px;display:grid}.zGbnIq_modelField{flex-direction:column;gap:4px;min-width:0;display:flex}.zGbnIq_modelInputTypes{border:none;grid-column:1/-1;min-width:0;margin:0;padding:0}.zGbnIq_modelInputTypes legend{margin-bottom:4px;padding:0}.zGbnIq_modelInputChoices{flex-wrap:wrap;align-items:center;gap:16px;min-height:32px;display:flex}.zGbnIq_modelFieldLabel{color:var(--dsw-alias-label-tertiary);font-size:12px;line-height:18px}.zGbnIq_modelEmpty{border:1px dashed var(--dsw-alias-border-l3);border-radius:var(--dsw-radius-lg);text-align:center;padding:12px}.zGbnIq_addModelButton{box-sizing:border-box;border:.5px solid var(--dsw-alias-border-l3);border-radius:var(--dsw-radius-sm);height:28px;color:var(--dsw-alias-label-primary);font:inherit;cursor:pointer;background:0 0;align-self:flex-start;align-items:center;gap:4px;padding:0 10px;font-size:12px;line-height:18px;display:inline-flex}.zGbnIq_addModelButton:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover)}.zGbnIq_input{box-sizing:border-box;border:.5px solid var(--dsw-alias-border-l4);border-radius:var(--dsw-radius-md);width:100%;height:32px;font:inherit;background:var(--dsw-alias-bg-layer-1);color:var(--dsw-alias-label-primary);padding:0 10px;font-size:14px;line-height:22px}select.zGbnIq_input{cursor:pointer;max-width:240px}.zGbnIq_input:focus{border-color:var(--dsw-alias-state-business-primary);outline:none}.zGbnIq_input::placeholder{color:var(--dsw-alias-label-dimmed)}.zGbnIq_input:disabled{opacity:.6;cursor:default}.zGbnIq_selectInput{appearance:none;background-image:url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12' fill='none'%3E%3Cpath d='M3 4.5L6 7.5L9 4.5' stroke='%2381858C' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E\");background-position:right 12px center;background-repeat:no-repeat;background-size:12px 12px;padding-right:32px}.zGbnIq_error{color:var(--dsw-alias-state-error-primary);margin:0;font-size:12px;line-height:18px}.zGbnIq_deleteDialog{width:min(480px,100%)}.zGbnIq_deleteConfirm:not(:disabled){border-color:var(--dsw-alias-state-error-primary);color:var(--dsw-alias-state-error-primary)}.zGbnIq_deleteConfirm:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover-danger)}.zGbnIq_hiddenLabel{clip:rect(0 0 0 0);white-space:nowrap;width:1px;height:1px;position:absolute;overflow:hidden}@media (prefers-reduced-motion:reduce){.zGbnIq_customizedSummary:before,.zGbnIq_switchThumb{transition:none}}.zGbnIq_fetchDialog{--dsh-scrollbar-thumb:var(--dsw-alias-scrollbar-bg-l2);--dsh-scrollbar-thumb-hover:var(--dsw-alias-scrollbar-hover-l2);max-width:520px}.zGbnIq_candidateToolbar{align-items:center;gap:8px;margin-bottom:6px;display:flex}.zGbnIq_candidateSearch{flex:240px;min-width:0}.zGbnIq_candidateList{flex-direction:column;gap:2px;max-height:320px;margin:0;padding:0;list-style:none;display:flex;overflow-y:auto}.zGbnIq_candidate{border-radius:var(--dsw-radius-md)}.zGbnIq_candidateLabel{cursor:pointer;align-items:center;gap:8px;padding:6px 8px;display:flex}.zGbnIq_candidateId{min-width:0;font-family:var(--ds-font-family-code);text-overflow:ellipsis;white-space:nowrap;flex:auto;font-size:13px;overflow:hidden}.zGbnIq_candidateEmpty{color:var(--dsw-alias-label-secondary);text-align:center;margin:24px 0;font-size:13px;line-height:20px}";
58
+ const css$3 = ".zGbnIq_section{max-width:720px;color:var(--dsw-alias-label-primary);flex-direction:column;gap:12px;display:flex}.zGbnIq_title{color:var(--dsw-alias-label-primary);margin:0;font-size:16px;font-weight:500;line-height:24px}.zGbnIq_intro{color:var(--dsw-alias-label-tertiary);margin:0;font-size:14px;line-height:22px}.zGbnIq_notice{color:var(--dsw-alias-state-warn-label);margin:0;font-size:12px;line-height:18px}.zGbnIq_savedNotice{color:var(--dsw-alias-state-success-primary);margin:0;font-size:12px;line-height:18px}.zGbnIq_rows{flex-direction:column;gap:8px;margin:12px 0 0;padding:0;list-style:none;display:flex}.zGbnIq_rowCard{border:.5px solid var(--dsw-alias-settings-card-stroke);background:var(--dsw-alias-settings-card-fill);border-radius:var(--dsw-radius-xl);flex-direction:column;gap:12px;padding:12px 14px;display:flex}.zGbnIq_rowHead{align-items:center;gap:10px;display:flex}.zGbnIq_rowIdentity{align-items:center;gap:6px;min-width:0;display:inline-flex}.zGbnIq_rowName{color:var(--dsw-alias-label-primary);font-size:14px;font-weight:500;line-height:22px}.zGbnIq_rowTag{border:.5px solid var(--dsw-alias-border-l3);border-radius:var(--dsw-radius-xs);color:var(--dsw-alias-label-secondary);flex:none;padding:1px 6px;font-size:11px;line-height:16px}.zGbnIq_credentialDot{box-sizing:border-box;corner-shape:round;border-radius:50%;flex:none;width:8px;height:8px;display:inline-block}.zGbnIq_credentialDotConfigured{background:var(--dsw-alias-state-success-primary)}.zGbnIq_credentialDotMissing{background:var(--dsw-alias-state-error-primary)}.zGbnIq_accountStatus{color:var(--dsw-alias-state-success-primary);flex:none;align-items:center;gap:6px;font-size:13px;line-height:20px;display:inline-flex}.zGbnIq_rowActions{align-items:center;gap:4px;margin-left:auto;display:inline-flex}.zGbnIq_primaryButton,.zGbnIq_secondaryButton,.zGbnIq_addButton{box-sizing:border-box;border-radius:var(--dsw-radius-md);height:36px;font:inherit;cursor:pointer;border:none;justify-content:center;align-items:center;gap:4px;padding:0 14px;font-size:14px;line-height:22px;display:inline-flex}.zGbnIq_primaryButton{background:var(--dsw-alias-button-primary-fill);color:var(--dsw-alias-label-primary-foreground)}.zGbnIq_primaryButton:hover:not(:disabled){background:var(--dsw-alias-button-primary-hover)}.zGbnIq_secondaryButton,.zGbnIq_addButton{border:.5px solid var(--dsw-alias-border-l3);color:var(--dsw-alias-label-primary);background:0 0}.zGbnIq_secondaryButton:hover:not(:disabled),.zGbnIq_addButton:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover)}.zGbnIq_secondaryButton:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover-solid)}.zGbnIq_dangerButton{box-sizing:border-box;border-radius:var(--dsw-radius-md);height:36px;color:var(--dsw-alias-state-error-primary);font:inherit;cursor:pointer;background:0 0;border:none;justify-content:center;align-items:center;padding:0 14px;font-size:14px;line-height:22px;display:inline-flex}.zGbnIq_dangerButton:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover-danger)}.zGbnIq_rowActions .zGbnIq_secondaryButton,.zGbnIq_rowActions .zGbnIq_dangerButton{border-radius:var(--dsw-radius-sm);height:28px;padding:0 10px;font-size:12px;line-height:18px}.zGbnIq_primaryButton:disabled,.zGbnIq_secondaryButton:disabled,.zGbnIq_dangerButton:disabled,.zGbnIq_addButton:disabled,.zGbnIq_linkButton:disabled,.zGbnIq_addModelButton:disabled{opacity:.4;cursor:default}.zGbnIq_primaryButton:focus-visible,.zGbnIq_secondaryButton:focus-visible,.zGbnIq_dangerButton:focus-visible,.zGbnIq_addButton:focus-visible,.zGbnIq_linkButton:focus-visible,.zGbnIq_addModelButton:focus-visible,.zGbnIq_iconButton:focus-visible,.zGbnIq_customizedSummary:focus-visible{box-shadow:0 0 0 2px var(--dsw-focus-ring-color,var(--dsw-alias-state-business-primary));outline:none}.zGbnIq_editor{border-radius:var(--dsw-radius-lg);background:var(--dsw-alias-bg-module-platform);flex-direction:column;gap:14px;padding:14px 16px;display:flex}.zGbnIq_editorHeader{align-items:baseline;gap:8px;display:flex}.zGbnIq_editorTitle{color:var(--dsw-alias-label-primary);font-size:14px;font-weight:500;line-height:22px}.zGbnIq_editorRoute{color:var(--dsw-alias-label-tertiary);font-size:12px;line-height:18px}.zGbnIq_field{flex-direction:column;gap:6px;display:flex}.zGbnIq_fieldLabel{color:var(--dsw-alias-label-secondary);align-items:center;gap:10px;font-size:12px;font-weight:500;line-height:18px;display:inline-flex}.zGbnIq_helpButton{border:.5px solid var(--dsw-alias-border-l3);corner-shape:round;width:16px;height:16px;color:var(--dsw-alias-label-tertiary);font:inherit;text-align:center;cursor:help;background:0 0;border-radius:50%;padding:0;font-size:11px;line-height:15px}.zGbnIq_helpButton:hover,.zGbnIq_helpButton:focus-visible{color:var(--dsw-alias-label-primary);border-color:var(--dsw-alias-label-tertiary)}.zGbnIq_linkButton{box-sizing:border-box;border-radius:var(--dsw-radius-sm);height:28px;color:var(--dsw-alias-label-tertiary);font:inherit;cursor:pointer;background:0 0;border:none;align-items:center;padding:0 10px;font-size:12px;line-height:18px;display:inline-flex}.zGbnIq_linkButton:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-secondary)}.zGbnIq_advancedHint{color:var(--dsw-alias-label-tertiary);margin:0;font-size:12px;line-height:18px}.zGbnIq_editorActions{justify-content:flex-end;gap:8px;display:flex}.zGbnIq_addBlock{flex-direction:column;gap:12px;display:flex}.zGbnIq_addActions{display:flex}.zGbnIq_addButton{border:1px dashed var(--dsw-alias-border-l3);border-radius:var(--dsw-radius-lg);flex:1 1 0;gap:6px;min-width:180px;height:44px}.zGbnIq_addModes{flex-direction:column;align-items:flex-start;gap:8px;display:flex}.zGbnIq_addPanel{flex-direction:column;gap:14px;display:flex}.zGbnIq_addPanel[hidden]{display:none}.zGbnIq_addCard,.zGbnIq_setupCard{border-radius:var(--dsw-radius-lg);background:var(--dsw-alias-bg-module-platform);flex-direction:column;gap:14px;padding:14px 16px;list-style:none;display:flex}.zGbnIq_addCard .zGbnIq_editor,.zGbnIq_setupCard .zGbnIq_editor{background:0 0;padding:0}.zGbnIq_customized{border-top:.5px solid var(--dsw-alias-border-l2);padding-top:10px}.zGbnIq_customizedSummary{border-radius:var(--dsw-radius-sm);cursor:pointer;width:fit-content;color:var(--dsw-alias-label-secondary);align-items:center;gap:6px;margin-left:-4px;padding:2px 4px;font-size:12px;font-weight:500;line-height:18px;list-style:none;display:flex}.zGbnIq_customizedSummary::-webkit-details-marker{display:none}.zGbnIq_customizedSummary:before{content:\"\";border-bottom:1.5px solid;border-right:1.5px solid;width:5px;height:5px;transition:transform .12s;transform:rotate(-45deg)translate(-1px,-1px)}.zGbnIq_customized[open]>.zGbnIq_customizedSummary:before{transform:rotate(45deg)translate(-1px,-1px)}.zGbnIq_customizedSummary:hover{color:var(--dsw-alias-label-primary)}.zGbnIq_customizedBody{flex-direction:column;gap:12px;padding-top:12px;display:flex}.zGbnIq_modelCatalog{border-top:.5px solid var(--dsw-alias-border-l2);flex-direction:column;gap:10px;padding-top:12px;display:flex}.zGbnIq_modelCatalogHeading{flex-direction:column;gap:2px;display:flex}.zGbnIq_modelCatalogTitle{color:var(--dsw-alias-label-secondary);font-size:12px;font-weight:500;line-height:18px}.zGbnIq_modelCatalogMeta,.zGbnIq_modelEmpty{color:var(--dsw-alias-label-tertiary);margin:0;font-size:12px;line-height:18px}.zGbnIq_modelList{flex-direction:column;gap:8px;display:flex}.zGbnIq_modelListHead{justify-content:space-between;align-items:flex-start;gap:12px;display:flex}.zGbnIq_modelEntry{border:.5px solid var(--dsw-alias-border-l4);border-radius:var(--dsw-radius-lg);padding:6px}.zGbnIq_modelRow{grid-template-columns:minmax(0,1.4fr) minmax(0,1fr) auto auto;align-items:center;gap:6px;display:grid}.zGbnIq_iconButton{box-sizing:border-box;border-radius:var(--dsw-radius-sm);width:28px;height:28px;color:var(--dsw-alias-label-tertiary);cursor:pointer;background:0 0;border:none;justify-content:center;align-items:center;display:inline-flex}.zGbnIq_iconButton:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary)}.zGbnIq_iconButton:disabled{cursor:default;opacity:.4}.zGbnIq_iconButtonDanger:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover-danger);color:var(--dsw-alias-state-error-primary)}.zGbnIq_modelAdvanced{grid-template-columns:repeat(2,minmax(0,1fr));gap:8px;padding:8px 4px 2px;display:grid}.zGbnIq_modelField{flex-direction:column;gap:4px;min-width:0;display:flex}.zGbnIq_modelInputTypes{border:none;grid-column:1/-1;min-width:0;margin:0;padding:0}.zGbnIq_modelInputTypes legend{margin-bottom:4px;padding:0}.zGbnIq_modelInputChoices{flex-wrap:wrap;align-items:center;gap:16px;min-height:32px;display:flex}.zGbnIq_modelFieldLabel{color:var(--dsw-alias-label-tertiary);font-size:12px;line-height:18px}.zGbnIq_modelEmpty{border:1px dashed var(--dsw-alias-border-l3);border-radius:var(--dsw-radius-lg);text-align:center;padding:12px}.zGbnIq_addModelButton{box-sizing:border-box;border:.5px solid var(--dsw-alias-border-l3);border-radius:var(--dsw-radius-sm);height:28px;color:var(--dsw-alias-label-primary);font:inherit;cursor:pointer;background:0 0;align-self:flex-start;align-items:center;gap:4px;padding:0 10px;font-size:12px;line-height:18px;display:inline-flex}.zGbnIq_addModelButton:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover)}.zGbnIq_input{box-sizing:border-box;border:.5px solid var(--dsw-alias-border-l4);border-radius:var(--dsw-radius-md);width:100%;height:32px;font:inherit;background:var(--dsw-alias-bg-layer-1);color:var(--dsw-alias-label-primary);padding:0 10px;font-size:14px;line-height:22px}select.zGbnIq_input{cursor:pointer;max-width:240px}.zGbnIq_input:focus{border-color:var(--dsw-alias-state-business-primary);outline:none}.zGbnIq_input::placeholder{color:var(--dsw-alias-label-dimmed)}.zGbnIq_input:disabled{opacity:.6;cursor:default}.zGbnIq_keyInput{position:relative}.zGbnIq_keyInputFilled{padding-right:40px}.zGbnIq_keyToggle{border-radius:var(--dsw-radius-md);width:32px;color:var(--dsw-alias-label-secondary);cursor:pointer;background:0 0;border:none;justify-content:center;align-items:center;padding:0;display:inline-flex;position:absolute;inset:1px 1px 1px auto}.zGbnIq_keyToggle:hover:not(:disabled){color:var(--dsw-alias-label-primary)}.zGbnIq_keyToggle:focus-visible{outline:var(--dsw-focus-ring-width) solid var(--dsw-focus-ring-color,var(--dsw-alias-state-business-primary));outline-offset:-2px}.zGbnIq_keyToggle:disabled{opacity:.6;cursor:default}.zGbnIq_selectInput{appearance:none;background-image:url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12' fill='none'%3E%3Cpath d='M3 4.5L6 7.5L9 4.5' stroke='%2381858C' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E\");background-position:right 12px center;background-repeat:no-repeat;background-size:12px 12px;padding-right:32px}.zGbnIq_error{color:var(--dsw-alias-state-error-primary);margin:0;font-size:12px;line-height:18px}.zGbnIq_deleteDialog{width:min(480px,100%)}.zGbnIq_deleteConfirm:not(:disabled){border-color:var(--dsw-alias-state-error-primary);color:var(--dsw-alias-state-error-primary)}.zGbnIq_deleteConfirm:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover-danger)}.zGbnIq_hiddenLabel{clip:rect(0 0 0 0);white-space:nowrap;width:1px;height:1px;position:absolute;overflow:hidden}@media (prefers-reduced-motion:reduce){.zGbnIq_customizedSummary:before,.zGbnIq_switchThumb{transition:none}}.zGbnIq_fetchDialog{--dsh-scrollbar-thumb:var(--dsw-alias-scrollbar-bg-l2);--dsh-scrollbar-thumb-hover:var(--dsw-alias-scrollbar-hover-l2);max-width:520px}.zGbnIq_candidateToolbar{align-items:center;gap:8px;margin-bottom:6px;display:flex}.zGbnIq_candidateSearch{flex:240px;min-width:0}.zGbnIq_candidateList{flex-direction:column;gap:2px;max-height:320px;margin:0;padding:0;list-style:none;display:flex;overflow-y:auto}.zGbnIq_candidate{border-radius:var(--dsw-radius-md)}.zGbnIq_candidateLabel{cursor:pointer;align-items:center;gap:8px;padding:6px 8px;display:flex}.zGbnIq_candidateId{min-width:0;font-family:var(--ds-font-family-code);text-overflow:ellipsis;white-space:nowrap;flex:auto;font-size:13px;overflow:hidden}.zGbnIq_candidateEmpty{color:var(--dsw-alias-label-secondary);text-align:center;margin:24px 0;font-size:13px;line-height:20px}";
59
59
  const tagId$3 = "@deepseek-ai/dsh-client-ui-settings-models/ModelsSection.module.css";
60
60
  if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$3) + "]") === null) {
61
61
  const tag = document.createElement("style");
@@ -65,6 +65,7 @@ window.__ModuleLoader__.load({
65
65
  document.head.appendChild(tag);
66
66
  }
67
67
  var ModelsSection_module_css_default = {
68
+ "accountStatus": "zGbnIq_accountStatus",
68
69
  "addActions": "zGbnIq_addActions",
69
70
  "addBlock": "zGbnIq_addBlock",
70
71
  "addButton": "zGbnIq_addButton",
@@ -98,11 +99,15 @@ window.__ModuleLoader__.load({
98
99
  "fetchDialog": "zGbnIq_fetchDialog",
99
100
  "field": "zGbnIq_field",
100
101
  "fieldLabel": "zGbnIq_fieldLabel",
102
+ "helpButton": "zGbnIq_helpButton",
101
103
  "hiddenLabel": "zGbnIq_hiddenLabel",
102
104
  "iconButton": "zGbnIq_iconButton",
103
105
  "iconButtonDanger": "zGbnIq_iconButtonDanger",
104
106
  "input": "zGbnIq_input",
105
107
  "intro": "zGbnIq_intro",
108
+ "keyInput": "zGbnIq_keyInput",
109
+ "keyInputFilled": "zGbnIq_keyInputFilled",
110
+ "keyToggle": "zGbnIq_keyToggle",
106
111
  "linkButton": "zGbnIq_linkButton",
107
112
  "modelAdvanced": "zGbnIq_modelAdvanced",
108
113
  "modelCatalog": "zGbnIq_modelCatalog",
@@ -136,6 +141,55 @@ window.__ModuleLoader__.load({
136
141
  "title": "zGbnIq_title"
137
142
  };
138
143
  //#endregion
144
+ //#region lib/types/client/ApiKeyInput.js
145
+ /** Write-only credential input with the same reveal behavior as masked conversation text. */
146
+ const EYE_CONTOUR = "M1.5 8C2.9 5.25 5.25 3.5 8 3.5C10.75 3.5 13.1 5.25 14.5 8C13.1 10.75 10.75 12.5 8 12.5C5.25 12.5 2.9 10.75 1.5 8Z";
147
+ const EYE_PATH = `${EYE_CONTOUR}M10 8C10 9.1 9.1 10 8 10C6.9 10 6 9.1 6 8C6 6.9 6.9 6 8 6C9.1 6 10 6.9 10 8Z`;
148
+ const EYE_OFF_PATH = `${EYE_CONTOUR}M2.5 2.5L13.5 13.5`;
149
+ /**
150
+ * Reveal only a nonempty draft; a different value starts masked, as in SecretText.
151
+ * @param props - current draft, input attributes, and translated control labels.
152
+ * @returns a password input with an optional reveal button.
153
+ */
154
+ function ApiKeyInput({ value, t, ...props }) {
155
+ const [revealedValue, setRevealedValue] = (0, react.useState)();
156
+ const revealed = value.length > 0 && revealedValue === value;
157
+ return (0, react_jsx_runtime.jsxs)("div", {
158
+ className: ModelsSection_module_css_default["keyInput"],
159
+ children: [(0, react_jsx_runtime.jsx)("input", {
160
+ ...props,
161
+ className: `${ModelsSection_module_css_default["input"]} ${value.length > 0 ? ModelsSection_module_css_default["keyInputFilled"] : ""}`,
162
+ type: revealed ? "text" : "password",
163
+ autoComplete: "new-password",
164
+ value,
165
+ onChange: (event) => {
166
+ setRevealedValue(void 0);
167
+ props.onChange?.(event);
168
+ }
169
+ }), value.length === 0 ? null : (0, react_jsx_runtime.jsx)("button", {
170
+ type: "button",
171
+ className: ModelsSection_module_css_default["keyToggle"],
172
+ "aria-label": t(revealed ? "keyHide" : "keyReveal"),
173
+ "aria-pressed": revealed,
174
+ disabled: props.disabled,
175
+ onClick: () => {
176
+ setRevealedValue(revealed ? void 0 : value);
177
+ },
178
+ children: (0, react_jsx_runtime.jsx)("svg", {
179
+ width: "16",
180
+ height: "16",
181
+ viewBox: "0 0 16 16",
182
+ fill: "none",
183
+ stroke: "currentColor",
184
+ strokeWidth: 1.3,
185
+ strokeLinecap: "round",
186
+ "aria-hidden": "true",
187
+ children: (0, react_jsx_runtime.jsx)("path", { d: revealed ? EYE_OFF_PATH : EYE_PATH })
188
+ })
189
+ })]
190
+ });
191
+ }
192
+ //#endregion
139
193
  //#region lib/types/client/EditorFooter.js
140
194
  /**
141
195
  * Render one provider card's action row.
@@ -914,6 +968,9 @@ window.__ModuleLoader__.load({
914
968
  settingsPath: [...entry.settingsPath],
915
969
  active: active.has(entry.provider),
916
970
  ...entry.declared === void 0 ? {} : { declared: entry.declared },
971
+ ...entry.defaultBaseURL === void 0 ? {} : { defaultBaseURL: entry.defaultBaseURL },
972
+ ...entry.baseURLEnv === void 0 ? {} : { baseURLEnv: entry.baseURLEnv },
973
+ ...entry.nativeAuth === void 0 ? {} : { nativeAuth: entry.nativeAuth },
917
974
  ...entry.error === void 0 ? {} : { error: entry.error }
918
975
  }));
919
976
  for (const provider of registered) {
@@ -1041,7 +1098,9 @@ window.__ModuleLoader__.load({
1041
1098
  }
1042
1099
  const mirrored = this.describeFace.getSnapshot();
1043
1100
  if (mirrored.view === void 0) {
1044
- this.failLoad(mirrored.error ?? "settings are unavailable in this browser");
1101
+ /* v8 ignore next -- SettingsDescribeFace.ensure settles with a view or the read's error */
1102
+ if (mirrored.error === null) throw new Error("settings describe settled with neither a view nor an error");
1103
+ this.failLoad(mirrored.error);
1045
1104
  return;
1046
1105
  }
1047
1106
  const providers = joinProviderDirectory(registered.value, declared.value);
@@ -1062,13 +1121,16 @@ window.__ModuleLoader__.load({
1062
1121
  const catalog = await this.ctx.remote.session.modelCatalog();
1063
1122
  for (const row of rows) if (row.entry.provider === "deepseek-account") row.accountAvailable = catalog.ok && catalog.value.groups.some((group) => group.id === "deepseek-account" && group.models.length > 0);
1064
1123
  }
1065
- const refs = [...new Set(rows.filter((row) => row.entry.provider !== "deepseek-account").map((row) => row.apiKeyEnv ?? deriveKeyRef(row.entry.provider)))];
1066
- let credentials = {};
1124
+ const refs = [...new Set(rows.filter((row) => row.entry.provider !== "deepseek-account").flatMap((row) => row.apiKeyEnv === void 0 ? [deriveKeyRef(row.entry.provider), ...row.entry.nativeAuth?.env ?? []] : [row.apiKeyEnv]))];
1125
+ const credentials = {};
1067
1126
  let credentialError = null;
1068
- if (refs.length > 0) {
1069
- const response = await this.ctx.remote.credentials.describe(refs);
1070
- if (response.ok) credentials = response.value;
1071
- else credentialError = response.error.message;
1127
+ for (let index = 0; index < refs.length; index += 64) {
1128
+ const response = await this.ctx.remote.credentials.describe(refs.slice(index, index + 64));
1129
+ if (response.ok) Object.assign(credentials, response.value);
1130
+ else {
1131
+ credentialError = response.error.message;
1132
+ break;
1133
+ }
1072
1134
  }
1073
1135
  if (generation !== this.generation) return;
1074
1136
  this.store.update((s) => {
@@ -1083,7 +1145,11 @@ window.__ModuleLoader__.load({
1083
1145
  return {
1084
1146
  ...row,
1085
1147
  ...named === void 0 ? {} : { credential: named },
1086
- ...derived === void 0 ? {} : { derivedCredential: derived }
1148
+ ...derived === void 0 ? {} : { derivedCredential: derived },
1149
+ ...credentialError === null ? { credentialChecks: Object.fromEntries((row.apiKeyEnv === void 0 ? row.entry.nativeAuth?.env ?? [] : [row.apiKeyEnv]).flatMap((ref) => {
1150
+ const info = credentials[ref];
1151
+ return info === void 0 ? [] : [[ref, info]];
1152
+ })) } : {}
1087
1153
  };
1088
1154
  });
1089
1155
  s.namespaces = namespaces;
@@ -1401,10 +1467,8 @@ window.__ModuleLoader__.load({
1401
1467
  className: ModelsSection_module_css_default["fieldLabel"],
1402
1468
  children: t("keyInput")
1403
1469
  }),
1404
- (0, react_jsx_runtime.jsx)("input", {
1405
- className: ModelsSection_module_css_default["input"],
1406
- type: "password",
1407
- autoComplete: "new-password",
1470
+ (0, react_jsx_runtime.jsx)(ApiKeyInput, {
1471
+ t,
1408
1472
  value: keyDraft,
1409
1473
  placeholder: t("keyPlaceholder"),
1410
1474
  "aria-label": t("keyInput"),
@@ -1536,7 +1600,6 @@ window.__ModuleLoader__.load({
1536
1600
  const { namespace, schema, settingsPath, operations, t } = props;
1537
1601
  const [draft, setDraft] = (0, react.useState)(() => draftAt(schema, namespace, settingsPath));
1538
1602
  const [keyDraft, setKeyDraft] = (0, react.useState)("");
1539
- const [keyState, setKeyState] = (0, react.useState)(void 0);
1540
1603
  const [busy, setBusy] = (0, react.useState)(false);
1541
1604
  const [listBusy, setListBusy] = (0, react.useState)(false);
1542
1605
  const { onBusyChange } = props;
@@ -1558,30 +1621,13 @@ window.__ModuleLoader__.load({
1558
1621
  ]);
1559
1622
  const fallback = schema.getPath(namespace.value, settingsPath);
1560
1623
  const disabled = props.readOnly || busy;
1561
- const accountProvider = props.provider === "deepseek-account";
1562
- const layout = accountProvider ? "deepseek" : layoutOf(namespace.ns);
1624
+ const layout = layoutOf(namespace.ns);
1563
1625
  const keyRef = refFor(schema, namespace, settingsPath, props.provider);
1564
1626
  const protocols = (0, react.useMemo)(() => layout === "pi-ai" ? protocolChoices(namespace, schema) : [], [
1565
1627
  layout,
1566
1628
  namespace,
1567
1629
  schema
1568
1630
  ]);
1569
- (0, react.useEffect)(() => {
1570
- if (accountProvider) return;
1571
- let stale = false;
1572
- setKeyState(void 0);
1573
- operations.describeCredential(keyRef).then((described) => {
1574
- if (stale) return;
1575
- setKeyState(described);
1576
- });
1577
- return () => {
1578
- stale = true;
1579
- };
1580
- }, [
1581
- operations,
1582
- keyRef,
1583
- accountProvider
1584
- ]);
1585
1631
  const stringAt = (source, key) => {
1586
1632
  const value = schema.getPath(source, [key]);
1587
1633
  return typeof value === "string" && value.trim().length > 0 ? value : void 0;
@@ -1663,7 +1709,6 @@ window.__ModuleLoader__.load({
1663
1709
  props.t("settingsPathUnresolvable")
1664
1710
  ]
1665
1711
  });
1666
- const keyLocked = keyState?.writable === false;
1667
1712
  /**
1668
1713
  * The catalog beneath the user layer: what the composition entry pinned, or
1669
1714
  * else the schema default that `resolve` would supply. The effective value
@@ -1687,7 +1732,38 @@ window.__ModuleLoader__.load({
1687
1732
  const defaultContextWindow = schema.getPath(fallback, ["defaultContextWindow"]);
1688
1733
  const defaultMaxTokens = schema.getPath(fallback, ["maxTokens"]);
1689
1734
  const defaultInput = schema.getPath(fallback, ["defaultInput"]);
1690
- const keyPlaceholder = keyLocked ? t("keyEnvLocked") : keyState?.configured === true && props.credentialRequired !== true ? t("keyStored") : family === "pi-ai" ? t("keyPlaceholderNative") : t("keyPlaceholder");
1735
+ const baseURL = stringAt(fallback, "baseURL") ?? props.defaultBaseURL;
1736
+ const endpointEnv = props.baseURLEnv ?? [];
1737
+ const endpointHint = family === "deepseek" ? t("deepSeekEndpointHint") : baseURL === void 0 && endpointEnv.length > 0 ? t("baseUrlEnvironment").replace("{env}", () => endpointEnv.join(", ")) : void 0;
1738
+ const namedRef = stringAt(fallback, "apiKeyEnv");
1739
+ const nativeAuth = namedRef === void 0 ? props.nativeAuth : void 0;
1740
+ const authRefs = namedRef === void 0 ? (nativeAuth?.env ?? []).filter((ref) => !endpointEnv.includes(ref)) : [namedRef];
1741
+ const visibleRefs = authRefs.filter((ref) => !ref.toLowerCase().includes("oauth"));
1742
+ const keyHint = visibleRefs[0];
1743
+ const checkedRefs = authRefs.map((ref) => [ref, props.credentialChecks?.[ref] ?? (ref === namedRef ? props.credential : void 0)]);
1744
+ const detected = checkedRefs.find(([, info]) => info?.configured === true);
1745
+ const detectedRef = detected?.[0];
1746
+ const detectedVisibleRef = detectedRef === void 0 || !visibleRefs.includes(detectedRef) ? void 0 : detectedRef;
1747
+ const missingRefs = checkedRefs.length > 0 && checkedRefs.every(([, info]) => info?.configured === false);
1748
+ const savedCredential = detected?.[1]?.source === "file";
1749
+ const credentialHint = keyDraft.length > 0 || savedCredential || keyHint === void 0 || props.credentialRequired === true ? void 0 : t(detectedRef === void 0 ? missingRefs ? "keyFallbackMissing" : "keyFallbackUnchecked" : detectedVisibleRef === void 0 ? "keyFallbackDetectedHidden" : "keyFallbackDetected").replace("{hint}", () => detectedVisibleRef ?? keyHint);
1750
+ const keyHelp = visibleRefs.length === 0 ? void 0 : t("keyHelp").replace("{env}", () => visibleRefs.join(" / "));
1751
+ const authHelp = keyHelp === void 0 ? null : (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Tooltip, {
1752
+ label: keyHelp,
1753
+ side: "right",
1754
+ delayMs: 0,
1755
+ focusDelayMs: 0,
1756
+ portal: true,
1757
+ openOnClick: true,
1758
+ children: (0, react_jsx_runtime.jsx)("button", {
1759
+ type: "button",
1760
+ className: ModelsSection_module_css_default["helpButton"],
1761
+ "aria-label": t("authHelp"),
1762
+ children: "?"
1763
+ })
1764
+ });
1765
+ const keylessNativeAuth = nativeAuth?.env.length === 0 && nativeAuth.oauth;
1766
+ const keyPlaceholder = keyHint === void 0 || props.credentialRequired === true ? t("keyPlaceholder") : t(savedCredential ? "keyPlaceholderSaved" : "keyPlaceholderFallback").replace("{hint}", () => keyHint);
1691
1767
  /** What both family editors take: the rows, whose layer owns them, and the two writes. */
1692
1768
  const catalogProps = {
1693
1769
  models,
@@ -1701,33 +1777,32 @@ window.__ModuleLoader__.load({
1701
1777
  setDraft((current) => schema.deletePath(current, ["models"]));
1702
1778
  }
1703
1779
  };
1704
- if (accountProvider) return (0, react_jsx_runtime.jsx)(DeepSeekModelsEditor, {
1705
- ...catalogProps,
1706
- defaultContextWindow: typeof defaultContextWindow === "number" ? defaultContextWindow : void 0,
1707
- defaultMaxTokens: typeof defaultMaxTokens === "number" ? defaultMaxTokens : void 0
1708
- });
1709
- return (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [(0, react_jsx_runtime.jsxs)("div", {
1780
+ return (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [keylessNativeAuth ? null : (0, react_jsx_runtime.jsxs)("div", {
1710
1781
  className: ModelsSection_module_css_default["field"],
1711
1782
  children: [
1712
- (0, react_jsx_runtime.jsx)("span", {
1783
+ (0, react_jsx_runtime.jsxs)("span", {
1713
1784
  className: ModelsSection_module_css_default["fieldLabel"],
1714
- children: t("keyInput")
1785
+ children: [t("keyInput"), authHelp]
1715
1786
  }),
1716
- (0, react_jsx_runtime.jsx)("input", {
1717
- className: ModelsSection_module_css_default["input"],
1718
- type: "password",
1719
- autoComplete: "new-password",
1787
+ (0, react_jsx_runtime.jsx)(ApiKeyInput, {
1788
+ t,
1720
1789
  value: keyDraft,
1721
1790
  placeholder: keyPlaceholder,
1722
1791
  "aria-label": t("keyInput"),
1723
1792
  "aria-invalid": shownKeyFailure !== void 0,
1793
+ "aria-describedby": credentialHint === void 0 ? void 0 : `${props.provider}-credential-hint`,
1724
1794
  required: props.credentialRequired === true,
1725
1795
  autoFocus: props.autoFocusCredential === true,
1726
- disabled: disabled || keyLocked,
1796
+ disabled,
1727
1797
  onChange: (event) => {
1728
1798
  setKeyDraft(event.target.value);
1729
1799
  }
1730
1800
  }),
1801
+ credentialHint === void 0 ? null : (0, react_jsx_runtime.jsx)("p", {
1802
+ id: `${props.provider}-credential-hint`,
1803
+ className: ModelsSection_module_css_default[missingRefs ? "notice" : detectedRef === void 0 ? "advancedHint" : "savedNotice"],
1804
+ children: credentialHint
1805
+ }),
1731
1806
  shownKeyFailure === void 0 ? null : (0, react_jsx_runtime.jsx)("p", {
1732
1807
  className: ModelsSection_module_css_default["error"],
1733
1808
  children: t(shownKeyFailure)
@@ -1769,19 +1844,19 @@ window.__ModuleLoader__.load({
1769
1844
  className: ModelsSection_module_css_default["input"],
1770
1845
  type: "text",
1771
1846
  value: stringAt(draft, "baseURL") ?? "",
1772
- placeholder: family === "deepseek" ? t("deepSeekBaseUrl") : stringAt(fallback, "baseURL") ?? t("baseUrlDefault"),
1773
- "aria-describedby": family === "deepseek" ? `${props.provider}-endpoint-hint` : void 0,
1847
+ placeholder: family === "deepseek" ? t("deepSeekBaseUrl") : baseURL === void 0 ? t(endpointEnv.length > 0 ? "baseUrlConfigured" : "baseUrlDefault") : t("baseUrlPlaceholder").replace("{url}", () => baseURL),
1848
+ "aria-describedby": endpointHint === void 0 ? void 0 : `${props.provider}-endpoint-hint`,
1774
1849
  "aria-label": t("baseUrl"),
1775
1850
  disabled,
1776
1851
  onChange: (event) => {
1777
1852
  setField("baseURL", event.target.value === "" ? void 0 : event.target.value);
1778
1853
  }
1779
1854
  }),
1780
- family === "deepseek" ? (0, react_jsx_runtime.jsx)("span", {
1855
+ endpointHint === void 0 ? null : (0, react_jsx_runtime.jsx)("span", {
1781
1856
  id: `${props.provider}-endpoint-hint`,
1782
1857
  className: ModelsSection_module_css_default["advancedHint"],
1783
- children: t("deepSeekEndpointHint")
1784
- }) : null
1858
+ children: endpointHint
1859
+ })
1785
1860
  ]
1786
1861
  }),
1787
1862
  ownsIdentity ? (0, react_jsx_runtime.jsxs)("div", {
@@ -1891,12 +1966,17 @@ window.__ModuleLoader__.load({
1891
1966
  * post-apply reload.
1892
1967
  */
1893
1968
  /** Render an editor for either the setup posture or an expanded provider row. */
1894
- function renderProviderEditor({ target, ...props }) {
1969
+ function renderProviderEditor({ target, row, ...props }) {
1895
1970
  return (0, react_jsx_runtime.jsx)(ProviderEditor, {
1896
1971
  provider: target.provider,
1897
1972
  displayName: target.displayName,
1898
1973
  settingsPath: target.settingsPath,
1899
1974
  ...target.declared === true ? { declared: true } : {},
1975
+ ...target.defaultBaseURL === void 0 ? {} : { defaultBaseURL: target.defaultBaseURL },
1976
+ ...target.baseURLEnv === void 0 ? {} : { baseURLEnv: target.baseURLEnv },
1977
+ ...target.nativeAuth === void 0 ? {} : { nativeAuth: target.nativeAuth },
1978
+ ...row.credential === void 0 ? {} : { credential: row.credential },
1979
+ ...row.credentialChecks === void 0 ? {} : { credentialChecks: row.credentialChecks },
1900
1980
  ...props
1901
1981
  });
1902
1982
  }
@@ -1956,7 +2036,10 @@ window.__ModuleLoader__.load({
1956
2036
  settingsNs: row.entry.settingsNs,
1957
2037
  settingsPath: row.entry.settingsPath,
1958
2038
  ...credentialRef === void 0 ? {} : { credentialRef },
1959
- ...row.entry.declared === true ? { declared: true } : {}
2039
+ ...row.entry.declared === true ? { declared: true } : {},
2040
+ ...row.entry.defaultBaseURL === void 0 ? {} : { defaultBaseURL: row.entry.defaultBaseURL },
2041
+ ...row.entry.baseURLEnv === void 0 ? {} : { baseURLEnv: row.entry.baseURLEnv },
2042
+ ...row.entry.nativeAuth === void 0 ? {} : { nativeAuth: row.entry.nativeAuth }
1960
2043
  };
1961
2044
  }
1962
2045
  /** Stable visible and accessible identity for one provider target. */
@@ -2178,6 +2261,7 @@ window.__ModuleLoader__.load({
2178
2261
  error,
2179
2262
  renderProviderEditor({
2180
2263
  target,
2264
+ row,
2181
2265
  namespace,
2182
2266
  schema,
2183
2267
  operations,
@@ -2213,6 +2297,13 @@ window.__ModuleLoader__.load({
2213
2297
  className: ModelsSection_module_css_default["rowTag"],
2214
2298
  children: t("customTag")
2215
2299
  }) : null,
2300
+ row.entry.provider === "deepseek-account" ? (0, react_jsx_runtime.jsxs)("span", {
2301
+ className: ModelsSection_module_css_default["accountStatus"],
2302
+ children: [(0, react_jsx_runtime.jsx)("span", {
2303
+ className: `${ModelsSection_module_css_default["credentialDot"]} ${ModelsSection_module_css_default["credentialDotConfigured"]}`,
2304
+ "aria-hidden": "true"
2305
+ }), t("accountSignedIn")]
2306
+ }) : null,
2216
2307
  credentialConfigured ? (0, react_jsx_runtime.jsx)("span", {
2217
2308
  className: `${ModelsSection_module_css_default["credentialDot"]} ${ModelsSection_module_css_default["credentialDotConfigured"]}`,
2218
2309
  role: "img",
@@ -2227,7 +2318,7 @@ window.__ModuleLoader__.load({
2227
2318
  ]
2228
2319
  }), (0, react_jsx_runtime.jsxs)("span", {
2229
2320
  className: ModelsSection_module_css_default["rowActions"],
2230
- children: [(0, react_jsx_runtime.jsx)("button", {
2321
+ children: [row.entry.provider === "deepseek-account" ? null : (0, react_jsx_runtime.jsx)("button", {
2231
2322
  type: "button",
2232
2323
  className: ModelsSection_module_css_default["secondaryButton"],
2233
2324
  "aria-label": providerCopy(t("editProvider"), target),
@@ -2262,6 +2353,7 @@ window.__ModuleLoader__.load({
2262
2353
  }, { entryKey: row.entry.settingsNs }),
2263
2354
  open ? renderProviderEditor({
2264
2355
  target,
2356
+ row,
2265
2357
  namespace,
2266
2358
  schema,
2267
2359
  operations,
@@ -2352,6 +2444,10 @@ window.__ModuleLoader__.load({
2352
2444
  schema,
2353
2445
  settingsPath: draft.target.settingsPath,
2354
2446
  operations,
2447
+ ...draft.target.defaultBaseURL === void 0 ? {} : { defaultBaseURL: draft.target.defaultBaseURL },
2448
+ ...draft.target.baseURLEnv === void 0 ? {} : { baseURLEnv: draft.target.baseURLEnv },
2449
+ ...draft.target.nativeAuth === void 0 ? {} : { nativeAuth: draft.target.nativeAuth },
2450
+ ...addRow?.credentialChecks === void 0 ? {} : { credentialChecks: addRow.credentialChecks },
2355
2451
  t,
2356
2452
  readOnly: !state.writable,
2357
2453
  onClose: (changed) => {
@@ -2695,16 +2791,14 @@ window.__ModuleLoader__.load({
2695
2791
  //#endregion
2696
2792
  //#region lib/types/client/welcome-store.js
2697
2793
  /**
2698
- * Welcome-notice state derived from the welcome settings scope. The scope is
2699
- * the transport: a loopback browser follows the durable Host section, while a
2700
- * remote browser's memory-mode scope never answers and the acknowledgement
2701
- * stays process-local here.
2794
+ * Welcome-notice state derived from the welcome settings scope: the notice
2795
+ * follows the Host section and records its acknowledgement through it.
2702
2796
  */
2703
2797
  /* v8 ignore next 3 -- closed-union default only defends future source widening */
2704
2798
  function assertNever(_value) {
2705
2799
  throw new Error("unexpected welcome settings status");
2706
2800
  }
2707
- /** Coordinates durable Host acknowledgement or a process-local remote fallback. */
2801
+ /** Coordinates the durable Host acknowledgement. */
2708
2802
  var WelcomeNoticeStore = class {
2709
2803
  scope;
2710
2804
  /** uSES-safe state source shared by the registered welcome step. */
@@ -2713,13 +2807,8 @@ window.__ModuleLoader__.load({
2713
2807
  acknowledged: false,
2714
2808
  error: null
2715
2809
  });
2716
- localAcknowledged = false;
2717
2810
  saving = false;
2718
2811
  following;
2719
- /**
2720
- * @param scope - the welcome settings namespace scope; its memory mode is
2721
- * what keeps a remote browser process-local.
2722
- */
2723
2812
  constructor(scope) {
2724
2813
  this.scope = scope;
2725
2814
  }
@@ -2735,17 +2824,12 @@ window.__ModuleLoader__.load({
2735
2824
  return Promise.resolve();
2736
2825
  }
2737
2826
  /**
2738
- * Persist this copy version, or advance only this process for a remote
2739
- * browser. Success is judged against the state the write left behind, so a
2740
- * refused or failed write reports false after its recovery read settles.
2741
- * @returns true when the selected persistence mode holds the acknowledgement.
2827
+ * Persist this copy version through the scope. Success is judged against the
2828
+ * state the write left behind, so a refused or failed write reports false
2829
+ * after its recovery read settles.
2830
+ * @returns true when the Host holds the acknowledgement.
2742
2831
  */
2743
2832
  async acknowledge() {
2744
- if (this.scope.getSnapshot().mode === "memory") {
2745
- this.localAcknowledged = true;
2746
- this.derive();
2747
- return true;
2748
- }
2749
2833
  this.saving = true;
2750
2834
  this.store.update((state) => {
2751
2835
  state.status = "saving";
@@ -2772,14 +2856,6 @@ window.__ModuleLoader__.load({
2772
2856
  derive() {
2773
2857
  if (this.saving) return;
2774
2858
  const scope = this.scope.getSnapshot();
2775
- if (scope.mode === "memory") {
2776
- this.store.update((state) => {
2777
- state.status = "ready";
2778
- state.acknowledged = this.localAcknowledged;
2779
- state.error = null;
2780
- });
2781
- return;
2782
- }
2783
2859
  switch (scope.status) {
2784
2860
  case "loading":
2785
2861
  this.store.update((state) => {
@@ -2824,10 +2900,6 @@ window.__ModuleLoader__.load({
2824
2900
  */
2825
2901
  function createModelsOperations(ctx) {
2826
2902
  return {
2827
- describeCredential: async (ref) => {
2828
- const response = await ctx.remote.credentials.describe([ref]);
2829
- return response.ok ? response.value[ref] : void 0;
2830
- },
2831
2903
  storeCredential: async (ref, value) => {
2832
2904
  const response = await ctx.remote.credentials.set(ref, value);
2833
2905
  return response.ok ? void 0 : response.error.message;
@@ -2915,19 +2987,30 @@ window.__ModuleLoader__.load({
2915
2987
  savedProvider: "Saved {provider}.",
2916
2988
  credentialConfigured: "API key configured",
2917
2989
  credentialMissing: "API key missing",
2990
+ accountSignedIn: "Signed in",
2918
2991
  readOnly: "The settings document is read-only in this deployment.",
2919
2992
  loadFailed: "Loading the provider directory failed",
2920
2993
  conflict: "Someone else changed these settings while this card was open. Close it and reopen to edit the current values.",
2921
2994
  retry: "Retry",
2922
2995
  keyInput: "API key",
2996
+ keyReveal: "Show secret",
2997
+ keyHide: "Hide secret",
2923
2998
  keyPlaceholder: "Enter your API key",
2924
- keyPlaceholderNative: "Enter an API key, or leave blank to use environment authentication",
2925
- keyStored: "Configured — enter a new value to replace",
2926
- keyEnvLocked: "Provided by the launch environment (read-only)",
2999
+ keyPlaceholderFallback: "Leave blank to use env as auth ({hint})",
3000
+ keyPlaceholderSaved: "Leave blank to use saved credentials",
3001
+ keyFallbackMissing: "Env var not detected. Enter an API key, or configure {hint} in your env.",
3002
+ keyFallbackDetected: "Env var detected. ({hint})",
3003
+ keyFallbackDetectedHidden: "Env var detected.",
3004
+ keyFallbackUnchecked: "Environment credential status has not been confirmed.",
3005
+ keyHelp: "Saved credentials are used first. Environment fallbacks shown here, in order: {env}. Sources are launch environment, $cwd/.env, then $DSH_HOME/.env.",
3006
+ authHelp: "Authentication details",
2927
3007
  customized: "Customized settings",
2928
3008
  baseUrl: "Base URL",
2929
- baseUrlDefault: "Provider default",
2930
- deepSeekBaseUrl: "https://api.deepseek.com/anthropic",
3009
+ baseUrlDefault: "No default endpoint",
3010
+ baseUrlEnvironment: "Provider endpoint configuration: {env}",
3011
+ baseUrlConfigured: "Provider-configured endpoint",
3012
+ baseUrlPlaceholder: "{url}",
3013
+ deepSeekBaseUrl: "https://api.deepseek.com/anthropic (Default to use DEEPSEEK_BASE_URL)",
2931
3014
  deepSeekEndpointHint: "Use an API endpoint compatible with Anthropic Messages.",
2932
3015
  models: "Models",
2933
3016
  modelsInherited: "Using the adapter defaults",
@@ -3031,19 +3114,30 @@ window.__ModuleLoader__.load({
3031
3114
  savedProvider: "已保存 {provider}。",
3032
3115
  credentialConfigured: "API 密钥已配置",
3033
3116
  credentialMissing: "API 密钥缺失",
3117
+ accountSignedIn: "已登录",
3034
3118
  readOnly: "当前部署的设置文档为只读。",
3035
3119
  loadFailed: "加载提供商目录失败",
3036
3120
  conflict: "这张卡片打开期间,这些设置已被其他地方改动。请关闭后重新打开,在当前值上编辑。",
3037
3121
  retry: "重试",
3038
3122
  keyInput: "API 密钥",
3123
+ keyReveal: "显示密钥",
3124
+ keyHide: "隐藏密钥",
3039
3125
  keyPlaceholder: "输入 API 密钥",
3040
- keyPlaceholderNative: "输入 API 密钥,或留空使用环境认证",
3041
- keyStored: "已配置——输入新值可替换",
3042
- keyEnvLocked: "由启动环境提供(只读)",
3126
+ keyPlaceholderFallback: "留空使用环境认证({hint})",
3127
+ keyPlaceholderSaved: "留空使用已保存凭据",
3128
+ keyFallbackMissing: "未检测到环境变量。请填写 API 密钥,或设置环境变量 {hint}。",
3129
+ keyFallbackDetected: "已检测到环境变量({hint})",
3130
+ keyFallbackDetectedHidden: "已检测到环境变量",
3131
+ keyFallbackUnchecked: "环境凭据状态尚未确认",
3132
+ keyHelp: "优先使用已保存的凭据。此处显示的环境后备按以下顺序排列:{env}。来源依次为启动环境、$cwd/.env、$DSH_HOME/.env。",
3133
+ authHelp: "认证说明",
3043
3134
  customized: "自定义设置",
3044
3135
  baseUrl: "API 地址",
3045
- baseUrlDefault: "提供商默认",
3046
- deepSeekBaseUrl: "https://api.deepseek.com/anthropic",
3136
+ baseUrlDefault: "没有默认地址",
3137
+ baseUrlEnvironment: "提供方地址配置:{env}",
3138
+ baseUrlConfigured: "由提供方配置地址",
3139
+ baseUrlPlaceholder: "{url}",
3140
+ deepSeekBaseUrl: "https://api.deepseek.com/anthropic(默认使用环境 DEEPSEEK_BASE_URL)",
3047
3141
  deepSeekEndpointHint: "请填写兼容 Anthropic Messages 协议的 API 地址。",
3048
3142
  models: "模型目录",
3049
3143
  modelsInherited: "正在使用适配器默认模型",
@@ -0,0 +1,17 @@
1
+ import type { InputHTMLAttributes, ReactNode } from 'react';
2
+ import type { en } from './locales.ts';
3
+ /** Input attributes and section copy for the current credential draft. */
4
+ interface ApiKeyInputProps extends Omit<InputHTMLAttributes<HTMLInputElement>, 'value' | 'type' | 'className' | 'autoComplete'> {
5
+ /** Unsaved input; stored credentials are never read into this field. */
6
+ readonly value: string;
7
+ /** Section copy, including the same reveal labels as SecretText. */
8
+ readonly t: (key: keyof typeof en) => string;
9
+ }
10
+ /**
11
+ * Reveal only a nonempty draft; a different value starts masked, as in SecretText.
12
+ * @param props - current draft, input attributes, and translated control labels.
13
+ * @returns a password input with an optional reveal button.
14
+ */
15
+ export declare function ApiKeyInput({ value, t, ...props }: ApiKeyInputProps): ReactNode;
16
+ export {};
17
+ //# sourceMappingURL=ApiKeyInput.d.ts.map
@@ -21,7 +21,7 @@
21
21
  * see instead of rebuilding the whole subtree from a partial descriptor.
22
22
  */
23
23
  import type { ReactNode } from 'react';
24
- import type { SettingsNamespaceView, SettingsPathOpView } from '@deepseek-ai/dsh-api-remotes/client';
24
+ import type { CredentialInfo, LlmNativeAuth, SettingsNamespaceView, SettingsPathOpView } from '@deepseek-ai/dsh-api-remotes/client';
25
25
  import type { ModelsOperations } from './operations.ts';
26
26
  import type { SettingsSchemaOperations } from './schema-operations.ts';
27
27
  import type { en } from './locales.ts';
@@ -49,6 +49,16 @@ export interface ProviderEditorProps {
49
49
  settingsPath: readonly string[];
50
50
  /** The Host operations this card writes and interrogates through. */
51
51
  operations: ModelsOperations;
52
+ /** Endpoint the route uses when its profile sets no `baseURL`; absent when the adapter reports none. */
53
+ defaultBaseURL?: string;
54
+ /** Environment variables used by the provider to construct its endpoint. */
55
+ baseURLEnv?: readonly string[];
56
+ /** Authentication the route performs when its profile names no credential reference; absent when the adapter reports none. */
57
+ nativeAuth?: LlmNativeAuth;
58
+ /** Redacted state of the profile's named credential reference, from the page snapshot. */
59
+ credential?: CredentialInfo;
60
+ /** Redacted checks for the profile's named reference or the provider's native variables. */
61
+ credentialChecks?: Readonly<Record<string, CredentialInfo>>;
52
62
  /** Section copy. */
53
63
  t: (key: keyof typeof en) => string;
54
64
  /** Disable writes (read-only settings provider). */
@@ -7,7 +7,7 @@ import type { en } from './locales.ts';
7
7
  /** Registration-side dependencies of {@link WelcomeNotice}. */
8
8
  export interface WelcomeNoticeInjected {
9
9
  hooks: {
10
- /** Durable or process-local acknowledgement state. */
10
+ /** Durable acknowledgement state. */
11
11
  welcome: SnapshotStore<WelcomeNoticeState>;
12
12
  };
13
13
  /** Welcome acknowledgement controller. */
@@ -30,18 +30,29 @@ export declare const en: {
30
30
  savedProvider: string;
31
31
  credentialConfigured: string;
32
32
  credentialMissing: string;
33
+ accountSignedIn: string;
33
34
  readOnly: string;
34
35
  loadFailed: string;
35
36
  conflict: string;
36
37
  retry: string;
37
38
  keyInput: string;
39
+ keyReveal: string;
40
+ keyHide: string;
38
41
  keyPlaceholder: string;
39
- keyPlaceholderNative: string;
40
- keyStored: string;
41
- keyEnvLocked: string;
42
+ keyPlaceholderFallback: string;
43
+ keyPlaceholderSaved: string;
44
+ keyFallbackMissing: string;
45
+ keyFallbackDetected: string;
46
+ keyFallbackDetectedHidden: string;
47
+ keyFallbackUnchecked: string;
48
+ keyHelp: string;
49
+ authHelp: string;
42
50
  customized: string;
43
51
  baseUrl: string;
44
52
  baseUrlDefault: string;
53
+ baseUrlEnvironment: string;
54
+ baseUrlConfigured: string;
55
+ baseUrlPlaceholder: string;
45
56
  deepSeekBaseUrl: string;
46
57
  deepSeekEndpointHint: string;
47
58
  models: string;
@@ -5,7 +5,7 @@
5
5
  * failure codes and Remote namespaces stay in the apply world.
6
6
  */
7
7
  import type { Context as ClientContext } from '@deepseek-ai/cordis';
8
- import type { CredentialInfo, LlmDiscoveredModel, LlmModelDiscoveryRequest, SettingsNamespaceView, SettingsPathOpView } from '@deepseek-ai/dsh-api-remotes/client';
8
+ import type { LlmDiscoveredModel, LlmModelDiscoveryRequest, SettingsNamespaceView, SettingsPathOpView } from '@deepseek-ai/dsh-api-remotes/client';
9
9
  /** What one namespace write answered. */
10
10
  export type SettingsWriteOutcome =
11
11
  /** Committed; the view carries the stored user subtree and the new revision. */
@@ -40,12 +40,6 @@ export type ModelDiscoveryOutcome =
40
40
  };
41
41
  /** The Host operations the Models page and its cards invoke. */
42
42
  export interface ModelsOperations {
43
- /**
44
- * Read one credential reference's state.
45
- * @param ref - credential reference name.
46
- * @returns the state, or undefined when the reference is unknown or the read was refused.
47
- */
48
- describeCredential(ref: string): Promise<CredentialInfo | undefined>;
49
43
  /**
50
44
  * Store one credential literal under its reference.
51
45
  * @param ref - credential reference name.
@@ -7,7 +7,7 @@
7
7
  * re-renders from the next describe, pushed or refetched.
8
8
  */
9
9
  import type { Context as ClientContext } from '@deepseek-ai/cordis';
10
- import type { CredentialInfo, LlmConfigurableProvider, LlmProviderInfo, SettingsNamespaceView } from '@deepseek-ai/dsh-api-remotes/client';
10
+ import type { CredentialInfo, LlmConfigurableProvider, LlmNativeAuth, LlmProviderInfo, SettingsNamespaceView } from '@deepseek-ai/dsh-api-remotes/client';
11
11
  import type { SnapshotStore } from '@deepseek-ai/dsh-client-store';
12
12
  import type { SettingsDescribeFace } from '@deepseek-ai/dsh-client-ui-settings/client';
13
13
  import type { SettingsSchemaOperations } from './schema-operations.ts';
@@ -19,6 +19,9 @@ export interface ProviderDirectoryEntry {
19
19
  readonly settingsPath: readonly string[];
20
20
  readonly active: boolean;
21
21
  readonly declared?: boolean;
22
+ readonly defaultBaseURL?: string;
23
+ readonly baseURLEnv?: readonly string[];
24
+ readonly nativeAuth?: LlmNativeAuth;
22
25
  readonly error?: string;
23
26
  }
24
27
  /**
@@ -49,6 +52,8 @@ export interface ProviderRow {
49
52
  * own derivation rule.
50
53
  */
51
54
  derivedCredential?: CredentialInfo;
55
+ /** Redacted checks for named or native references; absent when their read failed. */
56
+ credentialChecks?: Readonly<Record<string, CredentialInfo>>;
52
57
  }
53
58
  /** Page snapshot. */
54
59
  export interface ModelsSettingsState {
@@ -1,8 +1,6 @@
1
1
  /**
2
- * Welcome-notice state derived from the welcome settings scope. The scope is
3
- * the transport: a loopback browser follows the durable Host section, while a
4
- * remote browser's memory-mode scope never answers and the acknowledgement
5
- * stays process-local here.
2
+ * Welcome-notice state derived from the welcome settings scope: the notice
3
+ * follows the Host section and records its acknowledgement through it.
6
4
  */
7
5
  import { type SnapshotStore } from '@deepseek-ai/dsh-client-store';
8
6
  import type { ConfigForm } from '@deepseek-ai/dsh-client-ui-settings/client';
@@ -22,18 +20,13 @@ export type WelcomeSection = Record<string, unknown>;
22
20
  * @returns the section object, or an empty one for non-object values.
23
21
  */
24
22
  export declare function decodeWelcomeSection(section: unknown): WelcomeSection;
25
- /** Coordinates durable Host acknowledgement or a process-local remote fallback. */
23
+ /** Coordinates the durable Host acknowledgement. */
26
24
  export declare class WelcomeNoticeStore {
27
25
  private readonly scope;
28
26
  /** uSES-safe state source shared by the registered welcome step. */
29
27
  readonly store: SnapshotStore<WelcomeNoticeState>;
30
- private localAcknowledged;
31
28
  private saving;
32
29
  private following;
33
- /**
34
- * @param scope - the welcome settings namespace scope; its memory mode is
35
- * what keeps a remote browser process-local.
36
- */
37
30
  constructor(scope: ConfigForm<WelcomeSection>);
38
31
  /**
39
32
  * Begin following the bound scope (idempotent) and publish its current answer.
@@ -41,10 +34,10 @@ export declare class WelcomeNoticeStore {
41
34
  */
42
35
  load(): Promise<void>;
43
36
  /**
44
- * Persist this copy version, or advance only this process for a remote
45
- * browser. Success is judged against the state the write left behind, so a
46
- * refused or failed write reports false after its recovery read settles.
47
- * @returns true when the selected persistence mode holds the acknowledgement.
37
+ * Persist this copy version through the scope. Success is judged against the
38
+ * state the write left behind, so a refused or failed write reports false
39
+ * after its recovery read settles.
40
+ * @returns true when the Host holds the acknowledgement.
48
41
  */
49
42
  acknowledge(): Promise<boolean>;
50
43
  /** Stop following the scope. */
package/locale/en.json ADDED
@@ -0,0 +1,5 @@
1
+ {
2
+ "meta": {
3
+ "title": "ui-settings-models"
4
+ }
5
+ }
package/locale/zh.json ADDED
@@ -0,0 +1,6 @@
1
+ {
2
+ "meta": {
3
+ "title": "模型设置界面",
4
+ "description": "管理模型服务及其接入配置,并提供相关引导。"
5
+ }
6
+ }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@deepseek-ai/dsh-client-ui-settings-models",
3
3
  "description": "Models settings and shared product-onboarding dialogs over existing settings and credential joins",
4
- "version": "0.2.1-alpha.2",
4
+ "version": "0.2.1-alpha.3",
5
5
  "publishConfig": {
6
6
  "access": "public"
7
7
  },
@@ -23,7 +23,8 @@
23
23
  "default": "./lib/client.js"
24
24
  },
25
25
  "./src/*": "./src/*",
26
- "./package.json": "./package.json"
26
+ "./package.json": "./package.json",
27
+ "./locale/*.json": "./locale/*.json"
27
28
  },
28
29
  "dsh": {
29
30
  "client": {
@@ -37,29 +38,29 @@
37
38
  },
38
39
  "license": "MIT",
39
40
  "peerDependencies": {
40
- "@deepseek-ai/cordis": "~4.0.5-alpha.1"
41
+ "@deepseek-ai/cordis": "~4.0.5-alpha.2"
41
42
  },
42
43
  "devDependencies": {
43
- "@deepseek-ai/dsh-host-webserver": "0.2.1-alpha.2",
44
- "@deepseek-ai/dsh-api-remotes": "0.2.1-alpha.2",
45
- "@deepseek-ai/dsh-client-locale": "0.2.1-alpha.2",
46
- "@deepseek-ai/dsh-client-store": "0.2.1-alpha.2",
47
- "@deepseek-ai/dsh-client-test-runtime": "0.2.1-alpha.2",
48
- "@deepseek-ai/dsh-client-ui-primitives": "0.2.1-alpha.2",
49
- "@deepseek-ai/dsh-client-ui-settings": "0.2.1-alpha.2",
50
- "@deepseek-ai/dsh-client-ui-slots": "0.2.1-alpha.2",
51
- "@types/react": "~18.3.1",
52
- "@deepseek-ai/cordis": "~4.0.5-alpha.1",
44
+ "@deepseek-ai/dsh-host-webserver": "0.2.1-alpha.3",
45
+ "@deepseek-ai/dsh-api-remotes": "0.2.1-alpha.3",
46
+ "@deepseek-ai/dsh-client-locale": "0.2.1-alpha.3",
47
+ "@deepseek-ai/dsh-client-store": "0.2.1-alpha.3",
48
+ "@deepseek-ai/dsh-client-test-runtime": "0.2.1-alpha.3",
49
+ "@deepseek-ai/dsh-client-ui-primitives": "0.2.1-alpha.3",
50
+ "@deepseek-ai/dsh-client-ui-settings": "0.2.1-alpha.3",
51
+ "@deepseek-ai/dsh-client-ui-slots": "0.2.1-alpha.3",
52
+ "@deepseek-ai/cordis": "~4.0.5-alpha.2",
53
53
  "react": "^18.2.0",
54
- "@deepseek-ai/dsh-client-ui-renderer": "0.2.1-alpha.2",
55
- "@deepseek-ai/dsh-util-values": "0.2.1-alpha.2",
56
- "@deepseek-ai/dsh-remote-mock": "0.2.1-alpha.2",
57
- "@deepseek-ai/dsh-client-product-analytics": "0.2.1-alpha.2"
54
+ "@deepseek-ai/dsh-client-ui-renderer": "0.2.1-alpha.3",
55
+ "@deepseek-ai/dsh-util-values": "0.2.1-alpha.3",
56
+ "@deepseek-ai/dsh-remote-mock": "0.2.1-alpha.3",
57
+ "@deepseek-ai/dsh-client-product-analytics": "0.2.1-alpha.3"
58
58
  },
59
59
  "dependencies": {
60
- "@deepseek-ai/schemastery": "~3.18.5-alpha.1"
60
+ "@deepseek-ai/schemastery": "~3.18.5-alpha.2"
61
61
  },
62
62
  "files": [
63
+ "locale/*.json",
63
64
  "lib/index.js",
64
65
  "lib/client.js",
65
66
  "lib/types/**/*.d.ts"