dsh-plugin-prompt-tool 0.3.0 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,53 +1,49 @@
1
1
  # 提示词工具(dsh-plugin-prompt-tool)
2
2
 
3
- DSH 插件:为 DeepSeek Harness 提供三层提示词规范注入,并通过 Web 界面在线编辑。核心是“最优组合”首轮锚定:保持官方 Minimal(极简)训练分布的首轮条件,在模型轨迹稳定后再恢复完整能力。
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
- 上游文件固化在 `upstream/dsh-anchored-standard/`(含 `LICENSE`、`NOTICE`、`REVISION`),
14
- `pnpm sync:anchored` 更新。
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`(先到者为准)落地后,按 `usePtcMode` 开关选择 wire 形态——默认开启时切换为 Code Mode(PTC,单一 `run_code`),完整插件工具经生成 SDK 调用;关闭时恢复原生完整工具目录。
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
- - **常驻层**:把 `AGENTS.md` 作为受管块写入 `~/.dsh/AGENTS.md`;开启 `injectAgentsPrompt` 时,以 `instruction-hint` 的位置每会话注入一次。
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
- ```sh
28
- pnpm install
29
- pnpm build # 生成 lib/
30
- pnpm typecheck # Host Client 两个 tsc program
31
- pnpm lint # oxlint
32
- pnpm test # pnpm build + node --test
33
- pnpm prepare # npm publish / git install 前自动触发
34
- pnpm sync:anchored # 从上游 main 刷新内联快照(可加 ref 参数)
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
+ - `usePtcMode`(默认开启):晋升后把 wire 切换为 Code Mode(PTC,单一 `run_code`),完整插件工具经生成 SDK 调用;关闭时恢复原生完整工具目录。两种模式都不再依赖 `dev_tool_search`,生成 preset 时直接移除该行且不复制 `dev-tool-search.mjs`。
25
+ - `router-first-turn`:只替换 persona 段,保留 plan-mode 段与第三方 section;首轮隐藏 `mnemon:*` 自动注入段,晋升后恢复。
26
+ - `near-anchor`:行为引导放在真实用户消息之后(近距离零衰减),只要求首句一次;复杂规划任务放行 Let 深度路径,日常任务锚 We。
27
+ - `router-guide`:简单任务快速收敛,复杂任务深度引导;子代理不注入,首轮不注入。
28
+ - `prompt-injector`:注入状态以持久事件为准,跨进程重启 / 插件热重载不重复注入。
29
+ - `injectAgentsPrompt`:开启时用 `AGENTS.md` 内容替换本地 instruction-hint 的默认提示文本;关闭时使用本地默认 hint(列出参考文件、按需读取)。
30
+ - `skillSwitches`:扫描 `skills/*/SKILL.md` 注册可开关技能,未列出的技能默认开启。
31
+ - `subagentFlash`:检测不到 DeepSeek 模型路由时 Web/TUI 禁用并强制降级为关闭。
36
32
 
37
- 安装到 `prompt-tool` profile:
33
+ ## 安装
38
34
 
39
35
  ```sh
40
36
  # 1. 先安装宿主服务(提供 webServer 等本插件依赖的服务)
41
37
  dsh plugin --profile prompt-tool add @deepseek-ai/dsh-web-app
42
38
  # 或使用 dsh-tui:dsh plugin --profile prompt-tool add @deepseek-harness-tui/dsh-tui
43
39
 
44
- # 2. npm 安装本插件(官方插件指令,自动加入 profile bundles)
40
+ # 2. 安装本插件(官方插件指令,自动加入 profile bundles)
45
41
  dsh plugin --profile prompt-tool add dsh-plugin-prompt-tool
46
42
 
47
- # 3. 本地开发安装(任选其一,会覆盖上一步的 registry 依赖)
43
+ # 3. 本地开发安装(任选其一,会覆盖 registry 依赖)
48
44
  dsh plugin --profile prompt-tool add link:<本仓库绝对路径>
49
45
 
50
- # 4. 启动方式(任选)
46
+ # 4. 启动
51
47
  dsh --profile prompt-tool
52
48
  dsh web
53
49
  dsh-tui
@@ -56,45 +52,51 @@ dsh-tui
56
52
  dsh plugin --profile prompt-tool remove dsh-plugin-prompt-tool
57
53
  ```
58
54
 
59
- 本插件声明了 `dsh.bundle`,所以官方 `add` 会自动把它追加进
60
- `dsh.profile.bundles`;`dsh-base` 与 `dsh-web-app` 不会由本插件写入。
61
- 如果启动时报 `waiting for service: webServer`,说明该 profile 缺少宿主
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
- ```
55
+ 装完**完整重启 `dsh web`**,新建空 session,预设选择 **prompt-tool**。插件会在启动时生成并刷新 `~/.dsh/.agent-presets/prompt-tool/`(升级插件后重启即自动更新)。
56
+
57
+ ## 验证
76
58
 
77
- 临时调试可用官方 `--patch` 覆盖层(不落盘、不改 profile):
59
+ 导出 session JSONL,检查 `request/header`:
60
+
61
+ - 第一份 header 的 `tools` 应恰好是 `["bash", "str_replace_editor"]`;
62
+ - 第一轮只包含用户消息与首句锚点:没有 workspace 指令 baseline、运行时快照、skill 目录消息;
63
+ - 首次工具调用或首次助手回复后,下一份变更 header 应包含 resident 目录:bootstrap 双工具 + `dev_tool_search` / `skill_search` / `skill_load` + 已解锁工具;
64
+ - 此后的请求保持 resident 集,只经 `dev_tool_search` 显式解锁增长;
65
+ - `we` 锚定确认后,事件流出现一次 `source.plugin === 'prompt-injector'` 的消息;未确认时最多等一轮兜底。
66
+
67
+ 本项目测试:
78
68
 
79
69
  ```sh
80
- dsh --profile prompt-tool --patch <cordis.yml>
70
+ pnpm test # pnpm build + node --test
71
+ pnpm typecheck # Host 与 Client 两个 tsc program
72
+ pnpm lint # oxlint
81
73
  ```
82
74
 
83
- 完全重启 dsh 后,新建会话并选择 prompt-tool 预设。
75
+ ## 行为与限制
84
76
 
85
- ## 原理
77
+ - Windows:DSH 的 PTY 后端仅支持 linux/darwin,持久 shell 组禁用;phase-1 的 `bash` 切换为 `custom-bash`——同名且 schema 与 Minimal 兼容,经普通跨平台子进程通道调起 Git Bash(运行时探测安装路径,不硬编码)。
78
+ - Linux/macOS:持久 shell 的 `shellPath` 自适应——`/bin/bash` 存在时保持默认,不存在(如 NixOS)回退 PATH 里的 `bash`。
79
+ - 首轮能力类提问可能基于被裁剪的双工具视图作答,晋升后由后续工具纠正;需要时可开启任务引导或直接首轮问任务类问题。
80
+ - 工具目录只变化一次(晋升点),因此第一、二次请求之间发生一次前缀缓存变化;之后每次 `dev_tool_search` 解锁再变化。
81
+ - preset 与 shell 访问具有相同信任等级,安装前可自行审阅 `upstream/` 与生成目录。
82
+ - 插件只监听本机回环设置桥,不发起网络请求,也不增加遥测。
83
+ - 不要在已经产生内容的会话中途切换 preset。
84
+ - 需要 DSH 0.1.0-rc.7+(preset 机制、`system-prompt/assemble` 钩子与 keyed `settings.plugin.item` 插槽)。
86
85
 
87
- 模型的首轮请求结构决定整条会话轨迹。上游实测:官方 Minimal 首轮(训练原句 + 持久 `bash` + `str_replace_editor`,无输出封顶)稳定锚定 we 轨迹;完整 Standard 目录与自动注入在场会破坏锚定。
86
+ ## 构建与上游管理
88
87
 
89
- 本插件把“首轮轨迹选择”和“后续完整能力”拆开:
88
+ ```sh
89
+ pnpm install
90
+ pnpm build # 生成 lib/
91
+ pnpm prepare # npm publish / git install 前自动触发
92
+ pnpm sync:anchored # 从上游 main 刷新内联快照(可加 ref 参数)
93
+ ```
90
94
 
91
- 1. **干净首轮**:`context-gate` 清空首轮自动上下文并剥离自动注入;`tool-bootstrap` 只暴露 Minimal 两个工具;`router-first-turn` 按主会话模型替换 persona——Pro 用训练原句,Flash 自动采用 dsh-router-standard Flash 弱路由人设(build/fix 分类 + 三锚 + 先深想再产出)。
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 路由、任务分类人设与三锚。
95
+ 上游 `dsh-anchored-standard` 以内联快照形式固化在 `upstream/dsh-anchored-standard/`(含 `LICENSE`、`NOTICE`、`REVISION`),对应提交见 `REVISION`。本项目运行时不直读上游任何文件:`preset/` 已自有化全部 `agent.cordis.yml` 与预设 JS 脚本(shared / context-gate / compaction-epoch / custom-bash / instruction-hint / skill-search / tool-bootstrap),生成时只注入 `usePtcMode` / `bootstrapMaxTokens` / `subagentFlash` 动态项;`upstream/` 仅用于溯源与 sync 对照。上游已转入维护期(2026-08-17);其 Project2 的 98/99/99 成绩来自当前实现之前的旧配置(issue #60),轨迹锚定有独立复现(#65),能力增益在小样本下未决(#51)。
96
96
 
97
- 主会话首轮始终只有两个工具;模型性能不受记忆、技能等自动注入影响,完整能力在轨迹稳定后恢复。
97
+ ## 许可
98
+
99
+ 插件本体 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)。本地 `preset/` 下的 cordis 模板与 JS 脚本基于 DeepSeek Harness Standard 预设与上游 anchored-standard 修改,原始 DeepSeek 版权与 MIT 声明保留在 `upstream/dsh-anchored-standard/NOTICE` 与 `LICENSE`。
98
100
 
99
101
  ## 配置参考
100
102
 
@@ -108,19 +110,20 @@ dsh --profile prompt-tool --patch <cordis.yml>
108
110
  text: '' # 覆盖 preset.md 文本;默认读项目文件
109
111
  agentsText: '' # 覆盖 AGENTS.md 文本;默认读项目文件
110
112
  injectAgentsPrompt: false # 用 AGENTS.md 替换 instruction-hint 提示文本
111
- writeAgents: true # 写 ~/.dsh/AGENTS.md 受管块(默认 true)
112
- writePreset: true # 启用锚定预设(总开关,默认 true)
113
- injectPrompt: true # we 确认后注入 preset.md(默认 true)
113
+ writeAgents: true # 写 ~/.dsh/AGENTS.md 受管块
114
+ writePreset: true # 启用锚定预设(总开关)
115
+ injectPrompt: true # we 确认后注入 preset.md
114
116
  skillSwitches: {} # 按 skills/* 目录名开关,未列出默认开启
115
- anchorFirstTurn: false # 追加任务引导(默认关闭)
117
+ anchorFirstTurn: false # 追加任务引导
116
118
  anchorText: '' # 自定义引导文本(首句)
117
119
  anchorCustom: false # 使用自定义引导(首句)
118
- guideText: '' # 自定义引导文本(每轮);默认写入自动引导(简单/复杂两段)
119
- guideCustom: false # 使用自定义引导(每轮;仅 Flash 主会话晋升后生效)
120
- subagentFlash: false # 子代理固定 Flash 模型(默认关闭)
120
+ guideText: '' # 自定义引导文本(每轮)
121
+ guideCustom: false # 使用自定义引导(每轮)
122
+ subagentFlash: false # 子代理固定 Flash 模型
121
123
  subagentFlashProvider: 'deepseek-official'
122
124
  subagentFlashModel: 'deepseek-v4-flash'
123
- customBashPath: 'bash.exe' # 自定义 bash 路径(默认 PATH 查找)
125
+ bootstrapMaxTokens: 0 # 首轮输出封顶:0=关闭;正整数=请求 #1 maxTokens
126
+ usePtcMode: true # 使用 PTC 模式:true=晋升后切换为 Code Mode(run_code);false=恢复原生完整目录
124
127
  skillsDir: '' # 可选技能目录(默认包内 skills/)
125
128
  skillRankBase: 250 # 技能候选排序基数
126
129
  residentAgentsPath: '' # 默认 ~/.dsh/AGENTS.md
@@ -129,22 +132,11 @@ dsh --profile prompt-tool --patch <cordis.yml>
129
132
  fallbackText: '' # preset.md 缺失或不可读时的回退文本
130
133
  ```
131
134
 
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
- ## 版权
135
+ TUI 命令:
143
136
 
144
- 本项目采用 MIT 许可证。
145
-
146
- - 首轮锚定机制源自 [xiaobright/dsh-anchored-standard](https://github.com/xiaobright/dsh-anchored-standard)(MIT),其 `preset/` 快照内联于本仓库 `upstream/`,对应上游提交记录见 `REVISION`。
147
- - 任务引导与 Flash 子代理方案参考 [yjh051108/dsh-router-standard](https://github.com/yjh051108/dsh-router-standard)(MIT)。
148
- - 缓存与工具面成本原则参考 [yjh051108/dsh-super-injector](https://github.com/yjh051108/dsh-super-injector)(MIT)。
149
- - 上游 `agent.cordis.yml` 基于 DeepSeek Harness Standard 预设修改;原始 DeepSeek 版权与 MIT 声明保留在 `upstream/dsh-anchored-standard/NOTICE` 与 `LICENSE`。
150
- - 本项目 `LICENSE` 见仓库根目录;随上游快照发布的 `upstream/dsh-anchored-standard/LICENSE` 与 `NOTICE` 继续保留。
137
+ ```text
138
+ /prompt-tool status
139
+ /prompt-tool on|off|toggle <开关>
140
+ /prompt-tool skill <技能目录名> on|off|toggle
141
+ /prompt-tool bootstrapMaxTokens <正整数|0>
142
+ ```
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,8 @@ window.__ModuleLoader__.load({
100
101
  guideText: "",
101
102
  guideCustom: false,
102
103
  subagentFlash: false,
104
+ bootstrapMaxTokens: 0,
105
+ usePtcMode: true,
103
106
  injectPrompt: true,
104
107
  skillSwitches: {},
105
108
  skillCatalog: [],
@@ -114,11 +117,15 @@ window.__ModuleLoader__.load({
114
117
  guideText: "",
115
118
  guideCustom: false,
116
119
  subagentFlash: false,
120
+ bootstrapMaxTokens: 0,
121
+ usePtcMode: true,
117
122
  injectPrompt: true,
118
123
  skillSwitches: {},
119
124
  writeAgents: true,
120
125
  writePreset: true
121
126
  };
127
+ /** 本项目默认不设上限时的显示值(adapter 默认 maxTokens)。 */
128
+ const DEFAULT_BOOTSTRAP_DISPLAY = "256000";
122
129
  const snapshotSwitches = (fields) => ({
123
130
  injectAgentsPrompt: fields.injectAgentsPrompt,
124
131
  anchorFirstTurn: fields.anchorFirstTurn,
@@ -127,12 +134,14 @@ window.__ModuleLoader__.load({
127
134
  guideText: fields.guideText,
128
135
  guideCustom: fields.guideCustom,
129
136
  subagentFlash: fields.subagentFlash,
137
+ bootstrapMaxTokens: fields.bootstrapMaxTokens,
138
+ usePtcMode: fields.usePtcMode,
130
139
  injectPrompt: fields.injectPrompt,
131
140
  skillSwitches: { ...fields.skillSwitches },
132
141
  writeAgents: fields.writeAgents,
133
142
  writePreset: fields.writePreset
134
143
  });
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;
144
+ 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.usePtcMode === b.usePtcMode && a.injectPrompt === b.injectPrompt && JSON.stringify(a.skillSwitches) === JSON.stringify(b.skillSwitches) && a.writeAgents === b.writeAgents && a.writePreset === b.writePreset;
136
145
  const asRecord = (value) => value !== null && typeof value === "object" ? value : {};
137
146
  const readString = (source, key) => {
138
147
  const value = source[key];
@@ -142,6 +151,10 @@ window.__ModuleLoader__.load({
142
151
  const value = source[key];
143
152
  return typeof value === "boolean" ? value : fallback;
144
153
  };
154
+ const readNumber = (source, key, fallback) => {
155
+ const value = source[key];
156
+ return typeof value === "number" && Number.isSafeInteger(value) && value >= 0 ? value : fallback;
157
+ };
145
158
  const readSkillSwitches = (source, key) => {
146
159
  const value = source[key];
147
160
  if (value === null || typeof value !== "object") return {};
@@ -204,6 +217,7 @@ window.__ModuleLoader__.load({
204
217
  const [deepseekError, setDeepseekError] = (0, react.useState)("");
205
218
  const [loaded, setLoaded] = (0, react.useState)(false);
206
219
  const [fields, setFields] = (0, react.useState)(EMPTY);
220
+ const [bootstrapTokensDraft, setBootstrapTokensDraft] = (0, react.useState)(DEFAULT_BOOTSTRAP_DISPLAY);
207
221
  const [savedPromptText, setSavedPromptText] = (0, react.useState)("");
208
222
  const [savedAgentsText, setSavedAgentsText] = (0, react.useState)("");
209
223
  const [savedSwitches, setSavedSwitches] = (0, react.useState)(EMPTY_SWITCHES);
@@ -247,6 +261,8 @@ window.__ModuleLoader__.load({
247
261
  guideText: readString(value, "guideText") ?? readString(base, "guideText") ?? "",
248
262
  guideCustom: readBoolean(value, "guideCustom", readBoolean(base, "guideCustom", false)),
249
263
  subagentFlash: readBoolean(value, "subagentFlash", readBoolean(base, "subagentFlash", false)),
264
+ bootstrapMaxTokens: readNumber(value, "bootstrapMaxTokens", readNumber(base, "bootstrapMaxTokens", 0)),
265
+ usePtcMode: readBoolean(value, "usePtcMode", readBoolean(base, "usePtcMode", true)),
250
266
  injectPrompt: readBoolean(value, "injectPrompt", readBoolean(base, "injectPrompt", true)),
251
267
  skillSwitches: value.skillSwitches !== void 0 || base.skillSwitches !== void 0 ? {
252
268
  ...readSkillSwitches(base, "skillSwitches"),
@@ -258,6 +274,7 @@ window.__ModuleLoader__.load({
258
274
  };
259
275
  fieldsRef.current = next;
260
276
  setFields(next);
277
+ setBootstrapTokensDraft(next.bootstrapMaxTokens > 0 ? String(next.bootstrapMaxTokens) : DEFAULT_BOOTSTRAP_DISPLAY);
261
278
  setSavedPromptText(next.promptText);
262
279
  setSavedAgentsText(next.agentsText);
263
280
  setSavedSwitches(snapshotSwitches(next));
@@ -416,6 +433,16 @@ window.__ModuleLoader__.load({
416
433
  path: ["subagentFlash"],
417
434
  value: fieldsRef.current.subagentFlash
418
435
  },
436
+ {
437
+ op: "set",
438
+ path: ["bootstrapMaxTokens"],
439
+ value: fieldsRef.current.bootstrapMaxTokens
440
+ },
441
+ {
442
+ op: "set",
443
+ path: ["usePtcMode"],
444
+ value: fieldsRef.current.usePtcMode
445
+ },
419
446
  {
420
447
  op: "set",
421
448
  path: ["injectPrompt"],
@@ -445,6 +472,20 @@ window.__ModuleLoader__.load({
445
472
  patch({ [key]: !fieldsRef.current[key] });
446
473
  persistSwitches();
447
474
  };
475
+ const toggleBootstrapMaxTokens = () => {
476
+ const next = fieldsRef.current.bootstrapMaxTokens > 0 ? 0 : 256e3;
477
+ patch({ bootstrapMaxTokens: next });
478
+ setBootstrapTokensDraft(DEFAULT_BOOTSTRAP_DISPLAY);
479
+ persistSwitches();
480
+ };
481
+ const commitBootstrapTokensDraft = () => {
482
+ const parsed = Number(bootstrapTokensDraft);
483
+ if (!Number.isSafeInteger(parsed) || parsed <= 0) {
484
+ setBootstrapTokensDraft(DEFAULT_BOOTSTRAP_DISPLAY);
485
+ patch({ bootstrapMaxTokens: 256e3 });
486
+ } else patch({ bootstrapMaxTokens: parsed });
487
+ persistSwitches();
488
+ };
448
489
  const skillEnabled = (folder) => fields.skillSwitches[folder] !== false;
449
490
  const toggleSkill = (folder) => {
450
491
  const enabled = fieldsRef.current.skillSwitches[folder] !== false;
@@ -462,7 +503,7 @@ window.__ModuleLoader__.load({
462
503
  const promptSwitchDirty = fields.injectPrompt !== savedSwitches.injectPrompt;
463
504
  const agentsSwitchDirty = fields.injectAgentsPrompt !== savedSwitches.injectAgentsPrompt || fields.writeAgents !== savedSwitches.writeAgents;
464
505
  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;
506
+ const presetSwitchDirty = fields.writePreset !== savedSwitches.writePreset || fields.anchorFirstTurn !== savedSwitches.anchorFirstTurn || fields.anchorText !== savedSwitches.anchorText || fields.bootstrapMaxTokens !== savedSwitches.bootstrapMaxTokens || fields.usePtcMode !== savedSwitches.usePtcMode;
466
507
  const discardPrompt = () => patch({ promptText: savedPromptText });
467
508
  const discardAgents = () => patch({ agentsText: savedAgentsText });
468
509
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("li", {
@@ -696,6 +737,57 @@ window.__ModuleLoader__.load({
696
737
  })]
697
738
  })]
698
739
  }),
740
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
741
+ className: PromptEditor_module_css_default.row,
742
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
743
+ type: "checkbox",
744
+ checked: fields.usePtcMode,
745
+ disabled: !fields.writePreset,
746
+ onChange: () => toggle("usePtcMode")
747
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
748
+ className: PromptEditor_module_css_default.rowText,
749
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
750
+ className: PromptEditor_module_css_default.rowName,
751
+ children: "使用 PTC 模式"
752
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
753
+ className: PromptEditor_module_css_default.rowDesc,
754
+ children: "默认开启:晋升后把 wire 切换为 Code Mode(PTC,单一 run_code),完整插件工具通过生成 SDK 调用。关闭后恢复原生完整工具目录"
755
+ })]
756
+ })]
757
+ }),
758
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
759
+ className: PromptEditor_module_css_default.row,
760
+ children: [
761
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
762
+ id: "prompt-tool-bootstrap-max-tokens",
763
+ type: "checkbox",
764
+ checked: fields.bootstrapMaxTokens > 0,
765
+ disabled: !fields.writePreset,
766
+ onChange: toggleBootstrapMaxTokens
767
+ }),
768
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
769
+ htmlFor: "prompt-tool-bootstrap-max-tokens",
770
+ className: PromptEditor_module_css_default.rowText,
771
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
772
+ className: PromptEditor_module_css_default.rowName,
773
+ children: "首轮输出封顶"
774
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
775
+ className: PromptEditor_module_css_default.rowDesc,
776
+ children: "关闭时显示项目默认 256000(不设上限);开启后右侧数值生效,晋升后自动剥离。清空或输入 0 会恢复 256000,不关闭开关"
777
+ })]
778
+ }),
779
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
780
+ className: PromptEditor_module_css_default.bootstrapTokensInput,
781
+ type: "number",
782
+ min: 1,
783
+ step: 1,
784
+ value: bootstrapTokensDraft,
785
+ disabled: !fields.writePreset || fields.bootstrapMaxTokens === 0,
786
+ onChange: (e) => setBootstrapTokensDraft(e.target.value),
787
+ onBlur: commitBootstrapTokensDraft
788
+ })
789
+ ]
790
+ }),
699
791
  /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
700
792
  className: PromptEditor_module_css_default.row,
701
793
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
@@ -826,8 +918,7 @@ window.__ModuleLoader__.load({
826
918
  const injected = () => ({ api: connection.api });
827
919
  ctx.slots.inject("settings.plugin.item", () => ctx.slots.register({
828
920
  name: "settings.plugin.item",
829
- id: "prompt-tool",
830
- order: 30,
921
+ key: "prompt-tool",
831
922
  inject: injected
832
923
  }, PromptEditor));
833
924
  }