dsh-better-dsh 0.10.0 → 0.11.0

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 CHANGED
@@ -55,17 +55,17 @@
55
55
 
56
56
  ```sh
57
57
  # npm
58
- dsh plugin --profile <profile> add dsh-better-dsh@0.10.0
58
+ dsh plugin --profile <profile> add dsh-better-dsh@0.11.0
59
59
 
60
60
  # 或从 GitHub tag 安装
61
- dsh plugin --profile <profile> add github:omdsh-dev/dsh-better-dsh#v0.10.0
61
+ dsh plugin --profile <profile> add github:omdsh-dev/dsh-better-dsh#v0.11.0
62
62
  ```
63
63
 
64
64
  > 安装、升级或换包后必须**重启对应 profile**;只刷新网页不够。
65
65
  >
66
66
  > 不要同时显式添加 Better DSH 和独立插件 bundle:行实例仍只有一个,但 DSH 0.2.2-rc.1 会把同一 id 的配置写入拒绝为只读。只保留一个显式入口。
67
67
 
68
- 本轮版本:**Better DSH `0.10.0`**,搭配 goal `0.4.1`、subagent `0.5.0`、compact `0.3.1`、ask-user `0.3.1`、ptc `0.2.0`。
68
+ 本轮版本:**Better DSH `0.11.0`**,搭配 goal `0.4.2`、subagent `0.5.1`、compact `0.4.0`、ask-user `0.3.2`、ptc `0.2.0`。
69
69
 
70
70
  ## 架构
71
71
 
@@ -120,7 +120,7 @@ Better DSH 的 bundle patch 直接声明这些行;DSH 不会自动应用传递
120
120
  | 技能 | 用途 |
121
121
  |---|---|
122
122
  | `/brainstorming` | 把大型需求设计为获批的主 Spec 与子 Spec |
123
- | `/exec` | 按依赖分波:worktree → 并行子代理实现 → 审查 → 验证与合并 |
123
+ | `/exec` | 先选自动 / 仅质量档 / 仅快速档;按依赖分波并行实现,子任务按需 CR,验证与合并后保留最终整体 CR |
124
124
  | `/dev` | 实现与审查节点的 prompt、报告结构与失败契约 |
125
125
  | `/main-agent-driven-development` | 实现一个边界明确的单个任务 |
126
126
  | `/tdd` | 测试先行、红绿循环、测试边界与反模式 |
@@ -128,6 +128,8 @@ Better DSH 的 bundle patch 直接声明这些行;DSH 不会自动应用传递
128
128
  | `/code-review` | 并行检查仓库标准与原始需求,并排报告 |
129
129
  | `/handoff` | 把当前上下文整理为交接文档;仅由用户手动触发 |
130
130
 
131
+ `/exec` 的选档约束实现与修复,所有 CR 始终使用质量档;超时未选默认自动,普通任务用快速档,特别难或实际遇阻时可升质量档。等待子代理每次使用至少 30 分钟的超时窗口,提前完成即返回,不因等待超时催促或换人。所有审查与复审节点仅由顶层主 agent 派发;子 agent(包括 reviewer)直接完成分配的工作并向主 agent 返回结果或审查需求,不再派发审查节点。
132
+
131
133
  技能需要在所选预设中挂载 DSH 的技能工具;两套工程预设已挂载。
132
134
  </details>
133
135
 
@@ -181,10 +183,10 @@ Better DSH 包详情里的「集成设置」按 Core、Subagents、Compaction、
181
183
  # 旧入口
182
184
  dsh plugin --profile <profile> remove @menghuan1918/dsh-apollo
183
185
  # 新入口
184
- dsh plugin --profile <profile> add dsh-better-dsh@0.10.0
186
+ dsh plugin --profile <profile> add dsh-better-dsh@0.11.0
185
187
  # subagent 独立安装的用户
186
188
  dsh plugin --profile <profile> remove @menghuan1918/dsh-better-subagent
187
- dsh plugin --profile <profile> add @oh-my-dsh/dsh-better-subagent@0.5.0
189
+ dsh plugin --profile <profile> add @oh-my-dsh/dsh-better-subagent@0.5.1
188
190
  ```
189
191
 
190
192
  <details>
@@ -207,10 +209,10 @@ dsh plugin --profile <profile> add @oh-my-dsh/dsh-better-subagent@0.5.0
207
209
  五个插件都可以单独安装;独立安装和 Better DSH 组合使用的是**同一组稳定行**。
208
210
 
209
211
  ```sh
210
- dsh plugin --profile <profile> add dsh-better-goal@0.4.1
211
- dsh plugin --profile <profile> add @oh-my-dsh/dsh-better-subagent@0.5.0
212
- dsh plugin --profile <profile> add dsh-better-compact@0.3.1
213
- dsh plugin --profile <profile> add dsh-better-ask-user@0.3.1 dsh-better-ptc@0.2.0
212
+ dsh plugin --profile <profile> add dsh-better-goal@0.4.2
213
+ dsh plugin --profile <profile> add @oh-my-dsh/dsh-better-subagent@0.5.1
214
+ dsh plugin --profile <profile> add dsh-better-compact@0.4.0
215
+ dsh plugin --profile <profile> add dsh-better-ask-user@0.3.2 dsh-better-ptc@0.2.0
214
216
  ```
215
217
 
216
218
  <details>
@@ -243,11 +245,11 @@ dsh plugin --profile <profile> add dsh-better-ask-user@0.3.1 dsh-better-ptc@0.2.
243
245
  **发布顺序**:先发布独立包,再发布 Better DSH(精确依赖必须已存在):
244
246
 
245
247
  1. `dsh-better-ptc@0.2.0`(不变)
246
- 2. `dsh-better-ask-user@0.3.1`
247
- 3. `dsh-better-compact@0.3.1`
248
- 4. `dsh-better-goal@0.4.1`
249
- 5. `@oh-my-dsh/dsh-better-subagent@0.5.0`
250
- 6. `dsh-better-dsh@0.10.0`
248
+ 2. `dsh-better-ask-user@0.3.2`
249
+ 3. `dsh-better-compact@0.4.0`
250
+ 4. `dsh-better-goal@0.4.2`
251
+ 5. `@oh-my-dsh/dsh-better-subagent@0.5.1`
252
+ 6. `dsh-better-dsh@0.11.0`
251
253
 
252
254
  各仓库使用 npm trusted publishing(OIDC);创建对应 GitHub Release 会发布 tag 指向的版本。旧包 `@menghuan1918/dsh-apollo` 与 `@menghuan1918/dsh-better-subagent` 已标记 deprecate,仅作为历史入口保留。
253
255
  </details>
@@ -2,7 +2,7 @@
2
2
 
3
3
  面向维护者、集成者和需要排查装配问题的用户。用户安装与配置请看 [README](../README.md);本文保留 DSH 插件的实现细节、旧配置迁移、组合安装边界与验证方法。
4
4
 
5
- 当前实现版本:`0.10.0`;npm 包名是 `dsh-better-dsh`。纯 ESM,无构建步骤;宿主浏览器半边是直接加载的闭包工厂。旧 `Apollo` 名称只保留在迁移、历史兼容和旧包 deprecate 说明里。
5
+ 当前实现版本:`0.11.0`;npm 包名是 `dsh-better-dsh`。纯 ESM,无构建步骤;宿主浏览器半边是直接加载的闭包工厂。旧 `Apollo` 名称只保留在迁移、历史兼容和旧包 deprecate 说明里。
6
6
 
7
7
  ## 目录
8
8
 
@@ -33,10 +33,10 @@
33
33
 
34
34
  | 依赖 | 版本 | 所有权 |
35
35
  |---|---|---|
36
- | `dsh-better-goal` | `0.4.1` | 目标域(`questionTimeoutSeconds` 已弃用、仅保留读取) |
37
- | `@oh-my-dsh/dsh-better-subagent` | `0.5.0` | 子代理 CLI/等待/child guard/分档/设置页;注册 `wait_subagent` PTC 豁免 |
38
- | `dsh-better-compact` | `0.3.1` | 压缩 companion + engine + 设置页/诊断 |
39
- | `dsh-better-ask-user` | `0.3.1` | 官方 `ask_user_question` 入参/返回 + 插件超时等待 + 历史预览行;注册 PTC 豁免;旧 goal 等待迁移 |
36
+ | `dsh-better-goal` | `0.4.2` | 目标域(`questionTimeoutSeconds` 已弃用、仅保留读取) |
37
+ | `@oh-my-dsh/dsh-better-subagent` | `0.5.1` | 子代理 CLI/等待/child guard/分档/设置页;注册 `wait_subagent` PTC 豁免 |
38
+ | `dsh-better-compact` | `0.4.0` | 压缩 companion + engine + 设置页/诊断 |
39
+ | `dsh-better-ask-user` | `0.3.2` | 官方 `ask_user_question` 入参/返回 + 插件超时等待 + 历史预览行;注册 PTC 豁免;旧 goal 等待迁移 |
40
40
  | `dsh-better-ptc` | `0.2.0` | 单例 PTC deadline 豁免服务 |
41
41
  | `@deepseek-ai/schemastery` | `~3.19.0` | Better DSH 行 Config |
42
42
  | `react` | peer | 宿主提供 |
@@ -319,7 +319,7 @@ DSH_PACKAGE_ROOT="/…/node_modules/@deepseek-ai/dsh" npm run prompts
319
319
  ### npm 安装
320
320
 
321
321
  ```sh
322
- dsh plugin --profile <profile> add dsh-better-dsh@0.10.0
322
+ dsh plugin --profile <profile> add dsh-better-dsh@0.10.1
323
323
  ```
324
324
 
325
325
  包发布后即可用此命令安装,并带入五个精确依赖、应用三份 bundle patch。安装后需要重启对应 profile 的 DSH 进程。本轮版本与精确依赖见上述包清单;发布后需重新验证 registry 干净安装。
@@ -381,7 +381,7 @@ dsh plugin --profile <profile> remove @menghuan1918/dsh-apollo # 旧包;新
381
381
 
382
382
  1. 先发布 `dsh-better-ptc@0.2.0`、`dsh-better-ask-user@0.3.1`、`@oh-my-dsh/dsh-better-subagent@0.5.0`、`dsh-better-goal@0.4.1`、`dsh-better-compact@0.3.1`(各自仓库的 Release);
383
383
  2. 在官方 registry(`https://registry.npmjs.org/`)确认五个版本可取得、可安装;
384
- 3. 再把 Better DSH 的精确依赖指向已发布版本,推已验证的发布提交及 tag 并发布 Better DSH Release(本轮为 `v0.10.0`);
384
+ 3. 再把 Better DSH 的精确依赖指向已发布版本,推已验证的发布提交及 tag 并发布 Better DSH Release(本轮为 `v0.10.1`);
385
385
  4. 子包版本可取得前,不要把指向它们的精确依赖推到 Apollo main,否则 `npm install` / GitHub 源码安装会 404。
386
386
 
387
387
  ## 测试与冒烟
package/docs/UI-KIT.md CHANGED
@@ -22,10 +22,10 @@ component rules; do not hard-code surfaces.
22
22
  | surface sunken | `color-mix(in srgb, ink-1 4%, canvas)` | same rule |
23
23
  | ink 1 / 2 / 3 | `--dsw-alias-label-primary/secondary/tertiary` | host dark labels |
24
24
  | line 1 / 2 / 3 | `--dsw-alias-border-l1/l2/l3` | host dark borders |
25
- | accent | `#3388BB` | `#4eb0e8` |
26
- | accent solid | `#20709e` | `#4eb0e8` |
27
- | accent foreground | `#fff` | `#0e1014` |
28
- | accent text | `#14587f` | `#6fc0ee` |
25
+ | accent / focus | `--dsw-alias-state-business-primary` | host dark business color |
26
+ | primary action / switch fill | `--dsw-alias-button-primary-fill` | host dark button fill |
27
+ | primary action foreground | `--dsw-alias-label-primary-foreground` | host dark foreground |
28
+ | accent text | `color-mix(in srgb, accent 70%, ink-1)` | same rule |
29
29
  | accent soft | `color-mix(in srgb, accent 10%, transparent)` | 14% |
30
30
  | success / danger / warn | `--dsw-alias-state-*` | host dark state tokens |
31
31
  | radius sm / md / lg / xl | `6 / 8 / 10 / 12px` | same |
@@ -55,40 +55,85 @@ Rules:
55
55
  - Rail 200px: 36px items, 8px radius. Active = accent-soft background +
56
56
  accent-text + 1px line; no left decoration bar.
57
57
  - Content padding 24px 32px; each page is a max-920px column, centered.
58
- - Narrow `<= 640px`: rail becomes a horizontal scrolling tab strip; content
59
- padding 16px; dialog full-bleed.
58
+ - Narrow `<= 800px`: rail becomes a horizontal scrolling tab strip; content
59
+ padding 16px. At `<= 640px` the dialog fills the viewport with no outer
60
+ margin or corner radius.
60
61
 
61
62
  ### Settings page
62
63
 
63
64
  - Content column `max-width: 920px; margin: 0 auto`.
64
65
  - Page title 20/28/500, letter-spacing -0.01em.
65
- - Section title 12/500, ink-3, 1px bottom line; section spacing 24px.
66
- - Setting row: label 13/500; one consequence line 12/ink-3 max two lines;
67
- control right-aligned. Row padding 10–12px, 1px line-1 between rows.
66
+ - Section label 12/500, ink-3, no rule; section spacing 24px.
67
+ - Setting row: label 13/500; control right-aligned. Add one neutral consequence
68
+ line (12/ink-3) only when the label cannot explain the choice. Row padding
69
+ 10–12px with a hover surface; no per-row divider. Explain model recommendations
70
+ and their scope where they are edited; do not hide essential effects in
71
+ screen-reader-only text.
72
+ - Dividers are reserved for group boundaries (footer, cards, inputs,
73
+ selectable rows). A form of anonymous horizontal rules between every row is a
74
+ bug, not a style.
75
+ - Everyday settings contain no compatibility notes, migration history, package
76
+ ownership or implementation terminology. Keep actionable loading, read-only,
77
+ conflict and reload feedback next to the affected controls.
68
78
  - Use sections, not card grids. Cards are reserved for selectable strategy
69
79
  cards, read-only budget panels, conversation cards and overlays.
70
- - Save footer: sticky, 1px top line, canvas background, 12px padding; only
80
+ - Save footer: normal flow at the end, 1px top line, canvas background, 12px padding; only
71
81
  visible while dirty, busy or showing a notice. Status left, actions right.
72
82
 
83
+ ### Editable compaction process
84
+
85
+ - Use one bold visualization as the primary surface: a capacity bar with drag
86
+ handles, four strategy cards (native, goal-aware, handoff, custom), a compact
87
+ generation row, and a custom-prompt editor. Edit the existing configuration
88
+ draft through these controls; saving and discarding use the same form.
89
+ - The capacity bar supports pointer dragging and keyboard adjustment
90
+ (`role=slider`), with one synchronized numeric field per value. Do not repeat
91
+ the bar as full-width range sliders. If the model window is unknown, show a
92
+ proportional schematic and say so; never invent token totals.
93
+ - The four strategy cards are compact choices: title, tag and one-line effect,
94
+ no repeated mini-diagrams. On wide screens they sit in a two-column
95
+ **选择 | 示意图** layout: choices on the left, one shared SVG process drawing on
96
+ the right, capped at 400px so it fits beside the choices. It uses labeled
97
+ nodes and arrows for context, trigger, summary and continuation; it stacks
98
+ below the choices on narrow screens.
99
+ Selected state uses accent border + accent-soft + check; keyboard arrows,
100
+ Home/End and Space/Enter work.
101
+ - Custom mode is the fourth strategy: its expanded prompt is the only
102
+ instruction sent to the summary model. It appends no built-in structure,
103
+ state block or safety rules; the ten `{{variable}}` chips are the only
104
+ context injection. Entering custom mode with an empty prompt pre-fills the
105
+ **goal-mode default instruction** as an editable template; never overwrite an
106
+ existing prompt. Clearing the pre-filled text blocks saving; output must be
107
+ non-empty. Built-in modes never use the custom prompt.
108
+ - Capacity, reserved output and measured usage are observations. Unknown values
109
+ stay unknown; do not present active-engine estimates as a prediction of
110
+ unsaved settings.
111
+ - Keep only genuinely rare advanced policies and long read-only diagnostics
112
+ expandable. Behavior and effect settings are always visible.
113
+
73
114
  ### Narrow `<= 640px`
74
115
 
75
- - Rows stack: label above, control full width, touch targets 44px.
76
- - Tables become cards; diagrams shrink or become 3–4 value rows.
116
+ - Field rows stack: label above, control full width, touch targets 44px.
117
+ - Binary switches stay beside their labels, with a 44px hit area. Help buttons
118
+ are 44px, with descriptions contained inside the content column.
119
+ - Tables become cards. Read-only diagrams may become value rows. The editable
120
+ compaction process reflows into connected vertical stages and keeps its controls
121
+ available; never shrink the entire diagram into unreadable labels.
77
122
  - No horizontal scrolling at 390px.
78
123
 
79
124
  ## 3. Controls
80
125
 
81
126
  | Control | Contract |
82
127
  | --- | --- |
83
- | Button | 32px; radius 8; 13/500; primary accent-solid, secondary 1px line-2, ghost transparent; hover line-1 fill; focus 2px accent ring offset 2; disabled .4; loading spinner 12px |
128
+ | Button | 32px; radius 8; 13/500; primary host button fill/foreground, secondary 1px line-2, ghost transparent; hover line-1 fill; focus 2px accent ring offset 2; disabled .4; loading spinner 12px |
84
129
  | Text input / textarea | 32px; radius 8; 1px line-2; raised background; focus accent border + ring; number inputs tabular, no native spinners |
85
130
  | Combobox | trigger shaped like text input; menu overlay surface, 1px line-3, radius 10, 4px padding, shadow; option 30px, radius 6, selected accent-soft + accent-text + check; ArrowUp/Down, Home/End, Enter/Space, Escape, typeahead; flip above when short; no native select/datalist |
86
131
  | Segmented | container 32px, sunken, 1px line-2, radius 8; item 28px radius 6; selected raised + 1px line + accent-text 500; Arrow keys/Home/End; used for tabs and exclusive modes |
87
- | Switch | 34×20 track, 2px padding, 14px thumb; on accent-solid, off sunken + line-3; focus ring; disabled .4 |
132
+ | Switch | 34×20 track, 2px padding, 14px thumb; on host button fill/foreground, off sunken + line-3; focus ring; disabled .4 |
88
133
  | Range | 4px track, accent filled portion, 14px thumb with 2px accent ring; number readout tabular and 76px wide |
89
134
  | Choice card | 1px line-2, radius 10, padding 12; selected 1px accent + accent-soft; title 13/500, one line of 12/ink-3, schematic 120–160px; radio semantics |
90
135
  | Chip / badge | 20px high, 11px, 1px line, radius 999; status only; at most one emphasized badge per screen |
91
- | Details | summary 28–32px, 6px chevron, Escape closes; only for advanced/diagnostics/compatibility |
136
+ | Details | summary 28–32px, 6px chevron, Escape closes; only for rare advanced fields and long read-only diagnostics; behavior settings never hide here |
92
137
  | Dialog / overlay | 1px line-2, radius 12; focus trapped and returned; Escape closes; shadow only here |
93
138
 
94
139
  Keyboard:
@@ -129,12 +174,14 @@ tests. Add classes instead. In particular:
129
174
  - Subagent: `.bs-root`, `.bs-title h2`, `.bs-header`, `.bs-switch`,
130
175
  `.bs-advanced`, `.bs-cellLabel`, `.bs-footer` first child `.bs-status`,
131
176
  `.bs-feedback`, `.bs-overviewGlyph`, combobox roles/ids, CSS literals.
132
- - Compact: `.dsh-bc-page`, three `data-diagram` SVGs, `.dsh-bc-row`,
133
- `.dsh-bc-current-line`, `.dsh-bc-explanation`, mode radios, `data-bc` hooks,
177
+ - Compact: `.dsh-bc-page`, four `data-mode` radios, `data-bc=capacity-bar`,
178
+ `[role=slider]` handles, `data-bc-section=capacity|strategy|generation|prompt`,
179
+ `data-bc=process-result`, custom-prompt textarea and variable buttons,
134
180
  form names/ids.
135
- - Goal: `.dbg-cfg`, `h3.dbg-title`, `.dbg-section`, `.dbg-segmented` ids,
136
- `.dbg-advanced`, `.dbg-help.dbg-info`, `.dbg-runtime`, `.dbg-footer`,
137
- `.dbg-status`, dock/history ids.
181
+ - Goal: `.dbg-cfg`, `h3.dbg-title`, `.dbg-section`, implementation/round-mode
182
+ radio ids, `.dbg-runtime`, `.dbg-footer`, `.dbg-status`, dock/history ids.
183
+ Native parameters and round policy are visible; no behavior `dbg-advanced`
184
+ or `dbg-diagnostics` fold.
138
185
  - Ask-user: `better-ask-user-*` ids, `data-settings-dirty/busy`,
139
186
  `data-settings-save`, `data-question-wait`, exact labels/aria.
140
187
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-better-dsh",
3
- "version": "0.10.0",
3
+ "version": "0.11.0",
4
4
  "description": "Better DSH: a DSH plugin bundle that installs workflow skills, engineering presets, and five independent plugins (goal, subagent, compact, ask-user, ptc). Pure ESM, no build step.",
5
5
  "license": "Apache-2.0",
6
6
  "repository": {
@@ -58,10 +58,10 @@
58
58
  },
59
59
  "dependencies": {
60
60
  "@deepseek-ai/schemastery": "~3.19.0",
61
- "@oh-my-dsh/dsh-better-subagent": "0.5.0",
62
- "dsh-better-ask-user": "0.3.1",
63
- "dsh-better-compact": "0.3.1",
64
- "dsh-better-goal": "0.4.1",
61
+ "@oh-my-dsh/dsh-better-subagent": "0.5.1",
62
+ "dsh-better-ask-user": "0.3.2",
63
+ "dsh-better-compact": "0.4.0",
64
+ "dsh-better-goal": "0.4.2",
65
65
  "dsh-better-ptc": "0.2.0"
66
66
  },
67
67
  "peerDependencies": {
@@ -9,6 +9,8 @@ Turn a large requirement into one approved master Spec and at least two executab
9
9
 
10
10
  **The end state is a handoff to `/exec`.** Do not implement features, create worktrees, or invoke development skills. Stop once the user approves the written Specs.
11
11
 
12
+ Only the top-level main agent serving the user may dispatch review or re-review nodes. Subagents do their assigned work directly and return drafts, findings, or review requests to the main agent; they never dispatch reviewers, even if another skill calls for it.
13
+
12
14
  ## Process
13
15
 
14
16
  1. **Explore project context** — inspect files, docs, and current project state. Look up facts yourself; do not ask the user.
@@ -16,7 +18,7 @@ Turn a large requirement into one approved master Spec and at least two executab
16
18
  3. **Offer 2-3 options** — with tradeoffs and a recommendation, leading with the recommended option.
17
19
  4. **Present the design in sections** — scale each section's length to its complexity, and get the user's confirmation on each. When a split is needed, present it (master Spec + sub-Specs, dependency order, shared contracts, integration acceptance).
18
20
  5. **Write all Specs** — self-review after writing (placeholders, contradictions, ambiguity, over-detail) and fix inline. See self-review below.
19
- 6. **Dispatch a spec-reviewer** — per [`spec-document-reviewer-prompt.md`](spec-document-reviewer-prompt.md), dispatch a fresh read-only `subagent` (quality tier) to review the master Spec and all sub-Specs; fix blockers and re-dispatch if needed.
21
+ 6. **Main agent dispatches a spec-reviewer** — per [`spec-document-reviewer-prompt.md`](spec-document-reviewer-prompt.md), dispatch a fresh read-only `subagent` (quality tier) to review the master Spec and all sub-Specs; fix blockers and re-dispatch if needed.
20
22
  7. **Ask the user to review** — revise per feedback until approved.
21
23
  8. **Hand off to `/exec`** — tell the user to invoke `/exec` with the master Spec path.
22
24
 
@@ -1,6 +1,6 @@
1
1
  # Spec Document Reviewer Prompt Template
2
2
 
3
- Use this template when dispatching a spec document reviewer via the `subagent` tool (fresh read-only child, quality tier).
3
+ Only the top-level main agent serving the user uses this template to dispatch a spec document reviewer via the `subagent` tool (fresh read-only child, quality tier). Subagents return review requests to the main agent instead of dispatching reviewers.
4
4
 
5
5
  **Purpose:** Verify a master Spec or sub-Spec is complete, consistent, and ready for implementation.
6
6
 
@@ -8,7 +8,7 @@ Use this template when dispatching a spec document reviewer via the `subagent` t
8
8
 
9
9
  ```
10
10
  subagent(
11
- prompt="You are a spec document reviewer. Verify this spec is complete and ready for implementation.
11
+ prompt="You are a spec document reviewer. Verify this spec is complete and ready for implementation. Perform the review directly; do not dispatch review nodes, even if another skill calls for it. Return findings and any further review needs to the main agent.
12
12
 
13
13
  **Spec to review:** [SPEC_FILE_PATH]
14
14
  **Spec type:** [master | sub]
@@ -10,7 +10,7 @@ Two-axis review of the diff between `HEAD` and a fixed point the user supplies:
10
10
  - **Standards** — does the code conform to this repo's documented coding standards?
11
11
  - **Spec** — does the code faithfully implement the originating issue / PRD / spec?
12
12
 
13
- Both axes run as parallel `subagent` delegations so they don't pollute each other's context, then this skill aggregates their findings.
13
+ Only the top-level main agent serving the user may dispatch review or re-review nodes. It dispatches both axes as parallel `subagent` delegations and aggregates their findings. If you are a subagent, perform only your assigned review directly and return findings or further review needs to the main agent; never dispatch reviewers, even if another skill calls for it.
14
14
 
15
15
  ## Process
16
16
 
@@ -57,7 +57,7 @@ Each smell reads *what it is* → *how to fix*; match it against the diff:
57
57
 
58
58
  ### 4. Spawn both sub-agents in parallel
59
59
 
60
- Send both `subagent` calls in a single message — each a fresh quality-tier child with a fully self-contained prompt; children see none of this conversation.
60
+ The top-level main agent sends both `subagent` calls in a single message — each a fresh quality-tier child with a fully self-contained prompt; children see none of this conversation. Include in both prompts: "Perform this review directly. Do not dispatch review nodes; return findings and any further review needs to the main agent."
61
61
 
62
62
  **Standards sub-agent prompt** — include:
63
63
 
@@ -5,11 +5,13 @@ description: "Node contract for the DSH execution backend: prompt requirements,
5
5
 
6
6
  # Built-in development backend (node contracts)
7
7
 
8
- This skill defines the execution backend's two node types. Wave orchestration (worktrees, merging, cleanup, review-loop scheduling) belongs to `/exec`; this skill must not create, merge, or delete worktrees. Subagents have no independent working directory and cannot see the orchestration session: every node input must come with the prompt (absolute worktree path, Spec path, shared contracts, verification commands), with bash always using `workdir` and file tools always using absolute paths.
8
+ This skill defines the execution backend's two node types. Wave orchestration (worktrees, merging, cleanup, review-loop scheduling) belongs to `/exec`; this skill must not create, merge, or delete worktrees. Subagents have no independent working directory and cannot see the orchestration session: every node input must come with the prompt (absolute worktree path, Spec path, shared contracts, verification commands; implementation/fix nodes also need the execution mode and assigned tier), with bash always using `workdir` and file tools always using absolute paths.
9
+
10
+ Only the top-level main agent serving the user may dispatch review or re-review nodes. All subagents, including implementation/fix nodes and reviewers, perform their assigned work directly and return findings or review requests to the main agent. Never dispatch reviewers from a subagent, even when another skill calls for it.
9
11
 
10
12
  ## Implementation node (develop)
11
13
 
12
- One brand-new subagent (quality tier) handles exactly one sub-Spec, following `main-agent-driven-development` in prebuilt-worktree mode (in an `/exec` wave, skip its internal review step — the review loop is run by `/exec`, and nodes do not dispatch reviewers themselves).
14
+ An implementation subagent handles exactly one sub-Spec at the caller-selected tier, following `main-agent-driven-development` in prebuilt-worktree mode. In `/exec`, skip its internal review step: the top-level main agent decides whether and when to request a sub-Spec review. Carry the execution mode into any further implementation/fix delegations. Fixes normally reuse the active node; `/exec` may hand off a node after it has stopped writing, either to escalate fast to quality in Automatic mode or to honor a later explicit mode change. Never run two implementation nodes writing to the same Spec at once.
13
15
 
14
16
  Report format (JSON code block at the end of the closing message):
15
17
 
@@ -25,7 +27,7 @@ Report format (JSON code block at the end of the closing message):
25
27
 
26
28
  ## Review node (review-only)
27
29
 
28
- A brand-new read-only subagent (quality tier). The prompt supplies: absolute worktree path, diff range, Spec path, implementation summary, and verification already run. Four-state verdict format (JSON code block at the end of the closing message):
30
+ A brand-new read-only subagent (quality tier), dispatched only by the top-level main agent. The reviewer performs the review directly and never delegates another review. The prompt supplies: absolute worktree path, diff range, Spec path, implementation summary, and verification already run. Four-state verdict format (JSON code block at the end of the closing message):
29
31
 
30
32
  ```js
31
33
  {
@@ -38,4 +40,4 @@ Serious correctness errors, Spec gaps, integration risks, security issues, or mi
38
40
 
39
41
  ## Failure semantics
40
42
 
41
- A subagent failure (error / empty return) = `node-failed`; `blocked`, timeouts, partial replies, or uncommitted results never count as complete. The caller decides whether to redispatch, or to continue via `send_message` only when unblocking the same sub-Spec. Never reuse a node for another sub-Spec.
43
+ A subagent failure (error / empty return) = `node-failed`; `blocked`, node execution timeouts, partial replies, or uncommitted results never count as complete. A `wait_subagent` timeout while the child is still running is not a node failure: wait again with `timeout_ms: 1800000` or longer, without status nudges or replacement merely because time elapsed. The caller decides whether to redispatch, or to continue via `send_message` only when unblocking the same sub-Spec. Never reuse a node for another sub-Spec.
@@ -11,7 +11,21 @@ Run approved sub-Specs in isolated worktrees under `.worktrees/` in the target r
11
11
 
12
12
  - The master Spec indexes at least two sub-Specs.
13
13
  - Confirm a single target repo; the main workspace is on a named branch and its working tree is clean.
14
- - `.worktrees/` is covered by the target repo's `.gitignore`; if not, ask the user to add it first.
14
+ - Ensure `.worktrees/` is covered by the target repo's `.gitignore`; if missing, add the rule yourself and commit the setup change before creating wave worktrees.
15
+
16
+ ## Execution mode
17
+
18
+ Before dispatching the first node, use `ask_user_question` to ask for the execution mode, unless the user already specified it for this run. The choice applies to implementation and fixes; **all code reviews use the quality tier**. Offer:
19
+
20
+ 1. **Automatic (Recommended)** — use the fast tier by default; reserve the quality tier for particularly difficult tasks.
21
+ 2. **Quality only** — use the quality tier for every implementation and fix.
22
+ 3. **Fast only** — use the fast tier for every implementation and fix, without automatic escalation.
23
+
24
+ Default to Automatic if the question times out or the user skips the choice; use the host's normal question waiting behavior. A later explicit answer applies to future implementation/fix turns; let running turns finish. If the next fix requires a different tier, use the stopped-node handoff below instead of resuming the old route.
25
+
26
+ Keep the mode in session context and pass it to implementation/fix nodes and any further implementation delegations. In Automatic, ordinary implementation and routine fixes use fast; use quality only when the task demands unusually difficult reasoning or evidence shows the fast node cannot converge. Implementation work alone is not a reason to choose quality.
27
+
28
+ Resolve fast/quality from the current system prompt's configured routes and pass their `provider` / `model` / `reasoning_effort` to `subagent`; do not hardcode model IDs or use `subagent_fork` to select a tier. If a tier is unconfigured, follow its documented parent-route inheritance and disclose that distinct tiers are not configured. If a selected route is unavailable, report the blocker rather than silently switching tiers.
15
29
 
16
30
  ## Execution
17
31
 
@@ -21,58 +35,65 @@ Run approved sub-Specs in isolated worktrees under `.worktrees/` in the target r
21
35
 
22
36
  ## Wave execution: subagent + wait_subagent
23
37
 
24
- The main agent orchestrates each wave; node contracts (prompt elements, report format, failure semantics) are in the `dev` skill.
38
+ The main agent orchestrates each wave; node contracts (prompt elements, report format, failure semantics) are in the `dev` skill. Only the top-level main agent serving the user may dispatch any review or re-review node. All subagents, including reviewers, must do their assigned work directly and return findings or review requests to the main agent; they never dispatch reviewers, even if another skill instructs them to.
25
39
 
26
- 1. **Dispatch**: in a single message, call `subagent` once per sub-Spec in this wave (quality tier), and record "Spec → subagent id". Implementation-node prompt template:
40
+ 1. **Dispatch**: in a single message, call `subagent` once per sub-Spec in this wave using the execution mode, and record "Spec → active subagent id and tier". Implementation-node prompt template:
27
41
 
28
42
  ```
29
43
  You work in the isolated worktree <worktree absolute path>: always run bash with workdir=<worktree>, and use absolute paths for file tools.
30
- Follow the main-agent-driven-development skill in prebuilt-worktree mode (skip its internal review step; the review loop is run by /exec).
44
+ Execution mode: <Automatic / Quality only / Fast only>; assigned tier: <fast / quality>. Carry the mode into any implementation/fix delegations.
45
+ Follow the main-agent-driven-development skill in prebuilt-worktree mode (skip its internal review step; the top-level main agent decides whether and when to request a sub-Spec review). Do not dispatch review nodes; report any review needs to the main agent.
31
46
  Implement only <sub-Spec path> and obey the shared contracts: <contracts>. Run verification: <verification command>.
32
47
  After committing, report in the dev skill's implementation-node format. Do not merge or delete the worktree; if blocked, set status=blocked and fill in blocker.
33
48
  ```
34
49
 
35
50
  2. **Collect**: pass every id in this wave to `wait_subagent` in one call; reports arrive with the settlement notice. A Spec with a missing report, `blocked`, or no commit is recorded as `node-failed` and does not affect the other Specs in the wave.
36
- 3. **Review loop** (each completed Spec advances independently; batches may be dispatched in parallel):
37
- - Dispatch a brand-new read-only reviewer (quality tier): `Read-only review of the full diff of worktree <worktree> against the baseline (always run bash with workdir=<worktree>). Spec: <path>. Implementation summary: <summary>. Verification already run: <verification>. List issues by severity, each with file and line number; judge with the dev skill's four-state format. Do not edit, commit, or merge.`
38
- - `CHANGES_REQUIRED` → send the findings to the original implementation subagent with `send_message` (preserving its context), and require it to fix each real issue, explain false positives, rerun verification, commit, and report again; then `wait_subagent` and dispatch a brand-new reviewer.
51
+ 3. **Choose sub-Spec reviews**: the orchestrator decides whether and when each completed Spec needs an independent code review, based on complexity, shared-contract impact, risk, and verification evidence. Ordinary low-risk changes can rely on the mandatory final integrated review. Briefly record the decision and reason in session context. For a selected review:
52
+ - Dispatch a brand-new read-only reviewer (quality tier): `Read-only review of the full diff of worktree <worktree> against the baseline (always run bash with workdir=<worktree>). Spec: <path>. Implementation summary: <summary>. Verification already run: <verification>. List issues by severity, each with file and line number; judge with the dev skill's four-state format. Perform the review directly; do not dispatch reviewers. Do not edit, commit, or merge.`
53
+ - `CHANGES_REQUIRED` → send the findings to the active implementation subagent with `send_message` (preserving its context), and require it to fix each real issue, explain false positives, rerun verification, commit, and report again; then wait and dispatch a brand-new quality reviewer. Apply the execution mode and escalation rules to fixes.
39
54
  - At most 5 rounds; if still failing, record `review-exhausted`.
40
- 4. Only Specs judged `APPROVED` / `APPROVED_WITH_NOTES` proceed to merge.
55
+ 4. **Merge eligibility**: committed, verified, in-scope Specs may proceed without a separate sub-Spec review when the orchestrator chose to omit it. A selected review must reach `APPROVED` / `APPROVED_WITH_NOTES`; never bypass required findings or a `BLOCKED` / exhausted review by changing the review decision.
41
56
 
42
57
  Key points:
43
58
 
44
- - Every review round uses a brand-new subagent; fixes reuse the original implementation subagent — never start another implementation node for the same Spec.
59
+ - Every review round uses a brand-new quality subagent; fixes normally reuse the active implementation subagent.
45
60
  - Report any node question as blocked for the main agent to handle; do not ask the user within a wave.
46
61
  - In PTC mode, a whole wave's dispatch and collection can be done in one `run_code`.
47
62
 
63
+ ## Waiting and escalation
64
+
65
+ For every implementation, review, fix, and handoff wait in this workflow, call `wait_subagent` with all needed ids and `timeout_ms: 1800000` (30 minutes) or longer. Early completion returns immediately. Do independent work first; when blocked on results, wait patiently. If a wait expires while a node is still running, wait again with the same long window or continue independent work. A wait timeout is not a node failure or evidence that the task is particularly difficult. Do not send status nudges, repeatedly poll agent lists, or interrupt/replace a normally running node because it is taking time.
66
+
67
+ In Automatic only, an actual blocker, repeated failed attempts, or evidence of exceptional difficulty can justify a fast-to-quality handoff. A later explicit mode change can also require a handoff for the next implementation/fix turn. Reuse the existing node otherwise. Confirm the old node has stopped writing before dispatching its replacement; if interruption is needed, request it and wait for the node to stop. Inspect the actual worktree state and hand off the Spec, contracts, existing commits, any uncommitted changes, verification results, and unresolved issues to a new implementation node in the same worktree at the required tier (quality for automatic escalation). Update the active-node mapping; only one implementation node may write to a Spec at a time. After escalation, keep that quality node for subsequent fixes unless the user explicitly changes the mode.
68
+
48
69
  ## Merge
49
70
 
50
- For each completed node: confirm it is committed and verification passed → check the changed files for out-of-scope edits → merge into the main workspace → verify after merging → delete the worktree and sub-branch.
71
+ For each eligible node: confirm it is committed and verification passed → check the changed files for out-of-scope edits → merge into the main workspace → verify after merging → delete the worktree and sub-branch.
51
72
 
52
- Small, well-defined conflicts are resolved directly by the main agent. For complex conflicts, use a new fix worktree under `.worktrees/` and a development node. Never merge failed or blocked nodes.
73
+ Resolve conflicts through an implementation/fix node under the execution mode; use a new fix worktree under `.worktrees/` for complex conflicts. Never merge failed or blocked nodes.
53
74
 
54
75
  ## Final review
55
76
 
56
- Once all sub-Specs are merged, run the full integration verification, then dispatch a brand-new read-only reviewer subagent (quality tier) to review the whole integrated result:
77
+ Once all sub-Specs are merged, run the full integration verification, then always dispatch a brand-new read-only reviewer subagent (quality tier) to review the whole integrated result, even when sub-Spec reviews were omitted:
57
78
 
58
79
  ```
59
80
  subagent(
60
81
  prompt="Read-only review of the <base>..HEAD diff in <workspace> (always run bash with workdir=<workspace>).
61
82
  Master Spec: <path> | all sub-Specs | shared contracts | changed files | implementation summary | verification results.
62
83
  List issues by severity, each with file and line number.
63
- Return APPROVED / APPROVED_WITH_NOTES / CHANGES_REQUIRED / BLOCKED. Do not edit, commit, or merge."
84
+ Return APPROVED / APPROVED_WITH_NOTES / CHANGES_REQUIRED / BLOCKED. Perform the review directly; do not dispatch reviewers. Do not edit, commit, or merge."
64
85
  )
65
86
  ```
66
87
 
67
- Wait with `wait_subagent`. On `CHANGES_REQUIRED` there is no need to ask the user — the main agent classifies and fixes all real bugs directly, and briefly explains false positives and existing behavior in context; after fixing, verify again and dispatch a brand-new reviewer for re-review. If serious or blocking issues remain after a soft cap of 3 rounds, stop the fix loop and truthfully report the remaining issues to the user.
88
+ Wait using the long window above. On `CHANGES_REQUIRED` there is no need to ask the user — the main agent classifies findings and briefly explains false positives and existing behavior in context. Delegate real fixes to an implementation/fix node in an isolated worktree under the execution mode, integrate the committed fixes, verify again, and dispatch a brand-new quality reviewer for re-review. If serious or blocking issues remain after a soft cap of 3 rounds, stop the fix loop and truthfully report the remaining issues to the user. A blocked review is not approval.
68
89
 
69
90
  ## Wrap-up
70
91
 
71
- Run the full verification, check the Specs, report branches, commits, verification results, and open issues, and ask the user what to do next. Do not create a PR or delete branches without the user's choice.
92
+ Run the full verification, check the Specs, report the execution mode, actual tier use and escalations, sub-Spec review decisions, branches, commits, verification results, and open issues, and ask the user what to do next. Do not create a PR or delete branches without the user's choice.
72
93
 
73
94
  ## KISS
74
95
 
75
- - One sub-Spec, one worktree, one development node.
76
- - The main agent holds repo topology (branches/worktrees/merges/cleanup) and in-wave scheduling; implementation and review go to subagents.
96
+ - One sub-Spec, one worktree, at most one active implementation node.
97
+ - The main agent holds repo topology (branches/worktrees/merges/cleanup) and scheduling; implementation, fixes, and selected reviews go to subagents.
77
98
  - State lives only in session context; add no integration branch, scheduler scripts, or state files.
78
99
  - Completion notices arrive automatically; wait only when you need results to proceed. Never poll with `sleep`.
@@ -14,7 +14,7 @@ Choose exactly one:
14
14
  - **Prebuilt mode** — when the caller already provided an isolated worktree and owns its lifecycle, use it directly; do not create, merge, or delete worktrees.
15
15
  - **Standalone mode** — otherwise, identify the target repo, require the baseline to be on a named branch, record the starting SHA, and create a worktree under the repo's `.worktrees/`.
16
16
 
17
- All operations must happen inside the chosen worktree. After isolation, do not edit the original checkout.
17
+ All operations must happen inside the chosen worktree. After isolation, do not edit the original checkout. When called by `/exec`, follow the assigned execution mode and tier, including in any further implementation/fix delegations; report blockers to the orchestrator rather than changing your own tier.
18
18
 
19
19
  ## Flow
20
20
 
@@ -26,14 +26,16 @@ All operations must happen inside the chosen worktree. After isolation, do not e
26
26
  6. After each logical step, run focused verification, self-review the diff, and commit when it is complete. Verification standard: run the command this round and confirm the output; never replace it with "it should pass".
27
27
  7. After implementation, run all required verification.
28
28
  8. When verification fails or review finds a bug, follow the `diagnosing-bugs` skill (bundled in this package): build a feedback loop to find the root cause first, then fix.
29
- 9. Run the internal review loop (see below). Exception: when acting as an implementation node in an `/exec` wave, **skip this step** — the review loop is run by `/exec`, and the node only implements, verifies, commits, and reports.
29
+ 9. Only the top-level main agent serving the user runs the internal review loop (see below). When acting as any implementation/fix subagent, **skip this step** — return the implementation and any review needs to the main agent, which owns all review dispatch.
30
30
  10. Commit all approved fixes and report to the caller.
31
31
 
32
32
  Keep it KISS. Prefer reusing existing patterns, small and complete changes, and only the targeted refactoring the Spec requires.
33
33
 
34
34
  ## Internal review loop
35
35
 
36
- After full verification, dispatch exactly one brand-new read-only reviewer subagent (quality tier):
36
+ Only the top-level main agent may dispatch review or re-review nodes. Subagents never dispatch reviewers, even if invoked outside `/exec` or another skill calls for review.
37
+
38
+ After full verification, the main agent dispatches exactly one brand-new read-only reviewer subagent (quality tier):
37
39
 
38
40
  ```
39
41
  subagent(
@@ -41,13 +43,14 @@ subagent(
41
43
  Spec: <path>
42
44
  Implementation summary: <brief>
43
45
  Changed files: <list>
44
- Verification already run: <commands and results>"
46
+ Verification already run: <commands and results>
47
+ Perform the review directly; do not dispatch review nodes. Return any further review needs to the main agent."
45
48
  )
46
49
  ```
47
50
 
48
51
  Require file and line numbers, and one status: `APPROVED` / `APPROVED_WITH_NOTES` / `CHANGES_REQUIRED` / `BLOCKED`.
49
52
 
50
- Wait for the review with `wait_subagent`. Once results arrive, fix all necessary correctness errors, Spec gaps, security issues, integration risks, and verification gaps directly — no need to ask the user. After verifying and committing the fixes, dispatch a brand-new reviewer with `subagent` again. Repeat until `APPROVED` or only non-blocking suggestions remain.
53
+ Wait for the review with `wait_subagent` and `timeout_ms: 1800000` (30 minutes) or longer; early completion returns immediately. If the reviewer is still running after a wait timeout, continue long waits without status nudges or replacing it merely because time elapsed. Once results arrive, fix all necessary correctness errors, Spec gaps, security issues, integration risks, and verification gaps directly — no need to ask the user. After verifying and committing the fixes, dispatch a brand-new reviewer with `subagent` again. Repeat until `APPROVED` or only non-blocking suggestions remain.
51
54
 
52
55
  Never self-approve, and never reuse an old reviewer.
53
56
 
@@ -58,7 +61,7 @@ Before reporting completion, all of the following must hold:
58
61
  - All assigned acceptance criteria are implemented
59
62
  - Required verification ran and passed this round (backed by command output)
60
63
  - No uncommitted implementation changes
61
- - Internal review passed with no required fixes
64
+ - Internal review passed with no required fixes, except for implementation/fix subagents whose review scheduling belongs to the top-level main agent
62
65
  - The final commit SHA is available
63
66
 
64
67
  Report blockers truthfully. Do not merge on your own; the caller owns integration and cleanup.
package/src/client.js CHANGED
@@ -15,7 +15,7 @@
15
15
  * `t` 用 `ctx.locale.bind(entry.locale)` 补齐。子插件页面永远是单一事实
16
16
  * 源,本文件不复制任何字段定义。
17
17
  *
18
- * 主题:局部强调色 #3388BB,中性表面与文字继承宿主 --dsw-alias-* 令牌。
18
+ * 主题:选择、按钮、表面与文字均映射宿主 --dsw-alias-* 令牌。
19
19
  * 零构建:closure factory,只 require('react') + 可选 ui-primitives(Modal
20
20
  * 兜底为自绘 overlay);不 fetch、不直接写 DOM。
21
21
  */
@@ -58,40 +58,35 @@ window.__ModuleLoader__.load({
58
58
  ];
59
59
 
60
60
  const zh = {
61
- summary: '后台任务退出守卫与兼容性说明',
61
+ summary: '后台任务与远程访问设置',
62
62
  title: '通用',
63
- connectionTitle: '连接与访问',
64
- guardTitle: '退出守卫',
65
- ownsHostLabel: '将反代页面声明为可信宿主',
63
+ purpose: '控制助手在后台任务运行时如何收尾,以及是否允许受信任的反向代理修改设置。',
64
+ connectionTitle: '远程访问',
65
+ guardTitle: '后台任务',
66
+ ownsHostLabel: '允许通过反向代理修改设置',
66
67
  ownsHostHint: '仅在你控制访问权限的可信反向代理后启用。这会允许该页面写入宿主设置;不改变子代理 API 的可信地址列表。',
67
68
  ownsHostReload: '保存后需重载 profile 并刷新页面。',
68
69
  savedReload: '已保存;重载 profile 并刷新页面后生效。',
69
- guardEnd: '回合结束',
70
- guardJobs: '后台任务',
71
- guardContinue: '有任务则继续',
72
- guardAllow: '允许结束',
73
- compatTitle: '兼容性',
74
- migratedBody: 'CLI 子代理、wait_subagent、运行中子代理守卫、模型分档与子代理设置页由 @oh-my-dsh/dsh-better-subagent 拥有;压缩模式与预算由 dsh-better-compact 拥有。请到 Plugins 中对应的行配置,或使用包详情页的集成设置弹窗。',
75
- deprecatedBody: '旧 Apollo 行里的 tiers / subagents / trustedHosts 只为迁移旧 profile 保留,运行时不再生效;迁移在启动后自动补齐新插件的缺失值,目标行已有显式设置时不会被覆盖。',
76
- reloadBody: '从 0.4.x 升级、或同时显式选中了独立 bundle 时,行可能显示为只读/不可寻址;请只保留一个显式入口并重载 profile。压缩设置的保存需要重载 profile 才会被引擎采用。',
77
70
  loading: '正在读取配置…',
78
- waitingForm: '正在等待宿主提供这一行的配置快照…',
79
- noFormHint: '长时间停在这里说明宿主没有为这一行提供可编辑配置:本部署没组合 dsh-settings/config-editor,或本行的 Config 未被识别。',
80
- unavailable: '当前连接下该配置不可用:请通过 loopback 地址访问,或在宿主部署层把该权威加入受信反代。',
81
- readonly: '当前连接只读(设置镜像为进程内 memory),无法写入宿主配置。',
82
- exitGuardLabel: '等待后台任务结束',
71
+ waitingForm: '正在读取设置…',
72
+ noFormHint: '暂时无法读取设置。请重新连接后再试。',
73
+ unavailable: '当前地址无法修改设置。请使用本机地址打开,或在服务器上允许此地址访问设置。',
74
+ readonly: '当前连接仅支持查看设置。',
75
+ exitGuardLabel: '等待后台任务完成',
76
+ exitGuardDescription: '后台命令尚未结束时,让助手继续跟进。',
77
+ ownsHostDescription: '仅对你控制访问权限的反向代理开启;保存后需重载。',
83
78
  exitGuardHint: '回合结束时仍有运行中的后台命令会注入提醒强制继续处理;Esc 中断始终放行。',
84
79
  save: '保存',
85
80
  saving: '保存中…',
86
81
  reset: '放弃改动',
87
82
  saved: '已保存,即时生效。',
88
- conflict: '宿主拒绝了这次写入:配置可能已被其他改动更新或被更高优先级配置覆盖,已重新读取宿主值。',
83
+ conflict: '设置已在其他地方更新。已重新读取最新值,请检查后重试。',
89
84
  saveFailed: '保存失败:',
90
85
  readonlyNote: '只读:当前无法写入宿主配置。',
91
86
  unavailableNote: '不可写:当前连接下该配置不可用。',
92
87
  hubButton: '集成设置',
93
88
  hubTitle: 'Better DSH',
94
- hubEmpty: '暂无可用的子插件设置:子插件客户端尚未注册设置页,或本部署未组合设置服务。',
89
+ hubEmpty: '暂无可用的设置页。请检查插件是否已启用。',
95
90
  close: '关闭',
96
91
  unsavedTitle: '有未保存的改动',
97
92
  unsavedBody: '关闭将放弃各页面尚未保存的设置。',
@@ -99,48 +94,43 @@ window.__ModuleLoader__.load({
99
94
  discardClose: '放弃并关闭',
100
95
  entryError: '此设置区加载失败:',
101
96
  retry: '重新加载',
102
- pluginBetterDsh: '核心',
97
+ pluginBetterDsh: '通用',
103
98
  pluginSubagent: '子代理',
104
99
  pluginCompact: '上下文压缩',
105
- pluginGoal: '目标',
100
+ pluginGoal: '目标与续跑',
106
101
  pluginAskUser: '提问',
107
102
  };
108
103
 
109
104
  const en = {
110
- summary: 'Background-job exit guard and compatibility notes',
105
+ summary: 'Background work and remote access settings',
111
106
  title: 'General',
112
- connectionTitle: 'Connection and access',
113
- guardTitle: 'Exit guard',
114
- ownsHostLabel: 'Trust this reverse-proxied page as the host',
107
+ purpose: 'Control how the assistant finishes while background work runs, and whether a trusted reverse proxy may change settings.',
108
+ connectionTitle: 'Remote access',
109
+ guardTitle: 'Background work',
110
+ ownsHostLabel: 'Allow settings changes through a reverse proxy',
115
111
  ownsHostHint: 'Enable only behind a trusted proxy whose access you control. This allows the page to write host settings; it does not change the subagent API’s trusted authorities.',
116
112
  ownsHostReload: 'Save, then reload the profile and refresh the page.',
117
113
  savedReload: 'Saved. Reload the profile and refresh the page to apply.',
118
- guardEnd: 'Turn ends',
119
- guardJobs: 'Background jobs',
120
- guardContinue: 'Continue if running',
121
- guardAllow: 'Allow completion',
122
- compatTitle: 'Compatibility',
123
- migratedBody: 'CLI subagents, wait_subagent, the running-child guard, model tiers and the subagent settings page are owned by @oh-my-dsh/dsh-better-subagent; compaction modes and budgets are owned by dsh-better-compact. Configure their rows under Plugins, or use the integrated settings dialog on the package page.',
124
- deprecatedBody: 'The old Apollo tiers / subagents / trustedHosts fields are kept only so 0.4.x profiles load; they are inert at runtime. After boot the migration fills the new plugins’ missing values and never overwrites an explicit target setting.',
125
- reloadBody: 'Upgrading from 0.4.x, or selecting both the standalone and Apollo bundles explicitly, can make the row read-only/unaddressable: keep a single explicit entry and reload the profile. Saved compaction settings take effect only after the profile reloads.',
126
114
  loading: 'Loading configuration…',
127
- waitingForm: 'Waiting for the host to provide this row’s configuration snapshot…',
128
- noFormHint: 'Staying here means the host exposes no editable config for this row: dsh-settings/config-editor is not composed, or this row’s Config was not recognized.',
129
- unavailable: 'This configuration is unavailable on the current connection: use a loopback address, or trust this authority in the host deployment.',
130
- readonly: 'This connection is read-only (settings mirror is process-local memory); host configuration cannot be written.',
115
+ waitingForm: 'Loading settings…',
116
+ noFormHint: 'Settings could not be loaded. Reconnect and try again.',
117
+ unavailable: 'Settings cannot be changed from this address. Open the local address or allow this address on the server.',
118
+ readonly: 'Settings can only be viewed on this connection.',
131
119
  exitGuardLabel: 'Wait for background work',
120
+ exitGuardDescription: 'Keep the assistant working while background commands are still running.',
121
+ ownsHostDescription: 'Enable for a reverse proxy whose access you control. Reload after saving.',
132
122
  exitGuardHint: 'Blocks turn end while background commands still run; Esc always passes through.',
133
123
  save: 'Save',
134
124
  saving: 'Saving…',
135
125
  reset: 'Discard',
136
126
  saved: 'Saved and applied.',
137
- conflict: 'The host refused this write: the configuration changed elsewhere or a higher layer overrides it. Host values were reloaded.',
127
+ conflict: 'Settings changed elsewhere. The latest values have been loaded; review them and try again.',
138
128
  saveFailed: 'Save failed: ',
139
129
  readonlyNote: 'Read-only: host configuration cannot be written.',
140
130
  unavailableNote: 'Not writable: this configuration is unavailable on the current connection.',
141
131
  hubButton: 'Integrated settings',
142
132
  hubTitle: 'Better DSH',
143
- hubEmpty: 'No sub-plugin settings are available yet: the sub-plugin clients have not registered their pages, or this deployment does not compose the settings service.',
133
+ hubEmpty: 'No settings pages are available. Check that the plugins are enabled.',
144
134
  close: 'Close',
145
135
  unsavedTitle: 'Unsaved changes',
146
136
  unsavedBody: 'Closing discards unsaved settings on all pages.',
@@ -148,10 +138,10 @@ window.__ModuleLoader__.load({
148
138
  discardClose: 'Discard and close',
149
139
  entryError: 'This settings pane failed to load: ',
150
140
  retry: 'Retry',
151
- pluginBetterDsh: 'Core',
141
+ pluginBetterDsh: 'General',
152
142
  pluginSubagent: 'Subagents',
153
143
  pluginCompact: 'Compaction',
154
- pluginGoal: 'Goals',
144
+ pluginGoal: 'Goals and continuation',
155
145
  pluginAskUser: 'Questions',
156
146
  };
157
147
 
@@ -165,9 +155,11 @@ window.__ModuleLoader__.load({
165
155
  const STYLE_ID = 'dsh-better-dsh/settings.css';
166
156
  const CSS = `
167
157
  /* UI-KIT v1 — keep in sync with docs/UI-KIT.md. Flat surfaces, 1px lines, one accent. */
168
- .apollo-cfg,.apollo-root,.apollo-hub,.apollo-modal,.apollo-modalCard,.apollo-button[data-apollo-hub=trigger]{--cfg-accent:#3388BB;--cfg-accent-solid:#20709e;--cfg-accent-text:#14587f;--cfg-accent-fg:#fff;--cfg-accent-soft:color-mix(in srgb,var(--cfg-accent) 10%,transparent);--cfg-accent-ink:color-mix(in srgb,var(--cfg-accent) 70%,var(--dsw-alias-label-primary));--cfg-surface:var(--dsw-alias-bg-layer-1);--cfg-raised:var(--dsw-alias-bg-layer-2);--cfg-overlay:var(--dsw-alias-bg-layer-3);--cfg-sunken:color-mix(in srgb,var(--dsw-alias-label-primary) 4%,var(--cfg-surface));--cfg-ink:var(--dsw-alias-label-primary);--cfg-ink-2:var(--dsw-alias-label-secondary);--cfg-ink-3:color-mix(in srgb,var(--dsw-alias-label-tertiary) 80%,var(--dsw-alias-label-primary));--cfg-border:var(--dsw-alias-border-l2,color-mix(in srgb,currentColor 14%,transparent));--cfg-border-strong:var(--dsw-alias-border-l3,color-mix(in srgb,currentColor 22%,transparent));--cfg-line:var(--dsw-alias-border-l1,color-mix(in srgb,currentColor 8%,transparent));--cfg-hover:var(--dsw-alias-interactive-bg-hover,color-mix(in srgb,currentColor 6%,transparent));--cfg-danger:var(--dsw-alias-state-error-primary);--cfg-success:color-mix(in srgb,var(--dsw-alias-state-success-primary) 60%,var(--dsw-alias-label-primary));--cfg-warn:color-mix(in srgb,var(--dsw-alias-state-warn-primary) 60%,var(--dsw-alias-label-primary));--cfg-mono:ui-monospace,SFMono-Regular,Menlo,monospace;--cfg-control:32px;--cfg-radius:8px;--cfg-dur:140ms;font-size:13px;line-height:20px;color:var(--cfg-ink);font-variant-numeric:tabular-nums}
169
- [data-ds-dark-theme] :is(.apollo-cfg,.apollo-root,.apollo-hub,.apollo-modal,.apollo-modalCard,.apollo-button[data-apollo-hub=trigger]){--cfg-accent:#4eb0e8;--cfg-accent-solid:#4eb0e8;--cfg-accent-text:#6fc0ee;--cfg-accent-fg:#0e1014;--cfg-accent-soft:color-mix(in srgb,var(--cfg-accent) 14%,transparent);--cfg-accent-ink:#6fc0ee}
170
- .apollo-cfg{display:flex;flex-direction:column;gap:24px;max-width:920px;width:100%;margin:0 auto;min-width:0}
158
+ .apollo-cfg,.apollo-root,.apollo-hub,.apollo-modal,.apollo-modalCard,.apollo-button[data-apollo-hub=trigger]{--cfg-accent:var(--dsw-alias-state-business-primary,#4176e6);--cfg-accent-solid:var(--dsw-alias-button-primary-fill,#0f1115);--cfg-accent-text:color-mix(in srgb,var(--cfg-accent) 70%,var(--dsw-alias-label-primary));--cfg-accent-fg:var(--dsw-alias-label-primary-foreground,#fff);--cfg-accent-soft:color-mix(in srgb,var(--cfg-accent) 10%,transparent);--cfg-accent-ink:color-mix(in srgb,var(--cfg-accent) 70%,var(--dsw-alias-label-primary));--cfg-surface:var(--dsw-alias-bg-layer-1);--cfg-raised:var(--dsw-alias-bg-layer-2);--cfg-overlay:var(--dsw-alias-bg-layer-3);--cfg-sunken:color-mix(in srgb,var(--dsw-alias-label-primary) 4%,var(--cfg-surface));--cfg-ink:var(--dsw-alias-label-primary);--cfg-ink-2:var(--dsw-alias-label-secondary);--cfg-ink-3:color-mix(in srgb,var(--dsw-alias-label-tertiary) 80%,var(--dsw-alias-label-primary));--cfg-border:var(--dsw-alias-border-l2,color-mix(in srgb,currentColor 14%,transparent));--cfg-border-strong:var(--dsw-alias-border-l3,color-mix(in srgb,currentColor 22%,transparent));--cfg-line:var(--dsw-alias-border-l1,color-mix(in srgb,currentColor 8%,transparent));--cfg-hover:var(--dsw-alias-interactive-bg-hover,color-mix(in srgb,currentColor 6%,transparent));--cfg-danger:color-mix(in srgb,var(--dsw-alias-state-error-primary) 60%,var(--dsw-alias-label-primary));--cfg-success:color-mix(in srgb,var(--dsw-alias-state-success-primary) 60%,var(--dsw-alias-label-primary));--cfg-warn:color-mix(in srgb,var(--dsw-alias-state-warn-primary) 60%,var(--dsw-alias-label-primary));--cfg-mono:ui-monospace,SFMono-Regular,Menlo,monospace;--cfg-control:32px;--cfg-radius:8px;--cfg-dur:140ms;font-size:13px;line-height:20px;color:var(--cfg-ink);font-variant-numeric:tabular-nums}
159
+ [data-ds-dark-theme] :is(.apollo-cfg,.apollo-root,.apollo-hub,.apollo-modal,.apollo-modalCard,.apollo-button[data-apollo-hub=trigger]){--cfg-accent:var(--dsw-alias-state-business-primary,#a6c4ff);--cfg-accent-solid:var(--dsw-alias-button-primary-fill,#e4e4e9);--cfg-accent-text:color-mix(in srgb,var(--cfg-accent) 70%,var(--dsw-alias-label-primary));--cfg-accent-fg:var(--dsw-alias-label-primary-foreground,#000);--cfg-accent-soft:color-mix(in srgb,var(--cfg-accent) 14%,transparent);--cfg-accent-ink:var(--cfg-accent-text)}
160
+ .apollo-cfg{display:flex;flex-direction:column;gap:20px;max-width:960px;width:100%;margin:0 auto;min-width:0}
161
+ .apollo-pageTitleBlock{display:flex;flex-direction:column;gap:4px;min-width:0}
162
+ .apollo-pageSub{margin:0;color:var(--cfg-ink-3);font-size:13px;line-height:20px}
171
163
  .apollo-pageHead{display:flex;align-items:center;justify-content:space-between;gap:12px;min-width:0}
172
164
  .apollo-pageTitle{margin:0;font-size:20px;line-height:28px;font-weight:500;letter-spacing:-.01em;color:var(--cfg-ink)}
173
165
  .apollo-badge{display:inline-flex;align-items:center;height:20px;padding:0 8px;border:1px solid var(--cfg-border);border-radius:999px;background:var(--cfg-raised);font-size:11px;line-height:18px;color:var(--cfg-ink-3);white-space:nowrap}
@@ -178,10 +170,11 @@ window.__ModuleLoader__.load({
178
170
  @keyframes apollo-pulse{0%{opacity:1}40%{opacity:.6}80%,to{opacity:1}}
179
171
  .apollo-hint{margin:0;font-size:12px;line-height:18px;color:var(--cfg-ink-3)}
180
172
  .apollo-mono{font-family:var(--cfg-mono);font-variant-numeric:tabular-nums}
181
- .apollo-card{display:flex;flex-direction:column;gap:12px;min-width:0;padding:16px 0 0;border:0;border-top:1px solid var(--cfg-border);border-radius:0;background:transparent}
182
- .apollo-sectionTitle{margin:0;font-size:12px;line-height:18px;font-weight:500;color:var(--cfg-ink-3)}
183
- .apollo-row{display:flex;align-items:flex-start;justify-content:space-between;gap:24px;padding:10px 0;min-width:0;border-bottom:1px solid var(--cfg-line)}
184
- .apollo-row:last-child{border-bottom:0;padding-bottom:0}
173
+ .apollo-card{display:flex;flex-direction:column;gap:4px;min-width:0;padding:0;border:0;border-radius:0;background:transparent}
174
+ .apollo-sectionTitle{margin:0;padding-bottom:0;border-bottom:0;font-size:12px;line-height:18px;font-weight:500;color:var(--cfg-ink-3)}
175
+ .apollo-row{display:flex;align-items:center;justify-content:space-between;gap:24px;padding:10px 8px;margin:0 -8px;min-width:0;border-bottom:0;border-radius:8px}
176
+ .apollo-row:hover{background:var(--cfg-hover)}
177
+ .apollo-row:last-child{padding-bottom:10px}
185
178
  .apollo-rowText{display:flex;flex-direction:column;gap:3px;min-width:0;flex:1}
186
179
  .apollo-rowTitle{font-size:13px;line-height:20px;font-weight:500;color:var(--cfg-ink);cursor:default}
187
180
  .apollo-rowDesc{max-width:560px;font-size:12px;line-height:18px;color:var(--cfg-ink-3)}
@@ -192,18 +185,18 @@ window.__ModuleLoader__.load({
192
185
  .apollo-help>button:focus-visible{outline:2px solid var(--cfg-accent);outline-offset:2px}
193
186
  .apollo-help>p{position:absolute;left:0;top:26px;z-index:40;width:320px;max-width:min(320px,70vw);margin:0;padding:10px 12px;border:1px solid var(--cfg-border-strong);border-radius:8px;background:var(--cfg-overlay);color:var(--cfg-ink-2);font-size:12px;line-height:18px;font-weight:400;box-shadow:0 12px 32px -16px rgb(0 0 0/.45)}
194
187
  .apollo-help>p[hidden]{display:none}
195
- .apollo-switch{box-sizing:border-box;position:relative;flex:none;width:34px;height:20px;margin:1px 0 0;padding:2px;border:1px solid var(--cfg-border-strong);border-radius:999px;background:var(--cfg-sunken);cursor:pointer;appearance:none;transition:background var(--cfg-dur) ease,border-color var(--cfg-dur) ease}
188
+ .apollo-switch{box-sizing:border-box;position:relative;flex:none;width:34px;height:20px;margin:1px 5px 0 0;padding:2px;border:1px solid var(--cfg-border-strong);border-radius:999px;background:var(--cfg-sunken);cursor:pointer;appearance:none;transition:background var(--cfg-dur) ease,border-color var(--cfg-dur) ease}
196
189
  .apollo-switch:hover:not(:disabled){border-color:var(--cfg-ink-3)}
197
- .apollo-switch[aria-checked=true]{border-color:var(--cfg-accent);background:var(--cfg-accent-solid)}
190
+ .apollo-switch[aria-checked=true]{border-color:var(--cfg-accent-solid);background:var(--cfg-accent-solid)}
198
191
  .apollo-switch:disabled{opacity:.4;cursor:not-allowed}
199
192
  .apollo-switchThumb{display:block;width:14px;height:14px;border-radius:50%;background:var(--cfg-ink-3);transition:transform var(--cfg-dur) ease,background var(--cfg-dur) ease}
200
193
  .apollo-switch[aria-checked=true] .apollo-switchThumb{transform:translateX(14px);background:var(--cfg-accent-fg)}
201
- .apollo-switch:before{content:"";position:absolute;inset:-11px 0 -11px -8px}
194
+ .apollo-switch:before{content:"";position:absolute;inset:-12px -5px}
202
195
  .apollo-switch:focus-visible{outline:2px solid var(--cfg-accent);outline-offset:2px}
203
196
  .apollo-button{box-sizing:border-box;display:inline-flex;align-items:center;justify-content:center;gap:6px;height:32px;padding:0 12px;border:1px solid transparent;border-radius:8px;font:inherit;font-size:13px;line-height:20px;font-weight:500;color:var(--cfg-ink);background:transparent;cursor:pointer;transition:background var(--cfg-dur) ease,border-color var(--cfg-dur) ease,color var(--cfg-dur) ease}
204
197
  .apollo-button:disabled{opacity:.4;cursor:not-allowed}
205
198
  .apollo-button[data-variant=primary]{background:var(--cfg-accent-solid);color:var(--cfg-accent-fg)}
206
- .apollo-button[data-variant=primary]:hover:not(:disabled){background:color-mix(in srgb,var(--cfg-accent-solid) 88%,black)}
199
+ .apollo-button[data-variant=primary]:hover:not(:disabled){background:color-mix(in srgb,var(--cfg-accent-solid) 88%,var(--cfg-accent-fg))}
207
200
  .apollo-button[data-variant=outline]{border-color:var(--cfg-border-strong)}
208
201
  .apollo-button[data-variant=outline]:hover:not(:disabled),.apollo-button[data-variant=ghost]:hover:not(:disabled){background:var(--cfg-hover)}
209
202
  .apollo-button:focus-visible{outline:2px solid var(--cfg-accent);outline-offset:2px}
@@ -217,38 +210,23 @@ window.__ModuleLoader__.load({
217
210
  .apollo-status[data-tone=ok]{color:var(--cfg-success)}
218
211
  .apollo-status[data-tone=error]{color:var(--cfg-danger)}
219
212
  .apollo-status[data-tone=warn]{color:var(--cfg-warn)}
220
- .apollo-details{min-width:0;border-top:1px solid var(--cfg-border);padding:8px 0 0;font-size:13px;line-height:20px}
221
- .apollo-details>summary{display:flex;align-items:center;gap:8px;list-style:none;cursor:pointer;min-height:32px;padding:4px 0;font-size:13px;line-height:20px;font-weight:500;color:var(--cfg-ink-2)}
222
- .apollo-details>summary::-webkit-details-marker{display:none}
223
- .apollo-details>summary:before{content:"";width:6px;height:6px;flex:none;border-right:1px solid currentColor;border-bottom:1px solid currentColor;transform:rotate(-45deg);transition:transform var(--cfg-dur) ease}
224
- .apollo-details[open]>summary:before{transform:rotate(45deg)}
225
- .apollo-details>summary:hover{color:var(--cfg-ink)}
226
- .apollo-details>summary:focus-visible{outline:2px solid var(--cfg-accent);outline-offset:2px;border-radius:4px}
227
- .apollo-detailsBody{display:flex;flex-direction:column;gap:10px;padding:6px 0 4px;color:var(--cfg-ink-2)}
228
- .apollo-guardFlow{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:0;margin:2px 0 0;padding:14px 12px;border:1px solid var(--cfg-border);border-radius:8px;background:var(--cfg-sunken)}
229
- .apollo-flowStep{position:relative;display:flex;flex-direction:column;align-items:center;gap:6px;min-width:0;text-align:center;color:var(--cfg-ink-2)}
230
- .apollo-flowStep svg{box-sizing:content-box;display:block;padding:6px;border:1px solid var(--cfg-border);border-radius:8px;background:var(--cfg-raised);color:var(--cfg-ink-2)}
231
- .apollo-flowLabel{font-size:12px;line-height:18px;max-width:130px;overflow-wrap:normal;white-space:nowrap;text-overflow:ellipsis;overflow:hidden}
232
- .apollo-flowStep:not(:last-child):after{content:"";position:absolute;left:calc(50% + 24px);top:15px;width:calc(100% - 40px);border-top:1px solid var(--cfg-border)}
233
- .apollo-guardFlow[data-enabled=true] .apollo-flowStep:last-child{color:var(--cfg-accent-text)}
234
- .apollo-guardFlow[data-enabled=true] .apollo-flowStep:last-child svg{border-color:color-mix(in srgb,var(--cfg-accent) 35%,var(--cfg-border));background:var(--cfg-accent-soft);color:var(--cfg-accent-text)}
235
213
  .apollo-hubGlyph{flex:none;color:var(--cfg-ink-3)}
236
214
  .apollo-closeConfirm{box-sizing:border-box;display:flex;flex-direction:column;justify-content:center;gap:16px;min-height:280px;width:100%;padding:32px}
237
215
  .apollo-closeConfirm p{margin:0;color:var(--cfg-ink-2);font-size:13px;line-height:20px}
238
216
  .apollo-closeActions{display:flex;justify-content:flex-end;gap:8px}
239
- .apollo-modal.apollo-modal{width:min(1240px,calc(100vw - 32px));max-width:calc(100vw - 32px);max-height:calc(100dvh - 32px);padding-bottom:0;border:1px solid var(--cfg-border);border-radius:12px}
217
+ .apollo-modal.apollo-modal{width:min(1240px,calc(100vw - 32px));max-width:calc(100vw - 32px);max-height:calc(100dvh - 32px);padding-bottom:0;border:1px solid var(--cfg-border);border-radius:10px}
240
218
  .apollo-hubModalContent>:first-child{margin:0;padding:14px 20px;border-bottom:1px solid var(--cfg-border)}
241
219
  .apollo-hubModalContent>:first-child h2{font-size:15px;line-height:22px;font-weight:500}
242
220
  .apollo-hubModalContent>:last-child{margin:0;padding:0}
243
221
  .apollo-hub{display:flex;gap:0;height:min(760px,calc(100dvh - 96px));min-height:320px;width:100%;overflow:hidden}
244
- .apollo-hubNav{box-sizing:border-box;flex:none;width:200px;display:flex;flex-direction:column;gap:2px;padding:12px 8px;border-right:1px solid var(--cfg-border);background:color-mix(in srgb,var(--cfg-ink) 2%,var(--cfg-surface));overflow-y:auto;scrollbar-width:thin}
245
- .apollo-hubNavItem{display:flex;align-items:center;gap:10px;flex-shrink:0;min-height:36px;padding:0 10px;border:1px solid transparent;border-radius:8px;background:transparent;font:inherit;font-size:13px;line-height:20px;text-align:left;cursor:pointer;color:var(--cfg-ink-2);transition:background var(--cfg-dur) ease,color var(--cfg-dur) ease,border-color var(--cfg-dur) ease;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
222
+ .apollo-hubNav{box-sizing:border-box;flex:none;width:188px;display:flex;flex-direction:column;gap:2px;padding:12px 8px;border-right:1px solid var(--cfg-border);background:color-mix(in srgb,var(--cfg-ink) 2%,var(--cfg-surface));overflow-y:auto;scrollbar-width:thin}
223
+ .apollo-hubNavItem{display:flex;align-items:center;gap:10px;flex-shrink:0;min-height:32px;padding:0 10px;border:1px solid transparent;border-radius:8px;background:transparent;font:inherit;font-size:13px;line-height:20px;text-align:left;cursor:pointer;color:var(--cfg-ink-2);transition:background var(--cfg-dur) ease,color var(--cfg-dur) ease,border-color var(--cfg-dur) ease;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
246
224
  .apollo-hubNavItem:hover{background:var(--cfg-hover);color:var(--cfg-ink)}
247
225
  .apollo-hubNavItem[data-active]{background:var(--cfg-accent-soft);border-color:color-mix(in srgb,var(--cfg-accent) 25%,var(--cfg-border));color:var(--cfg-accent-ink);font-weight:500}
248
226
  .apollo-hubNavItem svg{flex:none;opacity:.7}
249
227
  .apollo-hubNavItem[data-active] svg{opacity:1;color:var(--cfg-accent-ink)}
250
228
  .apollo-hubNavItem:focus-visible{outline:2px solid var(--cfg-accent);outline-offset:1px}
251
- .apollo-hubContent{flex:1;min-width:0;min-height:0;overflow-y:auto;overscroll-behavior:contain;padding:24px 32px 32px;scrollbar-width:thin;scrollbar-gutter:stable}
229
+ .apollo-hubContent{flex:1;min-width:0;min-height:0;overflow-y:auto;overscroll-behavior:contain;padding:24px 28px 32px;scrollbar-width:thin;scrollbar-gutter:stable}
252
230
  .apollo-hubContent .apollo-footer{position:sticky;bottom:-1px;background:var(--cfg-surface);padding-bottom:12px;margin-top:auto}.apollo-hubPane{display:flex;flex-direction:column;min-height:100%}.apollo-hubPane>:first-child{flex:1 0 auto;min-height:0;display:flex;flex-direction:column}.apollo-root{flex:1;min-height:0;display:flex;flex-direction:column}.apollo-cfg{flex:1;min-height:0}.apollo-footer{margin-top:auto}
253
231
  .apollo-hubModalContent{padding:0!important;overflow:hidden}
254
232
  .apollo-hubPane{min-width:0;width:100%;overflow-wrap:anywhere}
@@ -260,11 +238,11 @@ window.__ModuleLoader__.load({
260
238
  .apollo-modalHead{display:flex;align-items:center;justify-content:space-between;gap:12px;padding:14px 16px;border-bottom:1px solid var(--cfg-border)}
261
239
  .apollo-modalTitle{margin:0;font-size:15px;font-weight:500;line-height:22px}
262
240
  .apollo-modalBody{flex:1;min-height:0;overflow:hidden;display:flex}
263
- .apollo-iconBtn{display:inline-flex;align-items:center;justify-content:center;width:28px;height:28px;border:0;border-radius:6px;background:transparent;color:var(--cfg-ink-3);font-size:16px;line-height:1;cursor:pointer}
241
+ .apollo-iconBtn{display:inline-flex;align-items:center;justify-content:center;width:32px;height:32px;border:0;border-radius:6px;background:transparent;color:var(--cfg-ink-3);font-size:16px;line-height:1;cursor:pointer}
264
242
  .apollo-iconBtn:hover{background:var(--cfg-hover);color:var(--cfg-ink)}
265
243
  .apollo-iconBtn:focus-visible{outline:2px solid var(--cfg-accent);outline-offset:1px}
266
244
  @media (max-width:800px){.apollo-help>p{position:static;width:auto;max-width:none;margin-top:6px}.apollo-hub{flex-direction:column;height:min(80dvh,calc(100dvh - 24px))}.apollo-hubNav{width:auto;flex-direction:row;gap:4px;padding:8px;border-right:0;border-bottom:1px solid var(--cfg-border);overflow-x:auto}.apollo-hubNavItem{min-height:44px;flex:none}.apollo-hubContent{padding:20px 16px 24px}.apollo-cfg{gap:24px}.apollo-pageTitle{font-size:18px}.apollo-hubContent .apollo-footer{bottom:0}.apollo-mask{padding:12px}.apollo-modalCard{max-height:calc(100dvh - 24px)}}
267
- @media (max-width:640px){.apollo-row{flex-direction:column;gap:8px}.apollo-row .apollo-switch{align-self:flex-start}.apollo-guardFlow{padding:10px 6px}.apollo-flowLabel{font-size:11px}.apollo-footer{flex-wrap:wrap}.apollo-status{flex-basis:100%}}
245
+ @media (max-width:640px){.apollo-row{gap:12px;margin:0;padding:10px 0}.apollo-rowText{min-width:0;position:relative}.apollo-help{position:static}.apollo-row .apollo-switch{align-self:center}.apollo-footer{flex-wrap:wrap}.apollo-status{flex-basis:100%}.apollo-mask{padding:0}.apollo-modal.apollo-modal,.apollo-modalCard{flex-shrink:0;width:100vw;max-width:100vw;height:100dvh;max-height:100dvh;border:0;border-radius:0}.apollo-hubModalContent>:first-child button{width:44px;height:44px}.apollo-hub{height:calc(100dvh - 73px);min-height:0}.apollo-hubNav{scrollbar-width:none}.apollo-hubNav::-webkit-scrollbar{display:none}.apollo-help>button{width:44px;height:44px}.apollo-help>p{position:absolute;top:100%;left:0;right:auto;width:100%;max-width:none;box-sizing:border-box}}
268
246
  @media (pointer:coarse),(max-width:640px){.apollo-iconBtn{width:44px;height:44px}.apollo-button{height:44px}}
269
247
  @media (prefers-reduced-motion:reduce){.apollo-pulse{animation:none}.apollo-switch,.apollo-switchThumb,.apollo-button,.apollo-hubNavItem,.apollo-help>button{transition:none}}
270
248
  `.trim();
@@ -290,13 +268,14 @@ window.__ModuleLoader__.load({
290
268
  h('p', { id, hidden: !open, role: 'note' }, children));
291
269
  }
292
270
 
293
- function SwitchRow({ id, label, hint, checked, disabled, onChange }) {
271
+ function SwitchRow({ id, label, description, hint, checked, disabled, onChange }) {
294
272
  const hintId = hint === undefined ? undefined : id + '-hint';
295
273
  return h('div', { className: 'apollo-row' },
296
274
  h('div', { className: 'apollo-rowText' },
297
275
  h('div', { className: 'apollo-rowLabel' },
298
276
  h('label', { className: 'apollo-rowTitle', htmlFor: id }, label),
299
- hint === undefined ? null : h(Help, { label, id: hintId }, hint))),
277
+ hint === undefined ? null : h(Help, { label, id: hintId }, hint)),
278
+ description === undefined ? null : h('div', { className: 'apollo-rowDesc' }, description)),
300
279
  h('button', {
301
280
  type: 'button',
302
281
  id,
@@ -369,39 +348,32 @@ window.__ModuleLoader__.load({
369
348
 
370
349
  return h('div', { className: 'apollo-cfg', 'data-settings-dirty': dirty, 'data-settings-busy': busy },
371
350
  h('div', { className: 'apollo-pageHead' },
372
- h('h2', { className: 'apollo-pageTitle' }, translate('title'))),
351
+ h('div', { className: 'apollo-pageTitleBlock' },
352
+ h('h2', { className: 'apollo-pageTitle' }, translate('title')),
353
+ h('p', { className: 'apollo-pageSub' }, translate('purpose')))),
373
354
  writable ? null : h('p', { className: 'apollo-note', 'data-tone': 'warn' }, translate('readonlyNote')),
374
355
  h('section', { className: 'apollo-card' },
375
356
  h('h3', { className: 'apollo-sectionTitle' }, translate('guardTitle')),
376
357
  h(SwitchRow, {
377
358
  id: 'apollo-exit-guard',
378
359
  label: translate('exitGuardLabel'),
360
+ description: translate('exitGuardDescription'),
379
361
  hint: translate('exitGuardHint'),
380
362
  checked: live.exitGuard,
381
363
  disabled: !writable || busy,
382
364
  onChange: (next) => edit({ exitGuard: next }),
383
- }),
384
- h('div', { className: 'apollo-guardFlow', 'aria-hidden': 'true', 'data-enabled': live.exitGuard },
385
- ['guardEnd', 'guardJobs', live.exitGuard ? 'guardContinue' : 'guardAllow'].map((key, index) => h('div', { key, className: 'apollo-flowStep' },
386
- h('svg', { width: 18, height: 18, viewBox: '0 0 24 24', fill: 'none', stroke: 'currentColor', strokeWidth: 1.5, strokeLinecap: 'round', strokeLinejoin: 'round' },
387
- h('path', { d: ['M5 12h14m-6-6 6 6-6 6', 'M4 5h16v14H4ZM8 9l3 3-3 3m6 0h3', live.exitGuard ? 'M12 8v4l3 2M5 4 2 7m20 0-3-3M12 4a8 8 0 1 0 8 8' : 'M5 12l4 4L19 6'][index] })),
388
- h('span', { className: 'apollo-flowLabel' }, translate(key)))))),
365
+ })),
389
366
  h('section', { className: 'apollo-card' },
390
367
  h('h3', { className: 'apollo-sectionTitle' }, translate('connectionTitle')),
391
368
  h(SwitchRow, {
392
369
  id: 'apollo-owns-host',
393
370
  label: translate('ownsHostLabel'),
371
+ description: translate('ownsHostDescription'),
394
372
  hint: translate('ownsHostHint') + ' ' + translate('ownsHostReload'),
395
373
  checked: live.declareOwnsHost,
396
374
  disabled: !writable || busy,
397
375
  onChange: (next) => edit({ declareOwnsHost: next }),
398
376
  })),
399
- h('details', { className: 'apollo-details' },
400
- h('summary', null, translate('compatTitle')),
401
- h('div', { className: 'apollo-detailsBody' },
402
- h('p', { className: 'apollo-hint' }, translate('migratedBody')),
403
- h('p', { className: 'apollo-hint' }, translate('deprecatedBody')),
404
- h('p', { className: 'apollo-hint' }, translate('reloadBody')))),
405
377
  h('div', { className: 'apollo-footer', hidden: !dirty && !busy && notice === null },
406
378
  status,
407
379
  h('button', {