@huanlin/dsh-plugin-yet-another-subagent 0.1.2 → 0.1.4
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 +136 -130
- package/lib/client.js +145 -3
- package/lib/index.js +289 -27
- package/lib/types/client/SettingsPage.d.ts +49 -0
- package/lib/types/client/SubagentCard.d.ts +56 -0
- package/lib/types/client/SubagentTreeView.d.ts +63 -0
- package/lib/types/client/index.d.ts +29 -0
- package/lib/types/client/locales.d.ts +13 -0
- package/lib/types/index.d.ts +42 -0
- package/lib/types/invariant.d.ts +16 -0
- package/lib/types/profile-store.d.ts +59 -0
- package/lib/types/projection.d.ts +103 -0
- package/lib/types/repair.d.ts +49 -0
- package/lib/types/rpc.d.ts +59 -0
- package/lib/types/tool-factory.d.ts +45 -0
- package/lib/types/types.d.ts +116 -0
- package/package.json +159 -158
package/README.md
CHANGED
|
@@ -1,130 +1,136 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
- **
|
|
16
|
-
- `
|
|
17
|
-
-
|
|
18
|
-
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
|
54
|
-
|
|
55
|
-
| `
|
|
56
|
-
| `
|
|
57
|
-
| `
|
|
58
|
-
| `
|
|
59
|
-
| `
|
|
60
|
-
| `
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
dsh
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
```
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
```
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
##
|
|
109
|
-
|
|
110
|
-
Profile
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
-
|
|
1
|
+
<p align="center">
|
|
2
|
+
<a href="https://dshfind.com/zh/plugins/huanlinoto/dsh-plugin-yet-another-subagent"><img src="https://dshfind.com/api/card/huanlinoto/dsh-plugin-yet-another-subagent?lang=zh" alt="dsh-plugin-yet-another-subagent card"></a>
|
|
3
|
+
</p>
|
|
4
|
+
|
|
5
|
+
# yet-another-subagent
|
|
6
|
+
|
|
7
|
+
[](https://www.npmjs.com/package/@huanlin/dsh-plugin-yet-another-subagent)
|
|
8
|
+
|
|
9
|
+
可配置的子代理(subagent)profile 系统,提供单一 `subagent` 工具 + `profile` 参数选择,支持 Web UI 设置、实时进度展示(工具调用/token/活动)、子代理树标签页、点击跳转子会话。
|
|
10
|
+
|
|
11
|
+
## 架构
|
|
12
|
+
|
|
13
|
+
单 bundle,三入口(host `.` + invariant `./invariant` + client `./client`)。
|
|
14
|
+
|
|
15
|
+
- **Host 半**(`src/index.ts`):
|
|
16
|
+
- 单一 `subagent` 工具,通过 `profile` 枚举参数选择 profile(非每 profile 一个工具)
|
|
17
|
+
- 复用官方 `spawn` provider,支持前台(foreground)和后台(continuable / one-shot)两种模式
|
|
18
|
+
- Profile 状态通过 settings seam 持久化到 `$DSH_HOME/settings.yaml`
|
|
19
|
+
- RPC CRUD:`profiles.list` / `.add` / `.update` / `.remove`(专用 `/ya-subagent` 通道,不共享 `/api`)
|
|
20
|
+
- 两个 session projection:`subagentProfile`(父会话 childId→profileId 映射 + callId→childId)+ `yaSubagentProgress`(子会话实时 toolcall/token/活动状态)
|
|
21
|
+
- **Client 半**(`src/client/index.ts`):
|
|
22
|
+
- `settings.section` — Profile 编辑页
|
|
23
|
+
- `tool.call.toolview`(key `subagent`)— `SubagentCard` 工具调用卡片
|
|
24
|
+
- `conversation.view`(id `subagent-tree`)— `SubagentTreeView` 子代理树标签页
|
|
25
|
+
|
|
26
|
+
`cordis.patch.yml` 只禁用官方 `tool-subagent`(spawn 路径),保留 `tool-subagent-fork`(无名称冲突)。
|
|
27
|
+
|
|
28
|
+
## 配置
|
|
29
|
+
|
|
30
|
+
```yaml
|
|
31
|
+
# cordis.patch.yml
|
|
32
|
+
- id: tool-subagent
|
|
33
|
+
disabled: true
|
|
34
|
+
|
|
35
|
+
- insert:
|
|
36
|
+
- id: yet-another-subagent
|
|
37
|
+
name: '@huanlin/dsh-plugin-yet-another-subagent'
|
|
38
|
+
config:
|
|
39
|
+
profiles:
|
|
40
|
+
- id: general
|
|
41
|
+
label: General
|
|
42
|
+
model: { kind: 'auto' }
|
|
43
|
+
persona: { kind: 'inherit' }
|
|
44
|
+
toolFilter: { kind: 'none' }
|
|
45
|
+
maxDepth: 3
|
|
46
|
+
backgroundMode: continuable
|
|
47
|
+
builtin: true
|
|
48
|
+
generalFixed: true
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
### Profile 字段
|
|
52
|
+
|
|
53
|
+
| 字段 | 类型 | 默认值 | 说明 |
|
|
54
|
+
|------|------|--------|------|
|
|
55
|
+
| `id` | `string`(小写字母/数字/连字符,1-32 字符) | — | Profile 唯一标识 |
|
|
56
|
+
| `label` | `string` | — | 显示名 |
|
|
57
|
+
| `model.kind` | `'auto'` \| `'manual'` | — | `auto` 继承父代理模型;`manual` 指定 |
|
|
58
|
+
| `model.provider` | `string` | `''` | Provider(仅 `manual` 时使用) |
|
|
59
|
+
| `model.model` | `string` | `''` | 模型 ID(仅 `manual` 时使用) |
|
|
60
|
+
| `persona.kind` | `'inherit'` \| `'custom'` | `'inherit'` | `inherit` 跟随部署人设;`custom` 自定义 |
|
|
61
|
+
| `persona.text` | `string` | `''` | 自定义人设文本(仅 `custom` 时使用) |
|
|
62
|
+
| `toolFilter.kind` | `'none'` \| `'allow'` \| `'deny'` | `'none'` | 工具过滤策略 |
|
|
63
|
+
| `toolFilter.tools` | `string[]` | `[]` | 过滤工具列表 |
|
|
64
|
+
| `maxDepth` | `number` | `3` | 最大递归深度 |
|
|
65
|
+
| `backgroundMode` | `'continuable'` \| `'one-shot'` | `'continuable'` | `run_in_background: true` 时的后台策略 |
|
|
66
|
+
| `builtin` | `boolean` | `false` | 是否为内置 profile(仅展示用) |
|
|
67
|
+
|
|
68
|
+
## 开发
|
|
69
|
+
|
|
70
|
+
```sh
|
|
71
|
+
pnpm install # 安装开发依赖 + zod(唯一运行时 npm 依赖)
|
|
72
|
+
pnpm run typecheck # tsc --noEmit(通过 ../dsh 解析 DSH 源码)
|
|
73
|
+
pnpm test # vitest run
|
|
74
|
+
pnpm run build # tsc + tsdown → lib/index.js, lib/invariant.js, lib/client.js
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
### 类型检查
|
|
78
|
+
|
|
79
|
+
`tsconfig.json` 继承 `../dsh/tsconfig.base.client.json`,通过 `pnpm-workspace.yaml` 的 `packages/*/*` glob 解析 DSH checkout 的源码。需在 `../dsh` 存在 DSH checkout 的同级目录下运行。
|
|
80
|
+
|
|
81
|
+
## 运行
|
|
82
|
+
|
|
83
|
+
```sh
|
|
84
|
+
# 从 npm 安装(推荐):
|
|
85
|
+
dsh plugin --profile web add @huanlin/dsh-plugin-yet-another-subagent
|
|
86
|
+
|
|
87
|
+
# 本地引用(开发热更新)
|
|
88
|
+
dsh plugin --profile web add "link:D:/Projects/deepseek-harness/yet-another-subagent"
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
安装后重启 `dsh web` 进程,浏览器硬刷新(`Ctrl+Shift+R`)。
|
|
92
|
+
|
|
93
|
+
## 检查
|
|
94
|
+
|
|
95
|
+
```sh
|
|
96
|
+
pnpm run typecheck # 0 errors
|
|
97
|
+
pnpm test # 55 tests passing
|
|
98
|
+
pnpm run build # lib/index.js + lib/invariant.js + lib/client.js
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
### 产物验证
|
|
102
|
+
|
|
103
|
+
- `lib/index.js` — Host bundle
|
|
104
|
+
- `lib/invariant.js` — Invariant companion
|
|
105
|
+
- `lib/client.js` — Client bundle(CSS-modules inline,`d` 前缀 hash 防 CSS 类名数字开头)
|
|
106
|
+
- `cordis.patch.yml` — Bundle patch layer
|
|
107
|
+
|
|
108
|
+
## 持久化
|
|
109
|
+
|
|
110
|
+
Profile 状态通过 DSH settings seam 持久化到 `$DSH_HOME/settings.yaml` 的 `ya-subagent` 命名空间。cordis.yml 的 `profiles` 字段是组合 `base`(首次启动种子),运行时变更通过 `scope.replace()` 写入用户层。外部 yaml 编辑通过 `scope.watch` 热重载。
|
|
111
|
+
|
|
112
|
+
无 settings provider 的无头组装回退到内存状态(仅 cordis.yml 种子,不持久化)。
|
|
113
|
+
|
|
114
|
+
## RPC API
|
|
115
|
+
|
|
116
|
+
Profile CRUD 走 host 的专用 `/ya-subagent` 通道(不共享 `/api`,避免与 Typert gateway 的单拦截器冲突):
|
|
117
|
+
|
|
118
|
+
| endpoint | payload | result (ok) |
|
|
119
|
+
|----------|---------|-------------|
|
|
120
|
+
| `profiles.list` | `{}` | `{ profiles: SubagentProfile[] }` |
|
|
121
|
+
| `profiles.add` | `{ profile: SubagentProfile }` | `{ profiles: SubagentProfile[] }` |
|
|
122
|
+
| `profiles.update` | `{ profile: SubagentProfile }` | `{ profiles: SubagentProfile[] }` |
|
|
123
|
+
| `profiles.remove` | `{ id: string }` | `{ profiles: SubagentProfile[] }` |
|
|
124
|
+
| `tools.list` | `{}` | `{ tools: { name, description }[] }` |
|
|
125
|
+
|
|
126
|
+
URL 形如 `POST /ya-subagent/profiles.list`。业务错误返回 `{ ok: false, error: { code: 'internal', message } }`。
|
|
127
|
+
|
|
128
|
+
## 已知限制
|
|
129
|
+
|
|
130
|
+
- **旧会话不兼容**:`completed <label> subagent <id>` render 格式变更后,旧会话的结果文本无法被 `parseResult` 匹配,卡片不可点击。仅新会话(host 重启后)正常。
|
|
131
|
+
- **`yaSubagentProgress` stateVersion 2**:projection schema 变更(`activity` 字段 + `assistant/chunk` fold)需要 host 重启才能生效。
|
|
132
|
+
|
|
133
|
+
## 设计参考
|
|
134
|
+
|
|
135
|
+
- 官方 continuable subagent 设计:`.agents/notes/implemented/feature/2026-07-28-continuable-subagent-conversations.md`
|
|
136
|
+
- 插件开发指南:`plugin-development-guide.md`
|
package/lib/client.js
CHANGED
|
@@ -522,7 +522,7 @@ window.__ModuleLoader__.load({
|
|
|
522
522
|
}
|
|
523
523
|
//#endregion
|
|
524
524
|
//#region \0dsh-css:D:\Projects\deepseek-harness\yet-another-subagent\src\client\SettingsPage.module.css.mjs
|
|
525
|
-
const css = "/* Subagent settings section, in the settings-panel design language shared\n * with ModelsSection / GeneralSection: 14/22 body, 12/18 caption, 16/24 title,\n * capsule controls (h36 r18 primary, h28 r14 secondary), 32px fields,\n * border-l2 hairlines, and the editor as a filled module on the panel fill.\n *\n * Every color resolves through a --dsw-alias-* token (no literal colors). */\n\n.dun7765_section {\n display: flex;\n flex-direction: column;\n gap: 12px;\n max-width: 720px;\n color: var(--dsw-alias-label-primary);\n}\n\n.dun7765_title {\n margin: 0;\n font-size: 16px;\n line-height: 24px;\n font-weight: 500;\n color: var(--dsw-alias-label-primary);\n}\n\n.dun7765_intro {\n margin: 0;\n font-size: 14px;\n line-height: 22px;\n color: var(--dsw-alias-label-tertiary);\n}\n\n.dun7765_error {\n margin: 0;\n padding: 8px 12px;\n border: 1px solid var(--dsw-alias-state-error-primary);\n border-radius: 8px;\n background: var(--dsw-alias-interactive-bg-hover-danger);\n font-size: 12px;\n line-height: 18px;\n color: var(--dsw-alias-state-error-primary);\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 8px;\n}\n\n.dun7765_errorDismiss {\n flex: none;\n border: none;\n background: transparent;\n color: inherit;\n font-size: 16px;\n line-height: 1;\n cursor: pointer;\n padding: 0 4px;\n}\n\n.dun7765_rows {\n list-style: none;\n margin: 12px 0 0;\n padding: 0;\n display: flex;\n flex-direction: column;\n gap: 8px;\n}\n\n/* A configured profile: outlined on the panel fill, matching the rowCard\n * chrome in ModelsSection. */\n.dun7765_rowCard {\n border: 1px solid var(--dsw-alias-border-l2);\n border-radius: 12px;\n padding: 12px 14px;\n display: flex;\n flex-direction: column;\n gap: 12px;\n}\n\n.dun7765_rowHead {\n display: flex;\n align-items: center;\n gap: 10px;\n}\n\n/* Chevron toggle: a small square with two borders, rotated to point right\n * (collapsed) or down (expanded). Pure CSS, no icon font. */\n.dun7765_chevronButton {\n flex: none;\n width: 24px;\n height: 24px;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n border: none;\n background: transparent;\n color: var(--dsw-alias-label-secondary);\n cursor: pointer;\n padding: 0;\n border-radius: 4px;\n}\n\n.dun7765_chevronButton:hover {\n background: var(--dsw-alias-interactive-bg-hover-solid);\n color: var(--dsw-alias-label-primary);\n}\n\n/* Spacer that occupies the chevron slot on cards without a toggle (e.dun7765_g. the\n * new-draft card, which is always expanded). Keeps row-head alignment. */\n.dun7765_chevronSpacer {\n flex: none;\n width: 24px;\n height: 24px;\n}\n\n.dun7765_chevron {\n width: 7px;\n height: 7px;\n border-right: 1.5px solid currentColor;\n border-bottom: 1.5px solid currentColor;\n transform: rotate(-45deg);\n transition: transform 0.15s ease;\n}\n\n.dun7765_chevronExpanded {\n transform: rotate(45deg);\n}\n\n.dun7765_rowIdentity {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n min-width: 0;\n flex: 1 1 auto;\n}\n\n.dun7765_rowName {\n font-size: 14px;\n line-height: 22px;\n font-weight: 500;\n color: var(--dsw-alias-label-primary);\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.dun7765_rowNamePlaceholder {\n font-size: 14px;\n line-height: 22px;\n font-weight: 500;\n color: var(--dsw-alias-label-tertiary);\n font-style: italic;\n}\n\n/* Builtin badge: uses DSH <Pill> with a brand-colored override to mark\n * seed profiles. The Pill's default chrome is bg-layer-2/label-secondary;\n * this override shifts it to the brand fill for the \"builtin\" emphasis. */\n.dun7765_builtinBadge {\n height: 18px;\n padding: 0 6px;\n border-radius: 4px;\n font-size: 11px;\n line-height: 16px;\n font-weight: 500;\n background: var(--dsw-alias-brand-primary);\n color: var(--dsw-alias-label-primary-foreground);\n letter-spacing: 0.02em;\n}\n\n.dun7765_rowId {\n flex: none;\n padding: 1px 6px;\n border: 1px solid var(--dsw-alias-border-l3);\n border-radius: 4px;\n font-size: 11px;\n line-height: 16px;\n font-family: var(--dsw-font-markdown-code-block-small, monospace);\n color: var(--dsw-alias-label-secondary);\n}\n\n.dun7765_rowActions {\n display: inline-flex;\n align-items: center;\n gap: 4px;\n margin-left: auto;\n flex: none;\n}\n\n/* Editor surface: a filled module on the panel, matching ModelsSection's\n * editor chrome (bg-module-platform, r12, p14/16). */\n.dun7765_editor {\n border-radius: 12px;\n background: var(--dsw-alias-bg-module-platform);\n padding: 14px 16px;\n display: flex;\n flex-direction: column;\n gap: 14px;\n}\n\n.dun7765_field {\n display: flex;\n flex-direction: column;\n gap: 6px;\n}\n\n.dun7765_fieldLabel {\n display: inline-flex;\n align-items: center;\n gap: 10px;\n font-size: 12px;\n line-height: 18px;\n font-weight: 500;\n color: var(--dsw-alias-label-secondary);\n}\n\n.dun7765_fieldControl {\n display: flex;\n flex-direction: column;\n gap: 6px;\n}\n\n/* Input: matching ModelsSection .dun7765_input — h32, r8, border-l2, bg-layer-1. */\n.dun7765_input {\n box-sizing: border-box;\n width: 100%;\n height: 32px;\n padding: 0 10px;\n border: 1px solid var(--dsw-alias-border-l2);\n border-radius: 8px;\n font: inherit;\n font-size: 14px;\n line-height: 22px;\n background: var(--dsw-alias-bg-layer-1);\n color: var(--dsw-alias-label-primary);\n}\n\n.dun7765_input:focus {\n outline: none;\n border-color: var(--dsw-alias-brand-primary);\n}\n\n.dun7765_input::placeholder {\n color: var(--dsw-alias-label-dimmed);\n}\n\n.dun7765_input:disabled {\n opacity: 0.6;\n cursor: default;\n}\n\n/* DropdownPicker button: same chrome as .dun7765_input (h32, r8, border-l2,\n * bg-layer-1) but a button element with a trailing chevron icon. The\n * popup list is rendered by DSH's <Menu> component (portal mode). */\n.dun7765_dropdownButton {\n box-sizing: border-box;\n width: 100%;\n height: 32px;\n padding: 0 10px;\n border: 1px solid var(--dsw-alias-border-l2);\n border-radius: 8px;\n font: inherit;\n font-size: 14px;\n line-height: 22px;\n background: var(--dsw-alias-bg-layer-1);\n color: var(--dsw-alias-label-primary);\n cursor: pointer;\n display: inline-flex;\n align-items: center;\n justify-content: space-between;\n gap: 8px;\n}\n\n.dun7765_dropdownButton:hover:not(:disabled) {\n border-color: var(--dsw-alias-brand-primary);\n}\n\n.dun7765_dropdownButton:focus-visible {\n outline: none;\n border-color: var(--dsw-alias-brand-primary);\n box-shadow: 0 0 0 2px var(--dsw-alias-border-l3);\n}\n\n.dun7765_dropdownButton:disabled {\n opacity: 0.6;\n cursor: default;\n}\n\n.dun7765_dropdownButtonLabel {\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n flex: 1 1 auto;\n text-align: left;\n}\n\n.dun7765_dropdownCaret {\n flex: none;\n opacity: 0.6;\n}\n\n.dun7765_textarea {\n box-sizing: border-box;\n width: 100%;\n min-height: 64px;\n padding: 6px 10px;\n border: 1px solid var(--dsw-alias-border-l2);\n border-radius: 8px;\n font: inherit;\n font-size: 14px;\n line-height: 22px;\n background: var(--dsw-alias-bg-layer-1);\n color: var(--dsw-alias-label-primary);\n resize: vertical;\n}\n\n.dun7765_textarea:focus {\n outline: none;\n border-color: var(--dsw-alias-brand-primary);\n}\n\n.dun7765_textarea::placeholder {\n color: var(--dsw-alias-label-dimmed);\n}\n\n/* Radio group: inline, matching the model.dun7765_kind auto/manual picker. */\n.dun7765_radioGroup {\n display: flex;\n gap: 16px;\n flex-wrap: wrap;\n}\n\n.dun7765_radioOption {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n font-size: 14px;\n line-height: 22px;\n color: var(--dsw-alias-label-secondary);\n cursor: pointer;\n}\n\n.dun7765_radioOption input[type='radio'] {\n margin: 0;\n cursor: pointer;\n}\n\n/* Buttons: capsule controls matching ModelsSection (h36 r18 primary,\n * h28 r14 secondary in row context). */\n.dun7765_primaryButton,\n.dun7765_secondaryButton,\n.dun7765_dangerButton,\n.dun7765_addBlockButton {\n box-sizing: border-box;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n gap: 4px;\n height: 36px;\n padding: 0 14px;\n border: none;\n border-radius: 18px;\n font: inherit;\n font-size: 14px;\n line-height: 22px;\n cursor: pointer;\n}\n\n.dun7765_primaryButton {\n background: var(--dsw-alias-button-primary-fill);\n color: var(--dsw-alias-label-primary-foreground);\n}\n\n.dun7765_primaryButton:hover:not(:disabled) {\n background: var(--dsw-alias-button-primary-hover);\n}\n\n.dun7765_secondaryButton,\n.dun7765_addBlockButton {\n border: 1px solid var(--dsw-alias-border-l2);\n background: transparent;\n color: var(--dsw-alias-label-primary);\n}\n\n.dun7765_secondaryButton:hover:not(:disabled),\n.dun7765_addBlockButton:hover:not(:disabled) {\n background: var(--dsw-alias-interactive-bg-hover-solid);\n}\n\n.dun7765_dangerButton {\n background: transparent;\n color: var(--dsw-alias-state-error-primary);\n}\n\n.dun7765_dangerButton:hover:not(:disabled) {\n background: var(--dsw-alias-interactive-bg-hover-danger);\n}\n\n/* Row-context buttons go dense (h28 r14, 12/18). */\n.dun7765_rowActions .dun7765_secondaryButton,\n.dun7765_rowActions .dun7765_dangerButton {\n height: 28px;\n padding: 0 10px;\n border-radius: 14px;\n font-size: 12px;\n line-height: 18px;\n}\n\n.dun7765_rowActions .dun7765_primaryButton {\n height: 28px;\n padding: 0 10px;\n border-radius: 14px;\n font-size: 12px;\n line-height: 18px;\n}\n\n.dun7765_primaryButton:disabled,\n.dun7765_secondaryButton:disabled,\n.dun7765_dangerButton:disabled,\n.dun7765_addBlockButton:disabled {\n opacity: 0.4;\n cursor: default;\n}\n\n.dun7765_primaryButton:focus-visible,\n.dun7765_secondaryButton:focus-visible,\n.dun7765_dangerButton:focus-visible,\n.dun7765_addBlockButton:focus-visible {\n outline: none;\n box-shadow: 0 0 0 2px var(--dsw-alias-border-l3);\n}\n\n/* Add-profile action: a full-width dashed-outline place card matching\n * ModelsSection's addBlock — not a command pill. Clicking it reveals the\n * inline draft card (handled in JS); the button itself is the affordance. */\n.dun7765_addBlockButton {\n width: 100%;\n margin-top: 12px;\n border-style: dashed;\n border-radius: 12px;\n height: 40px;\n color: var(--dsw-alias-label-secondary);\n}\n\n.dun7765_addBlockButton:hover:not(:disabled) {\n color: var(--dsw-alias-label-primary);\n border-color: var(--dsw-alias-brand-primary);\n}\n\n/* Empty state. */\n.dun7765_empty {\n margin: 0;\n padding: 24px 12px;\n text-align: center;\n font-size: 14px;\n line-height: 22px;\n color: var(--dsw-alias-label-tertiary);\n}\n\n/* Modal confirm body text. */\n.dun7765_confirmText {\n margin: 0;\n font-size: 14px;\n line-height: 22px;\n color: var(--dsw-alias-label-secondary);\n}\n\n.dun7765_loading {\n padding: 12px;\n font-size: 14px;\n line-height: 22px;\n color: var(--dsw-alias-label-tertiary);\n}\n\n/* ─── Multi-select dropdown ─────────────────────────────────────────────── */\n\n.dun7765_multiSelect {\n position: relative;\n width: 100%;\n}\n\n.dun7765_msButton {\n box-sizing: border-box;\n width: 100%;\n height: 32px;\n padding: 0 10px;\n border: 1px solid var(--dsw-alias-border-l2);\n border-radius: 8px;\n font: inherit;\n font-size: 14px;\n line-height: 22px;\n background: var(--dsw-alias-bg-layer-1);\n color: var(--dsw-alias-label-primary);\n cursor: pointer;\n display: inline-flex;\n align-items: center;\n justify-content: space-between;\n gap: 8px;\n}\n\n.dun7765_msButton:hover {\n border-color: var(--dsw-alias-brand-primary);\n}\n\n.dun7765_msButton:focus-visible {\n outline: none;\n border-color: var(--dsw-alias-brand-primary);\n box-shadow: 0 0 0 2px var(--dsw-alias-border-l3);\n}\n\n.dun7765_msButtonLabel {\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n flex: 1 1 auto;\n text-align: left;\n}\n\n/* Caret: DSH IconChevronDownOutline14 icon. */\n.dun7765_msCaret {\n flex: none;\n opacity: 0.6;\n}\n\n.dun7765_msPopup {\n position: absolute;\n top: calc(100% + 4px);\n left: 0;\n right: 0;\n z-index: 10;\n border: 1px solid var(--dsw-alias-border-l2);\n border-radius: 8px;\n background: var(--dsw-alias-bg-layer-1);\n box-shadow: 0 4px 12px rgba(0, 0, 0, 0.12);\n display: flex;\n flex-direction: column;\n max-height: 280px;\n overflow: hidden;\n}\n\n.dun7765_msSearch {\n box-sizing: border-box;\n width: 100%;\n padding: 8px 10px;\n border: none;\n border-bottom: 1px solid var(--dsw-alias-border-l2);\n font: inherit;\n font-size: 14px;\n line-height: 22px;\n background: transparent;\n color: var(--dsw-alias-label-primary);\n}\n\n.dun7765_msSearch:focus {\n outline: none;\n}\n\n.dun7765_msSearch::placeholder {\n color: var(--dsw-alias-label-dimmed);\n}\n\n.dun7765_msActions {\n display: flex;\n justify-content: flex-end;\n padding: 6px 10px;\n border-bottom: 1px solid var(--dsw-alias-border-l2);\n}\n\n.dun7765_msActionLink {\n border: none;\n background: transparent;\n color: var(--dsw-alias-brand-primary);\n font: inherit;\n font-size: 12px;\n line-height: 18px;\n cursor: pointer;\n padding: 0;\n}\n\n.dun7765_msActionLink:hover {\n text-decoration: underline;\n}\n\n.dun7765_msList {\n list-style: none;\n margin: 0;\n padding: 4px 0;\n overflow-y: auto;\n flex: 1 1 auto;\n}\n\n.dun7765_msItem {\n margin: 0;\n}\n\n.dun7765_msItemLabel {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 6px 10px;\n cursor: pointer;\n font-size: 13px;\n line-height: 18px;\n color: var(--dsw-alias-label-primary);\n}\n\n.dun7765_msItemLabel:hover {\n background: var(--dsw-alias-interactive-bg-hover-solid);\n}\n\n.dun7765_msItemLabel input[type='checkbox'] {\n margin: 0;\n cursor: pointer;\n flex: none;\n}\n\n.dun7765_msItemName {\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n font-family: var(--dsw-font-markdown-code-block-small, monospace);\n}\n\n.dun7765_msEmpty {\n padding: 12px 10px;\n font-size: 13px;\n line-height: 18px;\n color: var(--dsw-alias-label-tertiary);\n text-align: center;\n}\n";
|
|
525
|
+
const css = "/* Subagent settings section, in the settings-panel design language shared\r\n * with ModelsSection / GeneralSection: 14/22 body, 12/18 caption, 16/24 title,\r\n * capsule controls (h36 r18 primary, h28 r14 secondary), 32px fields,\r\n * border-l2 hairlines, and the editor as a filled module on the panel fill.\r\n *\r\n * Every color resolves through a --dsw-alias-* token (no literal colors). */\r\n\r\n.dun7765_section {\r\n display: flex;\r\n flex-direction: column;\r\n gap: 12px;\r\n max-width: 720px;\r\n color: var(--dsw-alias-label-primary);\r\n}\r\n\r\n.dun7765_title {\r\n margin: 0;\r\n font-size: 16px;\r\n line-height: 24px;\r\n font-weight: 500;\r\n color: var(--dsw-alias-label-primary);\r\n}\r\n\r\n.dun7765_intro {\r\n margin: 0;\r\n font-size: 14px;\r\n line-height: 22px;\r\n color: var(--dsw-alias-label-tertiary);\r\n}\r\n\r\n.dun7765_error {\r\n margin: 0;\r\n padding: 8px 12px;\r\n border: 1px solid var(--dsw-alias-state-error-primary);\r\n border-radius: 8px;\r\n background: var(--dsw-alias-interactive-bg-hover-danger);\r\n font-size: 12px;\r\n line-height: 18px;\r\n color: var(--dsw-alias-state-error-primary);\r\n display: flex;\r\n align-items: center;\r\n justify-content: space-between;\r\n gap: 8px;\r\n}\r\n\r\n.dun7765_errorDismiss {\r\n flex: none;\r\n border: none;\r\n background: transparent;\r\n color: inherit;\r\n font-size: 16px;\r\n line-height: 1;\r\n cursor: pointer;\r\n padding: 0 4px;\r\n}\r\n\r\n.dun7765_rows {\r\n list-style: none;\r\n margin: 12px 0 0;\r\n padding: 0;\r\n display: flex;\r\n flex-direction: column;\r\n gap: 8px;\r\n}\r\n\r\n/* A configured profile: outlined on the panel fill, matching the rowCard\r\n * chrome in ModelsSection. */\r\n.dun7765_rowCard {\r\n border: 1px solid var(--dsw-alias-border-l2);\r\n border-radius: 12px;\r\n padding: 12px 14px;\r\n display: flex;\r\n flex-direction: column;\r\n gap: 12px;\r\n}\r\n\r\n.dun7765_rowHead {\r\n display: flex;\r\n align-items: center;\r\n gap: 10px;\r\n}\r\n\r\n/* Chevron toggle: a small square with two borders, rotated to point right\r\n * (collapsed) or down (expanded). Pure CSS, no icon font. */\r\n.dun7765_chevronButton {\r\n flex: none;\r\n width: 24px;\r\n height: 24px;\r\n display: inline-flex;\r\n align-items: center;\r\n justify-content: center;\r\n border: none;\r\n background: transparent;\r\n color: var(--dsw-alias-label-secondary);\r\n cursor: pointer;\r\n padding: 0;\r\n border-radius: 4px;\r\n}\r\n\r\n.dun7765_chevronButton:hover {\r\n background: var(--dsw-alias-interactive-bg-hover-solid);\r\n color: var(--dsw-alias-label-primary);\r\n}\r\n\r\n/* Spacer that occupies the chevron slot on cards without a toggle (e.dun7765_g. the\r\n * new-draft card, which is always expanded). Keeps row-head alignment. */\r\n.dun7765_chevronSpacer {\r\n flex: none;\r\n width: 24px;\r\n height: 24px;\r\n}\r\n\r\n.dun7765_chevron {\r\n width: 7px;\r\n height: 7px;\r\n border-right: 1.5px solid currentColor;\r\n border-bottom: 1.5px solid currentColor;\r\n transform: rotate(-45deg);\r\n transition: transform 0.15s ease;\r\n}\r\n\r\n.dun7765_chevronExpanded {\r\n transform: rotate(45deg);\r\n}\r\n\r\n.dun7765_rowIdentity {\r\n display: inline-flex;\r\n align-items: center;\r\n gap: 6px;\r\n min-width: 0;\r\n flex: 1 1 auto;\r\n}\r\n\r\n.dun7765_rowName {\r\n font-size: 14px;\r\n line-height: 22px;\r\n font-weight: 500;\r\n color: var(--dsw-alias-label-primary);\r\n overflow: hidden;\r\n text-overflow: ellipsis;\r\n white-space: nowrap;\r\n}\r\n\r\n.dun7765_rowNamePlaceholder {\r\n font-size: 14px;\r\n line-height: 22px;\r\n font-weight: 500;\r\n color: var(--dsw-alias-label-tertiary);\r\n font-style: italic;\r\n}\r\n\r\n/* Builtin badge: uses DSH <Pill> with a brand-colored override to mark\r\n * seed profiles. The Pill's default chrome is bg-layer-2/label-secondary;\r\n * this override shifts it to the brand fill for the \"builtin\" emphasis. */\r\n.dun7765_builtinBadge {\r\n height: 18px;\r\n padding: 0 6px;\r\n border-radius: 4px;\r\n font-size: 11px;\r\n line-height: 16px;\r\n font-weight: 500;\r\n background: var(--dsw-alias-brand-primary);\r\n color: var(--dsw-alias-label-primary-foreground);\r\n letter-spacing: 0.02em;\r\n}\r\n\r\n.dun7765_rowId {\r\n flex: none;\r\n padding: 1px 6px;\r\n border: 1px solid var(--dsw-alias-border-l3);\r\n border-radius: 4px;\r\n font-size: 11px;\r\n line-height: 16px;\r\n font-family: var(--dsw-font-markdown-code-block-small, monospace);\r\n color: var(--dsw-alias-label-secondary);\r\n}\r\n\r\n.dun7765_rowActions {\r\n display: inline-flex;\r\n align-items: center;\r\n gap: 4px;\r\n margin-left: auto;\r\n flex: none;\r\n}\r\n\r\n/* Editor surface: a filled module on the panel, matching ModelsSection's\r\n * editor chrome (bg-module-platform, r12, p14/16). */\r\n.dun7765_editor {\r\n border-radius: 12px;\r\n background: var(--dsw-alias-bg-module-platform);\r\n padding: 14px 16px;\r\n display: flex;\r\n flex-direction: column;\r\n gap: 14px;\r\n}\r\n\r\n.dun7765_field {\r\n display: flex;\r\n flex-direction: column;\r\n gap: 6px;\r\n}\r\n\r\n.dun7765_fieldLabel {\r\n display: inline-flex;\r\n align-items: center;\r\n gap: 10px;\r\n font-size: 12px;\r\n line-height: 18px;\r\n font-weight: 500;\r\n color: var(--dsw-alias-label-secondary);\r\n}\r\n\r\n.dun7765_fieldControl {\r\n display: flex;\r\n flex-direction: column;\r\n gap: 6px;\r\n}\r\n\r\n/* Input: matching ModelsSection .dun7765_input — h32, r8, border-l2, bg-layer-1. */\r\n.dun7765_input {\r\n box-sizing: border-box;\r\n width: 100%;\r\n height: 32px;\r\n padding: 0 10px;\r\n border: 1px solid var(--dsw-alias-border-l2);\r\n border-radius: 8px;\r\n font: inherit;\r\n font-size: 14px;\r\n line-height: 22px;\r\n background: var(--dsw-alias-bg-layer-1);\r\n color: var(--dsw-alias-label-primary);\r\n}\r\n\r\n.dun7765_input:focus {\r\n outline: none;\r\n border-color: var(--dsw-alias-brand-primary);\r\n}\r\n\r\n.dun7765_input::placeholder {\r\n color: var(--dsw-alias-label-dimmed);\r\n}\r\n\r\n.dun7765_input:disabled {\r\n opacity: 0.6;\r\n cursor: default;\r\n}\r\n\r\n/* DropdownPicker button: same chrome as .dun7765_input (h32, r8, border-l2,\r\n * bg-layer-1) but a button element with a trailing chevron icon. The\r\n * popup list is rendered by DSH's <Menu> component (portal mode). */\r\n.dun7765_dropdownButton {\r\n box-sizing: border-box;\r\n width: 100%;\r\n height: 32px;\r\n padding: 0 10px;\r\n border: 1px solid var(--dsw-alias-border-l2);\r\n border-radius: 8px;\r\n font: inherit;\r\n font-size: 14px;\r\n line-height: 22px;\r\n background: var(--dsw-alias-bg-layer-1);\r\n color: var(--dsw-alias-label-primary);\r\n cursor: pointer;\r\n display: inline-flex;\r\n align-items: center;\r\n justify-content: space-between;\r\n gap: 8px;\r\n}\r\n\r\n.dun7765_dropdownButton:hover:not(:disabled) {\r\n border-color: var(--dsw-alias-brand-primary);\r\n}\r\n\r\n.dun7765_dropdownButton:focus-visible {\r\n outline: none;\r\n border-color: var(--dsw-alias-brand-primary);\r\n box-shadow: 0 0 0 2px var(--dsw-alias-border-l3);\r\n}\r\n\r\n.dun7765_dropdownButton:disabled {\r\n opacity: 0.6;\r\n cursor: default;\r\n}\r\n\r\n.dun7765_dropdownButtonLabel {\r\n overflow: hidden;\r\n text-overflow: ellipsis;\r\n white-space: nowrap;\r\n flex: 1 1 auto;\r\n text-align: left;\r\n}\r\n\r\n.dun7765_dropdownCaret {\r\n flex: none;\r\n opacity: 0.6;\r\n}\r\n\r\n.dun7765_textarea {\r\n box-sizing: border-box;\r\n width: 100%;\r\n min-height: 64px;\r\n padding: 6px 10px;\r\n border: 1px solid var(--dsw-alias-border-l2);\r\n border-radius: 8px;\r\n font: inherit;\r\n font-size: 14px;\r\n line-height: 22px;\r\n background: var(--dsw-alias-bg-layer-1);\r\n color: var(--dsw-alias-label-primary);\r\n resize: vertical;\r\n}\r\n\r\n.dun7765_textarea:focus {\r\n outline: none;\r\n border-color: var(--dsw-alias-brand-primary);\r\n}\r\n\r\n.dun7765_textarea::placeholder {\r\n color: var(--dsw-alias-label-dimmed);\r\n}\r\n\r\n/* Radio group: inline, matching the model.dun7765_kind auto/manual picker. */\r\n.dun7765_radioGroup {\r\n display: flex;\r\n gap: 16px;\r\n flex-wrap: wrap;\r\n}\r\n\r\n.dun7765_radioOption {\r\n display: inline-flex;\r\n align-items: center;\r\n gap: 6px;\r\n font-size: 14px;\r\n line-height: 22px;\r\n color: var(--dsw-alias-label-secondary);\r\n cursor: pointer;\r\n}\r\n\r\n.dun7765_radioOption input[type='radio'] {\r\n margin: 0;\r\n cursor: pointer;\r\n}\r\n\r\n/* Buttons: capsule controls matching ModelsSection (h36 r18 primary,\r\n * h28 r14 secondary in row context). */\r\n.dun7765_primaryButton,\r\n.dun7765_secondaryButton,\r\n.dun7765_dangerButton,\r\n.dun7765_addBlockButton {\r\n box-sizing: border-box;\r\n display: inline-flex;\r\n align-items: center;\r\n justify-content: center;\r\n gap: 4px;\r\n height: 36px;\r\n padding: 0 14px;\r\n border: none;\r\n border-radius: 18px;\r\n font: inherit;\r\n font-size: 14px;\r\n line-height: 22px;\r\n cursor: pointer;\r\n}\r\n\r\n.dun7765_primaryButton {\r\n background: var(--dsw-alias-button-primary-fill);\r\n color: var(--dsw-alias-label-primary-foreground);\r\n}\r\n\r\n.dun7765_primaryButton:hover:not(:disabled) {\r\n background: var(--dsw-alias-button-primary-hover);\r\n}\r\n\r\n.dun7765_secondaryButton,\r\n.dun7765_addBlockButton {\r\n border: 1px solid var(--dsw-alias-border-l2);\r\n background: transparent;\r\n color: var(--dsw-alias-label-primary);\r\n}\r\n\r\n.dun7765_secondaryButton:hover:not(:disabled),\r\n.dun7765_addBlockButton:hover:not(:disabled) {\r\n background: var(--dsw-alias-interactive-bg-hover-solid);\r\n}\r\n\r\n.dun7765_dangerButton {\r\n background: transparent;\r\n color: var(--dsw-alias-state-error-primary);\r\n}\r\n\r\n.dun7765_dangerButton:hover:not(:disabled) {\r\n background: var(--dsw-alias-interactive-bg-hover-danger);\r\n}\r\n\r\n/* Row-context buttons go dense (h28 r14, 12/18). */\r\n.dun7765_rowActions .dun7765_secondaryButton,\r\n.dun7765_rowActions .dun7765_dangerButton {\r\n height: 28px;\r\n padding: 0 10px;\r\n border-radius: 14px;\r\n font-size: 12px;\r\n line-height: 18px;\r\n}\r\n\r\n.dun7765_rowActions .dun7765_primaryButton {\r\n height: 28px;\r\n padding: 0 10px;\r\n border-radius: 14px;\r\n font-size: 12px;\r\n line-height: 18px;\r\n}\r\n\r\n.dun7765_primaryButton:disabled,\r\n.dun7765_secondaryButton:disabled,\r\n.dun7765_dangerButton:disabled,\r\n.dun7765_addBlockButton:disabled {\r\n opacity: 0.4;\r\n cursor: default;\r\n}\r\n\r\n.dun7765_primaryButton:focus-visible,\r\n.dun7765_secondaryButton:focus-visible,\r\n.dun7765_dangerButton:focus-visible,\r\n.dun7765_addBlockButton:focus-visible {\r\n outline: none;\r\n box-shadow: 0 0 0 2px var(--dsw-alias-border-l3);\r\n}\r\n\r\n/* Add-profile action: a full-width dashed-outline place card matching\r\n * ModelsSection's addBlock — not a command pill. Clicking it reveals the\r\n * inline draft card (handled in JS); the button itself is the affordance. */\r\n.dun7765_addBlockButton {\r\n width: 100%;\r\n margin-top: 12px;\r\n border-style: dashed;\r\n border-radius: 12px;\r\n height: 40px;\r\n color: var(--dsw-alias-label-secondary);\r\n}\r\n\r\n.dun7765_addBlockButton:hover:not(:disabled) {\r\n color: var(--dsw-alias-label-primary);\r\n border-color: var(--dsw-alias-brand-primary);\r\n}\r\n\r\n/* Empty state. */\r\n.dun7765_empty {\r\n margin: 0;\r\n padding: 24px 12px;\r\n text-align: center;\r\n font-size: 14px;\r\n line-height: 22px;\r\n color: var(--dsw-alias-label-tertiary);\r\n}\r\n\r\n/* Modal confirm body text. */\r\n.dun7765_confirmText {\r\n margin: 0;\r\n font-size: 14px;\r\n line-height: 22px;\r\n color: var(--dsw-alias-label-secondary);\r\n}\r\n\r\n/* Repair history block: a discrete action below the add-profile button. */\r\n.dun7765_repairBlock {\r\n margin-top: 8px;\r\n}\r\n\r\n.dun7765_repairBlock button {\r\n width: 100%;\r\n}\r\n\r\n/* Repair result stats container. */\r\n.dun7765_repairStats {\r\n display: flex;\r\n flex-direction: column;\r\n gap: 4px;\r\n}\r\n\r\n/* Repair error list inside the result modal. */\r\n.dun7765_repairErrorList {\r\n margin: 8px 0 0;\r\n padding: 0 0 0 16px;\r\n display: flex;\r\n flex-direction: column;\r\n gap: 4px;\r\n max-height: 200px;\r\n overflow-y: auto;\r\n}\r\n\r\n.dun7765_loading {\r\n padding: 12px;\r\n font-size: 14px;\r\n line-height: 22px;\r\n color: var(--dsw-alias-label-tertiary);\r\n}\r\n\r\n/* ─── Multi-select dropdown ─────────────────────────────────────────────── */\r\n\r\n.dun7765_multiSelect {\r\n position: relative;\r\n width: 100%;\r\n}\r\n\r\n.dun7765_msButton {\r\n box-sizing: border-box;\r\n width: 100%;\r\n height: 32px;\r\n padding: 0 10px;\r\n border: 1px solid var(--dsw-alias-border-l2);\r\n border-radius: 8px;\r\n font: inherit;\r\n font-size: 14px;\r\n line-height: 22px;\r\n background: var(--dsw-alias-bg-layer-1);\r\n color: var(--dsw-alias-label-primary);\r\n cursor: pointer;\r\n display: inline-flex;\r\n align-items: center;\r\n justify-content: space-between;\r\n gap: 8px;\r\n}\r\n\r\n.dun7765_msButton:hover {\r\n border-color: var(--dsw-alias-brand-primary);\r\n}\r\n\r\n.dun7765_msButton:focus-visible {\r\n outline: none;\r\n border-color: var(--dsw-alias-brand-primary);\r\n box-shadow: 0 0 0 2px var(--dsw-alias-border-l3);\r\n}\r\n\r\n.dun7765_msButtonLabel {\r\n overflow: hidden;\r\n text-overflow: ellipsis;\r\n white-space: nowrap;\r\n flex: 1 1 auto;\r\n text-align: left;\r\n}\r\n\r\n/* Caret: DSH IconChevronDownOutline14 icon. */\r\n.dun7765_msCaret {\r\n flex: none;\r\n opacity: 0.6;\r\n}\r\n\r\n.dun7765_msPopup {\r\n position: absolute;\r\n top: calc(100% + 4px);\r\n left: 0;\r\n right: 0;\r\n z-index: 10;\r\n border: 1px solid var(--dsw-alias-border-l2);\r\n border-radius: 8px;\r\n background: var(--dsw-alias-bg-layer-1);\r\n box-shadow: 0 4px 12px rgba(0, 0, 0, 0.12);\r\n display: flex;\r\n flex-direction: column;\r\n max-height: 280px;\r\n overflow: hidden;\r\n}\r\n\r\n.dun7765_msSearch {\r\n box-sizing: border-box;\r\n width: 100%;\r\n padding: 8px 10px;\r\n border: none;\r\n border-bottom: 1px solid var(--dsw-alias-border-l2);\r\n font: inherit;\r\n font-size: 14px;\r\n line-height: 22px;\r\n background: transparent;\r\n color: var(--dsw-alias-label-primary);\r\n}\r\n\r\n.dun7765_msSearch:focus {\r\n outline: none;\r\n}\r\n\r\n.dun7765_msSearch::placeholder {\r\n color: var(--dsw-alias-label-dimmed);\r\n}\r\n\r\n.dun7765_msActions {\r\n display: flex;\r\n justify-content: flex-end;\r\n padding: 6px 10px;\r\n border-bottom: 1px solid var(--dsw-alias-border-l2);\r\n}\r\n\r\n.dun7765_msActionLink {\r\n border: none;\r\n background: transparent;\r\n color: var(--dsw-alias-brand-primary);\r\n font: inherit;\r\n font-size: 12px;\r\n line-height: 18px;\r\n cursor: pointer;\r\n padding: 0;\r\n}\r\n\r\n.dun7765_msActionLink:hover {\r\n text-decoration: underline;\r\n}\r\n\r\n.dun7765_msList {\r\n list-style: none;\r\n margin: 0;\r\n padding: 4px 0;\r\n overflow-y: auto;\r\n flex: 1 1 auto;\r\n}\r\n\r\n.dun7765_msItem {\r\n margin: 0;\r\n}\r\n\r\n.dun7765_msItemLabel {\r\n display: flex;\r\n align-items: center;\r\n gap: 8px;\r\n padding: 6px 10px;\r\n cursor: pointer;\r\n font-size: 13px;\r\n line-height: 18px;\r\n color: var(--dsw-alias-label-primary);\r\n}\r\n\r\n.dun7765_msItemLabel:hover {\r\n background: var(--dsw-alias-interactive-bg-hover-solid);\r\n}\r\n\r\n.dun7765_msItemLabel input[type='checkbox'] {\r\n margin: 0;\r\n cursor: pointer;\r\n flex: none;\r\n}\r\n\r\n.dun7765_msItemName {\r\n overflow: hidden;\r\n text-overflow: ellipsis;\r\n white-space: nowrap;\r\n font-family: var(--dsw-font-markdown-code-block-small, monospace);\r\n}\r\n\r\n.dun7765_msEmpty {\r\n padding: 12px 10px;\r\n font-size: 13px;\r\n line-height: 18px;\r\n color: var(--dsw-alias-label-tertiary);\r\n text-align: center;\r\n}\r\n";
|
|
526
526
|
const classMap = {
|
|
527
527
|
"section": "dun7765_section",
|
|
528
528
|
"title": "dun7765_title",
|
|
@@ -561,6 +561,9 @@ window.__ModuleLoader__.load({
|
|
|
561
561
|
"addBlockButton": "dun7765_addBlockButton",
|
|
562
562
|
"empty": "dun7765_empty",
|
|
563
563
|
"confirmText": "dun7765_confirmText",
|
|
564
|
+
"repairBlock": "dun7765_repairBlock",
|
|
565
|
+
"repairStats": "dun7765_repairStats",
|
|
566
|
+
"repairErrorList": "dun7765_repairErrorList",
|
|
564
567
|
"loading": "dun7765_loading",
|
|
565
568
|
"multiSelect": "dun7765_multiSelect",
|
|
566
569
|
"msButton": "dun7765_msButton",
|
|
@@ -650,6 +653,10 @@ window.__ModuleLoader__.load({
|
|
|
650
653
|
const [loading, setLoading] = (0, react.useState)(true);
|
|
651
654
|
const [error, setError] = (0, react.useState)(void 0);
|
|
652
655
|
const [confirmDelete, setConfirmDelete] = (0, react.useState)(void 0);
|
|
656
|
+
const [repairConfirmOpen, setRepairConfirmOpen] = (0, react.useState)(false);
|
|
657
|
+
const [repairRunning, setRepairRunning] = (0, react.useState)(false);
|
|
658
|
+
const [repairStats, setRepairStats] = (0, react.useState)(void 0);
|
|
659
|
+
const [repairError, setRepairError] = (0, react.useState)(void 0);
|
|
653
660
|
const refresh = (0, react.useCallback)(async () => {
|
|
654
661
|
setLoading(true);
|
|
655
662
|
setError(void 0);
|
|
@@ -706,6 +713,20 @@ window.__ModuleLoader__.load({
|
|
|
706
713
|
setExpanded(next);
|
|
707
714
|
} else setError(result.error.message);
|
|
708
715
|
}, [expanded, rpc]);
|
|
716
|
+
const runRepair = (0, react.useCallback)(async () => {
|
|
717
|
+
setRepairConfirmOpen(false);
|
|
718
|
+
setRepairRunning(true);
|
|
719
|
+
setRepairError(void 0);
|
|
720
|
+
try {
|
|
721
|
+
const result = await callRpc(rpc, "sessions.repair", {});
|
|
722
|
+
if (result.ok) setRepairStats(result.value);
|
|
723
|
+
else setRepairError(result.error.message);
|
|
724
|
+
} catch (err) {
|
|
725
|
+
setRepairError(err instanceof Error ? err.message : String(err));
|
|
726
|
+
} finally {
|
|
727
|
+
setRepairRunning(false);
|
|
728
|
+
}
|
|
729
|
+
}, [rpc]);
|
|
709
730
|
const patchDraft = (id, patch) => {
|
|
710
731
|
setDrafts((prev) => prev.map((d) => d.id === id ? {
|
|
711
732
|
...d,
|
|
@@ -777,6 +798,97 @@ window.__ModuleLoader__.load({
|
|
|
777
798
|
onClick: () => setAddingNew(true),
|
|
778
799
|
children: t("page.add")
|
|
779
800
|
}),
|
|
801
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
802
|
+
className: classMap.repairBlock,
|
|
803
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
804
|
+
type: "button",
|
|
805
|
+
className: classMap.secondaryButton,
|
|
806
|
+
disabled: repairRunning,
|
|
807
|
+
onClick: () => setRepairConfirmOpen(true),
|
|
808
|
+
children: repairRunning ? t("repair.running") : t("repair.button")
|
|
809
|
+
})
|
|
810
|
+
}),
|
|
811
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)(_deepseek_ai_dsh_client_ui_primitives.Modal, {
|
|
812
|
+
open: repairConfirmOpen,
|
|
813
|
+
onClose: () => {
|
|
814
|
+
setRepairConfirmOpen(false);
|
|
815
|
+
},
|
|
816
|
+
title: t("repair.confirm.title"),
|
|
817
|
+
footer: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
818
|
+
type: "button",
|
|
819
|
+
className: classMap.secondaryButton,
|
|
820
|
+
onClick: () => {
|
|
821
|
+
setRepairConfirmOpen(false);
|
|
822
|
+
},
|
|
823
|
+
children: t("repair.confirm.cancel")
|
|
824
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
825
|
+
type: "button",
|
|
826
|
+
className: classMap.primaryButton,
|
|
827
|
+
onClick: () => {
|
|
828
|
+
runRepair();
|
|
829
|
+
},
|
|
830
|
+
children: t("repair.confirm.proceed")
|
|
831
|
+
})] }),
|
|
832
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
833
|
+
className: classMap.confirmText,
|
|
834
|
+
children: t("repair.confirm.body")
|
|
835
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
836
|
+
className: classMap.confirmText,
|
|
837
|
+
children: t("repair.confirm.warning")
|
|
838
|
+
})]
|
|
839
|
+
}),
|
|
840
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Modal, {
|
|
841
|
+
open: repairStats !== void 0 || repairError !== void 0,
|
|
842
|
+
onClose: () => {
|
|
843
|
+
setRepairStats(void 0);
|
|
844
|
+
setRepairError(void 0);
|
|
845
|
+
},
|
|
846
|
+
title: t("repair.result.title"),
|
|
847
|
+
footer: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
848
|
+
type: "button",
|
|
849
|
+
className: classMap.secondaryButton,
|
|
850
|
+
onClick: () => {
|
|
851
|
+
setRepairStats(void 0);
|
|
852
|
+
setRepairError(void 0);
|
|
853
|
+
},
|
|
854
|
+
children: t("repair.result.close")
|
|
855
|
+
}),
|
|
856
|
+
children: repairError !== void 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("p", {
|
|
857
|
+
className: classMap.error,
|
|
858
|
+
children: [
|
|
859
|
+
t("repair.error"),
|
|
860
|
+
": ",
|
|
861
|
+
repairError
|
|
862
|
+
]
|
|
863
|
+
}) : repairStats !== void 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
864
|
+
className: classMap.repairStats,
|
|
865
|
+
children: [
|
|
866
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
867
|
+
className: classMap.confirmText,
|
|
868
|
+
children: t("repair.result.scanned").replace("{n}", String(repairStats.scanned))
|
|
869
|
+
}),
|
|
870
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
871
|
+
className: classMap.confirmText,
|
|
872
|
+
children: t("repair.result.repaired").replace("{n}", String(repairStats.repaired))
|
|
873
|
+
}),
|
|
874
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
875
|
+
className: classMap.confirmText,
|
|
876
|
+
children: t("repair.result.skipped").replace("{n}", String(repairStats.skipped))
|
|
877
|
+
}),
|
|
878
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
879
|
+
className: classMap.confirmText,
|
|
880
|
+
children: t("repair.result.errors").replace("{n}", String(repairStats.errors.length))
|
|
881
|
+
}),
|
|
882
|
+
repairStats.errors.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("ul", {
|
|
883
|
+
className: classMap.repairErrorList,
|
|
884
|
+
children: repairStats.errors.map((e, i) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("li", {
|
|
885
|
+
className: classMap.confirmText,
|
|
886
|
+
children: t("repair.result.errorEntry").replace("{path}", e.path).replace("{message}", e.message)
|
|
887
|
+
}, i))
|
|
888
|
+
})
|
|
889
|
+
]
|
|
890
|
+
}) : null
|
|
891
|
+
}),
|
|
780
892
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Modal, {
|
|
781
893
|
open: confirmDelete !== void 0,
|
|
782
894
|
onClose: () => {
|
|
@@ -1287,7 +1399,22 @@ window.__ModuleLoader__.load({
|
|
|
1287
1399
|
"tree.calling": "calling",
|
|
1288
1400
|
"tree.state.running": "running",
|
|
1289
1401
|
"tree.state.idle": "idle",
|
|
1290
|
-
"tree.state.settled": "settled"
|
|
1402
|
+
"tree.state.settled": "settled",
|
|
1403
|
+
"repair.button": "Repair session history",
|
|
1404
|
+
"repair.confirm.title": "Repair session history?",
|
|
1405
|
+
"repair.confirm.body": "Scans every session log under $DSH_HOME/sessions and stamps \"ignorable\" on legacy ya-subagent/started events so the harness can load them again. Each modified file is backed up to .bak first.",
|
|
1406
|
+
"repair.confirm.warning": "If dsh is running, a session being written right now may conflict; prefer running this when no agent is active.",
|
|
1407
|
+
"repair.confirm.cancel": "Cancel",
|
|
1408
|
+
"repair.confirm.proceed": "Repair",
|
|
1409
|
+
"repair.running": "Repairing…",
|
|
1410
|
+
"repair.result.title": "Repair complete",
|
|
1411
|
+
"repair.result.scanned": "Scanned: {n}",
|
|
1412
|
+
"repair.result.repaired": "Repaired: {n}",
|
|
1413
|
+
"repair.result.skipped": "Skipped (already clean): {n}",
|
|
1414
|
+
"repair.result.errors": "Errors: {n}",
|
|
1415
|
+
"repair.result.errorEntry": "{path}: {message}",
|
|
1416
|
+
"repair.result.close": "Close",
|
|
1417
|
+
"repair.error": "Repair failed"
|
|
1291
1418
|
};
|
|
1292
1419
|
/** Chinese dictionary. */
|
|
1293
1420
|
const zh = {
|
|
@@ -1352,7 +1479,22 @@ window.__ModuleLoader__.load({
|
|
|
1352
1479
|
"tree.calling": "调用中",
|
|
1353
1480
|
"tree.state.running": "运行中",
|
|
1354
1481
|
"tree.state.idle": "空闲",
|
|
1355
|
-
"tree.state.settled": "已结束"
|
|
1482
|
+
"tree.state.settled": "已结束",
|
|
1483
|
+
"repair.button": "修复历史会话",
|
|
1484
|
+
"repair.confirm.title": "修复历史会话?",
|
|
1485
|
+
"repair.confirm.body": "将扫描 $DSH_HOME/sessions 下的所有会话日志,为遗留的 ya-subagent/started 事件补上 \"ignorable\" 标记,使 harness 能重新加载。每个被修改的文件会先备份为 .bak。",
|
|
1486
|
+
"repair.confirm.warning": "若 dsh 正在运行,正在写入的会话可能冲突;建议在无活跃代理时执行。",
|
|
1487
|
+
"repair.confirm.cancel": "取消",
|
|
1488
|
+
"repair.confirm.proceed": "修复",
|
|
1489
|
+
"repair.running": "修复中…",
|
|
1490
|
+
"repair.result.title": "修复完成",
|
|
1491
|
+
"repair.result.scanned": "扫描:{n}",
|
|
1492
|
+
"repair.result.repaired": "已修复:{n}",
|
|
1493
|
+
"repair.result.skipped": "跳过(已干净):{n}",
|
|
1494
|
+
"repair.result.errors": "错误:{n}",
|
|
1495
|
+
"repair.result.errorEntry": "{path}:{message}",
|
|
1496
|
+
"repair.result.close": "关闭",
|
|
1497
|
+
"repair.error": "修复失败"
|
|
1356
1498
|
};
|
|
1357
1499
|
//#endregion
|
|
1358
1500
|
//#region src/client/index.ts
|