dsh-better-dsh 0.10.1 → 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.1
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.1
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.1`**,搭配 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
 
@@ -183,10 +183,10 @@ Better DSH 包详情里的「集成设置」按 Core、Subagents、Compaction、
183
183
  # 旧入口
184
184
  dsh plugin --profile <profile> remove @menghuan1918/dsh-apollo
185
185
  # 新入口
186
- dsh plugin --profile <profile> add dsh-better-dsh@0.10.1
186
+ dsh plugin --profile <profile> add dsh-better-dsh@0.11.0
187
187
  # subagent 独立安装的用户
188
188
  dsh plugin --profile <profile> remove @menghuan1918/dsh-better-subagent
189
- 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
190
190
  ```
191
191
 
192
192
  <details>
@@ -209,10 +209,10 @@ dsh plugin --profile <profile> add @oh-my-dsh/dsh-better-subagent@0.5.0
209
209
  五个插件都可以单独安装;独立安装和 Better DSH 组合使用的是**同一组稳定行**。
210
210
 
211
211
  ```sh
212
- dsh plugin --profile <profile> add dsh-better-goal@0.4.1
213
- dsh plugin --profile <profile> add @oh-my-dsh/dsh-better-subagent@0.5.0
214
- dsh plugin --profile <profile> add dsh-better-compact@0.3.1
215
- 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
216
216
  ```
217
217
 
218
218
  <details>
@@ -245,11 +245,11 @@ dsh plugin --profile <profile> add dsh-better-ask-user@0.3.1 dsh-better-ptc@0.2.
245
245
  **发布顺序**:先发布独立包,再发布 Better DSH(精确依赖必须已存在):
246
246
 
247
247
  1. `dsh-better-ptc@0.2.0`(不变)
248
- 2. `dsh-better-ask-user@0.3.1`
249
- 3. `dsh-better-compact@0.3.1`
250
- 4. `dsh-better-goal@0.4.1`
251
- 5. `@oh-my-dsh/dsh-better-subagent@0.5.0`
252
- 6. `dsh-better-dsh@0.10.1`
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`
253
253
 
254
254
  各仓库使用 npm trusted publishing(OIDC);创建对应 GitHub Release 会发布 tag 指向的版本。旧包 `@menghuan1918/dsh-apollo` 与 `@menghuan1918/dsh-better-subagent` 已标记 deprecate,仅作为历史入口保留。
255
255
  </details>
@@ -2,7 +2,7 @@
2
2
 
3
3
  面向维护者、集成者和需要排查装配问题的用户。用户安装与配置请看 [README](../README.md);本文保留 DSH 插件的实现细节、旧配置迁移、组合安装边界与验证方法。
4
4
 
5
- 当前实现版本:`0.10.1`;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 | 宿主提供 |
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.1",
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": {
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', {