dsh-plugin-prompt-tool 0.3.0 → 0.3.1
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 +75 -85
- package/lib/client.js +68 -3
- package/lib/client.js.map +1 -1
- package/lib/index.d.mts +3 -2
- package/lib/index.mjs +33 -7
- package/lib/preset-core.d.mts +2 -2
- package/lib/preset-core.mjs +11 -6
- package/package.json +1 -1
- package/plan.md +4 -0
- package/upstream/dsh-anchored-standard/REVISION +1 -1
- package/upstream/dsh-anchored-standard/preset/agent.cordis.yml +22 -11
- package/upstream/dsh-anchored-standard/preset/custom-bash.mjs +98 -5
package/README.md
CHANGED
|
@@ -1,53 +1,48 @@
|
|
|
1
1
|
# 提示词工具(dsh-plugin-prompt-tool)
|
|
2
2
|
|
|
3
|
-
DSH
|
|
3
|
+
把「Anchored Standard + dsh-router-standard 最优组合」做成 DSH 全家桶里的一键安装插件:插件启动时生成并维护 `~/.dsh/.agent-presets/prompt-tool/` 预设,首轮模型请求只看到官方 Minimal 精确双工具——持久 `bash` 与 `str_replace_editor`——和正确的 persona,没有运行时上下文与指令注入;锚定建立后进入 resident 目录,恢复常规注入,并在确认轨迹后注入 `preset.md`。同时提供 Web 界面在线编辑 `preset.md` / `AGENTS.md`、切换全部开关,以及可开关的 skills 技能层。全部通过官方插件接口实现,不修改 DSH 源码。
|
|
4
4
|
|
|
5
|
-
##
|
|
5
|
+
## 原理
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
|---|---|---|
|
|
9
|
-
| [xiaobright/dsh-anchored-standard](https://github.com/xiaobright/dsh-anchored-standard) | 上游,内联快照 | 两阶段首轮锚定、tool-bootstrap、context-gate、resident 目录与按需解锁 |
|
|
10
|
-
| [yjh051108/dsh-router-standard](https://github.com/yjh051108/dsh-router-standard) | 参考 | 首轮结构、追加任务引导、Flash 弱路由人设与三锚、子代理方案 |
|
|
11
|
-
| [yjh051108/dsh-super-injector](https://github.com/yjh051108/dsh-super-injector) | 参考 | 缓存铁律、工具面成本原则 |
|
|
7
|
+
DeepSeek V4 会强烈依赖 API 中可见的**首轮工具目录与 persona** 选择执行轨迹。完整 Standard 目录与自动注入在场会破坏 Minimal 轨迹,而全程 Minimal 又会失去重型工具。本项目把「首次轨迹选择」与「后续完整工具能力」拆开:
|
|
12
8
|
|
|
13
|
-
|
|
14
|
-
|
|
9
|
+
1. **干净首轮**:`context-gate` 清空首轮 runtime-context 并剥离自动注入;`tool-bootstrap` 只暴露 Minimal 双工具;`router-first-turn` 按主会话模型替换 persona——Pro 使用训练原句,Flash 自动采用 dsh-router-standard 的 Flash 弱路由人设(build/fix 分类 + 回顾锚 + 反跑题锚 + 先深想再产出)。
|
|
10
|
+
2. **晋升**:首次持久 `tool/call` 或 `assistant/message`(先到者为准)落地后,目录进入 resident 集——bootstrap 双工具 + 发现工具 + 已解锁工具;上下文与注入恢复,重型工具经 `dev_tool_search` 按需解锁。
|
|
11
|
+
3. **任务引导**:可选 `near-anchor` 在首条真实用户消息后追加一次近距离首句引导(we/let 按任务自动选择);Flash 主会话晋升后 `router-guide` 按任务复杂度追加每轮深度引导。
|
|
12
|
+
4. **提示词注入**:we 锚定确认后把 `preset.md` 作为用户消息注入一次;we 未确认最多等一轮兜底,绝不卡死。
|
|
13
|
+
5. **子代理**:目录直接全量放行(仍受调用方工具白名单过滤);可选 `subagentFlash` 固定 Flash 路由 + 任务分类人设 + 三锚。
|
|
15
14
|
|
|
16
|
-
|
|
15
|
+
阶段全部从持久 session events 推导,resume / reload 不丢失状态。
|
|
17
16
|
|
|
18
|
-
|
|
19
|
-
- **按需层**:扫描 `skills/*/SKILL.md` 注册可开关技能,内容只来自技能自身。
|
|
20
|
-
- **锚定层**:生成独立的 `~/.dsh/.agent-presets/prompt-tool/` 预设,承载首轮工具引导、上下文闸门、任务引导注入与提示词注入。
|
|
21
|
-
- **Web 界面**:自建回环设置桥,在线编辑 `preset.md` 与 `AGENTS.md`,切换全部开关;不占用模型设置区。
|
|
22
|
-
- **TUI(终端界面)命令**:`/prompt-tool status` 查看状态,`/prompt-tool on|off|toggle <开关>` 切换。
|
|
23
|
-
- **上游管理**:上游 dsh-anchored-standard 以内联快照形式放在 `upstream/`,`pnpm sync:anchored` 刷新;不再使用 git 子模块。
|
|
17
|
+
## 稳定化控制
|
|
24
18
|
|
|
25
|
-
|
|
19
|
+
全部在生成 preset 的 `agent.cordis.yml` 行中配置:
|
|
26
20
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
21
|
+
- `bootstrapMaxTokens`:首轮输出封顶。`0` = 本项目默认不设封顶(Web 界面显示 256000,即不设上限);正整数 = 请求 #1 的 `maxTokens`,晋升后自动剥离,不会焊进后续请求。不锁定 1024,任意正整数均可。
|
|
22
|
+
- `context-gate`:未晋升期间关闭两条统一注入路径,pre-step 只保留 claimed 批次 + `allowKinds`(放行用户技能手势与 `near-anchor` / `router-guide`);晋升后差分恢复一条 runtime-context 消息。
|
|
23
|
+
- `tool-bootstrap`:`promoteOn: either` 避免纯文字首答永久困在双工具;compaction 后回到 bootstrap + `compactionTools` 受控阶段。
|
|
24
|
+
- `router-first-turn`:只替换 persona 段,保留 plan-mode 段与第三方 section;首轮隐藏 `mnemon:*` 自动注入段,晋升后恢复。
|
|
25
|
+
- `near-anchor`:行为引导放在真实用户消息之后(近距离零衰减),只要求首句一次;复杂规划任务放行 Let 深度路径,日常任务锚 We。
|
|
26
|
+
- `router-guide`:简单任务快速收敛,复杂任务深度引导;子代理不注入,首轮不注入。
|
|
27
|
+
- `prompt-injector`:注入状态以持久事件为准,跨进程重启 / 插件热重载不重复注入。
|
|
28
|
+
- `injectAgentsPrompt`:开启时用 `AGENTS.md` 内容替换上游 instruction-hint 提示文本;关闭时保留上游原版 hint。
|
|
29
|
+
- `skillSwitches`:扫描 `skills/*/SKILL.md` 注册可开关技能,未列出的技能默认开启。
|
|
30
|
+
- `subagentFlash`:检测不到 DeepSeek 模型路由时 Web/TUI 禁用并强制降级为关闭。
|
|
36
31
|
|
|
37
|
-
|
|
32
|
+
## 安装
|
|
38
33
|
|
|
39
34
|
```sh
|
|
40
35
|
# 1. 先安装宿主服务(提供 webServer 等本插件依赖的服务)
|
|
41
36
|
dsh plugin --profile prompt-tool add @deepseek-ai/dsh-web-app
|
|
42
37
|
# 或使用 dsh-tui:dsh plugin --profile prompt-tool add @deepseek-harness-tui/dsh-tui
|
|
43
38
|
|
|
44
|
-
# 2.
|
|
39
|
+
# 2. 安装本插件(官方插件指令,自动加入 profile bundles)
|
|
45
40
|
dsh plugin --profile prompt-tool add dsh-plugin-prompt-tool
|
|
46
41
|
|
|
47
|
-
# 3.
|
|
42
|
+
# 3. 本地开发安装(任选其一,会覆盖 registry 依赖)
|
|
48
43
|
dsh plugin --profile prompt-tool add link:<本仓库绝对路径>
|
|
49
44
|
|
|
50
|
-
# 4.
|
|
45
|
+
# 4. 启动
|
|
51
46
|
dsh --profile prompt-tool
|
|
52
47
|
dsh web
|
|
53
48
|
dsh-tui
|
|
@@ -56,45 +51,51 @@ dsh-tui
|
|
|
56
51
|
dsh plugin --profile prompt-tool remove dsh-plugin-prompt-tool
|
|
57
52
|
```
|
|
58
53
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
服务,先执行第 1 步。等价的 profile 清单如下:
|
|
63
|
-
|
|
64
|
-
```jsonc
|
|
65
|
-
// <DSH_HOME>/profiles/prompt-tool/package.json
|
|
66
|
-
"dsh": {
|
|
67
|
-
"profile": {
|
|
68
|
-
"bundles": [
|
|
69
|
-
"@deepseek-ai/dsh-base",
|
|
70
|
-
"@deepseek-ai/dsh-web-app",
|
|
71
|
-
"dsh-plugin-prompt-tool"
|
|
72
|
-
]
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
```
|
|
54
|
+
装完**完整重启 `dsh web`**,新建空 session,预设选择 **prompt-tool**。插件会在启动时生成并刷新 `~/.dsh/.agent-presets/prompt-tool/`(升级插件后重启即自动更新)。
|
|
55
|
+
|
|
56
|
+
## 验证
|
|
76
57
|
|
|
77
|
-
|
|
58
|
+
导出 session JSONL,检查 `request/header`:
|
|
59
|
+
|
|
60
|
+
- 第一份 header 的 `tools` 应恰好是 `["bash", "str_replace_editor"]`;
|
|
61
|
+
- 第一轮只包含用户消息与首句锚点:没有 workspace 指令 baseline、运行时快照、skill 目录消息;
|
|
62
|
+
- 首次工具调用或首次助手回复后,下一份变更 header 应包含 resident 目录:bootstrap 双工具 + `dev_tool_search` / `skill_search` / `skill_load` + 已解锁工具;
|
|
63
|
+
- 此后的请求保持 resident 集,只经 `dev_tool_search` 显式解锁增长;
|
|
64
|
+
- `we` 锚定确认后,事件流出现一次 `source.plugin === 'prompt-injector'` 的消息;未确认时最多等一轮兜底。
|
|
65
|
+
|
|
66
|
+
本项目测试:
|
|
78
67
|
|
|
79
68
|
```sh
|
|
80
|
-
|
|
69
|
+
pnpm test # pnpm build + node --test
|
|
70
|
+
pnpm typecheck # Host 与 Client 两个 tsc program
|
|
71
|
+
pnpm lint # oxlint
|
|
81
72
|
```
|
|
82
73
|
|
|
83
|
-
|
|
74
|
+
## 行为与限制
|
|
84
75
|
|
|
85
|
-
|
|
76
|
+
- Windows:DSH 的 PTY 后端仅支持 linux/darwin,持久 shell 组禁用;phase-1 的 `bash` 切换为 `custom-bash`——同名且 schema 与 Minimal 兼容,经普通跨平台子进程通道调起 Git Bash(运行时探测安装路径,不硬编码)。
|
|
77
|
+
- Linux/macOS:持久 shell 的 `shellPath` 自适应——`/bin/bash` 存在时保持默认,不存在(如 NixOS)回退 PATH 里的 `bash`。
|
|
78
|
+
- 首轮能力类提问可能基于被裁剪的双工具视图作答,晋升后由后续工具纠正;需要时可开启任务引导或直接首轮问任务类问题。
|
|
79
|
+
- 工具目录只变化一次(晋升点),因此第一、二次请求之间发生一次前缀缓存变化;之后每次 `dev_tool_search` 解锁再变化。
|
|
80
|
+
- preset 与 shell 访问具有相同信任等级,安装前可自行审阅 `upstream/` 与生成目录。
|
|
81
|
+
- 插件只监听本机回环设置桥,不发起网络请求,也不增加遥测。
|
|
82
|
+
- 不要在已经产生内容的会话中途切换 preset。
|
|
83
|
+
- 需要 DSH 0.1.0-rc.5+(preset 机制与 `system-prompt/assemble` 钩子)。
|
|
86
84
|
|
|
87
|
-
|
|
85
|
+
## 构建与上游管理
|
|
88
86
|
|
|
89
|
-
|
|
87
|
+
```sh
|
|
88
|
+
pnpm install
|
|
89
|
+
pnpm build # 生成 lib/
|
|
90
|
+
pnpm prepare # npm publish / git install 前自动触发
|
|
91
|
+
pnpm sync:anchored # 从上游 main 刷新内联快照(可加 ref 参数)
|
|
92
|
+
```
|
|
90
93
|
|
|
91
|
-
|
|
92
|
-
2. **晋升**:首次工具调用或助手回复落地后,目录进入 resident(常驻)集,上下文与注入恢复;工具按需解锁。
|
|
93
|
-
3. **追加任务引导**:可选 `near-anchor`,在首条真实用户消息之后追加一次引导——默认按任务自动选择 we/let 首句,也可固定使用自定义文本。Flash 主会话晋升后,`router-guide` 还会在每个真实用户消息后追加固定深度引导;首句与每轮分别有独立的自定义开关和文本框。
|
|
94
|
-
4. **提示词注入**:we 锚定确认后,把 `preset.md` 作为用户消息注入一次;未确认最多等一轮兜底。
|
|
95
|
-
5. **子代理**:目录直接全量放行(实际仍受调用方工具白名单过滤);开启 `subagentFlash` 时,采用 dsh-router-standard 的 Flash 方案——固定 Flash 路由、任务分类人设与三锚。
|
|
94
|
+
上游 `dsh-anchored-standard` 以内联快照形式固化在 `upstream/dsh-anchored-standard/`(含 `LICENSE`、`NOTICE`、`REVISION`),对应提交见 `REVISION`。上游已转入维护期(2026-08-17);其 Project2 的 98/99/99 成绩来自当前实现之前的旧配置(issue #60),轨迹锚定有独立复现(#65),能力增益在小样本下未决(#51)。
|
|
96
95
|
|
|
97
|
-
|
|
96
|
+
## 许可
|
|
97
|
+
|
|
98
|
+
插件本体 MIT(Czerror)。首轮锚定机制源自 [xiaobright/dsh-anchored-standard](https://github.com/xiaobright/dsh-anchored-standard)(MIT),任务引导与 Flash 方案参考 [yjh051108/dsh-router-standard](https://github.com/yjh051108/dsh-router-standard)(MIT),缓存与工具面成本原则参考 [yjh051108/dsh-super-injector](https://github.com/yjh051108/dsh-super-injector)(MIT)。上游 `agent.cordis.yml` 基于 DeepSeek Harness Standard 预设修改,原始 DeepSeek 版权与 MIT 声明保留在 `upstream/dsh-anchored-standard/NOTICE` 与 `LICENSE`。
|
|
98
99
|
|
|
99
100
|
## 配置参考
|
|
100
101
|
|
|
@@ -108,19 +109,19 @@ dsh --profile prompt-tool --patch <cordis.yml>
|
|
|
108
109
|
text: '' # 覆盖 preset.md 文本;默认读项目文件
|
|
109
110
|
agentsText: '' # 覆盖 AGENTS.md 文本;默认读项目文件
|
|
110
111
|
injectAgentsPrompt: false # 用 AGENTS.md 替换 instruction-hint 提示文本
|
|
111
|
-
writeAgents: true # 写 ~/.dsh/AGENTS.md
|
|
112
|
-
writePreset: true #
|
|
113
|
-
injectPrompt: true # we 确认后注入 preset.md
|
|
112
|
+
writeAgents: true # 写 ~/.dsh/AGENTS.md 受管块
|
|
113
|
+
writePreset: true # 启用锚定预设(总开关)
|
|
114
|
+
injectPrompt: true # we 确认后注入 preset.md
|
|
114
115
|
skillSwitches: {} # 按 skills/* 目录名开关,未列出默认开启
|
|
115
|
-
anchorFirstTurn: false #
|
|
116
|
+
anchorFirstTurn: false # 追加任务引导
|
|
116
117
|
anchorText: '' # 自定义引导文本(首句)
|
|
117
118
|
anchorCustom: false # 使用自定义引导(首句)
|
|
118
|
-
guideText: '' #
|
|
119
|
-
guideCustom: false #
|
|
120
|
-
subagentFlash: false # 子代理固定 Flash
|
|
119
|
+
guideText: '' # 自定义引导文本(每轮)
|
|
120
|
+
guideCustom: false # 使用自定义引导(每轮)
|
|
121
|
+
subagentFlash: false # 子代理固定 Flash 模型
|
|
121
122
|
subagentFlashProvider: 'deepseek-official'
|
|
122
123
|
subagentFlashModel: 'deepseek-v4-flash'
|
|
123
|
-
|
|
124
|
+
bootstrapMaxTokens: 0 # 首轮输出封顶:0=关闭;正整数=请求 #1 maxTokens
|
|
124
125
|
skillsDir: '' # 可选技能目录(默认包内 skills/)
|
|
125
126
|
skillRankBase: 250 # 技能候选排序基数
|
|
126
127
|
residentAgentsPath: '' # 默认 ~/.dsh/AGENTS.md
|
|
@@ -129,22 +130,11 @@ dsh --profile prompt-tool --patch <cordis.yml>
|
|
|
129
130
|
fallbackText: '' # preset.md 缺失或不可读时的回退文本
|
|
130
131
|
```
|
|
131
132
|
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
- **启用锚定预设**:总开关。开启时生成并刷新 `~/.dsh/.agent-presets/prompt-tool/`;关闭时移除已生成目录,锚定相关开关失效。
|
|
135
|
-
- **追加任务引导**:开启时挂载 `near-anchor`,在首条真实用户消息后追加一次任务引导。
|
|
136
|
-
- **使用自定义引导(首句)**:开启时固定使用 `anchorText`;关闭时按任务自动选择 we/let 首句。开启且文本为空时不注入。
|
|
137
|
-
- **使用自定义引导(每轮)**:开启时每轮固定使用 `guideText`,Pro 与 Flash 都注入(便于对照测试);关闭时按任务自动选择快速收敛/深度引导,仅 Flash 主会话晋升后由 router-guide 注入。留空则不注入。
|
|
138
|
-
- **子代理固定 Flash 模型**:开启时采用 dsh-router-standard 的 Flash 子代理方案——通用子代理行加固定 Flash 路由、任务分类人设与三锚;宿主直派子代理(含 dsh-mnemon)自动补 Flash 路由,调用方显式模型优先。检测不到 DeepSeek 模型路由时 Web/TUI 禁用,且运行时强制降级为关闭。
|
|
139
|
-
- **自定义 bash 路径**:上游若带作者机器固定路径,生成 preset 时归一化为该值,默认 PATH 查找 `bash.exe`。
|
|
140
|
-
- 其他字段语义见上方配置注释;设置文件优先级高于挂载配置,首次安装时用项目文件内容初始化设置。
|
|
141
|
-
|
|
142
|
-
## 版权
|
|
133
|
+
TUI 命令:
|
|
143
134
|
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
-
|
|
148
|
-
-
|
|
149
|
-
|
|
150
|
-
- 本项目 `LICENSE` 见仓库根目录;随上游快照发布的 `upstream/dsh-anchored-standard/LICENSE` 与 `NOTICE` 继续保留。
|
|
135
|
+
```text
|
|
136
|
+
/prompt-tool status
|
|
137
|
+
/prompt-tool on|off|toggle <开关>
|
|
138
|
+
/prompt-tool skill <技能目录名> on|off|toggle
|
|
139
|
+
/prompt-tool bootstrapMaxTokens <正整数|0>
|
|
140
|
+
```
|
package/lib/client.js
CHANGED
|
@@ -23,7 +23,7 @@ window.__ModuleLoader__.load({
|
|
|
23
23
|
}
|
|
24
24
|
//#endregion
|
|
25
25
|
//#region \0dsh-css:E:\Documents\GitHub\dsh-plugin-prompt-tool\src\client\PromptEditor.module.css.mjs
|
|
26
|
-
const css = ".Ru2OGG_card{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-3);border-radius:12px;list-style:none;transition:border-color .16s,background .16s}.Ru2OGG_card:hover{border-color:var(--dsw-alias-label-dimmed)}.Ru2OGG_cardOpen{background:var(--dsw-alias-bg-layer-2);border-color:var(--dsw-alias-label-dimmed)}.Ru2OGG_header{appearance:none;width:100%;font:inherit;color:inherit;text-align:left;cursor:pointer;background:0 0;border:0;border-radius:12px;align-items:center;gap:12px;padding:14px 16px;display:flex}.Ru2OGG_header:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:-2px}.Ru2OGG_headText{flex-direction:column;flex:1;gap:4px;min-width:0;display:flex}.Ru2OGG_name{color:var(--dsw-alias-label-primary);font-size:15px;font-weight:600;line-height:1.4}.Ru2OGG_description{color:var(--dsw-alias-label-tertiary);font-size:13px;line-height:1.5}.Ru2OGG_chevron{color:var(--dsw-alias-label-tertiary);flex:none;transition:transform .16s}.Ru2OGG_chevronOpen{transform:rotate(180deg)}.Ru2OGG_pending{white-space:nowrap;background:var(--dsw-alias-bg-module-platform);color:var(--dsw-alias-label-secondary);border-radius:999px;flex:none;padding:1px 8px;font-size:11px;font-weight:500;line-height:17px}.Ru2OGG_body{border-top:1px solid var(--dsw-alias-border-l2);flex-direction:column;gap:14px;margin:0 16px;padding:14px 0 16px;display:flex}.Ru2OGG_loading{color:var(--dsw-alias-label-tertiary);font-size:12px;display:inline-block}.Ru2OGG_group{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-3);border-radius:12px;flex-direction:column;gap:8px;padding:12px 14px;display:flex}.Ru2OGG_groupTitle{color:var(--dsw-alias-label-secondary);font-size:13px;font-weight:600}.Ru2OGG_subSection{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-3);border-radius:12px;flex-direction:column;display:flex;overflow:hidden}.Ru2OGG_subHeader{appearance:none;width:100%;font:inherit;color:inherit;text-align:left;cursor:pointer;background:0 0;border:0;align-items:center;gap:12px;padding:12px 14px;display:flex}.Ru2OGG_subHeader:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:-2px}.Ru2OGG_subTitle{color:var(--dsw-alias-label-primary);flex:1;font-size:13px;font-weight:600;line-height:1.5}.Ru2OGG_subCount{color:var(--dsw-alias-label-tertiary);flex:none;font-size:12px}.Ru2OGG_subBody{flex-direction:column;gap:8px;padding:2px 14px 12px;display:flex}.Ru2OGG_subEmpty{color:var(--dsw-alias-label-tertiary);padding:4px 0 8px;font-size:12px}.Ru2OGG_row{cursor:pointer;align-items:flex-start;gap:10px;padding:6px 0;display:flex}.Ru2OGG_rowStack{flex-direction:column;align-items:stretch;gap:8px;padding:6px 0;display:flex}.Ru2OGG_row input{flex:none;margin-top:3px}.Ru2OGG_rowText{flex-direction:column;gap:2px;display:flex}.Ru2OGG_rowName{color:var(--dsw-alias-label-primary);font-size:13px;line-height:1.5}.Ru2OGG_rowDesc{color:var(--dsw-alias-label-tertiary);font-size:12px;line-height:1.5}.Ru2OGG_rowDisabled{opacity:.55}.Ru2OGG_anchorInput{box-sizing:border-box;width:100%;min-height:64px;color:var(--dsw-alias-label-primary);background:var(--dsw-alias-bg-layer-2);border:1px solid var(--dsw-alias-border-l2);resize:vertical;border-radius:8px;padding:8px 10px;font-family:ui-monospace,monospace;font-size:12px;line-height:1.6}.Ru2OGG_textarea{box-sizing:border-box;width:100%;min-height:420px;color:var(--dsw-alias-label-primary);background:var(--dsw-alias-bg-layer-2);border:1px solid var(--dsw-alias-border-l2);resize:vertical;border-radius:8px;padding:10px;font-family:ui-monospace,monospace;font-size:13px;line-height:1.6}.Ru2OGG_actions{flex-wrap:wrap;align-items:center;gap:8px;display:flex}.Ru2OGG_primary,.Ru2OGG_secondary{appearance:none;font:inherit;cursor:pointer;border:1px solid #0000;border-radius:8px;padding:5px 14px;font-size:13px;line-height:1.5}.Ru2OGG_primary{background:var(--dsw-alias-label-primary);color:var(--dsw-alias-bg-layer-3)}.Ru2OGG_secondary{border-color:var(--dsw-alias-border-l2);color:var(--dsw-alias-label-secondary);background:0 0}.Ru2OGG_primary:disabled,.Ru2OGG_secondary:disabled{opacity:.55;cursor:default}.Ru2OGG_primary:focus-visible,.Ru2OGG_secondary:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:1px}.Ru2OGG_notice{color:var(--dsw-alias-state-success-primary);font-size:12px}.Ru2OGG_noticeError{color:var(--dsw-alias-state-error-primary,#d5484d)}";
|
|
26
|
+
const css = ".Ru2OGG_card{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-3);border-radius:12px;list-style:none;transition:border-color .16s,background .16s}.Ru2OGG_card:hover{border-color:var(--dsw-alias-label-dimmed)}.Ru2OGG_cardOpen{background:var(--dsw-alias-bg-layer-2);border-color:var(--dsw-alias-label-dimmed)}.Ru2OGG_header{appearance:none;width:100%;font:inherit;color:inherit;text-align:left;cursor:pointer;background:0 0;border:0;border-radius:12px;align-items:center;gap:12px;padding:14px 16px;display:flex}.Ru2OGG_header:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:-2px}.Ru2OGG_headText{flex-direction:column;flex:1;gap:4px;min-width:0;display:flex}.Ru2OGG_name{color:var(--dsw-alias-label-primary);font-size:15px;font-weight:600;line-height:1.4}.Ru2OGG_description{color:var(--dsw-alias-label-tertiary);font-size:13px;line-height:1.5}.Ru2OGG_chevron{color:var(--dsw-alias-label-tertiary);flex:none;transition:transform .16s}.Ru2OGG_chevronOpen{transform:rotate(180deg)}.Ru2OGG_pending{white-space:nowrap;background:var(--dsw-alias-bg-module-platform);color:var(--dsw-alias-label-secondary);border-radius:999px;flex:none;padding:1px 8px;font-size:11px;font-weight:500;line-height:17px}.Ru2OGG_body{border-top:1px solid var(--dsw-alias-border-l2);flex-direction:column;gap:14px;margin:0 16px;padding:14px 0 16px;display:flex}.Ru2OGG_loading{color:var(--dsw-alias-label-tertiary);font-size:12px;display:inline-block}.Ru2OGG_group{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-3);border-radius:12px;flex-direction:column;gap:8px;padding:12px 14px;display:flex}.Ru2OGG_groupTitle{color:var(--dsw-alias-label-secondary);font-size:13px;font-weight:600}.Ru2OGG_subSection{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-3);border-radius:12px;flex-direction:column;display:flex;overflow:hidden}.Ru2OGG_subHeader{appearance:none;width:100%;font:inherit;color:inherit;text-align:left;cursor:pointer;background:0 0;border:0;align-items:center;gap:12px;padding:12px 14px;display:flex}.Ru2OGG_subHeader:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:-2px}.Ru2OGG_subTitle{color:var(--dsw-alias-label-primary);flex:1;font-size:13px;font-weight:600;line-height:1.5}.Ru2OGG_subCount{color:var(--dsw-alias-label-tertiary);flex:none;font-size:12px}.Ru2OGG_subBody{flex-direction:column;gap:8px;padding:2px 14px 12px;display:flex}.Ru2OGG_subEmpty{color:var(--dsw-alias-label-tertiary);padding:4px 0 8px;font-size:12px}.Ru2OGG_row{cursor:pointer;align-items:flex-start;gap:10px;padding:6px 0;display:flex}.Ru2OGG_rowStack{flex-direction:column;align-items:stretch;gap:8px;padding:6px 0;display:flex}.Ru2OGG_row input{flex:none;margin-top:3px}.Ru2OGG_rowText{flex-direction:column;gap:2px;display:flex}.Ru2OGG_rowName{color:var(--dsw-alias-label-primary);font-size:13px;line-height:1.5}.Ru2OGG_rowDesc{color:var(--dsw-alias-label-tertiary);font-size:12px;line-height:1.5}.Ru2OGG_rowDisabled{opacity:.55}.Ru2OGG_anchorInput{box-sizing:border-box;width:100%;min-height:64px;color:var(--dsw-alias-label-primary);background:var(--dsw-alias-bg-layer-2);border:1px solid var(--dsw-alias-border-l2);resize:vertical;border-radius:8px;padding:8px 10px;font-family:ui-monospace,monospace;font-size:12px;line-height:1.6}.Ru2OGG_textarea{box-sizing:border-box;width:100%;min-height:420px;color:var(--dsw-alias-label-primary);background:var(--dsw-alias-bg-layer-2);border:1px solid var(--dsw-alias-border-l2);resize:vertical;border-radius:8px;padding:10px;font-family:ui-monospace,monospace;font-size:13px;line-height:1.6}.Ru2OGG_actions{flex-wrap:wrap;align-items:center;gap:8px;display:flex}.Ru2OGG_primary,.Ru2OGG_secondary{appearance:none;font:inherit;cursor:pointer;border:1px solid #0000;border-radius:8px;padding:5px 14px;font-size:13px;line-height:1.5}.Ru2OGG_primary{background:var(--dsw-alias-label-primary);color:var(--dsw-alias-bg-layer-3)}.Ru2OGG_secondary{border-color:var(--dsw-alias-border-l2);color:var(--dsw-alias-label-secondary);background:0 0}.Ru2OGG_primary:disabled,.Ru2OGG_secondary:disabled{opacity:.55;cursor:default}.Ru2OGG_primary:focus-visible,.Ru2OGG_secondary:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:1px}.Ru2OGG_notice{color:var(--dsw-alias-state-success-primary);font-size:12px}.Ru2OGG_noticeError{color:var(--dsw-alias-state-error-primary,#d5484d)}.Ru2OGG_bootstrapTokensInput{box-sizing:border-box;width:96px;min-height:36px;max-height:48px;color:var(--dsw-alias-label-primary);background:var(--dsw-alias-bg-layer-2);border:1px solid var(--dsw-alias-border-l2);text-align:right;border-radius:8px;flex:none;align-self:stretch;margin:0 0 0 auto;padding:4px 8px;font-size:12px;line-height:1.4}.Ru2OGG_bootstrapTokensInput:disabled{opacity:.55;cursor:default}";
|
|
27
27
|
const tagId = "dsh-plugin-prompt-tool/PromptEditor.module.css";
|
|
28
28
|
if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId) + "]") === null) {
|
|
29
29
|
const tag = document.createElement("style");
|
|
@@ -36,6 +36,7 @@ window.__ModuleLoader__.load({
|
|
|
36
36
|
"actions": "Ru2OGG_actions",
|
|
37
37
|
"anchorInput": "Ru2OGG_anchorInput",
|
|
38
38
|
"body": "Ru2OGG_body",
|
|
39
|
+
"bootstrapTokensInput": "Ru2OGG_bootstrapTokensInput",
|
|
39
40
|
"card": "Ru2OGG_card",
|
|
40
41
|
"cardOpen": "Ru2OGG_cardOpen",
|
|
41
42
|
"chevron": "Ru2OGG_chevron",
|
|
@@ -100,6 +101,7 @@ window.__ModuleLoader__.load({
|
|
|
100
101
|
guideText: "",
|
|
101
102
|
guideCustom: false,
|
|
102
103
|
subagentFlash: false,
|
|
104
|
+
bootstrapMaxTokens: 0,
|
|
103
105
|
injectPrompt: true,
|
|
104
106
|
skillSwitches: {},
|
|
105
107
|
skillCatalog: [],
|
|
@@ -114,11 +116,14 @@ window.__ModuleLoader__.load({
|
|
|
114
116
|
guideText: "",
|
|
115
117
|
guideCustom: false,
|
|
116
118
|
subagentFlash: false,
|
|
119
|
+
bootstrapMaxTokens: 0,
|
|
117
120
|
injectPrompt: true,
|
|
118
121
|
skillSwitches: {},
|
|
119
122
|
writeAgents: true,
|
|
120
123
|
writePreset: true
|
|
121
124
|
};
|
|
125
|
+
/** 本项目默认不设上限时的显示值(adapter 默认 maxTokens)。 */
|
|
126
|
+
const DEFAULT_BOOTSTRAP_DISPLAY = "256000";
|
|
122
127
|
const snapshotSwitches = (fields) => ({
|
|
123
128
|
injectAgentsPrompt: fields.injectAgentsPrompt,
|
|
124
129
|
anchorFirstTurn: fields.anchorFirstTurn,
|
|
@@ -127,12 +132,13 @@ window.__ModuleLoader__.load({
|
|
|
127
132
|
guideText: fields.guideText,
|
|
128
133
|
guideCustom: fields.guideCustom,
|
|
129
134
|
subagentFlash: fields.subagentFlash,
|
|
135
|
+
bootstrapMaxTokens: fields.bootstrapMaxTokens,
|
|
130
136
|
injectPrompt: fields.injectPrompt,
|
|
131
137
|
skillSwitches: { ...fields.skillSwitches },
|
|
132
138
|
writeAgents: fields.writeAgents,
|
|
133
139
|
writePreset: fields.writePreset
|
|
134
140
|
});
|
|
135
|
-
const switchesEqual = (a, b) => a.injectAgentsPrompt === b.injectAgentsPrompt && a.anchorFirstTurn === b.anchorFirstTurn && a.anchorText === b.anchorText && a.anchorCustom === b.anchorCustom && a.guideText === b.guideText && a.guideCustom === b.guideCustom && a.subagentFlash === b.subagentFlash && a.injectPrompt === b.injectPrompt && JSON.stringify(a.skillSwitches) === JSON.stringify(b.skillSwitches) && a.writeAgents === b.writeAgents && a.writePreset === b.writePreset;
|
|
141
|
+
const switchesEqual = (a, b) => a.injectAgentsPrompt === b.injectAgentsPrompt && a.anchorFirstTurn === b.anchorFirstTurn && a.anchorText === b.anchorText && a.anchorCustom === b.anchorCustom && a.guideText === b.guideText && a.guideCustom === b.guideCustom && a.subagentFlash === b.subagentFlash && a.bootstrapMaxTokens === b.bootstrapMaxTokens && a.injectPrompt === b.injectPrompt && JSON.stringify(a.skillSwitches) === JSON.stringify(b.skillSwitches) && a.writeAgents === b.writeAgents && a.writePreset === b.writePreset;
|
|
136
142
|
const asRecord = (value) => value !== null && typeof value === "object" ? value : {};
|
|
137
143
|
const readString = (source, key) => {
|
|
138
144
|
const value = source[key];
|
|
@@ -142,6 +148,10 @@ window.__ModuleLoader__.load({
|
|
|
142
148
|
const value = source[key];
|
|
143
149
|
return typeof value === "boolean" ? value : fallback;
|
|
144
150
|
};
|
|
151
|
+
const readNumber = (source, key, fallback) => {
|
|
152
|
+
const value = source[key];
|
|
153
|
+
return typeof value === "number" && Number.isSafeInteger(value) && value >= 0 ? value : fallback;
|
|
154
|
+
};
|
|
145
155
|
const readSkillSwitches = (source, key) => {
|
|
146
156
|
const value = source[key];
|
|
147
157
|
if (value === null || typeof value !== "object") return {};
|
|
@@ -204,6 +214,7 @@ window.__ModuleLoader__.load({
|
|
|
204
214
|
const [deepseekError, setDeepseekError] = (0, react.useState)("");
|
|
205
215
|
const [loaded, setLoaded] = (0, react.useState)(false);
|
|
206
216
|
const [fields, setFields] = (0, react.useState)(EMPTY);
|
|
217
|
+
const [bootstrapTokensDraft, setBootstrapTokensDraft] = (0, react.useState)(DEFAULT_BOOTSTRAP_DISPLAY);
|
|
207
218
|
const [savedPromptText, setSavedPromptText] = (0, react.useState)("");
|
|
208
219
|
const [savedAgentsText, setSavedAgentsText] = (0, react.useState)("");
|
|
209
220
|
const [savedSwitches, setSavedSwitches] = (0, react.useState)(EMPTY_SWITCHES);
|
|
@@ -247,6 +258,7 @@ window.__ModuleLoader__.load({
|
|
|
247
258
|
guideText: readString(value, "guideText") ?? readString(base, "guideText") ?? "",
|
|
248
259
|
guideCustom: readBoolean(value, "guideCustom", readBoolean(base, "guideCustom", false)),
|
|
249
260
|
subagentFlash: readBoolean(value, "subagentFlash", readBoolean(base, "subagentFlash", false)),
|
|
261
|
+
bootstrapMaxTokens: readNumber(value, "bootstrapMaxTokens", readNumber(base, "bootstrapMaxTokens", 0)),
|
|
250
262
|
injectPrompt: readBoolean(value, "injectPrompt", readBoolean(base, "injectPrompt", true)),
|
|
251
263
|
skillSwitches: value.skillSwitches !== void 0 || base.skillSwitches !== void 0 ? {
|
|
252
264
|
...readSkillSwitches(base, "skillSwitches"),
|
|
@@ -258,6 +270,7 @@ window.__ModuleLoader__.load({
|
|
|
258
270
|
};
|
|
259
271
|
fieldsRef.current = next;
|
|
260
272
|
setFields(next);
|
|
273
|
+
setBootstrapTokensDraft(next.bootstrapMaxTokens > 0 ? String(next.bootstrapMaxTokens) : DEFAULT_BOOTSTRAP_DISPLAY);
|
|
261
274
|
setSavedPromptText(next.promptText);
|
|
262
275
|
setSavedAgentsText(next.agentsText);
|
|
263
276
|
setSavedSwitches(snapshotSwitches(next));
|
|
@@ -416,6 +429,11 @@ window.__ModuleLoader__.load({
|
|
|
416
429
|
path: ["subagentFlash"],
|
|
417
430
|
value: fieldsRef.current.subagentFlash
|
|
418
431
|
},
|
|
432
|
+
{
|
|
433
|
+
op: "set",
|
|
434
|
+
path: ["bootstrapMaxTokens"],
|
|
435
|
+
value: fieldsRef.current.bootstrapMaxTokens
|
|
436
|
+
},
|
|
419
437
|
{
|
|
420
438
|
op: "set",
|
|
421
439
|
path: ["injectPrompt"],
|
|
@@ -445,6 +463,20 @@ window.__ModuleLoader__.load({
|
|
|
445
463
|
patch({ [key]: !fieldsRef.current[key] });
|
|
446
464
|
persistSwitches();
|
|
447
465
|
};
|
|
466
|
+
const toggleBootstrapMaxTokens = () => {
|
|
467
|
+
const next = fieldsRef.current.bootstrapMaxTokens > 0 ? 0 : 256e3;
|
|
468
|
+
patch({ bootstrapMaxTokens: next });
|
|
469
|
+
setBootstrapTokensDraft(DEFAULT_BOOTSTRAP_DISPLAY);
|
|
470
|
+
persistSwitches();
|
|
471
|
+
};
|
|
472
|
+
const commitBootstrapTokensDraft = () => {
|
|
473
|
+
const parsed = Number(bootstrapTokensDraft);
|
|
474
|
+
if (!Number.isSafeInteger(parsed) || parsed <= 0) {
|
|
475
|
+
setBootstrapTokensDraft(DEFAULT_BOOTSTRAP_DISPLAY);
|
|
476
|
+
patch({ bootstrapMaxTokens: 256e3 });
|
|
477
|
+
} else patch({ bootstrapMaxTokens: parsed });
|
|
478
|
+
persistSwitches();
|
|
479
|
+
};
|
|
448
480
|
const skillEnabled = (folder) => fields.skillSwitches[folder] !== false;
|
|
449
481
|
const toggleSkill = (folder) => {
|
|
450
482
|
const enabled = fieldsRef.current.skillSwitches[folder] !== false;
|
|
@@ -462,7 +494,7 @@ window.__ModuleLoader__.load({
|
|
|
462
494
|
const promptSwitchDirty = fields.injectPrompt !== savedSwitches.injectPrompt;
|
|
463
495
|
const agentsSwitchDirty = fields.injectAgentsPrompt !== savedSwitches.injectAgentsPrompt || fields.writeAgents !== savedSwitches.writeAgents;
|
|
464
496
|
const skillsSwitchDirty = JSON.stringify(fields.skillSwitches) !== JSON.stringify(savedSwitches.skillSwitches);
|
|
465
|
-
const presetSwitchDirty = fields.writePreset !== savedSwitches.writePreset || fields.anchorFirstTurn !== savedSwitches.anchorFirstTurn || fields.anchorText !== savedSwitches.anchorText;
|
|
497
|
+
const presetSwitchDirty = fields.writePreset !== savedSwitches.writePreset || fields.anchorFirstTurn !== savedSwitches.anchorFirstTurn || fields.anchorText !== savedSwitches.anchorText || fields.bootstrapMaxTokens !== savedSwitches.bootstrapMaxTokens;
|
|
466
498
|
const discardPrompt = () => patch({ promptText: savedPromptText });
|
|
467
499
|
const discardAgents = () => patch({ agentsText: savedAgentsText });
|
|
468
500
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("li", {
|
|
@@ -696,6 +728,39 @@ window.__ModuleLoader__.load({
|
|
|
696
728
|
})]
|
|
697
729
|
})]
|
|
698
730
|
}),
|
|
731
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
732
|
+
className: PromptEditor_module_css_default.row,
|
|
733
|
+
children: [
|
|
734
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
|
|
735
|
+
id: "prompt-tool-bootstrap-max-tokens",
|
|
736
|
+
type: "checkbox",
|
|
737
|
+
checked: fields.bootstrapMaxTokens > 0,
|
|
738
|
+
disabled: !fields.writePreset,
|
|
739
|
+
onChange: toggleBootstrapMaxTokens
|
|
740
|
+
}),
|
|
741
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
|
|
742
|
+
htmlFor: "prompt-tool-bootstrap-max-tokens",
|
|
743
|
+
className: PromptEditor_module_css_default.rowText,
|
|
744
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
745
|
+
className: PromptEditor_module_css_default.rowName,
|
|
746
|
+
children: "首轮输出封顶"
|
|
747
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
748
|
+
className: PromptEditor_module_css_default.rowDesc,
|
|
749
|
+
children: "关闭时显示项目默认 256000(不设上限);开启后右侧数值生效,晋升后自动剥离。清空或输入 0 会恢复 256000,不关闭开关"
|
|
750
|
+
})]
|
|
751
|
+
}),
|
|
752
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
|
|
753
|
+
className: PromptEditor_module_css_default.bootstrapTokensInput,
|
|
754
|
+
type: "number",
|
|
755
|
+
min: 1,
|
|
756
|
+
step: 1,
|
|
757
|
+
value: bootstrapTokensDraft,
|
|
758
|
+
disabled: !fields.writePreset || fields.bootstrapMaxTokens === 0,
|
|
759
|
+
onChange: (e) => setBootstrapTokensDraft(e.target.value),
|
|
760
|
+
onBlur: commitBootstrapTokensDraft
|
|
761
|
+
})
|
|
762
|
+
]
|
|
763
|
+
}),
|
|
699
764
|
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
|
|
700
765
|
className: PromptEditor_module_css_default.row,
|
|
701
766
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
|
package/lib/client.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.js","names":["styles","IconChevronDownOutline14","useState","useRef","useCallback"],"sources":["../node_modules/.pnpm/clsx@2.1.1/node_modules/clsx/dist/clsx.mjs","../src/client/PromptEditor.tsx","../src/client/index.ts"],"sourcesContent":["function r(e){var t,f,n=\"\";if(\"string\"==typeof e||\"number\"==typeof e)n+=e;else if(\"object\"==typeof e)if(Array.isArray(e)){var o=e.length;for(t=0;t<o;t++)e[t]&&(f=r(e[t]))&&(n&&(n+=\" \"),n+=f)}else for(f in e)e[f]&&(n&&(n+=\" \"),n+=f);return n}export function clsx(){for(var e,t,f=0,n=\"\",o=arguments.length;f<o;f++)(e=arguments[f])&&(t=r(e))&&(n&&(n+=\" \"),n+=t);return n}export default clsx;","import { useCallback, useRef, useState } from 'react'\r\nimport type { ReactNode } from 'react'\r\nimport clsx from 'clsx'\r\nimport { IconChevronDownOutline14 } from '@deepseek-ai/dsh-client-ui-primitives'\r\nimport type { IApiClient } from '@deepseek-ai/dsh-client-connection/client'\r\nimport type { InjectFace, PropsRuntime } from '@deepseek-ai/dsh-client-ui-slots'\r\nimport type {} from '@deepseek-ai/dsh-client-ui-settings-plugins/client'\r\nimport styles from './PromptEditor.module.css'\r\n\r\nconst SETTINGS_BRIDGE_PREFIX = '/api/prompt-tool/settings'\r\n\r\ntype BridgePathOp = { op: 'set' | 'unset'; path: string[]; value?: unknown }\r\ninterface BridgeSettingsView { ns: string; value: unknown; base?: unknown; revision: number }\r\ntype BridgeResult<T> = { ok: true; value: T; deepseekAvailable?: boolean; deepseekProviders?: string[]; deepseekError?: string } | { ok: false; code?: string; message?: string }\r\n\r\nasync function bridgePost<T>(path: string, body: unknown): Promise<BridgeResult<T>> {\r\n try {\r\n const response = await fetch(SETTINGS_BRIDGE_PREFIX + path, {\r\n method: 'POST',\r\n headers: { 'content-type': 'application/json' },\r\n body: JSON.stringify(body),\r\n })\r\n const payload = await response.json() as unknown\r\n if (payload !== null && typeof payload === 'object') return payload as BridgeResult<T>\r\n return { ok: false, message: 'settings bridge unavailable' }\r\n } catch (error) {\r\n return { ok: false, message: errorMessage(error) }\r\n }\r\n}\r\n\r\nexport interface PromptEditorInjected {\r\n api: IApiClient\r\n}\r\n\r\nexport type PromptEditorProps = PropsRuntime<'settings.plugin.item'> & InjectFace<PromptEditorInjected>\r\n\r\ninterface SkillCatalogEntry {\r\n folder: string\r\n name: string\r\n description: string\r\n}\r\n\r\ninterface Fields {\r\n promptText: string\r\n promptPath: string\r\n agentsText: string\r\n agentsPath: string\r\n injectAgentsPrompt: boolean\r\n anchorFirstTurn: boolean\r\n anchorText: string\r\n anchorCustom: boolean\r\n guideText: string\r\n guideCustom: boolean\r\n subagentFlash: boolean\r\n injectPrompt: boolean\r\n skillSwitches: Record<string, boolean>\r\n skillCatalog: SkillCatalogEntry[]\r\n writeAgents: boolean\r\n writePreset: boolean\r\n}\r\n\r\nconst EMPTY: Fields = {\r\n promptText: '',\r\n promptPath: '',\r\n agentsText: '',\r\n agentsPath: '',\r\n injectAgentsPrompt: false,\r\n anchorFirstTurn: false,\r\n anchorText: '',\r\n anchorCustom: false,\r\n guideText: '',\r\n guideCustom: false,\r\n subagentFlash: false,\r\n injectPrompt: true,\r\n skillSwitches: {},\r\n skillCatalog: [],\r\n writeAgents: true,\r\n writePreset: true,\r\n}\r\n\r\ninterface SwitchSnapshot {\r\n injectAgentsPrompt: boolean\r\n anchorFirstTurn: boolean\r\n anchorText: string\r\n anchorCustom: boolean\r\n guideText: string\r\n guideCustom: boolean\r\n subagentFlash: boolean\r\n injectPrompt: boolean\r\n skillSwitches: Record<string, boolean>\r\n writeAgents: boolean\r\n writePreset: boolean\r\n}\r\n\r\nconst EMPTY_SWITCHES: SwitchSnapshot = {\r\n injectAgentsPrompt: false,\r\n anchorFirstTurn: false,\r\n anchorText: '',\r\n anchorCustom: false,\r\n guideText: '',\r\n guideCustom: false,\r\n subagentFlash: false,\r\n injectPrompt: true,\r\n skillSwitches: {},\r\n writeAgents: true,\r\n writePreset: true,\r\n}\r\n\r\nconst snapshotSwitches = (fields: Fields): SwitchSnapshot => ({\r\n injectAgentsPrompt: fields.injectAgentsPrompt,\r\n anchorFirstTurn: fields.anchorFirstTurn,\r\n anchorText: fields.anchorText,\r\n anchorCustom: fields.anchorCustom,\r\n guideText: fields.guideText,\r\n guideCustom: fields.guideCustom,\r\n subagentFlash: fields.subagentFlash,\r\n injectPrompt: fields.injectPrompt,\r\n skillSwitches: { ...fields.skillSwitches },\r\n writeAgents: fields.writeAgents,\r\n writePreset: fields.writePreset,\r\n})\r\n\r\nconst switchesEqual = (a: SwitchSnapshot, b: SwitchSnapshot): boolean =>\r\n a.injectAgentsPrompt === b.injectAgentsPrompt\r\n && a.anchorFirstTurn === b.anchorFirstTurn\r\n && a.anchorText === b.anchorText\r\n && a.anchorCustom === b.anchorCustom\r\n && a.guideText === b.guideText\r\n && a.guideCustom === b.guideCustom\r\n && a.subagentFlash === b.subagentFlash\r\n && a.injectPrompt === b.injectPrompt\r\n && JSON.stringify(a.skillSwitches) === JSON.stringify(b.skillSwitches)\r\n && a.writeAgents === b.writeAgents\r\n && a.writePreset === b.writePreset\r\n\r\nconst asRecord = (value: unknown): Record<string, unknown> =>\r\n value !== null && typeof value === 'object' ? value as Record<string, unknown> : {}\r\n\r\nconst readString = (source: Record<string, unknown>, key: string): string | undefined => {\r\n const value = source[key]\r\n return typeof value === 'string' ? value : undefined\r\n}\r\n\r\nconst readBoolean = (source: Record<string, unknown>, key: string, fallback: boolean): boolean => {\r\n const value = source[key]\r\n return typeof value === 'boolean' ? value : fallback\r\n}\r\n\r\nconst readSkillSwitches = (source: Record<string, unknown>, key: string): Record<string, boolean> => {\r\n const value = source[key]\r\n if (value === null || typeof value !== 'object') return {}\r\n const entries = Object.entries(value as Record<string, unknown>)\r\n const result: Record<string, boolean> = {}\r\n for (const [name, enabled] of entries) {\r\n if (typeof enabled === 'boolean') result[name] = enabled\r\n }\r\n return result\r\n}\r\n\r\nconst readSkillCatalog = (source: Record<string, unknown>, key: string): SkillCatalogEntry[] => {\r\n const value = source[key]\r\n if (!Array.isArray(value)) return []\r\n return value.flatMap((entry) => {\r\n if (entry === null || typeof entry !== 'object') return []\r\n const record = entry as Record<string, unknown>\r\n const folder = readString(record, 'folder')\r\n const name = readString(record, 'name')\r\n if (folder === undefined || name === undefined) return []\r\n return [{ folder, name, description: readString(record, 'description') ?? '' }]\r\n })\r\n}\r\n\r\nconst errorMessage = (error: unknown): string => error instanceof Error ? error.message : String(error)\r\n\r\nfunction CollapsibleSection(props: { title: string; hint?: string; open: boolean; onToggle: () => void; children: ReactNode }): ReactNode {\r\n return (\r\n <div className={styles.subSection}>\r\n <button type=\"button\" className={styles.subHeader} aria-expanded={props.open} onClick={props.onToggle}>\r\n <span className={styles.subTitle}>{props.title}</span>\r\n {props.hint && <span className={styles.subCount}>{props.hint}</span>}\r\n <IconChevronDownOutline14 className={clsx(styles.chevron, props.open && styles.chevronOpen)} />\r\n </button>\r\n {props.open && <div className={styles.subBody}>{props.children}</div>}\r\n </div>\r\n )\r\n}\r\n\r\nexport function PromptEditor(props: PromptEditorProps): ReactNode {\r\n const { api } = props\r\n const [open, setOpen] = useState(false)\r\n const [promptOpen, setPromptOpen] = useState(false)\r\n const [agentsOpen, setAgentsOpen] = useState(false)\r\n const [skillsOpen, setSkillsOpen] = useState(false)\r\n const [presetOpen, setPresetOpen] = useState(false)\r\n const [deepseekAvailable, setDeepseekAvailable] = useState(false)\r\n const [deepseekProviders, setDeepseekProviders] = useState<string[]>([])\r\n const [deepseekError, setDeepseekError] = useState('')\r\n const [loaded, setLoaded] = useState(false)\r\n const [fields, setFields] = useState<Fields>(EMPTY)\r\n const [savedPromptText, setSavedPromptText] = useState('')\r\n const [savedAgentsText, setSavedAgentsText] = useState('')\r\n const [savedSwitches, setSavedSwitches] = useState<SwitchSnapshot>(EMPTY_SWITCHES)\r\n const [loading, setLoading] = useState(false)\r\n const [savingPrompt, setSavingPrompt] = useState(false)\r\n const [savingAgents, setSavingAgents] = useState(false)\r\n const [restoringPrompt, setRestoringPrompt] = useState(false)\r\n const [restoringAgents, setRestoringAgents] = useState(false)\r\n const [notice, setNotice] = useState('')\r\n const [noticeKind, setNoticeKind] = useState<'ok' | 'error'>('ok')\r\n const fieldsRef = useRef<Fields>(EMPTY)\r\n const revisionRef = useRef<number | undefined>(undefined)\r\n const saveQueueRef = useRef<Promise<void>>(Promise.resolve())\r\n\r\n const showNotice = useCallback((kind: 'ok' | 'error', message: string) => {\r\n setNotice(message)\r\n setNoticeKind(kind)\r\n }, [])\r\n\r\n const load = useCallback(async () => {\r\n setLoading(true)\r\n try {\r\n const res = await bridgePost<BridgeSettingsView>('/describe', {})\r\n if (!res.ok) { showNotice('error', '读取配置失败:' + (res.message ?? '')); return }\r\n setDeepseekAvailable(res.deepseekAvailable === true)\r\n setDeepseekProviders(res.deepseekProviders ?? [])\r\n setDeepseekError(res.deepseekError ?? '')\r\n const ns = res.value\r\n const value = asRecord(ns.value)\r\n const base = asRecord(ns.base)\r\n const next: Fields = {\r\n promptText: readString(value, 'promptText') ?? readString(base, 'promptText') ?? '',\r\n promptPath: readString(value, 'promptPath') ?? readString(base, 'promptPath') ?? '',\r\n agentsText: readString(value, 'agentsText') ?? readString(base, 'agentsText') ?? '',\r\n agentsPath: readString(value, 'agentsPath') ?? readString(base, 'agentsPath') ?? '',\r\n injectAgentsPrompt: readBoolean(value, 'injectAgentsPrompt', readBoolean(base, 'injectAgentsPrompt', false)),\r\n anchorFirstTurn: readBoolean(value, 'anchorFirstTurn', readBoolean(base, 'anchorFirstTurn', false)),\r\n anchorText: readString(value, 'anchorText') ?? readString(base, 'anchorText') ?? '',\r\n anchorCustom: readBoolean(value, 'anchorCustom', readBoolean(base, 'anchorCustom', false)),\r\n guideText: readString(value, 'guideText') ?? readString(base, 'guideText') ?? '',\r\n guideCustom: readBoolean(value, 'guideCustom', readBoolean(base, 'guideCustom', false)),\r\n subagentFlash: readBoolean(value, 'subagentFlash', readBoolean(base, 'subagentFlash', false)),\r\n injectPrompt: readBoolean(value, 'injectPrompt', readBoolean(base, 'injectPrompt', true)),\r\n skillSwitches: value.skillSwitches !== undefined || base.skillSwitches !== undefined\r\n ? { ...readSkillSwitches(base, 'skillSwitches'), ...readSkillSwitches(value, 'skillSwitches') }\r\n : {},\r\n skillCatalog: readSkillCatalog(value, 'skillCatalog').length > 0\r\n ? readSkillCatalog(value, 'skillCatalog')\r\n : readSkillCatalog(base, 'skillCatalog'),\r\n writeAgents: readBoolean(value, 'writeAgents', readBoolean(base, 'writeAgents', true)),\r\n writePreset: readBoolean(value, 'writePreset', readBoolean(base, 'writePreset', true)),\r\n }\r\n fieldsRef.current = next\r\n setFields(next)\r\n setSavedPromptText(next.promptText)\r\n setSavedAgentsText(next.agentsText)\r\n setSavedSwitches(snapshotSwitches(next))\r\n revisionRef.current = ns.revision\r\n setNotice('')\r\n } catch (error) {\r\n showNotice('error', '读取失败:' + errorMessage(error))\r\n } finally {\r\n setLoading(false)\r\n }\r\n }, [showNotice])\r\n\r\n const refreshRevision = useCallback(async () => {\r\n try {\r\n const res = await bridgePost<BridgeSettingsView>('/describe', {})\r\n if (!res.ok) return\r\n revisionRef.current = res.value.revision\r\n } catch {\r\n // 刷新失败保持原 revision,用户可重试。\r\n }\r\n }, [])\r\n\r\n const restoreOriginal = useCallback(async (scope: 'preset' | 'agents') => {\r\n const setBusy = scope === 'preset' ? setRestoringPrompt : setRestoringAgents\r\n setBusy(true)\r\n try {\r\n const res = await bridgePost<BridgeSettingsView>('/restore-originals', {\r\n scope,\r\n expectedRevision: revisionRef.current,\r\n })\r\n if (!res.ok) {\r\n await refreshRevision()\r\n showNotice('error', '从项目还原失败:' + (res.message ?? '') + '(已刷新配置版本,可重试)')\r\n return\r\n }\r\n revisionRef.current = res.value.revision\r\n await load()\r\n showNotice('ok', scope === 'preset' ? 'preset.md 已从项目原文还原到设置' : 'AGENTS.md 已从项目原文还原到设置')\r\n } catch (error) {\r\n await refreshRevision()\r\n showNotice('error', '从项目还原失败:' + errorMessage(error) + '(已刷新配置版本,可重试)')\r\n } finally {\r\n setBusy(false)\r\n }\r\n }, [load, refreshRevision, showNotice])\r\n\r\n const patch = (partial: Partial<Fields>) => {\r\n const next = { ...fieldsRef.current, ...partial }\r\n fieldsRef.current = next\r\n setFields(next)\r\n }\r\n\r\n const toggleOpen = () => {\r\n const next = !open\r\n setOpen(next)\r\n if (!next) return\r\n if (!loaded) {\r\n setLoaded(true)\r\n void load()\r\n } else if (!dirty) {\r\n // 无未保存草稿时,每次展开同步最新 settings(其他客户端可能已修改)。\r\n void load()\r\n }\r\n }\r\n\r\n const openEdit = async () => {\r\n if (!fields.promptPath) { showNotice('error', '路径未知,请先保存一次或在下方直接编辑'); return }\r\n try {\r\n const res = await api.host.openPath({ path: fields.promptPath })\r\n if (res.result.ok) showNotice('ok', '已用系统编辑器打开 preset.md')\r\n else showNotice('error', '打开失败:' + (res.result.error?.message ?? '') + ';可直接在下方编辑框保存')\r\n } catch (error) {\r\n showNotice('error', '打开失败:' + errorMessage(error) + ';可直接在下方编辑框保存')\r\n }\r\n }\r\n\r\n const openAgents = async () => {\r\n if (!fields.agentsPath) { showNotice('error', '路径未知,请先保存一次或在下方直接编辑'); return }\r\n try {\r\n const res = await api.host.openPath({ path: fields.agentsPath })\r\n if (res.result.ok) showNotice('ok', '已用系统编辑器打开 AGENTS.md')\r\n else showNotice('error', '打开失败:' + (res.result.error?.message ?? '') + ';可直接在下方编辑框保存')\r\n } catch (error) {\r\n showNotice('error', '打开失败:' + errorMessage(error) + ';可直接在下方编辑框保存')\r\n }\r\n }\r\n\r\n const enqueueSave = useCallback((ops: BridgePathOp[], okMessage: string | undefined, onSaved: () => void, setBusy?: (busy: boolean) => void) => {\r\n setBusy?.(true)\r\n saveQueueRef.current = saveQueueRef.current.then(async () => {\r\n try {\r\n const res = await bridgePost<BridgeSettingsView>('/mutate', { ops, expectedRevision: revisionRef.current })\r\n if (res.ok) {\r\n revisionRef.current = res.value.revision\r\n onSaved()\r\n if (okMessage) showNotice('ok', okMessage)\r\n } else {\r\n await refreshRevision()\r\n showNotice('error', '保存失败:' + (res.message ?? '') + '(已刷新配置版本,可重试)')\r\n }\r\n } catch (error) {\r\n await refreshRevision()\r\n showNotice('error', '保存失败:' + errorMessage(error) + '(已刷新配置版本,可重试)')\r\n } finally {\r\n setBusy?.(false)\r\n }\r\n }).catch(() => {})\r\n }, [refreshRevision, showNotice])\r\n\r\n const savePrompt = () => enqueueSave(\r\n [{ op: 'set', path: ['promptText'], value: fieldsRef.current.promptText }],\r\n 'preset.md 已保存并生效',\r\n () => setSavedPromptText(fieldsRef.current.promptText),\r\n setSavingPrompt,\r\n )\r\n\r\n const saveAgents = () => enqueueSave(\r\n [{ op: 'set', path: ['agentsText'], value: fieldsRef.current.agentsText }],\r\n 'AGENTS.md 已保存并生效',\r\n () => setSavedAgentsText(fieldsRef.current.agentsText),\r\n setSavingAgents,\r\n )\r\n\r\n const persistSwitches = () => enqueueSave(\r\n [\r\n { op: 'set', path: ['injectAgentsPrompt'], value: fieldsRef.current.injectAgentsPrompt },\r\n { op: 'set', path: ['anchorFirstTurn'], value: fieldsRef.current.anchorFirstTurn },\r\n { op: 'set', path: ['anchorText'], value: fieldsRef.current.anchorText },\r\n { op: 'set', path: ['anchorCustom'], value: fieldsRef.current.anchorCustom },\r\n { op: 'set', path: ['guideText'], value: fieldsRef.current.guideText },\r\n { op: 'set', path: ['guideCustom'], value: fieldsRef.current.guideCustom },\r\n { op: 'set', path: ['subagentFlash'], value: fieldsRef.current.subagentFlash },\r\n { op: 'set', path: ['injectPrompt'], value: fieldsRef.current.injectPrompt },\r\n { op: 'set', path: ['skillSwitches'], value: fieldsRef.current.skillSwitches },\r\n { op: 'set', path: ['writeAgents'], value: fieldsRef.current.writeAgents },\r\n { op: 'set', path: ['writePreset'], value: fieldsRef.current.writePreset },\r\n ],\r\n undefined,\r\n () => setSavedSwitches(snapshotSwitches(fieldsRef.current)),\r\n )\r\n\r\n const toggle = (key: 'injectAgentsPrompt' | 'anchorFirstTurn' | 'anchorCustom' | 'guideCustom' | 'subagentFlash' | 'injectPrompt' | 'writeAgents' | 'writePreset') => {\r\n if (key === 'subagentFlash' && !deepseekAvailable) {\r\n showNotice('error', '未检测到 DeepSeek 模型配置,子代理 Flash 开关不可用')\r\n return\r\n }\r\n patch({ [key]: !fieldsRef.current[key] })\r\n persistSwitches()\r\n }\r\n\r\n const skillEnabled = (folder: string) => fields.skillSwitches[folder] !== false\r\n\r\n const toggleSkill = (folder: string) => {\r\n const enabled = fieldsRef.current.skillSwitches[folder] !== false\r\n patch({ skillSwitches: { ...fieldsRef.current.skillSwitches, [folder]: !enabled } })\r\n persistSwitches()\r\n }\r\n\r\n const currentSwitches = snapshotSwitches(fields)\r\n const dirtyPrompt = fields.promptText !== savedPromptText\r\n const dirtyAgents = fields.agentsText !== savedAgentsText\r\n const dirtySwitches = !switchesEqual(currentSwitches, savedSwitches)\r\n const dirty = dirtyPrompt || dirtyAgents || dirtySwitches\r\n const promptSwitchDirty = fields.injectPrompt !== savedSwitches.injectPrompt\r\n const agentsSwitchDirty = fields.injectAgentsPrompt !== savedSwitches.injectAgentsPrompt\r\n || fields.writeAgents !== savedSwitches.writeAgents\r\n const skillsSwitchDirty = JSON.stringify(fields.skillSwitches) !== JSON.stringify(savedSwitches.skillSwitches)\r\n const presetSwitchDirty = fields.writePreset !== savedSwitches.writePreset\r\n || fields.anchorFirstTurn !== savedSwitches.anchorFirstTurn\r\n || fields.anchorText !== savedSwitches.anchorText\r\n\r\n const discardPrompt = () => patch({ promptText: savedPromptText })\r\n const discardAgents = () => patch({ agentsText: savedAgentsText })\r\n\r\n return (\r\n <li className={clsx(styles.card, open && styles.cardOpen)}>\r\n <button type=\"button\" className={styles.header} aria-expanded={open} onClick={toggleOpen}>\r\n <span className={styles.headText}>\r\n <span className={styles.name}>提示词工具</span>\r\n <span className={styles.description}>编辑 preset.md / AGENTS.md 与各层注入开关,保存后自动生效</span>\r\n </span>\r\n {dirty && <span className={styles.pending}>未保存</span>}\r\n <IconChevronDownOutline14 className={clsx(styles.chevron, open && styles.chevronOpen)} />\r\n </button>\r\n {open && (\r\n <div className={styles.body}>\r\n {loading && <span className={styles.loading}>正在读取配置…</span>}\r\n\r\n <CollapsibleSection\r\n title=\"Preset预设\"\r\n hint={dirtyPrompt || promptSwitchDirty ? '未保存' : undefined}\r\n open={promptOpen}\r\n onToggle={() => setPromptOpen(!promptOpen)}\r\n >\r\n <label className={styles.row}>\r\n <input\r\n type=\"checkbox\"\r\n checked={fields.injectPrompt}\r\n disabled={!fields.writePreset}\r\n onChange={() => toggle('injectPrompt')}\r\n />\r\n <span className={styles.rowText}>\r\n <span className={styles.rowName}>注入 preset.md(锚定层)</span>\r\n <span className={styles.rowDesc}>注入会话晋升后的 agent/pre-step,消息插入决策消息开头,每会话一次</span>\r\n </span>\r\n </label>\r\n <textarea\r\n className={styles.textarea}\r\n aria-label=\"preset.md 内容\"\r\n value={fields.promptText}\r\n onChange={(e) => patch({ promptText: e.target.value })}\r\n spellCheck={false}\r\n />\r\n <div className={styles.actions}>\r\n <button type=\"button\" className={styles.primary} disabled={savingPrompt || savingAgents || !dirtyPrompt} onClick={savePrompt}>{savingPrompt ? '保存中…' : '保存'}</button>\r\n <button type=\"button\" className={styles.secondary} disabled={!dirtyPrompt} onClick={discardPrompt}>还原草稿</button>\r\n <button type=\"button\" className={styles.secondary} disabled={savingPrompt || savingAgents || restoringPrompt || restoringAgents} onClick={() => void restoreOriginal('preset')}>{restoringPrompt ? '还原中…' : '项目还原'}</button>\r\n <button type=\"button\" className={styles.secondary} onClick={openEdit}>打开</button>\r\n </div>\r\n </CollapsibleSection>\r\n\r\n <CollapsibleSection\r\n title=\"AGENTS设置\"\r\n hint={dirtyAgents || agentsSwitchDirty ? '未保存' : undefined}\r\n open={agentsOpen}\r\n onToggle={() => setAgentsOpen(!agentsOpen)}\r\n >\r\n <label className={styles.row}>\r\n <input\r\n type=\"checkbox\"\r\n checked={fields.injectAgentsPrompt}\r\n disabled={!fields.writePreset}\r\n onChange={() => toggle('injectAgentsPrompt')}\r\n />\r\n <span className={styles.rowText}>\r\n <span className={styles.rowName}>注入 AGENTS.md</span>\r\n <span className={styles.rowDesc}>注入会话晋升后的第一个 agent/pre-step,消息追加在决策消息末尾,每会话一次</span>\r\n </span>\r\n </label>\r\n <label className={styles.row}>\r\n <input\r\n type=\"checkbox\"\r\n checked={fields.writeAgents}\r\n onChange={() => toggle('writeAgents')}\r\n />\r\n <span className={styles.rowText}>\r\n <span className={styles.rowName}>写入 ~/.dsh/AGENTS.md</span>\r\n <span className={styles.rowDesc}>保持 AGENTS.md 的全局常驻注入;关闭后不再写入,已有文件保持原样</span>\r\n </span>\r\n </label>\r\n <textarea\r\n className={styles.textarea}\r\n aria-label=\"AGENTS.md 内容\"\r\n value={fields.agentsText}\r\n onChange={(e) => patch({ agentsText: e.target.value })}\r\n spellCheck={false}\r\n />\r\n <div className={styles.actions}>\r\n <button type=\"button\" className={styles.primary} disabled={savingPrompt || savingAgents || !dirtyAgents} onClick={saveAgents}>{savingAgents ? '保存中…' : '保存'}</button>\r\n <button type=\"button\" className={styles.secondary} disabled={!dirtyAgents} onClick={discardAgents}>还原草稿</button>\r\n <button type=\"button\" className={styles.secondary} disabled={savingPrompt || savingAgents || restoringPrompt || restoringAgents} onClick={() => void restoreOriginal('agents')}>{restoringAgents ? '还原中…' : '项目还原'}</button>\r\n <button type=\"button\" className={styles.secondary} onClick={openAgents}>打开</button>\r\n </div>\r\n </CollapsibleSection>\r\n\r\n <CollapsibleSection\r\n title=\"Skills设置\"\r\n hint={`${fields.skillCatalog.length} 个${skillsSwitchDirty ? ' · 未保存' : ''}`}\r\n open={skillsOpen}\r\n onToggle={() => setSkillsOpen(!skillsOpen)}\r\n >\r\n {fields.skillCatalog.length === 0 ? (\r\n <span className={styles.subEmpty}>skills 目录下没有技能</span>\r\n ) : fields.skillCatalog.map((skill) => (\r\n <label key={skill.folder} className={styles.row}>\r\n <input\r\n type=\"checkbox\"\r\n checked={skillEnabled(skill.folder)}\r\n onChange={() => toggleSkill(skill.folder)}\r\n />\r\n <span className={styles.rowText}>\r\n <span className={styles.rowName}>{skill.name || skill.folder}</span>\r\n <span className={styles.rowDesc}>skills/{skill.folder}{skill.description ? ` · ${skill.description}` : ''}</span>\r\n </span>\r\n </label>\r\n ))}\r\n </CollapsibleSection>\r\n\r\n <CollapsibleSection\r\n title=\"锚定与 preset\"\r\n hint={presetSwitchDirty ? '未保存' : undefined}\r\n open={presetOpen}\r\n onToggle={() => setPresetOpen(!presetOpen)}\r\n >\r\n\r\n <label className={styles.row}>\r\n <input\r\n type=\"checkbox\"\r\n checked={fields.writePreset}\r\n onChange={() => toggle('writePreset')}\r\n />\r\n <span className={styles.rowText}>\r\n <span className={styles.rowName}>启用锚定预设</span>\r\n <span className={styles.rowDesc}>总开关:开启时生成并刷新 ~/.dsh/.agent-presets/prompt-tool/,整套锚定预设才有载体;关闭时移除已生成的目录,下面锚定开关随之失效</span>\r\n </span>\r\n </label>\r\n <label className={styles.row}>\r\n <input\r\n type=\"checkbox\"\r\n checked={fields.subagentFlash}\r\n disabled={!fields.writePreset || !deepseekAvailable}\r\n onChange={() => toggle('subagentFlash')}\r\n />\r\n <span className={styles.rowText}>\r\n <span className={styles.rowName}>子代理固定 Flash 模型</span>\r\n <span className={styles.rowDesc}>{deepseekAvailable ? '开启时采用 dsh-router-standard 的 Flash 子代理方案:固定 Flash 路由 + 任务分类人设 + 三锚;宿主直派子代理(含 dsh-mnemon)也会自动补 Flash 路由。关闭时继承主会话模型,工具目录全量放行' : `未检测到 DeepSeek 模型配置,此开关不可用。providers=[${deepseekProviders.join(', ') || '空'}]${deepseekError ? ' error=' + deepseekError : ''}`}</span>\r\n </span>\r\n </label>\r\n <label className={styles.row}>\r\n <input\r\n type=\"checkbox\"\r\n checked={fields.anchorFirstTurn}\r\n disabled={!fields.writePreset}\r\n onChange={() => toggle('anchorFirstTurn')}\r\n />\r\n <span className={styles.rowText}>\r\n <span className={styles.rowName}>追加任务引导</span>\r\n <span className={styles.rowDesc}>总开关:开启后在首条真实用户消息之后追加任务引导;关闭时下方首句与每轮的自定义开关、编辑框全部禁用</span>\r\n </span>\r\n </label>\r\n <label className={styles.row}>\r\n <input\r\n type=\"checkbox\"\r\n checked={fields.anchorCustom}\r\n disabled={!fields.writePreset || !fields.anchorFirstTurn}\r\n onChange={() => toggle('anchorCustom')}\r\n />\r\n <span className={styles.rowText}>\r\n <span className={styles.rowName}>使用自定义引导(首句)</span>\r\n <span className={styles.rowDesc}>开启时使用下方文本作为引导;关闭时忽略下方文本,按任务自动选择 we/let 引导</span>\r\n </span>\r\n </label>\r\n <label className={clsx(styles.rowStack, (!fields.anchorFirstTurn || !fields.anchorCustom) && styles.rowDisabled)}>\r\n <span className={styles.rowText}>\r\n <span className={styles.rowName}>自定义引导文本(首句)</span>\r\n <span className={styles.rowDesc}>仅在上方“使用自定义引导(首句)”开启时生效;关闭时自动文本优先</span>\r\n </span>\r\n <textarea\r\n className={styles.anchorInput}\r\n value={fields.anchorText}\r\n disabled={!fields.writePreset || !fields.anchorFirstTurn || !fields.anchorCustom}\r\n onChange={(e) => patch({ anchorText: e.target.value })}\r\n onBlur={() => persistSwitches()}\r\n spellCheck={false}\r\n />\r\n </label>\r\n <label className={styles.row}>\r\n <input\r\n type=\"checkbox\"\r\n checked={fields.guideCustom}\r\n disabled={!fields.writePreset || !fields.anchorFirstTurn}\r\n onChange={() => toggle('guideCustom')}\r\n />\r\n <span className={styles.rowText}>\r\n <span className={styles.rowName}>使用自定义引导(每轮)</span>\r\n <span className={styles.rowDesc}>开启时每轮固定使用下方文本作为引导;关闭时忽略下方文本,按任务自动选择</span>\r\n </span>\r\n </label>\r\n <label className={clsx(styles.rowStack, (!fields.anchorFirstTurn || !fields.guideCustom) && styles.rowDisabled)}>\r\n <span className={styles.rowText}>\r\n <span className={styles.rowName}>自定义引导文本(每轮)</span>\r\n <span className={styles.rowDesc}>仅在上方“使用自定义引导(每轮)”开启时生效;留空则不注入</span>\r\n </span>\r\n <textarea\r\n className={styles.anchorInput}\r\n value={fields.guideText}\r\n disabled={!fields.writePreset || !fields.anchorFirstTurn || !fields.guideCustom}\r\n onChange={(e) => patch({ guideText: e.target.value })}\r\n onBlur={() => persistSwitches()}\r\n spellCheck={false}\r\n />\r\n </label>\r\n </CollapsibleSection>\r\n\r\n {notice && <span className={clsx(styles.notice, noticeKind === 'error' && styles.noticeError)}>{notice}</span>}\r\n </div>\r\n )}\r\n </li>\r\n )\r\n}\r\n","import type { ClientContext } from '@deepseek-ai/dsh-client-runtime/client'\nimport type { ConnectionHandle } from '@deepseek-ai/dsh-api-remotes/client'\nimport type {} from '@deepseek-ai/dsh-client-ui-settings/client'\nimport type {} from '@deepseek-ai/dsh-client-ui-settings-plugins/client'\nimport { PromptEditor, type PromptEditorInjected } from './PromptEditor.tsx'\n\nexport const inject = ['slots', 'connection']\n\nexport function apply(ctx: ClientContext): void {\n const connection = ctx.get('connection') as ConnectionHandle\n\n const injected = (): PromptEditorInjected => ({\n api: connection.api,\n })\n\n ctx.slots.inject('settings.plugin.item', () => ctx.slots.register({\n name: 'settings.plugin.item',\n id: 'prompt-tool',\n order: 30,\n inject: injected,\n }, PromptEditor))\n}\r\n"],"x_google_ignoreList":[0],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"client.js","names":["styles","IconChevronDownOutline14","useState","useRef","useCallback"],"sources":["../node_modules/.pnpm/clsx@2.1.1/node_modules/clsx/dist/clsx.mjs","../src/client/PromptEditor.tsx","../src/client/index.ts"],"sourcesContent":["function r(e){var t,f,n=\"\";if(\"string\"==typeof e||\"number\"==typeof e)n+=e;else if(\"object\"==typeof e)if(Array.isArray(e)){var o=e.length;for(t=0;t<o;t++)e[t]&&(f=r(e[t]))&&(n&&(n+=\" \"),n+=f)}else for(f in e)e[f]&&(n&&(n+=\" \"),n+=f);return n}export function clsx(){for(var e,t,f=0,n=\"\",o=arguments.length;f<o;f++)(e=arguments[f])&&(t=r(e))&&(n&&(n+=\" \"),n+=t);return n}export default clsx;","import { useCallback, useRef, useState } from 'react'\r\nimport type { ReactNode } from 'react'\r\nimport clsx from 'clsx'\r\nimport { IconChevronDownOutline14 } from '@deepseek-ai/dsh-client-ui-primitives'\r\nimport type { IApiClient } from '@deepseek-ai/dsh-client-connection/client'\r\nimport type { InjectFace, PropsRuntime } from '@deepseek-ai/dsh-client-ui-slots'\r\nimport type {} from '@deepseek-ai/dsh-client-ui-settings-plugins/client'\r\nimport styles from './PromptEditor.module.css'\r\n\r\nconst SETTINGS_BRIDGE_PREFIX = '/api/prompt-tool/settings'\r\n\r\ntype BridgePathOp = { op: 'set' | 'unset'; path: string[]; value?: unknown }\r\ninterface BridgeSettingsView { ns: string; value: unknown; base?: unknown; revision: number }\r\ntype BridgeResult<T> = { ok: true; value: T; deepseekAvailable?: boolean; deepseekProviders?: string[]; deepseekError?: string } | { ok: false; code?: string; message?: string }\r\n\r\nasync function bridgePost<T>(path: string, body: unknown): Promise<BridgeResult<T>> {\r\n try {\r\n const response = await fetch(SETTINGS_BRIDGE_PREFIX + path, {\r\n method: 'POST',\r\n headers: { 'content-type': 'application/json' },\r\n body: JSON.stringify(body),\r\n })\r\n const payload = await response.json() as unknown\r\n if (payload !== null && typeof payload === 'object') return payload as BridgeResult<T>\r\n return { ok: false, message: 'settings bridge unavailable' }\r\n } catch (error) {\r\n return { ok: false, message: errorMessage(error) }\r\n }\r\n}\r\n\r\nexport interface PromptEditorInjected {\r\n api: IApiClient\r\n}\r\n\r\nexport type PromptEditorProps = PropsRuntime<'settings.plugin.item'> & InjectFace<PromptEditorInjected>\r\n\r\ninterface SkillCatalogEntry {\r\n folder: string\r\n name: string\r\n description: string\r\n}\r\n\r\ninterface Fields {\r\n promptText: string\r\n promptPath: string\r\n agentsText: string\r\n agentsPath: string\r\n injectAgentsPrompt: boolean\r\n anchorFirstTurn: boolean\r\n anchorText: string\r\n anchorCustom: boolean\r\n guideText: string\r\n guideCustom: boolean\r\n subagentFlash: boolean\r\n bootstrapMaxTokens: number\r\n injectPrompt: boolean\r\n skillSwitches: Record<string, boolean>\r\n skillCatalog: SkillCatalogEntry[]\r\n writeAgents: boolean\r\n writePreset: boolean\r\n}\r\n\r\nconst EMPTY: Fields = {\r\n promptText: '',\r\n promptPath: '',\r\n agentsText: '',\r\n agentsPath: '',\r\n injectAgentsPrompt: false,\r\n anchorFirstTurn: false,\r\n anchorText: '',\r\n anchorCustom: false,\r\n guideText: '',\r\n guideCustom: false,\r\n subagentFlash: false,\r\n bootstrapMaxTokens: 0,\r\n injectPrompt: true,\r\n skillSwitches: {},\r\n skillCatalog: [],\r\n writeAgents: true,\r\n writePreset: true,\r\n}\r\n\r\ninterface SwitchSnapshot {\r\n injectAgentsPrompt: boolean\r\n anchorFirstTurn: boolean\r\n anchorText: string\r\n anchorCustom: boolean\r\n guideText: string\r\n guideCustom: boolean\r\n subagentFlash: boolean\r\n bootstrapMaxTokens: number\r\n injectPrompt: boolean\r\n skillSwitches: Record<string, boolean>\r\n writeAgents: boolean\r\n writePreset: boolean\r\n}\r\n\r\nconst EMPTY_SWITCHES: SwitchSnapshot = {\r\n injectAgentsPrompt: false,\r\n anchorFirstTurn: false,\r\n anchorText: '',\r\n anchorCustom: false,\r\n guideText: '',\r\n guideCustom: false,\r\n subagentFlash: false,\r\n bootstrapMaxTokens: 0,\r\n injectPrompt: true,\r\n skillSwitches: {},\r\n writeAgents: true,\r\n writePreset: true,\r\n}\r\n\r\n/** 本项目默认不设上限时的显示值(adapter 默认 maxTokens)。 */\r\nconst DEFAULT_BOOTSTRAP_DISPLAY = '256000'\r\n\r\nconst snapshotSwitches = (fields: Fields): SwitchSnapshot => ({\r\n injectAgentsPrompt: fields.injectAgentsPrompt,\r\n anchorFirstTurn: fields.anchorFirstTurn,\r\n anchorText: fields.anchorText,\r\n anchorCustom: fields.anchorCustom,\r\n guideText: fields.guideText,\r\n guideCustom: fields.guideCustom,\r\n subagentFlash: fields.subagentFlash,\r\n bootstrapMaxTokens: fields.bootstrapMaxTokens,\r\n injectPrompt: fields.injectPrompt,\r\n skillSwitches: { ...fields.skillSwitches },\r\n writeAgents: fields.writeAgents,\r\n writePreset: fields.writePreset,\r\n})\r\n\r\nconst switchesEqual = (a: SwitchSnapshot, b: SwitchSnapshot): boolean =>\r\n a.injectAgentsPrompt === b.injectAgentsPrompt\r\n && a.anchorFirstTurn === b.anchorFirstTurn\r\n && a.anchorText === b.anchorText\r\n && a.anchorCustom === b.anchorCustom\r\n && a.guideText === b.guideText\r\n && a.guideCustom === b.guideCustom\r\n && a.subagentFlash === b.subagentFlash\r\n && a.bootstrapMaxTokens === b.bootstrapMaxTokens\r\n && a.injectPrompt === b.injectPrompt\r\n && JSON.stringify(a.skillSwitches) === JSON.stringify(b.skillSwitches)\r\n && a.writeAgents === b.writeAgents\r\n && a.writePreset === b.writePreset\r\n\r\nconst asRecord = (value: unknown): Record<string, unknown> =>\r\n value !== null && typeof value === 'object' ? value as Record<string, unknown> : {}\r\n\r\nconst readString = (source: Record<string, unknown>, key: string): string | undefined => {\r\n const value = source[key]\r\n return typeof value === 'string' ? value : undefined\r\n}\r\n\r\nconst readBoolean = (source: Record<string, unknown>, key: string, fallback: boolean): boolean => {\r\n const value = source[key]\r\n return typeof value === 'boolean' ? value : fallback\r\n}\r\n\r\nconst readNumber = (source: Record<string, unknown>, key: string, fallback: number): number => {\r\n const value = source[key]\r\n return typeof value === 'number' && Number.isSafeInteger(value) && value >= 0 ? value : fallback\r\n}\r\n\r\nconst readSkillSwitches = (source: Record<string, unknown>, key: string): Record<string, boolean> => {\r\n const value = source[key]\r\n if (value === null || typeof value !== 'object') return {}\r\n const entries = Object.entries(value as Record<string, unknown>)\r\n const result: Record<string, boolean> = {}\r\n for (const [name, enabled] of entries) {\r\n if (typeof enabled === 'boolean') result[name] = enabled\r\n }\r\n return result\r\n}\r\n\r\nconst readSkillCatalog = (source: Record<string, unknown>, key: string): SkillCatalogEntry[] => {\r\n const value = source[key]\r\n if (!Array.isArray(value)) return []\r\n return value.flatMap((entry) => {\r\n if (entry === null || typeof entry !== 'object') return []\r\n const record = entry as Record<string, unknown>\r\n const folder = readString(record, 'folder')\r\n const name = readString(record, 'name')\r\n if (folder === undefined || name === undefined) return []\r\n return [{ folder, name, description: readString(record, 'description') ?? '' }]\r\n })\r\n}\r\n\r\nconst errorMessage = (error: unknown): string => error instanceof Error ? error.message : String(error)\r\n\r\nfunction CollapsibleSection(props: { title: string; hint?: string; open: boolean; onToggle: () => void; children: ReactNode }): ReactNode {\r\n return (\r\n <div className={styles.subSection}>\r\n <button type=\"button\" className={styles.subHeader} aria-expanded={props.open} onClick={props.onToggle}>\r\n <span className={styles.subTitle}>{props.title}</span>\r\n {props.hint && <span className={styles.subCount}>{props.hint}</span>}\r\n <IconChevronDownOutline14 className={clsx(styles.chevron, props.open && styles.chevronOpen)} />\r\n </button>\r\n {props.open && <div className={styles.subBody}>{props.children}</div>}\r\n </div>\r\n )\r\n}\r\n\r\nexport function PromptEditor(props: PromptEditorProps): ReactNode {\r\n const { api } = props\r\n const [open, setOpen] = useState(false)\r\n const [promptOpen, setPromptOpen] = useState(false)\r\n const [agentsOpen, setAgentsOpen] = useState(false)\r\n const [skillsOpen, setSkillsOpen] = useState(false)\r\n const [presetOpen, setPresetOpen] = useState(false)\r\n const [deepseekAvailable, setDeepseekAvailable] = useState(false)\r\n const [deepseekProviders, setDeepseekProviders] = useState<string[]>([])\r\n const [deepseekError, setDeepseekError] = useState('')\r\n const [loaded, setLoaded] = useState(false)\r\n const [fields, setFields] = useState<Fields>(EMPTY)\r\n const [bootstrapTokensDraft, setBootstrapTokensDraft] = useState(DEFAULT_BOOTSTRAP_DISPLAY)\r\n const [savedPromptText, setSavedPromptText] = useState('')\r\n const [savedAgentsText, setSavedAgentsText] = useState('')\r\n const [savedSwitches, setSavedSwitches] = useState<SwitchSnapshot>(EMPTY_SWITCHES)\r\n const [loading, setLoading] = useState(false)\r\n const [savingPrompt, setSavingPrompt] = useState(false)\r\n const [savingAgents, setSavingAgents] = useState(false)\r\n const [restoringPrompt, setRestoringPrompt] = useState(false)\r\n const [restoringAgents, setRestoringAgents] = useState(false)\r\n const [notice, setNotice] = useState('')\r\n const [noticeKind, setNoticeKind] = useState<'ok' | 'error'>('ok')\r\n const fieldsRef = useRef<Fields>(EMPTY)\r\n const revisionRef = useRef<number | undefined>(undefined)\r\n const saveQueueRef = useRef<Promise<void>>(Promise.resolve())\r\n\r\n const showNotice = useCallback((kind: 'ok' | 'error', message: string) => {\r\n setNotice(message)\r\n setNoticeKind(kind)\r\n }, [])\r\n\r\n const load = useCallback(async () => {\r\n setLoading(true)\r\n try {\r\n const res = await bridgePost<BridgeSettingsView>('/describe', {})\r\n if (!res.ok) { showNotice('error', '读取配置失败:' + (res.message ?? '')); return }\r\n setDeepseekAvailable(res.deepseekAvailable === true)\r\n setDeepseekProviders(res.deepseekProviders ?? [])\r\n setDeepseekError(res.deepseekError ?? '')\r\n const ns = res.value\r\n const value = asRecord(ns.value)\r\n const base = asRecord(ns.base)\r\n const next: Fields = {\r\n promptText: readString(value, 'promptText') ?? readString(base, 'promptText') ?? '',\r\n promptPath: readString(value, 'promptPath') ?? readString(base, 'promptPath') ?? '',\r\n agentsText: readString(value, 'agentsText') ?? readString(base, 'agentsText') ?? '',\r\n agentsPath: readString(value, 'agentsPath') ?? readString(base, 'agentsPath') ?? '',\r\n injectAgentsPrompt: readBoolean(value, 'injectAgentsPrompt', readBoolean(base, 'injectAgentsPrompt', false)),\r\n anchorFirstTurn: readBoolean(value, 'anchorFirstTurn', readBoolean(base, 'anchorFirstTurn', false)),\r\n anchorText: readString(value, 'anchorText') ?? readString(base, 'anchorText') ?? '',\r\n anchorCustom: readBoolean(value, 'anchorCustom', readBoolean(base, 'anchorCustom', false)),\r\n guideText: readString(value, 'guideText') ?? readString(base, 'guideText') ?? '',\r\n guideCustom: readBoolean(value, 'guideCustom', readBoolean(base, 'guideCustom', false)),\r\n subagentFlash: readBoolean(value, 'subagentFlash', readBoolean(base, 'subagentFlash', false)),\r\n bootstrapMaxTokens: readNumber(value, 'bootstrapMaxTokens', readNumber(base, 'bootstrapMaxTokens', 0)),\r\n injectPrompt: readBoolean(value, 'injectPrompt', readBoolean(base, 'injectPrompt', true)),\r\n skillSwitches: value.skillSwitches !== undefined || base.skillSwitches !== undefined\r\n ? { ...readSkillSwitches(base, 'skillSwitches'), ...readSkillSwitches(value, 'skillSwitches') }\r\n : {},\r\n skillCatalog: readSkillCatalog(value, 'skillCatalog').length > 0\r\n ? readSkillCatalog(value, 'skillCatalog')\r\n : readSkillCatalog(base, 'skillCatalog'),\r\n writeAgents: readBoolean(value, 'writeAgents', readBoolean(base, 'writeAgents', true)),\r\n writePreset: readBoolean(value, 'writePreset', readBoolean(base, 'writePreset', true)),\r\n }\r\n fieldsRef.current = next\r\n setFields(next)\r\n setBootstrapTokensDraft(next.bootstrapMaxTokens > 0 ? String(next.bootstrapMaxTokens) : DEFAULT_BOOTSTRAP_DISPLAY)\r\n setSavedPromptText(next.promptText)\r\n setSavedAgentsText(next.agentsText)\r\n setSavedSwitches(snapshotSwitches(next))\r\n revisionRef.current = ns.revision\r\n setNotice('')\r\n } catch (error) {\r\n showNotice('error', '读取失败:' + errorMessage(error))\r\n } finally {\r\n setLoading(false)\r\n }\r\n }, [showNotice])\r\n\r\n const refreshRevision = useCallback(async () => {\r\n try {\r\n const res = await bridgePost<BridgeSettingsView>('/describe', {})\r\n if (!res.ok) return\r\n revisionRef.current = res.value.revision\r\n } catch {\r\n // 刷新失败保持原 revision,用户可重试。\r\n }\r\n }, [])\r\n\r\n const restoreOriginal = useCallback(async (scope: 'preset' | 'agents') => {\r\n const setBusy = scope === 'preset' ? setRestoringPrompt : setRestoringAgents\r\n setBusy(true)\r\n try {\r\n const res = await bridgePost<BridgeSettingsView>('/restore-originals', {\r\n scope,\r\n expectedRevision: revisionRef.current,\r\n })\r\n if (!res.ok) {\r\n await refreshRevision()\r\n showNotice('error', '从项目还原失败:' + (res.message ?? '') + '(已刷新配置版本,可重试)')\r\n return\r\n }\r\n revisionRef.current = res.value.revision\r\n await load()\r\n showNotice('ok', scope === 'preset' ? 'preset.md 已从项目原文还原到设置' : 'AGENTS.md 已从项目原文还原到设置')\r\n } catch (error) {\r\n await refreshRevision()\r\n showNotice('error', '从项目还原失败:' + errorMessage(error) + '(已刷新配置版本,可重试)')\r\n } finally {\r\n setBusy(false)\r\n }\r\n }, [load, refreshRevision, showNotice])\r\n\r\n const patch = (partial: Partial<Fields>) => {\r\n const next = { ...fieldsRef.current, ...partial }\r\n fieldsRef.current = next\r\n setFields(next)\r\n }\r\n\r\n const toggleOpen = () => {\r\n const next = !open\r\n setOpen(next)\r\n if (!next) return\r\n if (!loaded) {\r\n setLoaded(true)\r\n void load()\r\n } else if (!dirty) {\r\n // 无未保存草稿时,每次展开同步最新 settings(其他客户端可能已修改)。\r\n void load()\r\n }\r\n }\r\n\r\n const openEdit = async () => {\r\n if (!fields.promptPath) { showNotice('error', '路径未知,请先保存一次或在下方直接编辑'); return }\r\n try {\r\n const res = await api.host.openPath({ path: fields.promptPath })\r\n if (res.result.ok) showNotice('ok', '已用系统编辑器打开 preset.md')\r\n else showNotice('error', '打开失败:' + (res.result.error?.message ?? '') + ';可直接在下方编辑框保存')\r\n } catch (error) {\r\n showNotice('error', '打开失败:' + errorMessage(error) + ';可直接在下方编辑框保存')\r\n }\r\n }\r\n\r\n const openAgents = async () => {\r\n if (!fields.agentsPath) { showNotice('error', '路径未知,请先保存一次或在下方直接编辑'); return }\r\n try {\r\n const res = await api.host.openPath({ path: fields.agentsPath })\r\n if (res.result.ok) showNotice('ok', '已用系统编辑器打开 AGENTS.md')\r\n else showNotice('error', '打开失败:' + (res.result.error?.message ?? '') + ';可直接在下方编辑框保存')\r\n } catch (error) {\r\n showNotice('error', '打开失败:' + errorMessage(error) + ';可直接在下方编辑框保存')\r\n }\r\n }\r\n\r\n const enqueueSave = useCallback((ops: BridgePathOp[], okMessage: string | undefined, onSaved: () => void, setBusy?: (busy: boolean) => void) => {\r\n setBusy?.(true)\r\n saveQueueRef.current = saveQueueRef.current.then(async () => {\r\n try {\r\n const res = await bridgePost<BridgeSettingsView>('/mutate', { ops, expectedRevision: revisionRef.current })\r\n if (res.ok) {\r\n revisionRef.current = res.value.revision\r\n onSaved()\r\n if (okMessage) showNotice('ok', okMessage)\r\n } else {\r\n await refreshRevision()\r\n showNotice('error', '保存失败:' + (res.message ?? '') + '(已刷新配置版本,可重试)')\r\n }\r\n } catch (error) {\r\n await refreshRevision()\r\n showNotice('error', '保存失败:' + errorMessage(error) + '(已刷新配置版本,可重试)')\r\n } finally {\r\n setBusy?.(false)\r\n }\r\n }).catch(() => {})\r\n }, [refreshRevision, showNotice])\r\n\r\n const savePrompt = () => enqueueSave(\r\n [{ op: 'set', path: ['promptText'], value: fieldsRef.current.promptText }],\r\n 'preset.md 已保存并生效',\r\n () => setSavedPromptText(fieldsRef.current.promptText),\r\n setSavingPrompt,\r\n )\r\n\r\n const saveAgents = () => enqueueSave(\r\n [{ op: 'set', path: ['agentsText'], value: fieldsRef.current.agentsText }],\r\n 'AGENTS.md 已保存并生效',\r\n () => setSavedAgentsText(fieldsRef.current.agentsText),\r\n setSavingAgents,\r\n )\r\n\r\n const persistSwitches = () => enqueueSave(\r\n [\r\n { op: 'set', path: ['injectAgentsPrompt'], value: fieldsRef.current.injectAgentsPrompt },\r\n { op: 'set', path: ['anchorFirstTurn'], value: fieldsRef.current.anchorFirstTurn },\r\n { op: 'set', path: ['anchorText'], value: fieldsRef.current.anchorText },\r\n { op: 'set', path: ['anchorCustom'], value: fieldsRef.current.anchorCustom },\r\n { op: 'set', path: ['guideText'], value: fieldsRef.current.guideText },\r\n { op: 'set', path: ['guideCustom'], value: fieldsRef.current.guideCustom },\r\n { op: 'set', path: ['subagentFlash'], value: fieldsRef.current.subagentFlash },\r\n { op: 'set', path: ['bootstrapMaxTokens'], value: fieldsRef.current.bootstrapMaxTokens },\r\n { op: 'set', path: ['injectPrompt'], value: fieldsRef.current.injectPrompt },\r\n { op: 'set', path: ['skillSwitches'], value: fieldsRef.current.skillSwitches },\r\n { op: 'set', path: ['writeAgents'], value: fieldsRef.current.writeAgents },\r\n { op: 'set', path: ['writePreset'], value: fieldsRef.current.writePreset },\r\n ],\r\n undefined,\r\n () => setSavedSwitches(snapshotSwitches(fieldsRef.current)),\r\n )\r\n\r\n const toggle = (key: 'injectAgentsPrompt' | 'anchorFirstTurn' | 'anchorCustom' | 'guideCustom' | 'subagentFlash' | 'injectPrompt' | 'writeAgents' | 'writePreset') => {\r\n if (key === 'subagentFlash' && !deepseekAvailable) {\r\n showNotice('error', '未检测到 DeepSeek 模型配置,子代理 Flash 开关不可用')\r\n return\r\n }\r\n patch({ [key]: !fieldsRef.current[key] })\r\n persistSwitches()\r\n }\r\n\r\n const toggleBootstrapMaxTokens = () => {\r\n const next = fieldsRef.current.bootstrapMaxTokens > 0 ? 0 : 256000\r\n patch({ bootstrapMaxTokens: next })\r\n setBootstrapTokensDraft(DEFAULT_BOOTSTRAP_DISPLAY)\r\n persistSwitches()\r\n }\r\n\r\n const commitBootstrapTokensDraft = () => {\r\n const parsed = Number(bootstrapTokensDraft)\r\n if (!Number.isSafeInteger(parsed) || parsed <= 0) {\r\n // 清空或非法输入不关闭开关:恢复为项目默认 256000(不设上限)。\r\n setBootstrapTokensDraft(DEFAULT_BOOTSTRAP_DISPLAY)\r\n patch({ bootstrapMaxTokens: 256000 })\r\n } else {\r\n patch({ bootstrapMaxTokens: parsed })\r\n }\r\n persistSwitches()\r\n }\r\n\r\n const skillEnabled = (folder: string) => fields.skillSwitches[folder] !== false\r\n\r\n const toggleSkill = (folder: string) => {\r\n const enabled = fieldsRef.current.skillSwitches[folder] !== false\r\n patch({ skillSwitches: { ...fieldsRef.current.skillSwitches, [folder]: !enabled } })\r\n persistSwitches()\r\n }\r\n\r\n const currentSwitches = snapshotSwitches(fields)\r\n const dirtyPrompt = fields.promptText !== savedPromptText\r\n const dirtyAgents = fields.agentsText !== savedAgentsText\r\n const dirtySwitches = !switchesEqual(currentSwitches, savedSwitches)\r\n const dirty = dirtyPrompt || dirtyAgents || dirtySwitches\r\n const promptSwitchDirty = fields.injectPrompt !== savedSwitches.injectPrompt\r\n const agentsSwitchDirty = fields.injectAgentsPrompt !== savedSwitches.injectAgentsPrompt\r\n || fields.writeAgents !== savedSwitches.writeAgents\r\n const skillsSwitchDirty = JSON.stringify(fields.skillSwitches) !== JSON.stringify(savedSwitches.skillSwitches)\r\n const presetSwitchDirty = fields.writePreset !== savedSwitches.writePreset\r\n || fields.anchorFirstTurn !== savedSwitches.anchorFirstTurn\r\n || fields.anchorText !== savedSwitches.anchorText\r\n || fields.bootstrapMaxTokens !== savedSwitches.bootstrapMaxTokens\r\n\r\n const discardPrompt = () => patch({ promptText: savedPromptText })\r\n const discardAgents = () => patch({ agentsText: savedAgentsText })\r\n\r\n return (\r\n <li className={clsx(styles.card, open && styles.cardOpen)}>\r\n <button type=\"button\" className={styles.header} aria-expanded={open} onClick={toggleOpen}>\r\n <span className={styles.headText}>\r\n <span className={styles.name}>提示词工具</span>\r\n <span className={styles.description}>编辑 preset.md / AGENTS.md 与各层注入开关,保存后自动生效</span>\r\n </span>\r\n {dirty && <span className={styles.pending}>未保存</span>}\r\n <IconChevronDownOutline14 className={clsx(styles.chevron, open && styles.chevronOpen)} />\r\n </button>\r\n {open && (\r\n <div className={styles.body}>\r\n {loading && <span className={styles.loading}>正在读取配置…</span>}\r\n\r\n <CollapsibleSection\r\n title=\"Preset预设\"\r\n hint={dirtyPrompt || promptSwitchDirty ? '未保存' : undefined}\r\n open={promptOpen}\r\n onToggle={() => setPromptOpen(!promptOpen)}\r\n >\r\n <label className={styles.row}>\r\n <input\r\n type=\"checkbox\"\r\n checked={fields.injectPrompt}\r\n disabled={!fields.writePreset}\r\n onChange={() => toggle('injectPrompt')}\r\n />\r\n <span className={styles.rowText}>\r\n <span className={styles.rowName}>注入 preset.md(锚定层)</span>\r\n <span className={styles.rowDesc}>注入会话晋升后的 agent/pre-step,消息插入决策消息开头,每会话一次</span>\r\n </span>\r\n </label>\r\n <textarea\r\n className={styles.textarea}\r\n aria-label=\"preset.md 内容\"\r\n value={fields.promptText}\r\n onChange={(e) => patch({ promptText: e.target.value })}\r\n spellCheck={false}\r\n />\r\n <div className={styles.actions}>\r\n <button type=\"button\" className={styles.primary} disabled={savingPrompt || savingAgents || !dirtyPrompt} onClick={savePrompt}>{savingPrompt ? '保存中…' : '保存'}</button>\r\n <button type=\"button\" className={styles.secondary} disabled={!dirtyPrompt} onClick={discardPrompt}>还原草稿</button>\r\n <button type=\"button\" className={styles.secondary} disabled={savingPrompt || savingAgents || restoringPrompt || restoringAgents} onClick={() => void restoreOriginal('preset')}>{restoringPrompt ? '还原中…' : '项目还原'}</button>\r\n <button type=\"button\" className={styles.secondary} onClick={openEdit}>打开</button>\r\n </div>\r\n </CollapsibleSection>\r\n\r\n <CollapsibleSection\r\n title=\"AGENTS设置\"\r\n hint={dirtyAgents || agentsSwitchDirty ? '未保存' : undefined}\r\n open={agentsOpen}\r\n onToggle={() => setAgentsOpen(!agentsOpen)}\r\n >\r\n <label className={styles.row}>\r\n <input\r\n type=\"checkbox\"\r\n checked={fields.injectAgentsPrompt}\r\n disabled={!fields.writePreset}\r\n onChange={() => toggle('injectAgentsPrompt')}\r\n />\r\n <span className={styles.rowText}>\r\n <span className={styles.rowName}>注入 AGENTS.md</span>\r\n <span className={styles.rowDesc}>注入会话晋升后的第一个 agent/pre-step,消息追加在决策消息末尾,每会话一次</span>\r\n </span>\r\n </label>\r\n <label className={styles.row}>\r\n <input\r\n type=\"checkbox\"\r\n checked={fields.writeAgents}\r\n onChange={() => toggle('writeAgents')}\r\n />\r\n <span className={styles.rowText}>\r\n <span className={styles.rowName}>写入 ~/.dsh/AGENTS.md</span>\r\n <span className={styles.rowDesc}>保持 AGENTS.md 的全局常驻注入;关闭后不再写入,已有文件保持原样</span>\r\n </span>\r\n </label>\r\n <textarea\r\n className={styles.textarea}\r\n aria-label=\"AGENTS.md 内容\"\r\n value={fields.agentsText}\r\n onChange={(e) => patch({ agentsText: e.target.value })}\r\n spellCheck={false}\r\n />\r\n <div className={styles.actions}>\r\n <button type=\"button\" className={styles.primary} disabled={savingPrompt || savingAgents || !dirtyAgents} onClick={saveAgents}>{savingAgents ? '保存中…' : '保存'}</button>\r\n <button type=\"button\" className={styles.secondary} disabled={!dirtyAgents} onClick={discardAgents}>还原草稿</button>\r\n <button type=\"button\" className={styles.secondary} disabled={savingPrompt || savingAgents || restoringPrompt || restoringAgents} onClick={() => void restoreOriginal('agents')}>{restoringAgents ? '还原中…' : '项目还原'}</button>\r\n <button type=\"button\" className={styles.secondary} onClick={openAgents}>打开</button>\r\n </div>\r\n </CollapsibleSection>\r\n\r\n <CollapsibleSection\r\n title=\"Skills设置\"\r\n hint={`${fields.skillCatalog.length} 个${skillsSwitchDirty ? ' · 未保存' : ''}`}\r\n open={skillsOpen}\r\n onToggle={() => setSkillsOpen(!skillsOpen)}\r\n >\r\n {fields.skillCatalog.length === 0 ? (\r\n <span className={styles.subEmpty}>skills 目录下没有技能</span>\r\n ) : fields.skillCatalog.map((skill) => (\r\n <label key={skill.folder} className={styles.row}>\r\n <input\r\n type=\"checkbox\"\r\n checked={skillEnabled(skill.folder)}\r\n onChange={() => toggleSkill(skill.folder)}\r\n />\r\n <span className={styles.rowText}>\r\n <span className={styles.rowName}>{skill.name || skill.folder}</span>\r\n <span className={styles.rowDesc}>skills/{skill.folder}{skill.description ? ` · ${skill.description}` : ''}</span>\r\n </span>\r\n </label>\r\n ))}\r\n </CollapsibleSection>\r\n\r\n <CollapsibleSection\r\n title=\"锚定与 preset\"\r\n hint={presetSwitchDirty ? '未保存' : undefined}\r\n open={presetOpen}\r\n onToggle={() => setPresetOpen(!presetOpen)}\r\n >\r\n\r\n <label className={styles.row}>\r\n <input\r\n type=\"checkbox\"\r\n checked={fields.writePreset}\r\n onChange={() => toggle('writePreset')}\r\n />\r\n <span className={styles.rowText}>\r\n <span className={styles.rowName}>启用锚定预设</span>\r\n <span className={styles.rowDesc}>总开关:开启时生成并刷新 ~/.dsh/.agent-presets/prompt-tool/,整套锚定预设才有载体;关闭时移除已生成的目录,下面锚定开关随之失效</span>\r\n </span>\r\n </label>\r\n\r\n <div className={styles.row}>\r\n <input\r\n id=\"prompt-tool-bootstrap-max-tokens\"\r\n type=\"checkbox\"\r\n checked={fields.bootstrapMaxTokens > 0}\r\n disabled={!fields.writePreset}\r\n onChange={toggleBootstrapMaxTokens}\r\n />\r\n <label htmlFor=\"prompt-tool-bootstrap-max-tokens\" className={styles.rowText}>\r\n <span className={styles.rowName}>首轮输出封顶</span>\r\n <span className={styles.rowDesc}>关闭时显示项目默认 256000(不设上限);开启后右侧数值生效,晋升后自动剥离。清空或输入 0 会恢复 256000,不关闭开关</span>\r\n </label>\r\n <input\r\n className={styles.bootstrapTokensInput}\r\n type=\"number\"\r\n min={1}\r\n step={1}\r\n value={bootstrapTokensDraft}\r\n disabled={!fields.writePreset || fields.bootstrapMaxTokens === 0}\r\n onChange={(e) => setBootstrapTokensDraft(e.target.value)}\r\n onBlur={commitBootstrapTokensDraft}\r\n />\r\n </div>\r\n <label className={styles.row}>\r\n <input\r\n type=\"checkbox\"\r\n checked={fields.subagentFlash}\r\n disabled={!fields.writePreset || !deepseekAvailable}\r\n onChange={() => toggle('subagentFlash')}\r\n />\r\n <span className={styles.rowText}>\r\n <span className={styles.rowName}>子代理固定 Flash 模型</span>\r\n <span className={styles.rowDesc}>{deepseekAvailable ? '开启时采用 dsh-router-standard 的 Flash 子代理方案:固定 Flash 路由 + 任务分类人设 + 三锚;宿主直派子代理(含 dsh-mnemon)也会自动补 Flash 路由。关闭时继承主会话模型,工具目录全量放行' : `未检测到 DeepSeek 模型配置,此开关不可用。providers=[${deepseekProviders.join(', ') || '空'}]${deepseekError ? ' error=' + deepseekError : ''}`}</span>\r\n </span>\r\n </label>\r\n <label className={styles.row}>\r\n <input\r\n type=\"checkbox\"\r\n checked={fields.anchorFirstTurn}\r\n disabled={!fields.writePreset}\r\n onChange={() => toggle('anchorFirstTurn')}\r\n />\r\n <span className={styles.rowText}>\r\n <span className={styles.rowName}>追加任务引导</span>\r\n <span className={styles.rowDesc}>总开关:开启后在首条真实用户消息之后追加任务引导;关闭时下方首句与每轮的自定义开关、编辑框全部禁用</span>\r\n </span>\r\n </label>\r\n <label className={styles.row}>\r\n <input\r\n type=\"checkbox\"\r\n checked={fields.anchorCustom}\r\n disabled={!fields.writePreset || !fields.anchorFirstTurn}\r\n onChange={() => toggle('anchorCustom')}\r\n />\r\n <span className={styles.rowText}>\r\n <span className={styles.rowName}>使用自定义引导(首句)</span>\r\n <span className={styles.rowDesc}>开启时使用下方文本作为引导;关闭时忽略下方文本,按任务自动选择 we/let 引导</span>\r\n </span>\r\n </label>\r\n <label className={clsx(styles.rowStack, (!fields.anchorFirstTurn || !fields.anchorCustom) && styles.rowDisabled)}>\r\n <span className={styles.rowText}>\r\n <span className={styles.rowName}>自定义引导文本(首句)</span>\r\n <span className={styles.rowDesc}>仅在上方“使用自定义引导(首句)”开启时生效;关闭时自动文本优先</span>\r\n </span>\r\n <textarea\r\n className={styles.anchorInput}\r\n value={fields.anchorText}\r\n disabled={!fields.writePreset || !fields.anchorFirstTurn || !fields.anchorCustom}\r\n onChange={(e) => patch({ anchorText: e.target.value })}\r\n onBlur={() => persistSwitches()}\r\n spellCheck={false}\r\n />\r\n </label>\r\n <label className={styles.row}>\r\n <input\r\n type=\"checkbox\"\r\n checked={fields.guideCustom}\r\n disabled={!fields.writePreset || !fields.anchorFirstTurn}\r\n onChange={() => toggle('guideCustom')}\r\n />\r\n <span className={styles.rowText}>\r\n <span className={styles.rowName}>使用自定义引导(每轮)</span>\r\n <span className={styles.rowDesc}>开启时每轮固定使用下方文本作为引导;关闭时忽略下方文本,按任务自动选择</span>\r\n </span>\r\n </label>\r\n <label className={clsx(styles.rowStack, (!fields.anchorFirstTurn || !fields.guideCustom) && styles.rowDisabled)}>\r\n <span className={styles.rowText}>\r\n <span className={styles.rowName}>自定义引导文本(每轮)</span>\r\n <span className={styles.rowDesc}>仅在上方“使用自定义引导(每轮)”开启时生效;留空则不注入</span>\r\n </span>\r\n <textarea\r\n className={styles.anchorInput}\r\n value={fields.guideText}\r\n disabled={!fields.writePreset || !fields.anchorFirstTurn || !fields.guideCustom}\r\n onChange={(e) => patch({ guideText: e.target.value })}\r\n onBlur={() => persistSwitches()}\r\n spellCheck={false}\r\n />\r\n </label>\r\n </CollapsibleSection>\r\n\r\n {notice && <span className={clsx(styles.notice, noticeKind === 'error' && styles.noticeError)}>{notice}</span>}\r\n </div>\r\n )}\r\n </li>\r\n )\r\n}\r\n","import type { ClientContext } from '@deepseek-ai/dsh-client-runtime/client'\nimport type { ConnectionHandle } from '@deepseek-ai/dsh-api-remotes/client'\nimport type {} from '@deepseek-ai/dsh-client-ui-settings/client'\nimport type {} from '@deepseek-ai/dsh-client-ui-settings-plugins/client'\nimport { PromptEditor, type PromptEditorInjected } from './PromptEditor.tsx'\n\nexport const inject = ['slots', 'connection']\n\nexport function apply(ctx: ClientContext): void {\n const connection = ctx.get('connection') as ConnectionHandle\n\n const injected = (): PromptEditorInjected => ({\n api: connection.api,\n })\n\n ctx.slots.inject('settings.plugin.item', () => ctx.slots.register({\n name: 'settings.plugin.item',\n id: 'prompt-tool',\n order: 30,\n inject: injected,\n }, PromptEditor))\n}\r\n"],"x_google_ignoreList":[0],"mappings":"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"}
|
package/lib/index.d.mts
CHANGED
|
@@ -34,8 +34,8 @@ interface Config {
|
|
|
34
34
|
subagentFlashProvider: string;
|
|
35
35
|
/** 子代理 Flash 模型名(默认 deepseek-v4-flash)。 */
|
|
36
36
|
subagentFlashModel: string;
|
|
37
|
-
/**
|
|
38
|
-
|
|
37
|
+
/** 首轮输出封顶;0 或未设置 = 不设封顶(本项目默认),正整数 = 请求 #1 的 maxTokens。 */
|
|
38
|
+
bootstrapMaxTokens: number;
|
|
39
39
|
/** 技能目录(默认包内 skills/,可指向本地测试目录)。 */
|
|
40
40
|
skillsDir: string;
|
|
41
41
|
/** 技能候选排序基数,技能目录内按下标递增。 */
|
|
@@ -67,6 +67,7 @@ interface PromptSettings {
|
|
|
67
67
|
guideText: string;
|
|
68
68
|
guideCustom: boolean;
|
|
69
69
|
subagentFlash: boolean;
|
|
70
|
+
bootstrapMaxTokens: number;
|
|
70
71
|
/** 运行时检测:是否注册了 DeepSeek 模型路由(不写入 settings)。 */
|
|
71
72
|
deepseekAvailable: boolean;
|
|
72
73
|
injectPrompt: boolean;
|
package/lib/index.mjs
CHANGED
|
@@ -50,7 +50,7 @@ const Config = z.object({
|
|
|
50
50
|
subagentFlash: z.boolean().default(false),
|
|
51
51
|
subagentFlashProvider: z.string().default("deepseek-official"),
|
|
52
52
|
subagentFlashModel: z.string().default("deepseek-v4-flash"),
|
|
53
|
-
|
|
53
|
+
bootstrapMaxTokens: z.natural().default(0),
|
|
54
54
|
skillsDir: z.string().default(DEFAULT_SKILLS_DIR),
|
|
55
55
|
skillRankBase: z.natural().default(DEFAULT_SKILL_RANK_BASE),
|
|
56
56
|
residentAgentsPath: z.string().default(DEFAULT_RESIDENT_AGENTS_PATH),
|
|
@@ -70,6 +70,7 @@ const PromptSettingsSchema = z.object({
|
|
|
70
70
|
guideText: z.string().default(DEFAULT_GUIDE_TEXT),
|
|
71
71
|
guideCustom: z.boolean().default(false),
|
|
72
72
|
subagentFlash: z.boolean().default(false),
|
|
73
|
+
bootstrapMaxTokens: z.natural().default(0),
|
|
73
74
|
deepseekAvailable: z.boolean().default(true),
|
|
74
75
|
injectPrompt: z.boolean().default(true),
|
|
75
76
|
skillSwitches: z.dict(z.boolean()).default({}),
|
|
@@ -309,6 +310,7 @@ function renderTuiStatus(source) {
|
|
|
309
310
|
"锚点文本:",
|
|
310
311
|
` anchorText ${source.anchorText.length > 0 ? source.anchorText : "(空 = 按任务自动选择)"}`,
|
|
311
312
|
` deepseekAvailable ${source.deepseekAvailable ? "是" : "否(未检测到 DeepSeek 模型,subagentFlash 不可用)"}`,
|
|
313
|
+
` bootstrapMaxTokens ${source.bootstrapMaxTokens > 0 ? source.bootstrapMaxTokens : "0(关闭,不设封顶)"}`,
|
|
312
314
|
"技能开关:"
|
|
313
315
|
];
|
|
314
316
|
for (const skill of source.skillCatalog) {
|
|
@@ -333,7 +335,7 @@ function registerTuiCommand(ctx, getSource, getDeepseekAvailable, getDeepseekSta
|
|
|
333
335
|
handler: async (invocation) => {
|
|
334
336
|
const usage = () => ({
|
|
335
337
|
kind: "error",
|
|
336
|
-
text: "用法:/prompt-tool status\n /prompt-tool on|off|toggle <writeAgents|writePreset|injectPrompt|injectAgentsPrompt|anchorFirstTurn|anchorCustom|guideCustom|subagentFlash>\n /prompt-tool skill <技能目录名> on|off|toggle"
|
|
338
|
+
text: "用法:/prompt-tool status\n /prompt-tool on|off|toggle <writeAgents|writePreset|injectPrompt|injectAgentsPrompt|anchorFirstTurn|anchorCustom|guideCustom|subagentFlash>\n /prompt-tool skill <技能目录名> on|off|toggle\n /prompt-tool bootstrapMaxTokens <正整数|0(关闭)>"
|
|
337
339
|
});
|
|
338
340
|
const tokens = invocation.rawInput.trim().split(/\s+/).filter((token) => token.length > 0);
|
|
339
341
|
const source = getSource();
|
|
@@ -360,6 +362,25 @@ function registerTuiCommand(ctx, getSource, getDeepseekAvailable, getDeepseekSta
|
|
|
360
362
|
kind: "success",
|
|
361
363
|
text: `已把技能 ${folder} 设为 ${next ? "开" : "关"}
|
|
362
364
|
|
|
365
|
+
${renderTuiStatus(getSource())}`
|
|
366
|
+
};
|
|
367
|
+
}
|
|
368
|
+
if (tokens[0] === "bootstrapMaxTokens") {
|
|
369
|
+
const raw = tokens[1];
|
|
370
|
+
const value = raw === void 0 ? NaN : Number(raw);
|
|
371
|
+
if (!Number.isSafeInteger(value) || value < 0) return {
|
|
372
|
+
kind: "error",
|
|
373
|
+
text: "bootstrapMaxTokens 需要非负整数:0 关闭封顶,正整数设置首轮 maxTokens。"
|
|
374
|
+
};
|
|
375
|
+
await sctx.settings.mutate(NS, [{
|
|
376
|
+
op: "set",
|
|
377
|
+
path: ["bootstrapMaxTokens"],
|
|
378
|
+
value
|
|
379
|
+
}]);
|
|
380
|
+
return {
|
|
381
|
+
kind: "success",
|
|
382
|
+
text: `已把 bootstrapMaxTokens 设为 ${value === 0 ? "关闭(不设封顶)" : String(value)}
|
|
383
|
+
|
|
363
384
|
${renderTuiStatus(getSource())}`
|
|
364
385
|
};
|
|
365
386
|
}
|
|
@@ -668,7 +689,7 @@ function writePreset(prompt, options) {
|
|
|
668
689
|
subagentFlash: options.subagentFlash,
|
|
669
690
|
subagentFlashProvider: options.subagentFlashProvider,
|
|
670
691
|
subagentFlashModel: options.subagentFlashModel,
|
|
671
|
-
|
|
692
|
+
bootstrapMaxTokens: options.bootstrapMaxTokens
|
|
672
693
|
}), "utf8");
|
|
673
694
|
const meta = readFileSync(PRESET_TEMPLATE_META, "utf8").replace(/^order:.*$/m, `order: ${options.presetOrder}`);
|
|
674
695
|
writeFileSync(join(presetDir, "preset.yml"), meta, "utf8");
|
|
@@ -763,7 +784,8 @@ function apply(ctx, config) {
|
|
|
763
784
|
anchorCustom: config.anchorCustom,
|
|
764
785
|
guideText: config.guideText,
|
|
765
786
|
guideCustom: config.guideCustom,
|
|
766
|
-
subagentFlash: config.subagentFlash && getDeepseekAvailable()
|
|
787
|
+
subagentFlash: config.subagentFlash && getDeepseekAvailable(),
|
|
788
|
+
bootstrapMaxTokens: config.bootstrapMaxTokens
|
|
767
789
|
};
|
|
768
790
|
installSubagentFlashRoute(ctx, () => runtime.subagentFlash, config.subagentFlashProvider, config.subagentFlashModel);
|
|
769
791
|
let currentSource = () => ({
|
|
@@ -778,6 +800,7 @@ function apply(ctx, config) {
|
|
|
778
800
|
guideText: runtime.guideText,
|
|
779
801
|
guideCustom: runtime.guideCustom,
|
|
780
802
|
subagentFlash: runtime.subagentFlash,
|
|
803
|
+
bootstrapMaxTokens: runtime.bootstrapMaxTokens,
|
|
781
804
|
deepseekAvailable: getDeepseekAvailable(),
|
|
782
805
|
injectPrompt: runtime.injectPrompt,
|
|
783
806
|
skillSwitches: runtime.skillSwitches,
|
|
@@ -800,12 +823,13 @@ function apply(ctx, config) {
|
|
|
800
823
|
anchorCustom: typeof next.anchorCustom === "boolean" ? next.anchorCustom : config.anchorCustom,
|
|
801
824
|
guideText: typeof next.guideText === "string" ? next.guideText : config.guideText,
|
|
802
825
|
guideCustom: typeof next.guideCustom === "boolean" ? next.guideCustom : config.guideCustom,
|
|
803
|
-
subagentFlash: (typeof next.subagentFlash === "boolean" ? next.subagentFlash : config.subagentFlash) && getDeepseekAvailable()
|
|
826
|
+
subagentFlash: (typeof next.subagentFlash === "boolean" ? next.subagentFlash : config.subagentFlash) && getDeepseekAvailable(),
|
|
827
|
+
bootstrapMaxTokens: Number.isSafeInteger(next.bootstrapMaxTokens) && next.bootstrapMaxTokens >= 0 ? next.bootstrapMaxTokens : config.bootstrapMaxTokens
|
|
804
828
|
};
|
|
805
829
|
const promptChanged = next.promptText !== current;
|
|
806
830
|
const agentsChanged = next.agentsText !== currentAgents;
|
|
807
831
|
const skillSwitchesChanged = JSON.stringify(runtime.skillSwitches) !== JSON.stringify(nextRuntime.skillSwitches);
|
|
808
|
-
const settingsChanged = runtime.writeAgents !== nextRuntime.writeAgents || runtime.writePreset !== nextRuntime.writePreset || runtime.injectAgentsPrompt !== nextRuntime.injectAgentsPrompt || runtime.injectPrompt !== nextRuntime.injectPrompt || skillSwitchesChanged || runtime.anchorFirstTurn !== nextRuntime.anchorFirstTurn || runtime.anchorText !== nextRuntime.anchorText || runtime.anchorCustom !== nextRuntime.anchorCustom || runtime.guideText !== nextRuntime.guideText || runtime.guideCustom !== nextRuntime.guideCustom || runtime.subagentFlash !== nextRuntime.subagentFlash;
|
|
832
|
+
const settingsChanged = runtime.writeAgents !== nextRuntime.writeAgents || runtime.writePreset !== nextRuntime.writePreset || runtime.injectAgentsPrompt !== nextRuntime.injectAgentsPrompt || runtime.injectPrompt !== nextRuntime.injectPrompt || skillSwitchesChanged || runtime.anchorFirstTurn !== nextRuntime.anchorFirstTurn || runtime.anchorText !== nextRuntime.anchorText || runtime.anchorCustom !== nextRuntime.anchorCustom || runtime.guideText !== nextRuntime.guideText || runtime.guideCustom !== nextRuntime.guideCustom || runtime.subagentFlash !== nextRuntime.subagentFlash || runtime.bootstrapMaxTokens !== nextRuntime.bootstrapMaxTokens;
|
|
809
833
|
if (!needsInitialApply && !promptChanged && !agentsChanged && !settingsChanged) return;
|
|
810
834
|
needsInitialApply = false;
|
|
811
835
|
if (promptChanged) current = next.promptText;
|
|
@@ -821,6 +845,7 @@ function apply(ctx, config) {
|
|
|
821
845
|
runtime.guideText = nextRuntime.guideText;
|
|
822
846
|
runtime.guideCustom = nextRuntime.guideCustom;
|
|
823
847
|
runtime.subagentFlash = nextRuntime.subagentFlash;
|
|
848
|
+
runtime.bootstrapMaxTokens = nextRuntime.bootstrapMaxTokens;
|
|
824
849
|
skillSwitches = runtime.skillSwitches;
|
|
825
850
|
if (skillSwitchesChanged) invalidateSkills?.();
|
|
826
851
|
let residentAgentsWritten = false;
|
|
@@ -841,7 +866,7 @@ function apply(ctx, config) {
|
|
|
841
866
|
subagentFlash: runtime.subagentFlash,
|
|
842
867
|
subagentFlashProvider: config.subagentFlashProvider,
|
|
843
868
|
subagentFlashModel: config.subagentFlashModel,
|
|
844
|
-
|
|
869
|
+
bootstrapMaxTokens: runtime.bootstrapMaxTokens,
|
|
845
870
|
agentsInstructionText: runtime.injectAgentsPrompt && currentAgents.length > 0 ? currentAgents : void 0,
|
|
846
871
|
presetDir: config.presetDir,
|
|
847
872
|
presetOrder: config.presetOrder
|
|
@@ -867,6 +892,7 @@ function apply(ctx, config) {
|
|
|
867
892
|
guideText: config.guideText,
|
|
868
893
|
guideCustom: config.guideCustom,
|
|
869
894
|
subagentFlash: config.subagentFlash && getDeepseekAvailable(),
|
|
895
|
+
bootstrapMaxTokens: config.bootstrapMaxTokens,
|
|
870
896
|
deepseekAvailable: getDeepseekAvailable(),
|
|
871
897
|
injectPrompt: config.injectPrompt,
|
|
872
898
|
skillSwitches: { ...config.skillSwitches },
|
package/lib/preset-core.d.mts
CHANGED
|
@@ -28,8 +28,8 @@ interface BuildCordisOptions {
|
|
|
28
28
|
subagentFlashProvider?: string;
|
|
29
29
|
/** 子代理 Flash 模型名(默认 deepseek-v4-flash)。 */
|
|
30
30
|
subagentFlashModel?: string;
|
|
31
|
-
/**
|
|
32
|
-
|
|
31
|
+
/** 首轮输出封顶(bootstrapMaxTokens);0 或未设置 = 本项目默认无封顶。 */
|
|
32
|
+
bootstrapMaxTokens?: number;
|
|
33
33
|
}
|
|
34
34
|
declare function buildCordis(prompt: string, options?: BuildCordisOptions): string;
|
|
35
35
|
//#endregion
|
package/lib/preset-core.mjs
CHANGED
|
@@ -86,11 +86,16 @@ function normalizeContextGate(source) {
|
|
|
86
86
|
if (!source.includes(block)) throw new Error("vendor agent.cordis.yml missing context-gate row");
|
|
87
87
|
return source.replace(block, replaced);
|
|
88
88
|
}
|
|
89
|
-
/**
|
|
90
|
-
function
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
89
|
+
/** 按开关向上游 tool-bootstrap 行注入 bootstrapMaxTokens;0/未设置保持无封顶。 */
|
|
90
|
+
function applyBootstrapMaxTokens(source, value) {
|
|
91
|
+
if (value === void 0 || !Number.isSafeInteger(value) || value <= 0) return source;
|
|
92
|
+
const rowStart = source.indexOf("- id: tool-bootstrap\n name: ./tool-bootstrap.mjs\n config:\n");
|
|
93
|
+
if (rowStart < 0) throw new Error("vendor agent.cordis.yml missing tool-bootstrap config block");
|
|
94
|
+
const include = source.indexOf(" includeSubagents: true\n", rowStart);
|
|
95
|
+
if (include < 0) throw new Error("vendor agent.cordis.yml tool-bootstrap row missing includeSubagents");
|
|
96
|
+
const at = include + 26 + 1;
|
|
97
|
+
return source.slice(0, at) + ` bootstrapMaxTokens: ${value}
|
|
98
|
+
` + source.slice(at);
|
|
94
99
|
}
|
|
95
100
|
/** 给 subagent/subagent_fork 行加 dsh-router-standard 的 Flash 子代理方案;关闭时保持继承主会话路由。 */
|
|
96
101
|
function applySubagentFlash(source, enabled, provider, model) {
|
|
@@ -133,7 +138,7 @@ function buildCordis(prompt, options = {}) {
|
|
|
133
138
|
const injectPrompt = options.injectPrompt !== false;
|
|
134
139
|
const anchorText = typeof options.anchorText === "string" && options.anchorText.length > 0 ? options.anchorText : "";
|
|
135
140
|
const indent = (s) => s.split(/\r?\n/).map((l) => l.length === 0 ? "" : " " + l).join("\n");
|
|
136
|
-
const up = normalizeContextGate(
|
|
141
|
+
const up = applyBootstrapMaxTokens(normalizeContextGate(applySubagentFlash(readFileSync(VENDOR_CORDIS, "utf8").replace(/\r\n/g, "\n"), options.subagentFlash === true, typeof options.subagentFlashProvider === "string" && options.subagentFlashProvider.length > 0 ? options.subagentFlashProvider : "deepseek-official", typeof options.subagentFlashModel === "string" && options.subagentFlashModel.length > 0 ? options.subagentFlashModel : "deepseek-v4-flash")), options.bootstrapMaxTokens);
|
|
137
142
|
const bootstrap = /^-\s+id:\s+tool-bootstrap\s*$/m.exec(up);
|
|
138
143
|
if (!bootstrap) throw new Error("vendor agent.cordis.yml missing tool-bootstrap row");
|
|
139
144
|
let cursor = up.indexOf("\n", bootstrap.index);
|
package/package.json
CHANGED
package/plan.md
CHANGED
|
@@ -1,4 +1,8 @@
|
|
|
1
1
|
# dsh-plugin-prompt-tool 重新设计计划(v2)
|
|
2
|
+
> **v2.15 上游同步(当前实现)**:同步上游到 `25f21ae`;移除
|
|
3
|
+
> `customBashPath` 生成时改写,直接沿用上游 custom-bash 运行时探测。
|
|
4
|
+
> 新增 `bootstrapMaxTokens` 开关(0=关闭;正整数写入上游 tool-bootstrap)。
|
|
5
|
+
|
|
2
6
|
> **v2.14 上游同步与路径校对(当前实现)**:已从上游 main 同步到
|
|
3
7
|
> `ba7a27c`;新增 context-gate.mjs;custom-bash 的固定路径在生成时归一化为
|
|
4
8
|
> `customBashPath`(默认 bash.exe,PATH 查找)。
|
|
@@ -1 +1 @@
|
|
|
1
|
-
|
|
1
|
+
25f21aefaf8ddc414da54d2e581e43740d977c6e
|
|
@@ -149,12 +149,19 @@
|
|
|
149
149
|
name: '@deepseek-ai/dsh-tool-pwsh'
|
|
150
150
|
disabled: !!js process.platform !== 'win32'
|
|
151
151
|
|
|
152
|
-
# The Minimal preset's shell: a PTY-backed persistent bash,
|
|
153
|
-
#
|
|
154
|
-
#
|
|
155
|
-
#
|
|
156
|
-
#
|
|
157
|
-
#
|
|
152
|
+
# The Minimal preset's shell: a PTY-backed persistent bash, schema-identical
|
|
153
|
+
# to the official `minimal` preset's `persistent-shell` group so the first
|
|
154
|
+
# request exposes exactly Minimal's real `bash` schema. ONE deliberate config
|
|
155
|
+
# difference: an adaptive `shellPath` — the terminal-bash plugin default
|
|
156
|
+
# `/bin/bash` where that absolute path exists (every host that ships it keeps
|
|
157
|
+
# the previous behavior), otherwise a bare `bash` resolved through the same
|
|
158
|
+
# scrubbed PATH the other harness tools use. The fallback exists because
|
|
159
|
+
# `/bin/bash` does not exist on NixOS and other hosts that keep bash
|
|
160
|
+
# elsewhere; there `execvp("/bin/bash")` exits during PTY startup ("PTY shell
|
|
161
|
+
# exited during startup") and every bash call fails. The PTY registry is an
|
|
162
|
+
# agent-owned service, so it lives in an entry-local realm; the backend still
|
|
163
|
+
# consumes the host sandbox policy and subprocess implementation, while the
|
|
164
|
+
# tool registers into this agent's scoped catalog.
|
|
158
165
|
#
|
|
159
166
|
# DISABLED ON WINDOWS: DSH's PTY backend is linux/darwin-only, so the
|
|
160
167
|
# persistent shell cannot serve win32. The `custom-bash` row below registers
|
|
@@ -172,6 +179,7 @@
|
|
|
172
179
|
- id: terminal-bash
|
|
173
180
|
name: '@deepseek-ai/dsh-terminal-bash'
|
|
174
181
|
config:
|
|
182
|
+
shellPath: !!js "process.getBuiltinModule?.('node:fs')?.existsSync('/bin/bash') ? '/bin/bash' : 'bash'"
|
|
175
183
|
timeoutMs: 300000
|
|
176
184
|
|
|
177
185
|
- id: persistent-bash
|
|
@@ -191,15 +199,18 @@
|
|
|
191
199
|
# Windows-only `bash` tool (see custom-bash.mjs): registers the SAME
|
|
192
200
|
# tool name as the persistent shell with a Minimal-compatible description, but
|
|
193
201
|
# executes through the ordinary cross-platform subprocess seam (`bash -c`)
|
|
194
|
-
# instead of a PTY.
|
|
195
|
-
#
|
|
202
|
+
# instead of a PTY. The shell is resolved WITHOUT a hardcoded install path
|
|
203
|
+
# (issue #24): `bashPath` unset probes the `git` executable's install root,
|
|
204
|
+
# then the well-known Git-for-Windows roots (Program Files(/x86), per-user
|
|
205
|
+
# LOCALAPPDATA, scoop's `current` junction), then plain `bash` on PATH — set
|
|
206
|
+
# `bashPath` explicitly only to pin a shell that probing cannot find. No OS
|
|
196
207
|
# sandbox confinement on Windows (landlock is linux-only); the tool
|
|
197
|
-
# description says so.
|
|
208
|
+
# description says so. When no bash exists at all the tool errors with
|
|
209
|
+
# guidance instead of switching shells — pwsh stays its own tool in the
|
|
210
|
+
# promoted catalog.
|
|
198
211
|
- id: custom-bash
|
|
199
212
|
name: ./custom-bash.mjs
|
|
200
213
|
disabled: !!js process.platform !== 'win32'
|
|
201
|
-
config:
|
|
202
|
-
bashPath: 'C:\Program Files\Git\bin\bash.exe'
|
|
203
214
|
|
|
204
215
|
# ── filesystem ──────────────────────────────────────────────────────────────
|
|
205
216
|
|
|
@@ -13,9 +13,27 @@
|
|
|
13
13
|
* the ordinary (cross-platform) subprocess seam keeps the schema anchor
|
|
14
14
|
* without the PTY dependency.
|
|
15
15
|
*
|
|
16
|
-
* Executable resolution (config `bashPath
|
|
17
|
-
*
|
|
18
|
-
*
|
|
16
|
+
* Executable resolution (config `bashPath`, issue #24 — no hardcoded install
|
|
17
|
+
* path): an explicit non-empty `bashPath` wins unconditionally. Unset, the
|
|
18
|
+
* Git Bash executable is INFERRED, in probe order:
|
|
19
|
+
* 1. the `git` executable on PATH — its install root carries `bin\bash.exe`
|
|
20
|
+
* one level up from `cmd\`, beside `bin\`, or two levels up from
|
|
21
|
+
* `mingw64\bin\` (the standard installer, choco, and winget all resolve
|
|
22
|
+
* here; a scoop SHIM does not — its directory is the shims root, not the
|
|
23
|
+
* app — which is what step 2 covers);
|
|
24
|
+
* 2. the well-known Git-for-Windows roots derived from environment variables
|
|
25
|
+
* (`ProgramFiles`, `ProgramFiles(x86)`, per-user `LOCALAPPDATA\Programs
|
|
26
|
+
* \Git`, scoop's `~\scoop\apps\git\current` junction);
|
|
27
|
+
* 3. plain `bash` through `ctx.subprocess.resolveExecutable` (PATH lookup —
|
|
28
|
+
* last resort, since on Windows that may pick the WSL shim; WSL bash is
|
|
29
|
+
* still true bash, only the filesystem paths shift to /mnt/…).
|
|
30
|
+
*
|
|
31
|
+
* If NOTHING resolves, the tool fails with an actionable error naming the
|
|
32
|
+
* remedies — it does NOT silently execute under a different shell: the
|
|
33
|
+
* schema above promises `bash -c` semantics, and pwsh/cmd are different
|
|
34
|
+
* command languages. PowerShell stays available as its OWN tool (`pwsh`,
|
|
35
|
+
* present in the promoted catalog on Windows, unlockable via
|
|
36
|
+
* dev_tool_search).
|
|
19
37
|
*
|
|
20
38
|
* Semantics mirror the official bash tool: `bash -c <command>` in a fresh
|
|
21
39
|
* process, bounded output, non-zero exit reported not thrown. No sandbox
|
|
@@ -24,6 +42,9 @@
|
|
|
24
42
|
* `str_replace_editor` (Minimal's two tools).
|
|
25
43
|
*/
|
|
26
44
|
|
|
45
|
+
import { access } from 'node:fs/promises'
|
|
46
|
+
import { dirname, join } from 'node:path'
|
|
47
|
+
|
|
27
48
|
/** Cordis plugin name used by loader diagnostics. */
|
|
28
49
|
export const name = 'custom-bash'
|
|
29
50
|
|
|
@@ -33,6 +54,34 @@ export const inject = ['subprocess', 'tools']
|
|
|
33
54
|
const DEFAULT_TIMEOUT_MS = 120000
|
|
34
55
|
const DEFAULT_MAX_OUTPUT_BYTES = 64000
|
|
35
56
|
|
|
57
|
+
/**
|
|
58
|
+
* Git Bash candidate paths, in probe order (see the header): the `git`
|
|
59
|
+
* executable's install root first, then the well-known env-derived roots.
|
|
60
|
+
* Exported for tests; pure — existence probing happens at the call site.
|
|
61
|
+
*/
|
|
62
|
+
export function bashCandidates(env, gitExe) {
|
|
63
|
+
const candidates = []
|
|
64
|
+
// git at <root>\cmd\git.exe (installer/scoop) or <root>\bin\git.exe →
|
|
65
|
+
// <root>\bin\bash.exe; <root>\mingw64\bin\git.exe (portable) → two up.
|
|
66
|
+
// A bare relative name means `git` did not actually resolve to a path.
|
|
67
|
+
if (typeof gitExe === 'string' && /[/\\]/.test(gitExe)) {
|
|
68
|
+
const dir = dirname(gitExe)
|
|
69
|
+
const root = dirname(dir)
|
|
70
|
+
candidates.push(
|
|
71
|
+
join(root, 'bin', 'bash.exe'),
|
|
72
|
+
join(dir, 'bash.exe'),
|
|
73
|
+
join(dirname(root), 'bin', 'bash.exe'),
|
|
74
|
+
)
|
|
75
|
+
}
|
|
76
|
+
if (env.ProgramFiles) candidates.push(join(env.ProgramFiles, 'Git', 'bin', 'bash.exe'))
|
|
77
|
+
if (env['ProgramFiles(x86)']) candidates.push(join(env['ProgramFiles(x86)'], 'Git', 'bin', 'bash.exe'))
|
|
78
|
+
if (env.LOCALAPPDATA) candidates.push(join(env.LOCALAPPDATA, 'Programs', 'Git', 'bin', 'bash.exe'))
|
|
79
|
+
if (env.USERPROFILE) candidates.push(join(env.USERPROFILE, 'scoop', 'apps', 'git', 'current', 'bin', 'bash.exe'))
|
|
80
|
+
// Layouts overlap (a `bin` git.exe derives the same bash twice) — probe
|
|
81
|
+
// order survives the dedupe, insertion order is preserved.
|
|
82
|
+
return [...new Set(candidates)]
|
|
83
|
+
}
|
|
84
|
+
|
|
36
85
|
/** Tool parameter schema for the model-facing command. */
|
|
37
86
|
const commandSchema = {
|
|
38
87
|
type: 'object',
|
|
@@ -52,10 +101,54 @@ const commandSchema = {
|
|
|
52
101
|
|
|
53
102
|
/** Register the model-facing `bash` tool. */
|
|
54
103
|
export function apply(ctx, config) {
|
|
55
|
-
const
|
|
104
|
+
const explicitBashPath = typeof config?.bashPath === 'string' && config.bashPath.length > 0 ? config.bashPath : undefined
|
|
56
105
|
const timeoutMs = Number.isSafeInteger(config?.timeoutMs) && config.timeoutMs > 0 ? config.timeoutMs : DEFAULT_TIMEOUT_MS
|
|
57
106
|
const maxOutputBytes = Number.isSafeInteger(config?.maxOutputBytes) && config.maxOutputBytes > 0 ? config.maxOutputBytes : DEFAULT_MAX_OUTPUT_BYTES
|
|
58
107
|
|
|
108
|
+
// The inferred executable is memoized per plugin instance: candidate probing
|
|
109
|
+
// walks the filesystem, and the answer cannot change within a mount. A
|
|
110
|
+
// failed inference is NOT memoized — the plain `bash` fallback resolves
|
|
111
|
+
// fresh on every execute until some probe succeeds.
|
|
112
|
+
let inferredShell
|
|
113
|
+
const exists = (path) => access(path).then(() => true, () => false)
|
|
114
|
+
const resolveShell = async (signal) => {
|
|
115
|
+
if (explicitBashPath !== undefined) {
|
|
116
|
+
// A misconfigured explicit path must fail as itself, not as a
|
|
117
|
+
// discovery miss — the raw resolution error says which path failed.
|
|
118
|
+
return ctx.subprocess.resolveExecutable(explicitBashPath, undefined, signal)
|
|
119
|
+
}
|
|
120
|
+
if (inferredShell !== undefined) {
|
|
121
|
+
return ctx.subprocess.resolveExecutable(inferredShell, undefined, signal)
|
|
122
|
+
}
|
|
123
|
+
let gitExe
|
|
124
|
+
try {
|
|
125
|
+
gitExe = await ctx.subprocess.resolveExecutable('git', undefined, signal)
|
|
126
|
+
} catch {
|
|
127
|
+
// git unresolvable → the env-derived candidates below still apply
|
|
128
|
+
}
|
|
129
|
+
for (const candidate of bashCandidates(process.env, gitExe)) {
|
|
130
|
+
if (!(await exists(candidate))) continue
|
|
131
|
+
try {
|
|
132
|
+
inferredShell = await ctx.subprocess.resolveExecutable(candidate, undefined, signal)
|
|
133
|
+
return inferredShell
|
|
134
|
+
} catch {
|
|
135
|
+
// Exists but unresolvable (EPERM, a broken scoop junction): keep
|
|
136
|
+
// probing — one bad root must not block the rest of the chain, and
|
|
137
|
+
// nothing is memoized so later executes can still find a good one.
|
|
138
|
+
continue
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
try {
|
|
142
|
+
return await ctx.subprocess.resolveExecutable('bash', undefined, signal)
|
|
143
|
+
} catch (error) {
|
|
144
|
+
// Total discovery failure (no Git Bash root, no env root, no bash on
|
|
145
|
+
// PATH): name the remedies instead of leaking a raw ENOENT. Never
|
|
146
|
+
// fall back to pwsh/cmd here — the schema promises `bash -c`
|
|
147
|
+
// semantics; a different shell would silently break every command.
|
|
148
|
+
throw new Error(`bash executable not found — install Git for Windows, expose a bash on PATH, or set the custom-bash \`bashPath\` config (${String((error && error.message) || error)})`)
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
|
|
59
152
|
ctx.tools.register({
|
|
60
153
|
name: 'bash',
|
|
61
154
|
description: [
|
|
@@ -81,7 +174,7 @@ export function apply(ctx, config) {
|
|
|
81
174
|
render: (_args, value) => [{ type: 'text', text: value.text }],
|
|
82
175
|
},
|
|
83
176
|
async execute(args, exec) {
|
|
84
|
-
const shell = await
|
|
177
|
+
const shell = await resolveShell(exec?.signal)
|
|
85
178
|
const workdir = typeof args.workdir === 'string' && args.workdir.length > 0
|
|
86
179
|
? args.workdir
|
|
87
180
|
: exec?.agent?.session?.header?.cwd
|