dsh-advisor 0.5.0 → 0.5.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +12 -11
- package/README.zh.md +12 -11
- package/icon.svg +18 -0
- package/lib/client/advisor-card.d.ts +53 -54
- package/lib/client/advisor-store.d.ts +15 -14
- package/lib/client/locales.d.ts +8 -7
- package/lib/client.js +175 -227
- package/lib/commands.d.ts +8 -13
- package/lib/commands.js +11 -20
- package/lib/commands.js.map +1 -1
- package/lib/config.d.ts +44 -25
- package/lib/config.js +57 -27
- package/lib/config.js.map +1 -1
- package/lib/gateway.d.ts +4 -1
- package/lib/gateway.js +14 -7
- package/lib/gateway.js.map +1 -1
- package/lib/index.d.ts +5 -2
- package/lib/index.js +38 -37
- package/lib/index.js.map +1 -1
- package/lib/settings.d.ts +6 -3
- package/lib/settings.js +6 -3
- package/lib/settings.js.map +1 -1
- package/lib/tui-settings.d.ts +15 -14
- package/lib/tui-settings.js +19 -26
- package/lib/tui-settings.js.map +1 -1
- package/locale/en.json +6 -0
- package/locale/zh.json +6 -0
- package/package.json +26 -23
package/README.md
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
[](https://www.npmjs.com/package/dsh-advisor)
|
|
6
6
|
[](LICENSE)
|
|
7
7
|

|
|
8
|
-

|
|
9
9
|

|
|
10
10
|
[](https://dshfind.com/plugins/omdsh-dev/dsh-advisor?ref=badge)
|
|
11
11
|
|
|
@@ -28,29 +28,30 @@ Same plugin, either front end — the only difference is the `--profile` flag. P
|
|
|
28
28
|
|
|
29
29
|
### Configuration
|
|
30
30
|
|
|
31
|
-
Edit the `config` of the `advisor` row in your profile's patch layer (`~/.dsh/profiles/<profile>/cordis.patch.yml`). All
|
|
31
|
+
Edit the `config` of the `advisor` row in your profile's patch layer (`~/.dsh/profiles/<profile>/cordis.patch.yml`). All five fields are schema-volatile live fields (dsh ≥ 0.1.7-rc.1): the web card and the TUI `/settings` screen write this same entry config — persisted in the profile patch, committed without a remount. (A pre-0.1.7 `$DSH_HOME/settings.yaml` `advisor:` section no longer exists: dsh imports it into the active profile once and renames the file `.imported`.)
|
|
32
|
+
|
|
33
|
+
> **Breaking change (2026-09-26): the `enabled` config key was removed.** The plugin-row enable/disable toggle in the host UI is the master switch — a running row is enabled, and there is nothing left to configure for it. A stored profile still carrying an `enabled:` line keeps working: the line is **silently ignored** (accepted, never read, never re-persisted — 2026-09-27 ruling, no manual deletion needed); the key is deprecated and the write paths no longer persist it.
|
|
32
34
|
|
|
33
35
|
```yaml
|
|
34
36
|
# ~/.dsh/profiles/<profile>/cordis.patch.yml — the advisor row's config
|
|
35
37
|
- id: advisor
|
|
36
38
|
config:
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
model: deepseek-flash # REQUIRED when enabled; fallback: deepseek-v4-flash (or another V4 id) until the gateway enables the V41 route
|
|
39
|
+
provider: deepseek-official # REQUIRED (non-empty) for the advisor to run
|
|
40
|
+
model: deepseek-flash # REQUIRED (non-empty); fallback: deepseek-v4-flash (or another V4 id) until the gateway enables the V41 route
|
|
40
41
|
systemPrompt: "" # optional; "" = built-in reviewer prompt
|
|
41
42
|
immuneTurns: 3 # int ≥ 0, default 3 — cooldown after a delivered steer
|
|
42
43
|
maxDeltaMessages: 60 # int ≥ 0, default 60 — delta window; 0 = unbounded
|
|
43
44
|
```
|
|
44
45
|
|
|
45
|
-
|
|
46
|
+
`provider` and `model` are **mandatory**: either missing or empty is a hard gate — the advisor never starts a model call and reports a disabled-with-reason status; unknown config keys are rejected.
|
|
46
47
|
|
|
47
48
|
The same keys are read and edited from **three surfaces** (one store — the advisor entry config above; every surface shares the same key set and the same hard gate, with the host-side gate as the final line of defense on every path):
|
|
48
49
|
|
|
49
50
|
1. **Plugin-row config** — the profile patch layer (`~/.dsh/profiles/<profile>/cordis.patch.yml`). This is where the config lives.
|
|
50
|
-
2. **dsh web Plugins page — the dsh-advisor bundle's own page** — the Advisor **card** (bundle key `dsh-advisor`)
|
|
51
|
+
2. **dsh web Plugins page — the dsh-advisor bundle's own page** — the Advisor **card** (bundle key `dsh-advisor`), a flat settings form (the page's title/description come from the plugin's locale meta) with provider / model selects restricted to system-configured providers and their models, and the optional fields. Saving writes the advisor entry's config (landed through the config editor into the profile patch) and applies to running sessions immediately — no restart. The card requires a dsh web build whose shell declares the `plugins.bundle.config` card slot (dsh ≥ 0.1.7-rc.1) and loads packages that declare `dsh.client`; it reads and writes the config through the official `GatewayService` RPC channel (`/api/advisor/get` + `/api/advisor/set`), which is not gated by the settings exposure allowlist. It additionally blocks saving while a required field is empty.
|
|
51
52
|
3. **`/advisor` command** — per-session and ephemeral: it flips a session override and pins a per-session reviewer model, never the persisted config (see [Verify](#verify)).
|
|
52
53
|
|
|
53
|
-
In a **dsh-tui** profile the same
|
|
54
|
+
In a **dsh-tui** profile the same four keys are editable in the TUI `/settings` screen: run `dsh --profile dsh-tui`, open `/settings`, and edit the **Advisor** section (`provider` / `model` / `immuneTurns` / `maxDeltaMessages`, each with zh/en label + hint). Edits are staged and written on save through the revision-fenced `settings.mutate` into the same advisor entry config the web card writes, and re-apply live without a restart. `systemPrompt` is NOT a TUI field (the TUI text control is single-line; a multi-line prompt would be truncated) — edit it via the web card or the profile patch layer. The section requires dsh-tui ≥ v0.8.0 (shipped in the `dsh-tui-settings-sections` row of the v0.8.0+ bundle); older dsh-tui versions no-op it cleanly and the profile patch layer remains the edit path. `/advisor config` stays a read-only readback whose edit hint names the `/settings` screen when the seam is mounted. Save behavior differs from the web card: the TUI seam has no cross-field validation, so a save may leave `provider`/`model` empty — the explicit model gate resolves that to disabled-with-reason at runtime (visible via `/advisor status` and `/advisor config`); the web card blocks such a save outright. Full reference → [docs/configuration.md](docs/configuration.md).
|
|
54
55
|
|
|
55
56
|

|
|
56
57
|
|
|
@@ -60,7 +61,7 @@ In a **dsh-tui** profile the same five keys are editable in the TUI `/settings`
|
|
|
60
61
|
dsh --profile web --dump-config # shows a "# == dsh-advisor" layer with the advisor row
|
|
61
62
|
```
|
|
62
63
|
|
|
63
|
-
With the advisor installed and enabled, control it in-session with the `/advisor` command (available when a command registry is composed):
|
|
64
|
+
With the advisor installed and its plugin row enabled (the row switch on the Plugins page is the master switch), control it in-session with the `/advisor` command (available when a command registry is composed):
|
|
64
65
|
|
|
65
66
|
```
|
|
66
67
|
/advisor toggle the advisor for this session
|
|
@@ -72,7 +73,7 @@ With the advisor installed and enabled, control it in-session with the `/advisor
|
|
|
72
73
|
/advisor model reset drop the session pin and re-inherit the global defaults
|
|
73
74
|
```
|
|
74
75
|
|
|
75
|
-
`/advisor on|off|toggle` are session-scoped and ephemeral: they flip a per-session override, never the persisted config. Enabling a session whose config lacks `provider`/`model` starts no model call — `/advisor status` (and the `/advisor on` reply) shows the gate reason: the advisor runs only
|
|
76
|
+
`/advisor on|off|toggle` are session-scoped and ephemeral: they flip a per-session override, never the persisted config. Enabling a session whose config lacks `provider`/`model` starts no model call — `/advisor status` (and the `/advisor on` reply) shows the gate reason: the advisor runs only with both configured. `/advisor on` is also the manual recovery path: a session advisor paused by a quota/rate-limit (`quota_exhausted` — no auto-resume timer) resumes in place, and a halted advisor (permanent model error, e.g. invalid credentials) is rebuilt fresh for the session.
|
|
76
77
|
|
|
77
78
|
`/advisor model set` pins a reviewer model for the **invoking session only** — an in-memory, atomic `provider + model` pair that lives for the live session (cleared on dispose, owner teardown, cold resume, or restart; a forked/new session inherits the global defaults). It rides above the persisted global defaults without rewriting them: a complete session pair is used even when the global config has no pair yet, a malformed global config still blocks every session, half-pairs are never merged, and setting/resetting never touches the enable switch. Validation resolves the pair through the LLM service before commit (60 s bound, cancellable, no auto-retry); on failure the previous selection stays untouched. `/advisor config` remains the readback of the **global defaults**, not the session state.
|
|
78
79
|
|
|
@@ -89,7 +90,7 @@ On the **web**, the same session model controls ride the session header's **Advi
|
|
|
89
90
|
[advisor:concern] extract the helper into a module and unit-test it
|
|
90
91
|
```
|
|
91
92
|
|
|
92
|
-
- **Explicit model gate**:
|
|
93
|
+
- **Explicit model gate**: a missing `provider` + `model` never starts a model call — status reports disabled-with-reason. The gate applies to the *effective* route after session resolution: a complete per-session override pair satisfies it for that session; a malformed global config cannot be bypassed. Unknown config keys are rejected — the removed `enabled` key is the one legacy exception (silently ignored; the plugin-row toggle is the switch).
|
|
93
94
|
- **Zero-tool minimal start**: the reviewer is an independent model call only — no advisor tools, nothing it can do to the session besides advisory messages.
|
|
94
95
|
- **No-stall failure policy**: a failing or quota-limited advisor only drops its own bounded backlog — it can never park or pollute the primary loop.
|
|
95
96
|
- **Session-scoped controls**: `/advisor on|off|status|config|model` work per session; the toggles and the per-session model pin are ephemeral overrides, never persisted config — `/advisor config` always reports the global defaults. On the web, the session header's **Advisor action** drives the same per-session pin through dedicated session endpoints (see [Verify](#verify)).
|
package/README.zh.md
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
[](https://www.npmjs.com/package/dsh-advisor)
|
|
6
6
|
[](LICENSE)
|
|
7
7
|

|
|
8
|
-

|
|
9
9
|

|
|
10
10
|
[](https://dshfind.com/zh/plugins/omdsh-dev/dsh-advisor?ref=badge)
|
|
11
11
|
|
|
@@ -28,29 +28,30 @@ dsh plugin --profile dsh-tui add dsh-advisor # dsh-tui 终端 profile
|
|
|
28
28
|
|
|
29
29
|
### 配置
|
|
30
30
|
|
|
31
|
-
编辑 profile 补丁层(`~/.dsh/profiles/<profile>/cordis.patch.yml`)里 `advisor` 行的 `config
|
|
31
|
+
编辑 profile 补丁层(`~/.dsh/profiles/<profile>/cordis.patch.yml`)里 `advisor` 行的 `config`。五个字段全部是 schema-volatile 的 live 字段(dsh ≥ 0.1.7-rc.1):web 卡片与 TUI `/settings` 屏幕写入的就是这同一份 entry config——持久化在 profile 补丁层,无需重挂载即生效。(pre-0.1.7 的 `$DSH_HOME/settings.yaml` `advisor:` 分节已不存在:dsh 会在首次启动时把它导入活跃 profile 一次,并将该文件改名为 `.imported`。)
|
|
32
|
+
|
|
33
|
+
> **破坏性变更(2026-09-26):`enabled` 配置键已移除。** 宿主 UI 中插件行的启用/停用开关就是总开关——插件行在运行即启用,无需任何配置键。存量 profile 若仍携带 `enabled:` 行**继续正常工作**:该行会被**静默忽略**(接受但剥离,永不读取、永不回写——2026-09-27 裁决,无需手工删除);该键已废弃,写入路径不再持久化它。
|
|
32
34
|
|
|
33
35
|
```yaml
|
|
34
36
|
# ~/.dsh/profiles/<profile>/cordis.patch.yml —— advisor 行的 config
|
|
35
37
|
- id: advisor
|
|
36
38
|
config:
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
model: deepseek-flash # enabled: true 时必填(非空);网关未开放 V41 路由时回退 deepseek-v4-flash(或其它 V4 id)
|
|
39
|
+
provider: deepseek-official # 必填(非空)
|
|
40
|
+
model: deepseek-flash # 必填(非空);网关未开放 V41 路由时回退 deepseek-v4-flash(或其它 V4 id)
|
|
40
41
|
systemPrompt: "" # 可选;"" = 内置评审 prompt
|
|
41
42
|
immuneTurns: 3 # 整数 ≥ 0,默认 3 —— 打断性送达后的冷却步数
|
|
42
43
|
maxDeltaMessages: 60 # 整数 ≥ 0,默认 60 —— delta 窗口;0 = 无上限
|
|
43
44
|
```
|
|
44
45
|
|
|
45
|
-
|
|
46
|
+
`provider` 与 `model` 为**必填**:任一缺失或为空是一个硬门禁——advisor 不会发起任何模型调用,并报告带原因的禁用状态(disabled-with-reason);未知配置键会被拒绝。
|
|
46
47
|
|
|
47
48
|
同一组键可在**三个配置面**读取与编辑(只有一份存储——上面的 advisor entry config;各处使用同一组键与同一个硬门禁,宿主侧门禁始终是所有路径上的最后防线):
|
|
48
49
|
|
|
49
50
|
1. **插件行 config** —— profile 补丁层(`~/.dsh/profiles/<profile>/cordis.patch.yml`)。配置就存放在这里。
|
|
50
|
-
2. **dsh web 的「插件」页 —— dsh-advisor 组合包自己的页面** —— Advisor **卡片**(bundle key `dsh-advisor
|
|
51
|
+
2. **dsh web 的「插件」页 —— dsh-advisor 组合包自己的页面** —— Advisor **卡片**(bundle key `dsh-advisor`),一个**平铺**的设置表单(页面标题/描述来自插件 locale 元数据),含只列出系统内已配置 provider 及其模型的 provider/model 选择框与可选字段。保存写入 advisor entry 的 config(经 config editor 落入 profile 补丁层),运行中的会话立即生效,无需重启。卡片要求 dsh web 构建的 shell 声明了 `plugins.bundle.config` 卡片 slot(dsh ≥ 0.1.7-rc.1)并能加载 `dsh.client` 声明包;它通过官方 `GatewayService` RPC 通道读写该配置(`/api/advisor/get` + `/api/advisor/set`),不受 settings 暴露白名单门控。卡片还会在必填字段为空时阻止保存。
|
|
51
52
|
3. **`/advisor` 指令** —— 按会话且临时:翻转的是会话级 override、并为会话钉住评审模型,从不修改持久化配置(见[验证](#验证))。
|
|
52
53
|
|
|
53
|
-
在 **dsh-tui** profile
|
|
54
|
+
在 **dsh-tui** profile 中,同样的四个键可在 TUI `/settings` 屏幕编辑:运行 `dsh --profile dsh-tui`、打开 `/settings`,编辑 **Advisor** 分节(`provider` / `model` / `immuneTurns` / `maxDeltaMessages`,每项均带中英文标签与提示)。编辑先暂存,保存时经 revision 栅栏保护的 `settings.mutate` 写入 web 卡片所写的同一份 advisor entry config,并 live 重应用、无需重启。`systemPrompt` **不是** TUI 字段(TUI text 控件为单行;多行 prompt 会被截断)——请经 web 卡片或 profile 补丁层编辑。该分节要求 dsh-tui ≥ v0.8.0(随 v0.8.0+ 组合包的 `dsh-tui-settings-sections` 行提供);旧版 dsh-tui 会干净地 no-op,profile 补丁层仍是编辑路径。`/advisor config` 仍是只读回读,seam 挂载时其编辑提示指向 `/settings` 屏幕。保存行为与 web 卡片不同:TUI seam 没有跨字段校验,一次保存可能把空 `provider`/`model` 写入——显式模型门禁会在运行时把它解析为 disabled-with-reason(可见于 `/advisor status` 与 `/advisor config`);web 卡片则会直接阻止这样的保存。完整参考 → [docs/configuration.md](docs/configuration.md)。
|
|
54
55
|
|
|
55
56
|

|
|
56
57
|
|
|
@@ -60,7 +61,7 @@ advisor 默认关闭。启用后,`provider` 与 `model` 为**必填**:`enabl
|
|
|
60
61
|
dsh --profile web --dump-config # 显示带 advisor 配置行的 "# == dsh-advisor" 层
|
|
61
62
|
```
|
|
62
63
|
|
|
63
|
-
|
|
64
|
+
安装并在插件页打开组件行的启用开关(row 开关即总开关)后,在会话内用 `/advisor` 指令控制它(组合了 command registry 时可用):
|
|
64
65
|
|
|
65
66
|
```
|
|
66
67
|
/advisor toggle the advisor for this session
|
|
@@ -72,7 +73,7 @@ dsh --profile web --dump-config # 显示带 advisor 配置行的 "# == dsh-adv
|
|
|
72
73
|
/advisor model reset drop the session pin and re-inherit the global defaults
|
|
73
74
|
```
|
|
74
75
|
|
|
75
|
-
`/advisor on|off|toggle` 是会话级且临时的:它们翻转的是按会话的 override,从不修改持久化配置。启用一个 config 缺少 `provider`/`model` 的会话不会发起模型调用——`/advisor status`(以及 `/advisor on` 的回复)会显示门禁原因:advisor
|
|
76
|
+
`/advisor on|off|toggle` 是会话级且临时的:它们翻转的是按会话的 override,从不修改持久化配置。启用一个 config 缺少 `provider`/`model` 的会话不会发起模型调用——`/advisor status`(以及 `/advisor on` 的回复)会显示门禁原因:advisor 只有在两者均已配置时才运行。`/advisor on` 也是手动恢复路径:被 quota/rate-limit 暂停的会话 advisor(`quota_exhausted`——无自动恢复定时器)会在原地恢复;被终止的 advisor(永久性模型错误,如凭据无效)会为该会话全新重建。
|
|
76
77
|
|
|
77
78
|
`/advisor model set` 只为**发起调用的会话**钉住一个评审模型——一个内存中的原子 `provider + model` 对,生存期为活跃会话(dispose、owner 卸载、冷恢复或重启时清除;fork 的新会话继承全局默认值)。它叠加在持久化的全局默认值之上而不改写它们:全局配置还没有 pair 时,完整的会话对即可生效;全局配置非法时所有会话照旧被阻挡;两级之间的半个 pair 永不拼接;set/reset 从不触碰启用开关。提交前会经 LLM 服务解析校验该对(60 秒上界、可取消、无自动重试);失败时先前选择保持不变。`/advisor config` 始终是**全局默认值**的回读,不是会话状态。
|
|
78
79
|
|
|
@@ -89,7 +90,7 @@ dsh --profile web --dump-config # 显示带 advisor 配置行的 "# == dsh-adv
|
|
|
89
90
|
[advisor:concern] extract the helper into a module and unit-test it
|
|
90
91
|
```
|
|
91
92
|
|
|
92
|
-
-
|
|
93
|
+
- **显式模型门禁**:缺少 `provider` + `model` 时绝不发起模型调用——状态报告 disabled-with-reason。门禁在会话解析**之后**作用于*有效*路由:完整的会话级覆盖对可为其会话满足门禁;非法的全局配置不可被绕过。未知配置键会被拒绝——包括已移除的 `enabled` 键(插件行开关即总开关)。
|
|
93
94
|
- **零工具的最小启动**:评审者只是一个独立的模型调用——无 advisor tools,除了 advisory 消息之外它无法对会话做任何事。
|
|
94
95
|
- **不卡主循环的失败策略**:失败或 quota 耗尽的 advisor 只会丢弃自己有界的 backlog——永远不会卡住或污染主循环。
|
|
95
96
|
- **会话级控制**:`/advisor on|off|status|config|model` 按会话工作;开关与会话级模型钉住都是临时的 override,从不修改持久化配置——`/advisor config` 始终报告全局默认值。在 web 端,会话头部的 **Advisor 动作**经由专属会话端点驱动同一个会话级钉住(见 [Verify](#verify))。
|
package/icon.svg
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
<svg width="36" height="36" viewBox="0 0 36 36" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
2
|
+
<defs>
|
|
3
|
+
<linearGradient id="dsh-advisor-icon-a" x1="14.9894" y1="9.0697" x2="14.9894" y2="21.3063" gradientUnits="userSpaceOnUse">
|
|
4
|
+
<stop stop-color="#69B9FF"/>
|
|
5
|
+
<stop offset="1" stop-color="#324DE2"/>
|
|
6
|
+
</linearGradient>
|
|
7
|
+
<linearGradient id="dsh-advisor-icon-b" x1="21.1075" y1="15.1877" x2="21.1075" y2="27.4243" gradientUnits="userSpaceOnUse">
|
|
8
|
+
<stop stop-color="#45E7A4"/>
|
|
9
|
+
<stop offset="1" stop-color="#05909D"/>
|
|
10
|
+
</linearGradient>
|
|
11
|
+
</defs>
|
|
12
|
+
<rect x="8.87109" y="9.0697" width="12.2365" height="12.2365" rx="2" fill="url(#dsh-advisor-icon-a)" fill-opacity="0.8"/>
|
|
13
|
+
<path d="M18.2 27.4243L18.2 31.6L23.4 27.4243Z" fill="url(#dsh-advisor-icon-b)" fill-opacity="0.8"/>
|
|
14
|
+
<rect x="14.9893" y="15.1877" width="12.2365" height="12.2365" rx="2" fill="url(#dsh-advisor-icon-b)" fill-opacity="0.8"/>
|
|
15
|
+
<circle cx="18.39" cy="21.31" r="1.15" fill="#F9FAFB" fill-opacity="0.95"/>
|
|
16
|
+
<circle cx="21.11" cy="21.31" r="1.15" fill="#F9FAFB" fill-opacity="0.95"/>
|
|
17
|
+
<circle cx="23.83" cy="21.31" r="1.15" fill="#F9FAFB" fill-opacity="0.95"/>
|
|
18
|
+
</svg>
|
|
@@ -1,40 +1,44 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Advisor settings card (plan dsh-advisor-plugin-config-card-ux, task 1
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
* the
|
|
6
|
-
* reads/writes the advisor config through
|
|
7
|
-
* `/api/advisor/set` (KD-G3) — while the
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
* `
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
* card-local state
|
|
22
|
-
*
|
|
23
|
-
*
|
|
2
|
+
* Advisor settings card (plan dsh-advisor-plugin-config-card-ux, task 1;
|
|
3
|
+
* flat rebuild 2026-09-26 — plan dsh-advisor-web-config-flat-n10): the card
|
|
4
|
+
* registered into the Plugins page's `plugins.bundle.config` keyed slot (key
|
|
5
|
+
* `dsh-advisor` — the bundle's package name the page dispatches). It keeps
|
|
6
|
+
* the n5 gateway channel — the store reads/writes the advisor config through
|
|
7
|
+
* `/api/advisor/get` + `/api/advisor/set` (KD-G3) — while the layout is the
|
|
8
|
+
* official settings-page language: NO collapsible box. The page already
|
|
9
|
+
* renders the plugin title/description above the card (the `locale/*.json`
|
|
10
|
+
* meta files the host resolves per UI language), so the fields tile directly
|
|
11
|
+
* beneath it: provider select, model select (ALWAYS rendered — there is no
|
|
12
|
+
* enable checkbox to gate them; the config-level `enabled` switch was removed
|
|
13
|
+
* and the plugin-row toggle is the master switch), system-prompt textarea,
|
|
14
|
+
* and the paired `immuneTurns`/`maxDeltaMessages` numbers; then the footer
|
|
15
|
+
* with the failed message + Discard/Save carrying the upstream disabled
|
|
16
|
+
* semantics — save = `!dirty || invalid || saving`, discard = `!dirty ||
|
|
17
|
+
* saving` (KD-U1, Global Constraints). Save additionally carries `!writable`
|
|
18
|
+
* and the store refuses writes outright in read-only environments (W-1, qc2
|
|
19
|
+
* fix wave) — see the disabled-term comment in the ready branch. The former
|
|
20
|
+
* collapsible chrome (header button, rotating chevron, dirty "unsaved" pill,
|
|
21
|
+
* card-local disclosure state) is gone with the switch it mirrored: nothing
|
|
22
|
+
* is hidden, so nothing needs disclosure state, and the readOnly / saved /
|
|
23
|
+
* error / namespaceUnavailable notices are flat and always-on (the derived-
|
|
24
|
+
* open semantics they used to ride — AC-1/AC-3 — have no surface left).
|
|
24
25
|
*
|
|
25
|
-
* The
|
|
26
|
-
*
|
|
27
|
-
*
|
|
28
|
-
*
|
|
29
|
-
* `
|
|
30
|
-
*
|
|
31
|
-
*
|
|
32
|
-
*
|
|
33
|
-
*
|
|
26
|
+
* The form behavior is unchanged from the card-form plan: provider/model
|
|
27
|
+
* selects limited to the system-configured providers and their models
|
|
28
|
+
* (KD-S2), the required-pair gate (KD-S4, also enforced in the store), and
|
|
29
|
+
* Save writing the advisor config through the gateway channel (store →
|
|
30
|
+
* `connection.rpc.call('/api', 'advisor/set', { patch })`). Discard rewinds
|
|
31
|
+
* the draft to the last-known host config (client-side only — no gateway
|
|
32
|
+
* write). The textarea's placeholder IS the built-in reviewer prompt
|
|
33
|
+
* (`DEFAULT_ADVISOR_SYSTEM_PROMPT` — same-package import, a pure string
|
|
34
|
+
* constant the bundler inlines; SSOT stays `src/prompts.ts`), so the field
|
|
35
|
+
* shows exactly what an empty prompt inherits; the "leave empty" hint rides
|
|
36
|
+
* below it.
|
|
34
37
|
*
|
|
35
|
-
* Presentation follows
|
|
36
|
-
* `advisor-card.module.css`
|
|
37
|
-
*
|
|
38
|
+
* Presentation follows the official settings-form values via
|
|
39
|
+
* `advisor-card.module.css` (12px field padding, 0.5px hairline separators,
|
|
40
|
+
* 34px inputs, dark solid Save) — every color resolves through a
|
|
41
|
+
* `--dsw-alias-*` token so the card adapts to the light/dark theme.
|
|
38
42
|
*
|
|
39
43
|
* A stored provider/model that is no longer among the current options
|
|
40
44
|
* surfaces warning copy (`staleProvider`/`staleModel`) instead of blocking
|
|
@@ -43,17 +47,15 @@
|
|
|
43
47
|
* Clearing a number input leaves the field empty; the store then omits that
|
|
44
48
|
* key from the apply patch (the stored value stays unchanged).
|
|
45
49
|
*
|
|
46
|
-
* Degraded/error
|
|
47
|
-
*
|
|
48
|
-
*
|
|
49
|
-
*
|
|
50
|
-
*
|
|
51
|
-
*
|
|
52
|
-
*
|
|
53
|
-
*
|
|
54
|
-
*
|
|
55
|
-
* latched `degraded` (qc1 S-2 fix wave), so the refresh window never
|
|
56
|
-
* collapses the AC-3 notice.
|
|
50
|
+
* Degraded/error states keep the flat layout (KD-U3): the config-channel
|
|
51
|
+
* notice or the load error + retry render as always-on blocks — a card that
|
|
52
|
+
* cannot render its form shows that state on every render, including through
|
|
53
|
+
* a background refresh of a degraded card (the store's latched `degraded`
|
|
54
|
+
* keeps the notice up while `status === 'loading'`, qc1 S-2 fix wave).
|
|
55
|
+
* A healthy card holds its form through the same refresh window (fields
|
|
56
|
+
* disabled — the store keeps the last settled providers/draft/applyState
|
|
57
|
+
* until the ready update), so a post-apply reload never unmounts the form or
|
|
58
|
+
* blinks the saved notice away.
|
|
57
59
|
* When the last load could not reach the `advisor.get` gateway endpoint (the
|
|
58
60
|
* gateway channel is down or not ready on this host), the form is replaced
|
|
59
61
|
* by the `namespaceUnavailable` notice and Save is never offered, so the
|
|
@@ -63,7 +65,7 @@
|
|
|
63
65
|
* clear "settings service is unavailable" error; the notice covers channel
|
|
64
66
|
* unreachability, not the no-settings-service case.
|
|
65
67
|
*/
|
|
66
|
-
import {
|
|
68
|
+
import type { ReactNode } from 'react';
|
|
67
69
|
import type { InjectFace, PropsLocale, PropsRuntime } from '@deepseek-ai/dsh-client-ui-slots';
|
|
68
70
|
import type { SnapshotStore } from '@deepseek-ai/dsh-client-store';
|
|
69
71
|
import type { AdvisorSettingsState, AdvisorSettingsStore } from './advisor-store.ts';
|
|
@@ -81,18 +83,15 @@ export interface AdvisorCardInjected {
|
|
|
81
83
|
/**
|
|
82
84
|
* Props the renderer binds for the card: the `plugins.bundle.config` runtime
|
|
83
85
|
* share (the owner passes the `view` the page asks for — this seat is
|
|
84
|
-
* `page`-only,
|
|
85
|
-
*
|
|
86
|
-
*
|
|
87
|
-
* face.
|
|
86
|
+
* `page`-only), the framework-synthesized `t` seat for the declared
|
|
87
|
+
* `settings.advisor` namespace (KD-1 — `t` is NOT part of the inject face),
|
|
88
|
+
* and the registrant's business face.
|
|
88
89
|
*/
|
|
89
90
|
export type AdvisorCardProps = PropsRuntime<'plugins.bundle.config'> & PropsLocale<'settings.advisor'> & InjectFace<AdvisorCardInjected>;
|
|
90
91
|
/**
|
|
91
92
|
* Render the advisor card inside its bundle's configuration section on the
|
|
92
|
-
* Plugins page
|
|
93
|
-
*
|
|
94
|
-
* rotating chevron, aria) and, when open, a divided body holding the readOnly
|
|
95
|
-
* notice, the form, and the footer (failed message + Discard/Save).
|
|
93
|
+
* Plugins page — flat: the notices, the form, and the footer tile directly
|
|
94
|
+
* under the page's plugin title/description, with no chrome of our own.
|
|
96
95
|
* @param props - slot-delivered injected dependencies and the synthesized t seat.
|
|
97
96
|
* @returns the card.
|
|
98
97
|
*/
|
|
@@ -82,7 +82,12 @@ export interface AdvisorStoreRemote {
|
|
|
82
82
|
* simply missing from the JSON), so every optional key reads as undefined.
|
|
83
83
|
*/
|
|
84
84
|
export interface AdvisorConfigView {
|
|
85
|
-
/**
|
|
85
|
+
/**
|
|
86
|
+
* Read-only wire fact — the post-gate switch (false while the gate blocks).
|
|
87
|
+
* NOT a draft field: there is no config-level `enabled` key (2026-09-26;
|
|
88
|
+
* the plugin-row toggle is the switch), so the draft cannot write it and
|
|
89
|
+
* the card renders it nowhere.
|
|
90
|
+
*/
|
|
86
91
|
enabled: boolean;
|
|
87
92
|
/** Provider route; absent when unset. */
|
|
88
93
|
provider?: string;
|
|
@@ -124,13 +129,11 @@ export type ModelsEmptyReason =
|
|
|
124
129
|
| 'catalog-empty'
|
|
125
130
|
/** No profile models; the catalog has no group for this provider. */
|
|
126
131
|
| 'unavailable';
|
|
127
|
-
/** The user-layer draft the form edits (
|
|
132
|
+
/** The user-layer draft the form edits (provider/model/systemPrompt/immuneTurns/maxDeltaMessages). */
|
|
128
133
|
export interface AdvisorDraft {
|
|
129
|
-
/**
|
|
130
|
-
enabled: boolean;
|
|
131
|
-
/** Provider route; required (non-empty) when enabled. */
|
|
134
|
+
/** Provider route; required (non-empty). */
|
|
132
135
|
provider?: string;
|
|
133
|
-
/** Model id; required (non-empty)
|
|
136
|
+
/** Model id; required (non-empty). */
|
|
134
137
|
model?: string;
|
|
135
138
|
/** Optional system prompt override; '' = built-in reviewer prompt. */
|
|
136
139
|
systemPrompt: string;
|
|
@@ -185,16 +188,16 @@ export interface AdvisorSettingsState {
|
|
|
185
188
|
* resolved `config === undefined` (qc1 S-2 fix wave). The snapshot cannot
|
|
186
189
|
* tell a "refresh of a degraded card" from a "first mount not yet settled"
|
|
187
190
|
* while `status === 'loading'` (both read loading + advisorPresent=false),
|
|
188
|
-
* so the card derives its degraded
|
|
189
|
-
*
|
|
191
|
+
* so the card derives its degraded notice from this latch during loading —
|
|
192
|
+
* keeping the config-channel notice visible through a background refresh
|
|
190
193
|
* of a degraded card. Set ONLY in the ready update (the load-error path
|
|
191
|
-
* leaves it alone — the error state has its own always-
|
|
194
|
+
* leaves it alone — the error state has its own always-on branch).
|
|
192
195
|
*/
|
|
193
196
|
degraded: boolean;
|
|
194
197
|
/**
|
|
195
|
-
* Whether the draft holds edits a save would write — the
|
|
196
|
-
*
|
|
197
|
-
*
|
|
198
|
+
* Whether the draft holds edits a save would write — the save/discard
|
|
199
|
+
* disabled semantics (upstream CardShell.dirty). Derived as
|
|
200
|
+
* `patchFor(draft)` non-empty (KD-U2, plan
|
|
198
201
|
* dsh-advisor-plugin-config-card-ux task 2), recomputed on load (seed
|
|
199
202
|
* settled, real config resolved only), every draft mutation, discard and a
|
|
200
203
|
* successful apply — always inside the same `store.update` callback that
|
|
@@ -273,8 +276,6 @@ export declare class AdvisorSettingsStore {
|
|
|
273
276
|
* the reload happened mid-fetch) and caches nothing.
|
|
274
277
|
*/
|
|
275
278
|
private fetchCatalog;
|
|
276
|
-
/** Set the enabled switch (gate fields become required while on). */
|
|
277
|
-
setEnabled(enabled: boolean): void;
|
|
278
279
|
/** Set or clear the provider ('' clears); switches invalidate the chosen model. */
|
|
279
280
|
setProvider(provider: string): void;
|
|
280
281
|
/** Set or clear the model ('' clears). */
|
package/lib/client/locales.d.ts
CHANGED
|
@@ -2,17 +2,18 @@
|
|
|
2
2
|
* Copy dictionaries for the Advisor settings card (namespace
|
|
3
3
|
* `settings.advisor`). The English dictionary is the key-set source of truth
|
|
4
4
|
* for the pair; the Chinese dictionary mirrors it exactly.
|
|
5
|
+
*
|
|
6
|
+
* Flat rebuild (2026-09-26): the page title/intro moved to the plugin meta
|
|
7
|
+
* locale files (`locale/en.json` / `locale/zh.json` — the host plugin manager
|
|
8
|
+
* renders them), and the collapsible chrome copy (`collapse`/`expand`/
|
|
9
|
+
* `unsaved`) and the `enabled` checkbox label died with the config-level
|
|
10
|
+
* switch. `providerRequired`/`modelRequired` are unconditional now — there is
|
|
11
|
+
* no enable checkbox to make the pair gate conditional.
|
|
5
12
|
*/
|
|
6
13
|
/** English strings (the key-set source of truth for this pair). */
|
|
7
14
|
export declare const en: {
|
|
8
|
-
title: string;
|
|
9
|
-
intro: string;
|
|
10
|
-
collapse: string;
|
|
11
|
-
expand: string;
|
|
12
|
-
unsaved: string;
|
|
13
15
|
loadFailed: string;
|
|
14
16
|
retry: string;
|
|
15
|
-
enabled: string;
|
|
16
17
|
provider: string;
|
|
17
18
|
providerPlaceholder: string;
|
|
18
19
|
providerRequired: string;
|
|
@@ -24,7 +25,7 @@ export declare const en: {
|
|
|
24
25
|
staleProvider: string;
|
|
25
26
|
staleModel: string;
|
|
26
27
|
systemPrompt: string;
|
|
27
|
-
|
|
28
|
+
systemPromptHint: string;
|
|
28
29
|
immuneTurns: string;
|
|
29
30
|
maxDeltaMessages: string;
|
|
30
31
|
save: string;
|