dsh-plugin-prompt-tool 0.4.0 → 0.4.2
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 +91 -11
- package/lib/client.js +90 -7
- package/lib/client.js.map +1 -1
- package/lib/index.d.mts +5 -1
- package/lib/index.mjs +285 -13
- package/package.json +5 -2
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# 提示词工具(dsh-plugin-prompt-tool)
|
|
2
2
|
|
|
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
|
|
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
|
|
|
@@ -32,27 +32,107 @@ DeepSeek V4 会强烈依赖 API 中可见的**首轮工具目录与 persona**
|
|
|
32
32
|
|
|
33
33
|
## 安装
|
|
34
34
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
dsh
|
|
38
|
-
|
|
35
|
+
依据官方[《打包与安装插件》](https://deepseek-harness.github.io/deepseek-harness/develop/basic/publish)准则:
|
|
36
|
+
`dsh plugin add` 只把**声明了 `dsh.bundle` 的直接依赖**追加进
|
|
37
|
+
`dsh.profile.bundles`;`@deepseek-ai/dsh-web-app` 是随 DSH 安装自带的 in-box
|
|
38
|
+
bundle(从 dsh 安装目录解析,不需要也不应写进 `dependencies`)。
|
|
39
|
+
|
|
40
|
+
### npm 安装与源码安装
|
|
41
|
+
|
|
42
|
+
两种安装源等价,后续初始化流程相同:
|
|
39
43
|
|
|
40
|
-
|
|
44
|
+
```sh
|
|
45
|
+
# 方式 A:npm / registry 安装
|
|
41
46
|
dsh plugin --profile prompt-tool add dsh-plugin-prompt-tool
|
|
42
47
|
|
|
43
|
-
#
|
|
48
|
+
# 方式 B:本地源码安装(link 会覆盖 registry 依赖)
|
|
44
49
|
dsh plugin --profile prompt-tool add link:<本仓库绝对路径>
|
|
50
|
+
```
|
|
45
51
|
|
|
46
|
-
|
|
52
|
+
### 初始化:启动一次即可
|
|
53
|
+
|
|
54
|
+
```sh
|
|
47
55
|
dsh --profile prompt-tool
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
第一次启动只负责完成初始化。首次进程尚未挂载 Web 表面,这是预期行为;
|
|
59
|
+
自愈完成后**插件会自动退出(exit 0)**,无需手动停止:
|
|
60
|
+
|
|
61
|
+
```text
|
|
62
|
+
prompt-tool: auto-added @deepseek-ai/dsh-web-app to dsh.profile.bundles for profile "prompt-tool"; next launch will mount the Web surface ...
|
|
63
|
+
prompt-tool: initialization complete — exiting so the repaired profile can be launched
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
这一次启动会自动完成:
|
|
67
|
+
|
|
68
|
+
1. **prompt-tool profile**:把 `@deepseek-ai/dsh-web-app` 补进
|
|
69
|
+
`dsh.profile.bundles`,最终为
|
|
70
|
+
`base → web-app → dsh-plugin-prompt-tool`;
|
|
71
|
+
2. **web profile**:若存在,把 `dsh-plugin-prompt-tool` 写进它的
|
|
72
|
+
`dependencies` + `bundles`(dependency 写法复用当前 profile 的安装
|
|
73
|
+
spec)。**只写 package.json,不手工创建 node_modules 链接**;
|
|
74
|
+
3. **dsh-tui profile**:若存在且确实装有
|
|
75
|
+
`@deepseek-harness-tui/dsh-tui`,同样写进 `dsh-plugin-prompt-tool`;
|
|
76
|
+
**没有 dsh-tui 则整体跳过,不写入本插件**。dsh-tui 不需要
|
|
77
|
+
`@deepseek-ai/dsh-web-app`,因此不会给它补 web-app。
|
|
78
|
+
|
|
79
|
+
所有写入幂等:文件已正确时不做任何改动。
|
|
80
|
+
|
|
81
|
+
### 初始化之后直接使用
|
|
82
|
+
|
|
83
|
+
```sh
|
|
84
|
+
# Web:官方内置 profile,本插件已自动写入
|
|
48
85
|
dsh web
|
|
86
|
+
|
|
87
|
+
# TUI:dsh-tui 的安装流程已经物化过其 profile 依赖
|
|
49
88
|
dsh-tui
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
`dsh web` 随 dsh 安装必然存在;`dsh-tui` 则在其自身安装说明中已经执行过
|
|
92
|
+
profile 依赖物化。因此初始化只需写入 package.json,不需要额外 `install`。
|
|
93
|
+
|
|
94
|
+
如果还想直接使用 `prompt-tool` 这个 profile 本身,再运行一次即可
|
|
95
|
+
(第二次启动时 web-app 已由官方装配路径加载):
|
|
96
|
+
|
|
97
|
+
```sh
|
|
98
|
+
dsh --profile prompt-tool
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
> TUI 前提:先安装/初始化过 `@deepseek-harness-tui/dsh-tui` 并已生成
|
|
102
|
+
> `dsh-tui` profile,再执行上面的初始化启动;否则按设计会跳过 dsh-tui
|
|
103
|
+
> profile。之后补装 dsh-tui 时,重新执行一次
|
|
104
|
+
> `dsh --profile prompt-tool` 即可把本插件补进 dsh-tui profile。
|
|
50
105
|
|
|
51
|
-
|
|
106
|
+
### 备选:直接把本插件装进官方 `web` 模板 profile
|
|
107
|
+
|
|
108
|
+
`web` 是官方内置模板,初始 bundles 已含
|
|
109
|
+
`@deepseek-ai/dsh-base` + `@deepseek-ai/dsh-web-app`:
|
|
110
|
+
|
|
111
|
+
```sh
|
|
112
|
+
# registry 安装
|
|
113
|
+
dsh plugin --profile web add dsh-plugin-prompt-tool
|
|
114
|
+
# 本地开发安装
|
|
115
|
+
dsh plugin --profile web add link:<本仓库绝对路径>
|
|
116
|
+
|
|
117
|
+
# 启动
|
|
118
|
+
dsh --profile web
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
完成初始化后,用 `dsh web`、`dsh-tui` 或 `dsh --profile prompt-tool` 启动,
|
|
122
|
+
新建空 session,预设选择 **prompt-tool**。插件会在启动时生成并刷新
|
|
123
|
+
`~/.dsh/.agent-presets/prompt-tool/`(升级插件后重启即自动更新)。
|
|
124
|
+
|
|
125
|
+
### 卸载
|
|
126
|
+
|
|
127
|
+
```sh
|
|
52
128
|
dsh plugin --profile prompt-tool remove dsh-plugin-prompt-tool
|
|
53
129
|
```
|
|
54
130
|
|
|
55
|
-
|
|
131
|
+
首次启动还会把包内 `skills/` 增量复制到**本插件自己的 profile** 目录下的
|
|
132
|
+
`$DSH_HOME/profiles/prompt-tool/skills`,并优先使用这份副本(从 `dsh web`
|
|
133
|
+
或 `dsh-tui` 启动也一样写这里,不会写到 web/dsh-tui profile):已有同名文件不覆盖,
|
|
134
|
+
用户对副本的编辑会保留;包内新增技能文件会在下次启动补齐。想改回包内原始
|
|
135
|
+
skills,删除该 `skills` 目录后重启即可(或在配置里显式设置 `skillsDir`)。
|
|
56
136
|
|
|
57
137
|
## 验证
|
|
58
138
|
|
|
@@ -124,7 +204,7 @@ pnpm sync:anchored # 从上游 main 刷新内联快照(可加 ref 参数)
|
|
|
124
204
|
subagentFlashModel: 'deepseek-v4-flash'
|
|
125
205
|
bootstrapMaxTokens: 0 # 首轮输出封顶:0=关闭;正整数=请求 #1 maxTokens
|
|
126
206
|
usePtcMode: true # 使用 PTC 模式:true=晋升后切换为 Code Mode(run_code);false=恢复原生完整目录
|
|
127
|
-
skillsDir: '' #
|
|
207
|
+
skillsDir: '' # 用户自定义技能目录;空 = 自动使用 prompt-tool profile 下 skills/ 副本
|
|
128
208
|
skillRankBase: 250 # 技能候选排序基数
|
|
129
209
|
residentAgentsPath: '' # 默认 ~/.dsh/AGENTS.md
|
|
130
210
|
presetDir: '' # 默认 ~/.dsh/.agent-presets/prompt-tool/
|
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)}.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}";
|
|
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_skillsBar{flex-direction:column;gap:8px;padding:2px 0 8px;display:flex}.Ru2OGG_skillsDirRow{align-items:center;gap:8px;min-width:0;display:flex}.Ru2OGG_skillsDirRow .Ru2OGG_secondary{flex:none}.Ru2OGG_skillsDirInput{box-sizing:border-box;min-width:0;min-height:34px;color:var(--dsw-alias-label-primary);background:var(--dsw-alias-bg-layer-2);border:1px solid var(--dsw-alias-border-l2);border-radius:8px;flex:1;padding:6px 10px;font-size:12px;line-height:1.4}.Ru2OGG_skillsDirInput:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:1px}.Ru2OGG_skillsPath{min-width:0;color:var(--dsw-alias-label-tertiary);overflow-wrap:anywhere;flex:1;font-size:12px;line-height:1.5}.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");
|
|
@@ -59,6 +59,10 @@ window.__ModuleLoader__.load({
|
|
|
59
59
|
"rowStack": "Ru2OGG_rowStack",
|
|
60
60
|
"rowText": "Ru2OGG_rowText",
|
|
61
61
|
"secondary": "Ru2OGG_secondary",
|
|
62
|
+
"skillsBar": "Ru2OGG_skillsBar",
|
|
63
|
+
"skillsDirInput": "Ru2OGG_skillsDirInput",
|
|
64
|
+
"skillsDirRow": "Ru2OGG_skillsDirRow",
|
|
65
|
+
"skillsPath": "Ru2OGG_skillsPath",
|
|
62
66
|
"subBody": "Ru2OGG_subBody",
|
|
63
67
|
"subCount": "Ru2OGG_subCount",
|
|
64
68
|
"subEmpty": "Ru2OGG_subEmpty",
|
|
@@ -106,6 +110,8 @@ window.__ModuleLoader__.load({
|
|
|
106
110
|
injectPrompt: true,
|
|
107
111
|
skillSwitches: {},
|
|
108
112
|
skillCatalog: [],
|
|
113
|
+
skillsDir: "",
|
|
114
|
+
activeSkillsDir: "",
|
|
109
115
|
writeAgents: true,
|
|
110
116
|
writePreset: true
|
|
111
117
|
};
|
|
@@ -121,6 +127,7 @@ window.__ModuleLoader__.load({
|
|
|
121
127
|
usePtcMode: true,
|
|
122
128
|
injectPrompt: true,
|
|
123
129
|
skillSwitches: {},
|
|
130
|
+
skillsDir: "",
|
|
124
131
|
writeAgents: true,
|
|
125
132
|
writePreset: true
|
|
126
133
|
};
|
|
@@ -138,10 +145,11 @@ window.__ModuleLoader__.load({
|
|
|
138
145
|
usePtcMode: fields.usePtcMode,
|
|
139
146
|
injectPrompt: fields.injectPrompt,
|
|
140
147
|
skillSwitches: { ...fields.skillSwitches },
|
|
148
|
+
skillsDir: fields.skillsDir,
|
|
141
149
|
writeAgents: fields.writeAgents,
|
|
142
150
|
writePreset: fields.writePreset
|
|
143
151
|
});
|
|
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;
|
|
152
|
+
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.skillsDir === b.skillsDir && a.writeAgents === b.writeAgents && a.writePreset === b.writePreset;
|
|
145
153
|
const asRecord = (value) => value !== null && typeof value === "object" ? value : {};
|
|
146
154
|
const readString = (source, key) => {
|
|
147
155
|
const value = source[key];
|
|
@@ -218,12 +226,14 @@ window.__ModuleLoader__.load({
|
|
|
218
226
|
const [loaded, setLoaded] = (0, react.useState)(false);
|
|
219
227
|
const [fields, setFields] = (0, react.useState)(EMPTY);
|
|
220
228
|
const [bootstrapTokensDraft, setBootstrapTokensDraft] = (0, react.useState)(DEFAULT_BOOTSTRAP_DISPLAY);
|
|
229
|
+
const [skillsDirDraft, setSkillsDirDraft] = (0, react.useState)("");
|
|
221
230
|
const [savedPromptText, setSavedPromptText] = (0, react.useState)("");
|
|
222
231
|
const [savedAgentsText, setSavedAgentsText] = (0, react.useState)("");
|
|
223
232
|
const [savedSwitches, setSavedSwitches] = (0, react.useState)(EMPTY_SWITCHES);
|
|
224
233
|
const [loading, setLoading] = (0, react.useState)(false);
|
|
225
234
|
const [savingPrompt, setSavingPrompt] = (0, react.useState)(false);
|
|
226
235
|
const [savingAgents, setSavingAgents] = (0, react.useState)(false);
|
|
236
|
+
const [savingSkillsDir, setSavingSkillsDir] = (0, react.useState)(false);
|
|
227
237
|
const [restoringPrompt, setRestoringPrompt] = (0, react.useState)(false);
|
|
228
238
|
const [restoringAgents, setRestoringAgents] = (0, react.useState)(false);
|
|
229
239
|
const [notice, setNotice] = (0, react.useState)("");
|
|
@@ -268,13 +278,16 @@ window.__ModuleLoader__.load({
|
|
|
268
278
|
...readSkillSwitches(base, "skillSwitches"),
|
|
269
279
|
...readSkillSwitches(value, "skillSwitches")
|
|
270
280
|
} : {},
|
|
271
|
-
skillCatalog: readSkillCatalog(value, "skillCatalog").length > 0 ? readSkillCatalog(value, "skillCatalog") : readSkillCatalog(base, "skillCatalog"),
|
|
281
|
+
skillCatalog: res.skillCatalog ?? (readSkillCatalog(value, "skillCatalog").length > 0 ? readSkillCatalog(value, "skillCatalog") : readSkillCatalog(base, "skillCatalog")),
|
|
282
|
+
skillsDir: readString(value, "skillsDir") ?? readString(base, "skillsDir") ?? "",
|
|
283
|
+
activeSkillsDir: res.activeSkillsDir ?? readString(value, "activeSkillsDir") ?? readString(base, "activeSkillsDir") ?? "",
|
|
272
284
|
writeAgents: readBoolean(value, "writeAgents", readBoolean(base, "writeAgents", true)),
|
|
273
285
|
writePreset: readBoolean(value, "writePreset", readBoolean(base, "writePreset", true))
|
|
274
286
|
};
|
|
275
287
|
fieldsRef.current = next;
|
|
276
288
|
setFields(next);
|
|
277
289
|
setBootstrapTokensDraft(next.bootstrapMaxTokens > 0 ? String(next.bootstrapMaxTokens) : DEFAULT_BOOTSTRAP_DISPLAY);
|
|
290
|
+
setSkillsDirDraft(next.skillsDir);
|
|
278
291
|
setSavedPromptText(next.promptText);
|
|
279
292
|
setSavedAgentsText(next.agentsText);
|
|
280
293
|
setSavedSwitches(snapshotSwitches(next));
|
|
@@ -363,6 +376,20 @@ window.__ModuleLoader__.load({
|
|
|
363
376
|
showNotice("error", "打开失败:" + errorMessage(error) + ";可直接在下方编辑框保存");
|
|
364
377
|
}
|
|
365
378
|
};
|
|
379
|
+
const openSkillsDir = async () => {
|
|
380
|
+
const path = fields.activeSkillsDir || fields.skillsDir;
|
|
381
|
+
if (!path) {
|
|
382
|
+
showNotice("error", "技能目录路径未知,请先重新展开面板读取配置");
|
|
383
|
+
return;
|
|
384
|
+
}
|
|
385
|
+
try {
|
|
386
|
+
const res = await api.host.openPath({ path });
|
|
387
|
+
if (res.result.ok) showNotice("ok", "已打开技能目录:" + path);
|
|
388
|
+
else showNotice("error", "打开失败:" + (res.result.error?.message ?? ""));
|
|
389
|
+
} catch (error) {
|
|
390
|
+
showNotice("error", "打开失败:" + errorMessage(error));
|
|
391
|
+
}
|
|
392
|
+
};
|
|
366
393
|
const enqueueSave = (0, react.useCallback)((ops, okMessage, onSaved, setBusy) => {
|
|
367
394
|
setBusy?.(true);
|
|
368
395
|
saveQueueRef.current = saveQueueRef.current.then(async () => {
|
|
@@ -453,6 +480,11 @@ window.__ModuleLoader__.load({
|
|
|
453
480
|
path: ["skillSwitches"],
|
|
454
481
|
value: fieldsRef.current.skillSwitches
|
|
455
482
|
},
|
|
483
|
+
{
|
|
484
|
+
op: "set",
|
|
485
|
+
path: ["skillsDir"],
|
|
486
|
+
value: fieldsRef.current.skillsDir
|
|
487
|
+
},
|
|
456
488
|
{
|
|
457
489
|
op: "set",
|
|
458
490
|
path: ["writeAgents"],
|
|
@@ -486,6 +518,18 @@ window.__ModuleLoader__.load({
|
|
|
486
518
|
} else patch({ bootstrapMaxTokens: parsed });
|
|
487
519
|
persistSwitches();
|
|
488
520
|
};
|
|
521
|
+
const applySkillsDir = () => {
|
|
522
|
+
const next = skillsDirDraft.trim();
|
|
523
|
+
patch({ skillsDir: next });
|
|
524
|
+
enqueueSave([{
|
|
525
|
+
op: "set",
|
|
526
|
+
path: ["skillsDir"],
|
|
527
|
+
value: next
|
|
528
|
+
}], next.length > 0 ? `自定义技能目录已保存并生效:${next}` : "已切回自动技能目录(当前 profile 下 skills/)", () => {
|
|
529
|
+
setSavedSwitches(snapshotSwitches(fieldsRef.current));
|
|
530
|
+
load();
|
|
531
|
+
}, setSavingSkillsDir);
|
|
532
|
+
};
|
|
489
533
|
const skillEnabled = (folder) => fields.skillSwitches[folder] !== false;
|
|
490
534
|
const toggleSkill = (folder) => {
|
|
491
535
|
const enabled = fieldsRef.current.skillSwitches[folder] !== false;
|
|
@@ -503,6 +547,7 @@ window.__ModuleLoader__.load({
|
|
|
503
547
|
const promptSwitchDirty = fields.injectPrompt !== savedSwitches.injectPrompt;
|
|
504
548
|
const agentsSwitchDirty = fields.injectAgentsPrompt !== savedSwitches.injectAgentsPrompt || fields.writeAgents !== savedSwitches.writeAgents;
|
|
505
549
|
const skillsSwitchDirty = JSON.stringify(fields.skillSwitches) !== JSON.stringify(savedSwitches.skillSwitches);
|
|
550
|
+
const skillsDirDirty = fields.skillsDir !== savedSwitches.skillsDir || skillsDirDraft.trim() !== fields.skillsDir;
|
|
506
551
|
const presetSwitchDirty = fields.writePreset !== savedSwitches.writePreset || fields.anchorFirstTurn !== savedSwitches.anchorFirstTurn || fields.anchorText !== savedSwitches.anchorText || fields.bootstrapMaxTokens !== savedSwitches.bootstrapMaxTokens || fields.usePtcMode !== savedSwitches.usePtcMode;
|
|
507
552
|
const discardPrompt = () => patch({ promptText: savedPromptText });
|
|
508
553
|
const discardAgents = () => patch({ agentsText: savedAgentsText });
|
|
@@ -684,12 +729,50 @@ window.__ModuleLoader__.load({
|
|
|
684
729
|
})
|
|
685
730
|
]
|
|
686
731
|
}),
|
|
687
|
-
/* @__PURE__ */ (0, react_jsx_runtime.
|
|
732
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)(CollapsibleSection, {
|
|
688
733
|
title: "Skills设置",
|
|
689
|
-
hint: `${fields.skillCatalog.length} 个${skillsSwitchDirty ? " · 未保存" : ""}`,
|
|
734
|
+
hint: `${fields.skillCatalog.length} 个${skillsSwitchDirty || skillsDirDirty ? " · 未保存" : ""}`,
|
|
690
735
|
open: skillsOpen,
|
|
691
736
|
onToggle: () => setSkillsOpen(!skillsOpen),
|
|
692
|
-
children:
|
|
737
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
738
|
+
className: PromptEditor_module_css_default.skillsBar,
|
|
739
|
+
children: [
|
|
740
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
741
|
+
className: PromptEditor_module_css_default.skillsDirRow,
|
|
742
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
743
|
+
type: "button",
|
|
744
|
+
className: PromptEditor_module_css_default.secondary,
|
|
745
|
+
disabled: !fields.activeSkillsDir && !fields.skillsDir,
|
|
746
|
+
onClick: () => void openSkillsDir(),
|
|
747
|
+
children: "打开技能目录"
|
|
748
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
749
|
+
className: PromptEditor_module_css_default.skillsPath,
|
|
750
|
+
children: fields.activeSkillsDir || fields.skillsDir || "(技能目录路径未知,请重新展开面板)"
|
|
751
|
+
})]
|
|
752
|
+
}),
|
|
753
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
754
|
+
className: PromptEditor_module_css_default.skillsDirRow,
|
|
755
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
|
|
756
|
+
className: PromptEditor_module_css_default.skillsDirInput,
|
|
757
|
+
"aria-label": "用户自定义技能目录",
|
|
758
|
+
value: skillsDirDraft,
|
|
759
|
+
placeholder: fields.activeSkillsDir || "留空 = 自动使用当前 profile 下的 skills/ 副本",
|
|
760
|
+
spellCheck: false,
|
|
761
|
+
onChange: (e) => setSkillsDirDraft(e.target.value)
|
|
762
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
763
|
+
type: "button",
|
|
764
|
+
className: PromptEditor_module_css_default.primary,
|
|
765
|
+
disabled: savingSkillsDir || skillsDirDraft.trim() === fields.skillsDir,
|
|
766
|
+
onClick: applySkillsDir,
|
|
767
|
+
children: savingSkillsDir ? "设置中…" : "设置自定义目录"
|
|
768
|
+
})]
|
|
769
|
+
}),
|
|
770
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
771
|
+
className: PromptEditor_module_css_default.rowDesc,
|
|
772
|
+
children: "留空并点“设置自定义目录”会切回自动目录(当前 profile 下的 skills/ 副本)。修改后技能目录立即重新扫描。"
|
|
773
|
+
})
|
|
774
|
+
]
|
|
775
|
+
}), fields.skillCatalog.length === 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
693
776
|
className: PromptEditor_module_css_default.subEmpty,
|
|
694
777
|
children: "skills 目录下没有技能"
|
|
695
778
|
}) : fields.skillCatalog.map((skill) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
|
|
@@ -712,7 +795,7 @@ window.__ModuleLoader__.load({
|
|
|
712
795
|
]
|
|
713
796
|
})]
|
|
714
797
|
})]
|
|
715
|
-
}, skill.folder))
|
|
798
|
+
}, skill.folder))]
|
|
716
799
|
}),
|
|
717
800
|
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)(CollapsibleSection, {
|
|
718
801
|
title: "锚定与 preset",
|
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 bootstrapMaxTokens: number\r\n usePtcMode: 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 bootstrapMaxTokens: 0,\r\n usePtcMode: true,\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 usePtcMode: 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 bootstrapMaxTokens: 0,\r\n usePtcMode: true,\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 usePtcMode: fields.usePtcMode,\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.usePtcMode === b.usePtcMode\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 usePtcMode: readBoolean(value, 'usePtcMode', readBoolean(base, 'usePtcMode', true)),\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: ['usePtcMode'], value: fieldsRef.current.usePtcMode },\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' | 'usePtcMode' | '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 || fields.usePtcMode !== savedSwitches.usePtcMode\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 <label className={styles.row}>\r\n <input\r\n type=\"checkbox\"\r\n checked={fields.usePtcMode}\r\n disabled={!fields.writePreset}\r\n onChange={() => toggle('usePtcMode')}\r\n />\r\n <span className={styles.rowText}>\r\n <span className={styles.rowName}>使用 PTC 模式</span>\r\n <span className={styles.rowDesc}>默认开启:晋升后把 wire 切换为 Code Mode(PTC,单一 run_code),完整插件工具通过生成 SDK 调用。关闭后恢复原生完整工具目录</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 // dsh 0.1.0-rc.7 起 settings.plugin.item 是 keyed slot,\n // key = 插件 settings namespace(与 Host 端 settingsNamespace('prompt-tool') 对应)。\n ctx.slots.inject('settings.plugin.item', () => ctx.slots.register({\n name: 'settings.plugin.item',\n key: 'prompt-tool',\n inject: injected,\n }, PromptEditor))\n}\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; activeSkillsDir?: string; skillCatalog?: SkillCatalogEntry[] } | { 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 usePtcMode: boolean\r\n injectPrompt: boolean\r\n skillSwitches: Record<string, boolean>\r\n skillCatalog: SkillCatalogEntry[]\r\n skillsDir: string\r\n activeSkillsDir: string\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 usePtcMode: true,\r\n injectPrompt: true,\r\n skillSwitches: {},\r\n skillCatalog: [],\r\n skillsDir: '',\r\n activeSkillsDir: '',\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 usePtcMode: boolean\r\n injectPrompt: boolean\r\n skillSwitches: Record<string, boolean>\r\n skillsDir: string\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 usePtcMode: true,\r\n injectPrompt: true,\r\n skillSwitches: {},\r\n skillsDir: '',\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 usePtcMode: fields.usePtcMode,\r\n injectPrompt: fields.injectPrompt,\r\n skillSwitches: { ...fields.skillSwitches },\r\n skillsDir: fields.skillsDir,\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.usePtcMode === b.usePtcMode\r\n && a.injectPrompt === b.injectPrompt\r\n && JSON.stringify(a.skillSwitches) === JSON.stringify(b.skillSwitches)\r\n && a.skillsDir === b.skillsDir\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 [skillsDirDraft, setSkillsDirDraft] = useState('')\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 [savingSkillsDir, setSavingSkillsDir] = 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 usePtcMode: readBoolean(value, 'usePtcMode', readBoolean(base, 'usePtcMode', true)),\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: res.skillCatalog ?? (readSkillCatalog(value, 'skillCatalog').length > 0\r\n ? readSkillCatalog(value, 'skillCatalog')\r\n : readSkillCatalog(base, 'skillCatalog')),\r\n skillsDir: readString(value, 'skillsDir') ?? readString(base, 'skillsDir') ?? '',\r\n activeSkillsDir: res.activeSkillsDir ?? readString(value, 'activeSkillsDir') ?? readString(base, 'activeSkillsDir') ?? '',\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 setSkillsDirDraft(next.skillsDir)\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 openSkillsDir = async () => {\r\n const path = fields.activeSkillsDir || fields.skillsDir\r\n if (!path) { showNotice('error', '技能目录路径未知,请先重新展开面板读取配置'); return }\r\n try {\r\n const res = await api.host.openPath({ path })\r\n if (res.result.ok) showNotice('ok', '已打开技能目录:' + path)\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: ['usePtcMode'], value: fieldsRef.current.usePtcMode },\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: ['skillsDir'], value: fieldsRef.current.skillsDir },\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' | 'usePtcMode' | '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 applySkillsDir = () => {\r\n const next = skillsDirDraft.trim()\r\n patch({ skillsDir: next })\r\n enqueueSave(\r\n [{ op: 'set', path: ['skillsDir'], value: next }],\r\n next.length > 0 ? `自定义技能目录已保存并生效:${next}` : '已切回自动技能目录(当前 profile 下 skills/)',\r\n () => {\r\n setSavedSwitches(snapshotSwitches(fieldsRef.current))\r\n void load()\r\n },\r\n setSavingSkillsDir,\r\n )\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 skillsDirDirty = fields.skillsDir !== savedSwitches.skillsDir || skillsDirDraft.trim() !== fields.skillsDir\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 || fields.usePtcMode !== savedSwitches.usePtcMode\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 || skillsDirDirty ? ' · 未保存' : ''}`}\r\n open={skillsOpen}\r\n onToggle={() => setSkillsOpen(!skillsOpen)}\r\n >\r\n <div className={styles.skillsBar}>\r\n <div className={styles.skillsDirRow}>\r\n <button\r\n type=\"button\"\r\n className={styles.secondary}\r\n disabled={!fields.activeSkillsDir && !fields.skillsDir}\r\n onClick={() => void openSkillsDir()}\r\n >\r\n 打开技能目录\r\n </button>\r\n <span className={styles.skillsPath}>{fields.activeSkillsDir || fields.skillsDir || '(技能目录路径未知,请重新展开面板)'}</span>\r\n </div>\r\n <div className={styles.skillsDirRow}>\r\n <input\r\n className={styles.skillsDirInput}\r\n aria-label=\"用户自定义技能目录\"\r\n value={skillsDirDraft}\r\n placeholder={fields.activeSkillsDir || '留空 = 自动使用当前 profile 下的 skills/ 副本'}\r\n spellCheck={false}\r\n onChange={(e) => setSkillsDirDraft(e.target.value)}\r\n />\r\n <button\r\n type=\"button\"\r\n className={styles.primary}\r\n disabled={savingSkillsDir || skillsDirDraft.trim() === fields.skillsDir}\r\n onClick={applySkillsDir}\r\n >\r\n {savingSkillsDir ? '设置中…' : '设置自定义目录'}\r\n </button>\r\n </div>\r\n <span className={styles.rowDesc}>留空并点“设置自定义目录”会切回自动目录(当前 profile 下的 skills/ 副本)。修改后技能目录立即重新扫描。</span>\r\n </div>\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 <label className={styles.row}>\r\n <input\r\n type=\"checkbox\"\r\n checked={fields.usePtcMode}\r\n disabled={!fields.writePreset}\r\n onChange={() => toggle('usePtcMode')}\r\n />\r\n <span className={styles.rowText}>\r\n <span className={styles.rowName}>使用 PTC 模式</span>\r\n <span className={styles.rowDesc}>默认开启:晋升后把 wire 切换为 Code Mode(PTC,单一 run_code),完整插件工具通过生成 SDK 调用。关闭后恢复原生完整工具目录</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 // dsh 0.1.0-rc.7 起 settings.plugin.item 是 keyed slot,\n // key = 插件 settings namespace(与 Host 端 settingsNamespace('prompt-tool') 对应)。\n ctx.slots.inject('settings.plugin.item', () => ctx.slots.register({\n name: 'settings.plugin.item',\n key: 'prompt-tool',\n inject: injected,\n }, PromptEditor))\n}\n"],"x_google_ignoreList":[0],"mappings":"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"}
|
package/lib/index.d.mts
CHANGED
|
@@ -38,7 +38,7 @@ interface Config {
|
|
|
38
38
|
bootstrapMaxTokens: number;
|
|
39
39
|
/** 使用 PTC 模式:默认开启——晋升后把 wire 切换为 Code Mode(单一 run_code,完整插件工具经生成 SDK 调用);关闭时晋升后恢复原生完整工具目录。 */
|
|
40
40
|
usePtcMode: boolean;
|
|
41
|
-
/**
|
|
41
|
+
/** 用户自定义技能目录;空 = 自动使用当前 profile 下的 skills/ 副本。 */
|
|
42
42
|
skillsDir: string;
|
|
43
43
|
/** 技能候选排序基数,技能目录内按下标递增。 */
|
|
44
44
|
skillRankBase: number;
|
|
@@ -76,6 +76,10 @@ interface PromptSettings {
|
|
|
76
76
|
injectPrompt: boolean;
|
|
77
77
|
skillSwitches: Record<string, boolean>;
|
|
78
78
|
skillCatalog: SkillCatalogEntry[];
|
|
79
|
+
/** 用户自定义技能目录;空 = 自动使用 profile skills 副本。 */
|
|
80
|
+
skillsDir: string;
|
|
81
|
+
/** 当前实际生效的技能目录(profile 副本或用户自定义路径)。 */
|
|
82
|
+
activeSkillsDir: string;
|
|
79
83
|
writeAgents: boolean;
|
|
80
84
|
writePreset: boolean;
|
|
81
85
|
}
|
package/lib/index.mjs
CHANGED
|
@@ -1,15 +1,251 @@
|
|
|
1
1
|
import { buildCordis, parseFrontmatter } from "./preset-core.mjs";
|
|
2
2
|
import z from "@deepseek-ai/schemastery";
|
|
3
3
|
import { installSettingsSection, settingsNamespace } from "@deepseek-ai/dsh-settings";
|
|
4
|
-
import { existsSync, mkdirSync, readFileSync, readdirSync, rmSync, writeFileSync } from "node:fs";
|
|
4
|
+
import { cpSync, existsSync, mkdirSync, readFileSync, readdirSync, rmSync, writeFileSync } from "node:fs";
|
|
5
5
|
import { fileURLToPath } from "node:url";
|
|
6
|
-
import { join } from "node:path";
|
|
6
|
+
import { basename, join } from "node:path";
|
|
7
7
|
import { homedir } from "node:os";
|
|
8
|
+
//#region src/web-surface.ts
|
|
9
|
+
/**
|
|
10
|
+
* prompt-tool 自愈层:补 profile manifest 与本插件相关的装配项。
|
|
11
|
+
*
|
|
12
|
+
* 官方 profile 组合规则:`dsh plugin add` 只把声明了 `dsh.bundle` 的
|
|
13
|
+
* **直接依赖**追加进 `dsh.profile.bundles`,而 `@deepseek-ai/dsh-web-app`
|
|
14
|
+
* 是随 dsh 安装自带的 in-box bundle。自定义 profile(如 prompt-tool)
|
|
15
|
+
* 首次初始化只含 `@deepseek-ai/dsh-base`,单独执行
|
|
16
|
+
* `dsh plugin --profile prompt-tool add link:<本仓库>` 后,本插件等待的
|
|
17
|
+
* `webServer` 服务不存在。
|
|
18
|
+
*
|
|
19
|
+
* 因此:
|
|
20
|
+
* 1. 当前 profile 缺 webServer 时,把 web-app 补进当前 profile 的
|
|
21
|
+
* bundles(base 之后、本插件之前),重启一次后生效;
|
|
22
|
+
* 2. 同级 `web` / `dsh-tui` profile 存在时,只把
|
|
23
|
+
* `dsh-plugin-prompt-tool` 写进它们的 dependencies + bundles。
|
|
24
|
+
* node_modules 的物化交给官方 `dsh plugin --profile <name> install`
|
|
25
|
+
* (本质是 pnpm)完成,本插件不手工创建链接。
|
|
26
|
+
* `dsh-tui` 只有在确实装有 `@deepseek-harness-tui/dsh-tui` 时才处理,
|
|
27
|
+
* 否则整体跳过——不写入本插件。dsh-tui **不需要** web-app。
|
|
28
|
+
*
|
|
29
|
+
* 官方 Loader 只会在进程启动时读取 profile 的 bundles 列表,因此本层只
|
|
30
|
+
* 持久化 manifest 并提示重启,不做运行中热挂载。所有写入都是幂等的。
|
|
31
|
+
* 当前 profile 首次补上 web-app 后会自动退出(exit 0),完成初始化。
|
|
32
|
+
*
|
|
33
|
+
* 失败只降级为日志告警,绝不阻断启动。
|
|
34
|
+
*/
|
|
35
|
+
const FALLBACK_WEB_APP_BUNDLE = "@deepseek-ai/dsh-web-app";
|
|
36
|
+
const BASE_BUNDLE = "@deepseek-ai/dsh-base";
|
|
37
|
+
const PLUGIN_BUNDLE = "dsh-plugin-prompt-tool";
|
|
38
|
+
const TUI_BUNDLE = "@deepseek-harness-tui/dsh-tui";
|
|
39
|
+
const SIBLING_PROFILES = ["web", "dsh-tui"];
|
|
40
|
+
/** 首次初始化完成后的自动退出延迟,给日志落盘与终端刷新留时间。 */
|
|
41
|
+
const AUTO_EXIT_DELAY_MS = 500;
|
|
42
|
+
/**
|
|
43
|
+
* 从本插件自己的 package.json 读取 `dsh.bundle.requires` 中声明的
|
|
44
|
+
* Web surface bundle(缺失时回退到 @deepseek-ai/dsh-web-app)。
|
|
45
|
+
* 这样“把 web-app 补进本插件 package.json”就是装配事实,而不是散落的魔法字符串。
|
|
46
|
+
*/
|
|
47
|
+
function readWebAppBundle() {
|
|
48
|
+
try {
|
|
49
|
+
const manifestPath = new URL("../package.json", import.meta.url);
|
|
50
|
+
const requires = JSON.parse(readFileSync(manifestPath, "utf8")).dsh?.bundle?.requires;
|
|
51
|
+
if (Array.isArray(requires)) {
|
|
52
|
+
const first = requires.find((entry) => typeof entry === "string");
|
|
53
|
+
if (first !== void 0 && first.length > 0) return first;
|
|
54
|
+
}
|
|
55
|
+
} catch {}
|
|
56
|
+
return FALLBACK_WEB_APP_BUNDLE;
|
|
57
|
+
}
|
|
58
|
+
const WEB_APP_BUNDLE = readWebAppBundle();
|
|
59
|
+
/** 从 loader 根 Include 的 baseUrl 推导 profile 目录。 */
|
|
60
|
+
function resolveProfileDir(ctx) {
|
|
61
|
+
const baseUrl = ctx.baseUrl;
|
|
62
|
+
if (typeof baseUrl !== "string" || baseUrl.length === 0) return void 0;
|
|
63
|
+
try {
|
|
64
|
+
return fileURLToPath(new URL(".", baseUrl));
|
|
65
|
+
} catch {
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
function readManifest(packagePath, warn) {
|
|
70
|
+
try {
|
|
71
|
+
return JSON.parse(readFileSync(packagePath, "utf8"));
|
|
72
|
+
} catch (error) {
|
|
73
|
+
warn(`prompt-tool: cannot read profile manifest ${packagePath}: ${error instanceof Error ? error.message : String(error)}`);
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
function writeManifest(packagePath, manifest, warn) {
|
|
78
|
+
try {
|
|
79
|
+
writeFileSync(packagePath, JSON.stringify(manifest, null, 2) + "\n", "utf8");
|
|
80
|
+
return true;
|
|
81
|
+
} catch (error) {
|
|
82
|
+
warn(`prompt-tool: cannot update profile manifest ${packagePath}: ${error instanceof Error ? error.message : String(error)}`);
|
|
83
|
+
return false;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
/** dsh-tui profile 是否真的装着 dsh-tui(依赖声明或 bundle 层都算)。 */
|
|
87
|
+
function hasDshTui(manifest) {
|
|
88
|
+
return manifest.dependencies?.[TUI_BUNDLE] !== void 0 || manifest.dsh?.profile?.bundles?.includes(TUI_BUNDLE) === true;
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* 把 web-app 补进当前 profile 的 bundles(base 之后、本插件之前)。
|
|
92
|
+
* 只用于当前 prompt-tool profile;dsh-tui 不需要 web-app。
|
|
93
|
+
*/
|
|
94
|
+
function ensureCurrentWebAppBundle(manifest) {
|
|
95
|
+
const bundles = manifest.dsh?.profile?.bundles;
|
|
96
|
+
if (!Array.isArray(bundles)) return "invalid";
|
|
97
|
+
if (bundles.includes(WEB_APP_BUNDLE)) return "already";
|
|
98
|
+
const pluginIndex = bundles.indexOf(PLUGIN_BUNDLE);
|
|
99
|
+
const baseIndex = bundles.indexOf(BASE_BUNDLE);
|
|
100
|
+
const insertAt = pluginIndex >= 0 ? pluginIndex : baseIndex >= 0 ? baseIndex + 1 : bundles.length;
|
|
101
|
+
bundles.splice(insertAt, 0, WEB_APP_BUNDLE);
|
|
102
|
+
return "added";
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* 把本插件补进同级 profile 的 dependencies + bundles。
|
|
106
|
+
* @returns 实际写入的条目描述;返回 undefined 表示跳过/失败。
|
|
107
|
+
*/
|
|
108
|
+
function ensurePluginInSiblingProfile(packagePath, manifest, pluginSpec, warn) {
|
|
109
|
+
const bundles = manifest.dsh?.profile?.bundles;
|
|
110
|
+
if (!Array.isArray(bundles)) {
|
|
111
|
+
warn(`prompt-tool: sibling profile manifest has no dsh.profile.bundles: ${packagePath}`);
|
|
112
|
+
return;
|
|
113
|
+
}
|
|
114
|
+
const hasDependency = manifest.dependencies?.[PLUGIN_BUNDLE] !== void 0;
|
|
115
|
+
const added = [];
|
|
116
|
+
if (!hasDependency) {
|
|
117
|
+
if (typeof pluginSpec !== "string" || pluginSpec.length === 0) {
|
|
118
|
+
warn(`prompt-tool: skip sibling profile ${packagePath} — current profile declares no install spec for ${PLUGIN_BUNDLE}`);
|
|
119
|
+
return;
|
|
120
|
+
}
|
|
121
|
+
manifest.dependencies = {
|
|
122
|
+
...manifest.dependencies,
|
|
123
|
+
[PLUGIN_BUNDLE]: pluginSpec
|
|
124
|
+
};
|
|
125
|
+
added.push(`dependency ${PLUGIN_BUNDLE}=${pluginSpec}`);
|
|
126
|
+
}
|
|
127
|
+
if (!bundles.includes(PLUGIN_BUNDLE)) {
|
|
128
|
+
bundles.push(PLUGIN_BUNDLE);
|
|
129
|
+
added.push(`bundle ${PLUGIN_BUNDLE}`);
|
|
130
|
+
}
|
|
131
|
+
if (added.length === 0) return void 0;
|
|
132
|
+
if (!writeManifest(packagePath, manifest, warn)) return void 0;
|
|
133
|
+
return added.join(", ");
|
|
134
|
+
}
|
|
135
|
+
/** 自愈同级 web / dsh-tui profile;只写 package.json,不创建 node_modules 链接。 */
|
|
136
|
+
function healSiblingProfiles(profileDir, pluginSpec, warn) {
|
|
137
|
+
const profilesDir = join(profileDir, "..");
|
|
138
|
+
for (const profileName of SIBLING_PROFILES) {
|
|
139
|
+
const packagePath = join(profilesDir, profileName, "package.json");
|
|
140
|
+
if (!existsSync(packagePath)) {
|
|
141
|
+
warn(`prompt-tool: skip sibling heal for "${profileName}" — profile package.json not found`);
|
|
142
|
+
continue;
|
|
143
|
+
}
|
|
144
|
+
const manifest = readManifest(packagePath, warn);
|
|
145
|
+
if (manifest === void 0) continue;
|
|
146
|
+
if (profileName === "dsh-tui" && !hasDshTui(manifest)) {
|
|
147
|
+
warn(`prompt-tool: skip sibling heal for "dsh-tui" — ${TUI_BUNDLE} is not installed; dsh-plugin-prompt-tool will not be written into it`);
|
|
148
|
+
continue;
|
|
149
|
+
}
|
|
150
|
+
const changes = ensurePluginInSiblingProfile(packagePath, manifest, pluginSpec, warn);
|
|
151
|
+
if (changes !== void 0) warn(`prompt-tool: healed sibling profile "${profileName}": added ${changes}`);
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
/**
|
|
155
|
+
* 每次启动:
|
|
156
|
+
* 1. 同级 web / dsh-tui 补本插件(dsh-tui 未安装则跳过);
|
|
157
|
+
* 2. 当前 profile 缺 webServer 时补 web-app 并提示重启。
|
|
158
|
+
* webServer 已存在时当前 profile 无需处理,但同级自愈仍会执行(幂等)。
|
|
159
|
+
*/
|
|
160
|
+
function ensureWebSurface(ctx, warn) {
|
|
161
|
+
const notify = (message) => {
|
|
162
|
+
process.stderr.write(message + "\n");
|
|
163
|
+
warn(message);
|
|
164
|
+
};
|
|
165
|
+
const profileDir = resolveProfileDir(ctx);
|
|
166
|
+
if (profileDir === void 0) {
|
|
167
|
+
notify("prompt-tool: cannot locate profile directory to repair bundles; add @deepseek-ai/dsh-web-app to dsh.profile.bundles manually");
|
|
168
|
+
return;
|
|
169
|
+
}
|
|
170
|
+
const packagePath = join(profileDir, "package.json");
|
|
171
|
+
const manifest = readManifest(packagePath, notify);
|
|
172
|
+
if (manifest === void 0) return;
|
|
173
|
+
healSiblingProfiles(profileDir, typeof manifest.dependencies?.[PLUGIN_BUNDLE] === "string" ? manifest.dependencies[PLUGIN_BUNDLE] : void 0, notify);
|
|
174
|
+
const profileName = basename(profileDir);
|
|
175
|
+
if (profileName === "dsh-tui" || hasDshTui(manifest)) return;
|
|
176
|
+
if (ctx.get("webServer") !== void 0) return;
|
|
177
|
+
const result = ensureCurrentWebAppBundle(manifest);
|
|
178
|
+
if (result === "invalid") {
|
|
179
|
+
notify(`prompt-tool: profile manifest has no dsh.profile.bundles: ${packagePath}`);
|
|
180
|
+
return;
|
|
181
|
+
}
|
|
182
|
+
if (result === "added" && !writeManifest(packagePath, manifest, notify)) return;
|
|
183
|
+
if (result === "added") {
|
|
184
|
+
notify(`prompt-tool: auto-added ${WEB_APP_BUNDLE} to dsh.profile.bundles for profile "${profileName}"; next launch will mount the Web surface (dsh web / dsh-tui / dsh --profile ${profileName})`);
|
|
185
|
+
notify("prompt-tool: initialization complete — exiting so the repaired profile can be launched");
|
|
186
|
+
setTimeout(() => process.exit(0), AUTO_EXIT_DELAY_MS);
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
//#endregion
|
|
190
|
+
//#region src/profile-skills.ts
|
|
191
|
+
/**
|
|
192
|
+
* prompt-tool skills 的 profile 副本。
|
|
193
|
+
*
|
|
194
|
+
* 安装命令 `dsh plugin add` 是官方的 pnpm 转发器,插件代码不会在该命令中
|
|
195
|
+
* 执行(本项目也不修改官方源码)。因此复制动作放在插件首次 apply 时:
|
|
196
|
+
* 把包内 `skills/` 增量复制到**本插件自己的 profile** 目录下的 `skills/`
|
|
197
|
+
* (`$DSH_HOME/profiles/prompt-tool/skills`),并且后续启动优先使用这份副本。
|
|
198
|
+
* 即使本插件从 `dsh web` / `dsh-tui` 启动,也固定写到 prompt-tool profile,
|
|
199
|
+
* 不会写到 web / dsh-tui 的 profile 下。
|
|
200
|
+
*
|
|
201
|
+
* 合并规则:
|
|
202
|
+
* - 只补缺失项,绝不覆盖已存在文件——用户在 profile 副本里的修改会保留;
|
|
203
|
+
* - 包内新增的技能目录/文件会在下次启动补进副本;
|
|
204
|
+
* - 副本目录不可写或 profile 定位失败时回退到包内目录,只告警不阻断。
|
|
205
|
+
*/
|
|
206
|
+
/** 本插件专属 profile 名;skills 副本固定放这里。 */
|
|
207
|
+
const PLUGIN_PROFILE = "prompt-tool";
|
|
208
|
+
/** 递归把 src 中缺失的目录/文件补到 dst,已有项保持不动。 */
|
|
209
|
+
function mergeMissing(src, dst) {
|
|
210
|
+
mkdirSync(dst, { recursive: true });
|
|
211
|
+
for (const entry of readdirSync(src, { withFileTypes: true })) {
|
|
212
|
+
const srcEntry = join(src, entry.name);
|
|
213
|
+
const dstEntry = join(dst, entry.name);
|
|
214
|
+
if (!existsSync(dstEntry)) cpSync(srcEntry, dstEntry, { recursive: true });
|
|
215
|
+
else if (entry.isDirectory()) mergeMissing(srcEntry, dstEntry);
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
/** 定位本插件自己的 profile 目录;不存在时回退到当前 profile。 */
|
|
219
|
+
function resolvePluginProfileDir(ctx) {
|
|
220
|
+
const currentDir = resolveProfileDir(ctx);
|
|
221
|
+
if (currentDir === void 0) return void 0;
|
|
222
|
+
const profilesDir = join(currentDir, "..");
|
|
223
|
+
const pluginDir = join(profilesDir, PLUGIN_PROFILE);
|
|
224
|
+
return existsSync(join(pluginDir, "package.json")) ? pluginDir : currentDir;
|
|
225
|
+
}
|
|
226
|
+
/**
|
|
227
|
+
* 返回本插件应使用的 skills 目录:
|
|
228
|
+
* 优先本插件 profile(prompt-tool)下的 `skills/` 副本;无法确定 profile
|
|
229
|
+
* 或复制失败时回退到 sourceDir(默认包内 `skills/`)。
|
|
230
|
+
*/
|
|
231
|
+
function resolveProfileSkillsDir(ctx, sourceDir, warn) {
|
|
232
|
+
const profileDir = resolvePluginProfileDir(ctx);
|
|
233
|
+
if (profileDir === void 0) return sourceDir;
|
|
234
|
+
const targetDir = join(profileDir, "skills");
|
|
235
|
+
try {
|
|
236
|
+
if (!existsSync(sourceDir)) return targetDir;
|
|
237
|
+
mergeMissing(sourceDir, targetDir);
|
|
238
|
+
return targetDir;
|
|
239
|
+
} catch (error) {
|
|
240
|
+
warn(`prompt-tool: failed to copy skills into profile directory ${targetDir}: ${error instanceof Error ? error.message : String(error)}`);
|
|
241
|
+
return sourceDir;
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
//#endregion
|
|
8
245
|
//#region src/index.ts
|
|
9
246
|
const name = "prompt-tool";
|
|
10
247
|
const inject = [
|
|
11
248
|
"skills",
|
|
12
|
-
"webServer",
|
|
13
249
|
"commands",
|
|
14
250
|
"llm",
|
|
15
251
|
"subagents"
|
|
@@ -90,6 +326,8 @@ const PromptSettingsSchema = z.object({
|
|
|
90
326
|
name: z.string(),
|
|
91
327
|
description: z.string().default("")
|
|
92
328
|
})).default([]),
|
|
329
|
+
skillsDir: z.string().default(""),
|
|
330
|
+
activeSkillsDir: z.string().default(""),
|
|
93
331
|
writeAgents: z.boolean().default(true),
|
|
94
332
|
writePreset: z.boolean().default(true)
|
|
95
333
|
});
|
|
@@ -301,6 +539,7 @@ function renderTuiStatus(source) {
|
|
|
301
539
|
` anchorText ${source.anchorText.length > 0 ? source.anchorText : "(空 = 按任务自动选择)"}`,
|
|
302
540
|
` deepseekAvailable ${source.deepseekAvailable ? "是" : "否(未检测到 DeepSeek 模型,subagentFlash 不可用)"}`,
|
|
303
541
|
` bootstrapMaxTokens ${source.bootstrapMaxTokens > 0 ? source.bootstrapMaxTokens : "0(关闭,不设封顶)"}`,
|
|
542
|
+
` activeSkillsDir ${source.activeSkillsDir || "(未解析到技能目录)"}`,
|
|
304
543
|
"技能开关:"
|
|
305
544
|
];
|
|
306
545
|
for (const skill of source.skillCatalog) {
|
|
@@ -408,8 +647,8 @@ ${renderTuiStatus(getSource())}`
|
|
|
408
647
|
});
|
|
409
648
|
}
|
|
410
649
|
/** 自建 loopback settings bridge:替代 registerConfigurableProviders,避免模型设置区出现插件条目。 */
|
|
411
|
-
function registerSettingsBridge(ctx, getDeepseekAvailable, getDeepseekState) {
|
|
412
|
-
ctx.inject(["settings"], (sctx) => {
|
|
650
|
+
function registerSettingsBridge(ctx, getDeepseekAvailable, getDeepseekState, getSkillsState) {
|
|
651
|
+
ctx.inject(["settings", "webServer"], (sctx) => {
|
|
413
652
|
sctx.effect(() => {
|
|
414
653
|
const findDescriptor = () => sctx.settings.describe({ redactSecrets: true }).find((entry) => String(entry.ns) === String(NS));
|
|
415
654
|
const guard = (req, res) => {
|
|
@@ -447,12 +686,15 @@ function registerSettingsBridge(ctx, getDeepseekAvailable, getDeepseekState) {
|
|
|
447
686
|
return;
|
|
448
687
|
}
|
|
449
688
|
const detection = getDeepseekState();
|
|
689
|
+
const skillsState = getSkillsState();
|
|
450
690
|
writeBridgeJson(res, 200, {
|
|
451
691
|
ok: true,
|
|
452
692
|
value: descriptor,
|
|
453
693
|
deepseekAvailable: detection.available,
|
|
454
694
|
deepseekProviders: detection.providers,
|
|
455
|
-
deepseekError: detection.error
|
|
695
|
+
deepseekError: detection.error,
|
|
696
|
+
activeSkillsDir: skillsState.activeSkillsDir,
|
|
697
|
+
skillCatalog: skillsState.skillCatalog
|
|
456
698
|
});
|
|
457
699
|
}
|
|
458
700
|
}),
|
|
@@ -685,11 +927,24 @@ function apply(ctx, config) {
|
|
|
685
927
|
const getDeepseekState = () => deepseekState();
|
|
686
928
|
let current = config.text || readPromptFile(config.fallbackText);
|
|
687
929
|
let currentAgents = config.agentsText || readAgents();
|
|
688
|
-
const
|
|
930
|
+
const configuredSkillsDir = config.skillsDir !== DEFAULT_SKILLS_DIR && config.skillsDir.length > 0 ? config.skillsDir : "";
|
|
931
|
+
let activeSkillsDir = configuredSkillsDir.length > 0 ? configuredSkillsDir : resolveProfileSkillsDir(ctx, DEFAULT_SKILLS_DIR, (message) => warn(ctx, message));
|
|
932
|
+
let skillCatalog = readSkills(activeSkillsDir).map((skill) => ({
|
|
689
933
|
folder: skill.folder,
|
|
690
934
|
name: skill.name,
|
|
691
935
|
description: skill.description
|
|
692
936
|
}));
|
|
937
|
+
/** 切换生效技能目录并刷新目录快照(供 describe / TUI 显示)。 */
|
|
938
|
+
const applyActiveSkillsDir = (dir) => {
|
|
939
|
+
activeSkillsDir = dir;
|
|
940
|
+
skillCatalog = readSkills(dir).map((skill) => ({
|
|
941
|
+
folder: skill.folder,
|
|
942
|
+
name: skill.name,
|
|
943
|
+
description: skill.description
|
|
944
|
+
}));
|
|
945
|
+
};
|
|
946
|
+
/** 用户 skillsDir 设置 → 实际生效目录。 */
|
|
947
|
+
const resolveActiveSkillsDir = (userDir) => userDir.length > 0 ? userDir : resolveProfileSkillsDir(ctx, DEFAULT_SKILLS_DIR, (message) => warn(ctx, message));
|
|
693
948
|
let skillSwitches = { ...config.skillSwitches };
|
|
694
949
|
let invalidateSkills;
|
|
695
950
|
ctx.skills.registerProvider((control) => {
|
|
@@ -698,7 +953,7 @@ function apply(ctx, config) {
|
|
|
698
953
|
name: "prompt-tool",
|
|
699
954
|
list: async (options) => {
|
|
700
955
|
if (options.signal?.aborted) return [];
|
|
701
|
-
return readSkills(
|
|
956
|
+
return readSkills(activeSkillsDir).filter((skill) => skillSwitches[skill.folder] !== false).map((skill, index) => ({
|
|
702
957
|
name: skill.name,
|
|
703
958
|
description: skill.description || skill.folder,
|
|
704
959
|
...skill.whenToUse !== void 0 ? { whenToUse: skill.whenToUse } : {},
|
|
@@ -710,7 +965,7 @@ function apply(ctx, config) {
|
|
|
710
965
|
provider: "prompt-tool",
|
|
711
966
|
resourceBase: {
|
|
712
967
|
kind: "directory",
|
|
713
|
-
path: join(
|
|
968
|
+
path: join(activeSkillsDir, skill.folder)
|
|
714
969
|
},
|
|
715
970
|
rank: config.skillRankBase + index,
|
|
716
971
|
locator: skill.folder,
|
|
@@ -720,7 +975,7 @@ function apply(ctx, config) {
|
|
|
720
975
|
},
|
|
721
976
|
get: async (candidate, options) => {
|
|
722
977
|
if (options.signal?.aborted) return void 0;
|
|
723
|
-
const skill = readSkills(
|
|
978
|
+
const skill = readSkills(activeSkillsDir).find((entry) => entry.folder === candidate.locator || entry.name === candidate.name);
|
|
724
979
|
if (skill === void 0 || skillSwitches[skill.folder] === false) return void 0;
|
|
725
980
|
return {
|
|
726
981
|
name: candidate.name,
|
|
@@ -737,13 +992,20 @@ function apply(ctx, config) {
|
|
|
737
992
|
}
|
|
738
993
|
};
|
|
739
994
|
});
|
|
740
|
-
registerSettingsBridge(ctx, getDeepseekAvailable, getDeepseekState)
|
|
995
|
+
registerSettingsBridge(ctx, getDeepseekAvailable, getDeepseekState, () => ({
|
|
996
|
+
activeSkillsDir,
|
|
997
|
+
skillCatalog
|
|
998
|
+
}));
|
|
999
|
+
setImmediate(() => {
|
|
1000
|
+
ensureWebSurface(ctx, (message) => warn(ctx, message));
|
|
1001
|
+
});
|
|
741
1002
|
const runtime = {
|
|
742
1003
|
writeAgents: config.writeAgents,
|
|
743
1004
|
writePreset: config.writePreset,
|
|
744
1005
|
injectAgentsPrompt: config.injectAgentsPrompt,
|
|
745
1006
|
injectPrompt: config.injectPrompt,
|
|
746
1007
|
skillSwitches: { ...config.skillSwitches },
|
|
1008
|
+
skillsDir: configuredSkillsDir,
|
|
747
1009
|
anchorFirstTurn: config.anchorFirstTurn,
|
|
748
1010
|
anchorText: config.anchorText,
|
|
749
1011
|
anchorCustom: config.anchorCustom,
|
|
@@ -772,6 +1034,8 @@ function apply(ctx, config) {
|
|
|
772
1034
|
injectPrompt: runtime.injectPrompt,
|
|
773
1035
|
skillSwitches: runtime.skillSwitches,
|
|
774
1036
|
skillCatalog,
|
|
1037
|
+
skillsDir: runtime.skillsDir,
|
|
1038
|
+
activeSkillsDir,
|
|
775
1039
|
writeAgents: runtime.writeAgents,
|
|
776
1040
|
writePreset: runtime.writePreset
|
|
777
1041
|
});
|
|
@@ -785,6 +1049,7 @@ function apply(ctx, config) {
|
|
|
785
1049
|
injectAgentsPrompt: typeof next.injectAgentsPrompt === "boolean" ? next.injectAgentsPrompt : config.injectAgentsPrompt,
|
|
786
1050
|
injectPrompt: typeof next.injectPrompt === "boolean" ? next.injectPrompt : config.injectPrompt,
|
|
787
1051
|
skillSwitches: next.skillSwitches !== void 0 ? next.skillSwitches : config.skillSwitches,
|
|
1052
|
+
skillsDir: typeof next.skillsDir === "string" ? next.skillsDir : configuredSkillsDir,
|
|
788
1053
|
anchorFirstTurn: typeof next.anchorFirstTurn === "boolean" ? next.anchorFirstTurn : config.anchorFirstTurn,
|
|
789
1054
|
anchorText: normalizeAnchorText(typeof next.anchorText === "string" ? next.anchorText : config.anchorText),
|
|
790
1055
|
anchorCustom: typeof next.anchorCustom === "boolean" ? next.anchorCustom : config.anchorCustom,
|
|
@@ -797,7 +1062,8 @@ function apply(ctx, config) {
|
|
|
797
1062
|
const promptChanged = next.promptText !== current;
|
|
798
1063
|
const agentsChanged = next.agentsText !== currentAgents;
|
|
799
1064
|
const skillSwitchesChanged = JSON.stringify(runtime.skillSwitches) !== JSON.stringify(nextRuntime.skillSwitches);
|
|
800
|
-
const
|
|
1065
|
+
const skillsDirChanged = runtime.skillsDir !== nextRuntime.skillsDir;
|
|
1066
|
+
const settingsChanged = runtime.writeAgents !== nextRuntime.writeAgents || runtime.writePreset !== nextRuntime.writePreset || runtime.injectAgentsPrompt !== nextRuntime.injectAgentsPrompt || runtime.injectPrompt !== nextRuntime.injectPrompt || skillSwitchesChanged || skillsDirChanged || 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 || runtime.usePtcMode !== nextRuntime.usePtcMode;
|
|
801
1067
|
if (!needsInitialApply && !promptChanged && !agentsChanged && !settingsChanged) return;
|
|
802
1068
|
needsInitialApply = false;
|
|
803
1069
|
if (promptChanged) current = next.promptText;
|
|
@@ -807,6 +1073,7 @@ function apply(ctx, config) {
|
|
|
807
1073
|
runtime.injectAgentsPrompt = nextRuntime.injectAgentsPrompt;
|
|
808
1074
|
runtime.injectPrompt = nextRuntime.injectPrompt;
|
|
809
1075
|
runtime.skillSwitches = nextRuntime.skillSwitches;
|
|
1076
|
+
runtime.skillsDir = nextRuntime.skillsDir;
|
|
810
1077
|
runtime.anchorFirstTurn = nextRuntime.anchorFirstTurn;
|
|
811
1078
|
runtime.anchorText = nextRuntime.anchorText;
|
|
812
1079
|
runtime.anchorCustom = nextRuntime.anchorCustom;
|
|
@@ -816,7 +1083,10 @@ function apply(ctx, config) {
|
|
|
816
1083
|
runtime.bootstrapMaxTokens = nextRuntime.bootstrapMaxTokens;
|
|
817
1084
|
runtime.usePtcMode = nextRuntime.usePtcMode;
|
|
818
1085
|
skillSwitches = runtime.skillSwitches;
|
|
819
|
-
if (
|
|
1086
|
+
if (skillsDirChanged) {
|
|
1087
|
+
applyActiveSkillsDir(resolveActiveSkillsDir(runtime.skillsDir));
|
|
1088
|
+
invalidateSkills?.();
|
|
1089
|
+
} else if (skillSwitchesChanged) invalidateSkills?.();
|
|
820
1090
|
let residentAgentsWritten = false;
|
|
821
1091
|
if (runtime.writeAgents) {
|
|
822
1092
|
residentAgentsWritten = writeAgents(currentAgents, config.residentAgentsPath);
|
|
@@ -868,6 +1138,8 @@ function apply(ctx, config) {
|
|
|
868
1138
|
injectPrompt: config.injectPrompt,
|
|
869
1139
|
skillSwitches: { ...config.skillSwitches },
|
|
870
1140
|
skillCatalog,
|
|
1141
|
+
skillsDir: configuredSkillsDir,
|
|
1142
|
+
activeSkillsDir,
|
|
871
1143
|
writeAgents: config.writeAgents,
|
|
872
1144
|
writePreset: config.writePreset
|
|
873
1145
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-plugin-prompt-tool",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.2",
|
|
4
4
|
"description": "DSH 插件:提示词工具,规范模型的思维链与回答内容,提供 Web UI 编辑 preset.md 与 AGENTS.md,并按 skills 目录注册可开关技能。",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -23,7 +23,10 @@
|
|
|
23
23
|
},
|
|
24
24
|
"dsh": {
|
|
25
25
|
"bundle": {
|
|
26
|
-
"patch": "./cordis.patch.yml"
|
|
26
|
+
"patch": "./cordis.patch.yml",
|
|
27
|
+
"requires": [
|
|
28
|
+
"@deepseek-ai/dsh-web-app"
|
|
29
|
+
]
|
|
27
30
|
},
|
|
28
31
|
"client": {
|
|
29
32
|
"inject": [
|