@dsh-plus/agent-preset-rea 0.1.1 → 0.1.3

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dsh-plus/agent-preset-rea",
3
- "version": "0.1.1",
3
+ "version": "0.1.3",
4
4
  "description": "dsh-plus service + UI plugin: 注册逆向工程 agent preset(id=rea)——官方 standard 全量行镜像 + 预设作用域的 REA MCP 客户端(mcp__rea__*)、随包 REA 官方 skill、提示词卡片与 REA/skill 的受管安装更新",
5
5
  "type": "module",
6
6
  "main": "lib/index.js",
@@ -32,17 +32,17 @@
32
32
  }
33
33
  },
34
34
  "dependencies": {
35
- "@dsh-plus/shared": "0.1.40"
35
+ "@dsh-plus/shared": "0.1.41"
36
36
  },
37
37
  "peerDependencies": {
38
38
  "@deepseek-ai/cordis": "^4.0.5-alpha.2",
39
- "@deepseek-ai/dsh-agent-preset-registry": "^0.2.1-alpha.3",
39
+ "@deepseek-ai/dsh-agent-preset-registry": "^0.2.1-alpha.4",
40
40
  "@deepseek-ai/schemastery": "^3.18.5-alpha.2"
41
41
  },
42
42
  "devDependencies": {
43
43
  "@deepseek-ai/cordis": "4.0.5-alpha.2",
44
- "@deepseek-ai/dsh-agent-preset-registry": "0.2.1-alpha.3",
45
- "@deepseek-ai/dsh-host-webserver": "0.2.1-alpha.3",
44
+ "@deepseek-ai/dsh-agent-preset-registry": "0.2.1-alpha.4",
45
+ "@deepseek-ai/dsh-host-webserver": "0.2.1-alpha.4",
46
46
  "@deepseek-ai/schemastery": "3.18.5-alpha.2",
47
47
  "@types/react": "~18.3.31",
48
48
  "react": "^18.2.0",
package/src/client/api.ts CHANGED
@@ -6,7 +6,7 @@
6
6
  * @module agent-preset-rea/client/api
7
7
  */
8
8
  import { getJson, postJson } from '@dsh-plus/shared/client'
9
- import type { JobActionDto, JobDto, StatusDto } from '../dto.ts'
9
+ import type { JobActionDto, JobDto, JobKind, StatusDto } from '../dto.ts'
10
10
 
11
11
  /** 载荷类型谓词(与 shared/client 的 fetch 同形;此处按本插件契约自持)。 */
12
12
  type Guard<T> = (value: unknown) => value is T
@@ -34,6 +34,7 @@ function isStatus(value: unknown): value is StatusDto {
34
34
  const install = body['install']
35
35
  const skill = body['skill']
36
36
  const mcp = body['mcp']
37
+ const reverse = body['reverse']
37
38
  return (
38
39
  typeof install === 'object' &&
39
40
  install !== null &&
@@ -41,6 +42,8 @@ function isStatus(value: unknown): value is StatusDto {
41
42
  skill !== null &&
42
43
  typeof mcp === 'object' &&
43
44
  mcp !== null &&
45
+ typeof reverse === 'object' &&
46
+ reverse !== null &&
44
47
  typeof body['config'] === 'object' &&
45
48
  body['config'] !== null
46
49
  )
@@ -60,13 +63,11 @@ export async function fetchStatus(): Promise<StatusDto> {
60
63
 
61
64
  /**
62
65
  * 启动作业。
63
- * @param kind - `install` = 安装/更新 REA 包;`skill` = 拉取并替换 skill 副本。
66
+ * @param kind - `install` = 安装/更新 REA 包;`skill` = 更新 REA skill 副本;
67
+ * `reverse` = 更新 reverse-skill(GitHub 源)。
64
68
  * @param proxyPort - 草稿里当前填的代理端口(未保存也即时生效)。
65
69
  */
66
- export async function startJob(
67
- kind: 'install' | 'skill',
68
- proxyPort: number,
69
- ): Promise<JobActionDto> {
70
+ export async function startJob(kind: JobKind, proxyPort: number): Promise<JobActionDto> {
70
71
  return postJson<JobActionDto>(`${ROUTE_BASE}/${kind}`, { proxyPort }, isJobAction)
71
72
  }
72
73
 
@@ -6,11 +6,14 @@
6
6
  * (CardChrome + useNamespaceDraft:staged 草稿、脏判定、revision fencing、
7
7
  * Host 更新不覆盖在途编辑),安装维护区见 client/install.tsx。
8
8
  *
9
- * 两个活动字段(`Config` 里标 `.volatile()` 的)都在这里给出编辑器:
10
- * - `personaPrefix`:system-prompt 的 persona 前缀段;
11
- * - `proxyPort`:安装/更新时的本机代理端口。
12
- * 其余字段(安装位置、MCP 参数、超时、附加 skill 根)属部署方平面,由 profile 的
13
- * cordis.patch.yml 行级配置覆盖,卡片只读展示关键事实。
9
+ * 六个活动字段(`Config` 里标 `.volatile()` 的)都在这里给出编辑器:
10
+ * - `personaPrefixMode` / `personaPrefix`:persona 前缀的来源与正文;默认取随包内置
11
+ * 文本(只读预览,见 persona-prefix.ts 的 DEFAULT_PROMPT_PREVIEW),切「自定义」
12
+ * 才写正文;
13
+ * - `proxyPort`:安装/更新时的本机代理端口;
14
+ * - `mcpEnabled` / `skillEnabled` / `reverseSkillEnabled`:三个能力开关(见 toggles.tsx)。
15
+ * 其余字段(受管目录、版本钉、skill 组、MCP 参数、超时、附加 skill 根)属部署方平面,
16
+ * 由 profile 的 cordis.patch.yml 行级配置覆盖,卡片只读展示关键事实。
14
17
  *
15
18
  * 安装维护为什么不放在注册期自动做:启动期 `npx`/npm 安装会跑依赖安装脚本
16
19
  * (原生 prebuild 下载),卡住即吊死预设激活与整个名册;因此改成显式动作
@@ -30,9 +33,33 @@ import {
30
33
  } from '@dsh-plus/shared/client'
31
34
  import type { ReactElement } from 'react'
32
35
 
36
+ import { DEFAULT_PERSONA_PREFIX_LENGTH, DEFAULT_PERSONA_PREFIX_PREVIEW } from '../persona-prefix.ts'
33
37
  import { type ConfigValue, type Draft, draftFromValue, parseProxyPort, toPatch } from './draft.ts'
34
38
  import type { Translate } from './i18n.ts'
35
39
  import { InstallSection } from './install.tsx'
40
+ import { ToggleSection } from './toggles.tsx'
41
+
42
+ /** 提示词来源的二选一按钮(与能力开关同形态的轻量控件)。 */
43
+ function ModeButton(props: {
44
+ id: string
45
+ label: string
46
+ active: boolean
47
+ disabled: boolean
48
+ onSelect(): void
49
+ }): ReactElement {
50
+ return (
51
+ <button
52
+ type="button"
53
+ id={props.id}
54
+ className={`apr-mode${props.active ? ' apr-mode-on' : ''}`}
55
+ aria-pressed={props.active}
56
+ disabled={props.disabled}
57
+ onClick={props.onSelect}
58
+ >
59
+ {props.label}
60
+ </button>
61
+ )
62
+ }
36
63
 
37
64
  export interface CardProps extends PluginConfigViewProps {
38
65
  t: Translate
@@ -87,6 +114,7 @@ export function ReaCard(props: CardProps): ReactElement | string | null {
87
114
 
88
115
  const disabled = state.disabled
89
116
  const port = parseProxyPort(draft.proxyPort)
117
+ const custom = draft.personaPrefixMode === 'custom'
90
118
  return (
91
119
  <CardChrome
92
120
  prefix="apr"
@@ -112,18 +140,56 @@ export function ReaCard(props: CardProps): ReactElement | string | null {
112
140
  {t('prompt')}
113
141
  </label>
114
142
  </div>
143
+ <div className="apr-modes">
144
+ <ModeButton
145
+ id="apr-prompt-mode-default"
146
+ label={t('promptModeDefault')}
147
+ active={custom === false}
148
+ disabled={disabled}
149
+ onSelect={() => state.edit({ personaPrefixMode: 'default' })}
150
+ />
151
+ <ModeButton
152
+ id="apr-prompt-mode-custom"
153
+ label={t('promptModeCustom')}
154
+ active={custom === true}
155
+ disabled={disabled}
156
+ onSelect={() => state.edit({ personaPrefixMode: 'custom' })}
157
+ />
158
+ </div>
115
159
  <textarea
116
160
  id="apr-prompt"
117
161
  className="apr-textarea"
118
162
  rows={10}
119
163
  spellCheck={false}
120
164
  placeholder={t('promptPlaceholder')}
121
- value={draft.personaPrefix}
165
+ value={custom === true ? draft.personaPrefix : DEFAULT_PERSONA_PREFIX_PREVIEW}
166
+ readOnly={custom !== true}
122
167
  disabled={disabled}
123
168
  onChange={(event) => state.edit({ personaPrefix: event.target.value })}
124
169
  />
125
170
  <p className="apr-hint">{t('promptHint')}</p>
126
- {draft.personaPrefix.trim() === '' ? <p className="apr-hint">{t('promptEmpty')}</p> : null}
171
+ {custom === true ? null : (
172
+ <p className="apr-hint">
173
+ {t('promptDefaultHint')} {t('promptChars')}
174
+ {String(DEFAULT_PERSONA_PREFIX_LENGTH)}
175
+ </p>
176
+ )}
177
+ {custom === true && draft.personaPrefix.trim() === '' ? (
178
+ <p className="apr-hint">{t('promptEmpty')}</p>
179
+ ) : null}
180
+ {custom === true && draft.personaPrefix.trim() !== '' ? (
181
+ <p className="apr-hint">
182
+ {t('promptLegacyHint')}{' '}
183
+ <button
184
+ type="button"
185
+ className="apr-link"
186
+ disabled={disabled}
187
+ onClick={() => state.edit({ personaPrefixMode: 'default', personaPrefix: '' })}
188
+ >
189
+ {t('promptResetToDefault')}
190
+ </button>
191
+ </p>
192
+ ) : null}
127
193
  </div>
128
194
 
129
195
  <TextField
@@ -139,6 +205,8 @@ export function ReaCard(props: CardProps): ReactElement | string | null {
139
205
  onEdit={(text) => state.edit({ proxyPort: text })}
140
206
  />
141
207
 
208
+ <ToggleSection t={t} draft={draft} disabled={disabled} onEdit={state.edit} />
209
+
142
210
  <InstallSection t={t} disabled={disabled} proxyPort={port} />
143
211
  </CardChrome>
144
212
  )
@@ -4,8 +4,9 @@
4
4
  * 构建产物为 window.__ModuleLoader__.load({id, factory}) 形式的 CJS factory
5
5
  * (包装见 tsdown.config.ts);样式沿用官方 data-plugin-css 约定,HMR 据此卸载。
6
6
  *
7
- * 卡片编辑两个活动字段(`personaPrefix`、`proxyPort`),并驱动宿主半的受管安装/更新
8
- * 作业(同源自定义端点,见 client/api.ts);配置读写经共享层直连 `ctx.remote.settings`
7
+ * 卡片编辑六个活动字段(`personaPrefixMode` 提示词来源、`personaPrefix` 提示词正文、
8
+ * `proxyPort` 与 mcp/skill/reverse 三个开关),
9
+ * 并驱动宿主半的受管安装/更新作业(同源自定义端点,见 client/api.ts);配置读写经共享层直连 `ctx.remote.settings`
9
10
  * (官方 `settingsScope` 服务不存在、由 `configForms` 取代),与 notify-email 同机制。
10
11
  * @module @dsh-plus/agent-preset-rea/client
11
12
  */
@@ -1,26 +1,49 @@
1
1
  /**
2
2
  * 卡片草稿的纯逻辑(无 JSX,node --test 可直接测):命名空间解析值 ⇄ 编辑草稿。
3
3
  *
4
- * 卡片编辑两个活动字段(`personaPrefix` 提示词、`proxyPort` 安装代理端口),其余字段
5
- * 属部署方平面不进卡片;命名空间值是整行配置的脱敏视图,读取时按字段收窄:
6
- * 值缺席或类型不符一律回落默认(提示词空串、代理 0)。
4
+ * 卡片编辑六个活动字段(`personaPrefixMode` 提示词来源、`personaPrefix` 提示词正文、
5
+ * `proxyPort` 安装代理端口、`mcpEnabled` / `skillEnabled` / `reverseSkillEnabled`
6
+ * 三个能力开关),其余字段属部署方平面不进卡片;命名空间值是整行配置的脱敏视图,
7
+ * 读取时按字段收窄:值缺席或类型不符一律回落默认(提示词来源 `default`、代理 0、
8
+ * 开关 true)。
7
9
  *
8
10
  * 代理端口以文本承载:越界/非法不静默改写,标 `invalid` 并禁用保存(见 card.tsx),
9
11
  * 避免「输入 99999 被悄悄存成 65535」这类静默数据损坏。
10
12
  * @module agent-preset-rea/client/draft
11
13
  */
14
+ import type { PersonaPrefixMode } from '../persona-prefix.ts'
12
15
 
13
16
  /** 命名空间解析值中本卡片消费的部分。 */
14
17
  export interface ConfigValue {
18
+ personaPrefixMode?: unknown
15
19
  personaPrefix?: unknown
16
20
  proxyPort?: unknown
21
+ mcpEnabled?: unknown
22
+ skillEnabled?: unknown
23
+ reverseSkillEnabled?: unknown
17
24
  }
18
25
 
19
26
  /** 编辑草稿。 */
20
27
  export interface Draft {
28
+ /** persona 前缀来源:`default` = 随包内置,`custom` = 取下面的用户文本。 */
29
+ personaPrefixMode: PersonaPrefixMode
21
30
  personaPrefix: string
22
31
  /** 代理端口文本(空串与 `'0'` 都表示不用代理)。 */
23
32
  proxyPort: string
33
+ /** 三个能力开关(REA MCP 行 / REA skill / reverse-skill)。 */
34
+ mcpEnabled: boolean
35
+ skillEnabled: boolean
36
+ reverseSkillEnabled: boolean
37
+ }
38
+
39
+ /** 布尔字段收窄(缺席或类型不符回落默认值)。 */
40
+ function boolOf(value: unknown, fallback: boolean): boolean {
41
+ return typeof value === 'boolean' ? value : fallback
42
+ }
43
+
44
+ /** 模式收窄:只认两个字面量,其余(含缺席与旧配置)回落 `default`。 */
45
+ function modeOf(value: unknown): PersonaPrefixMode {
46
+ return value === 'custom' ? 'custom' : 'default'
24
47
  }
25
48
 
26
49
  /** 代理端口上限。 */
@@ -29,8 +52,12 @@ export const PROXY_PORT_MAX = 65535
29
52
  /** 解析值 → 草稿(类型不符一律回落默认)。 */
30
53
  export function draftFromValue(value: ConfigValue): Draft {
31
54
  return {
55
+ personaPrefixMode: modeOf(value.personaPrefixMode),
32
56
  personaPrefix: typeof value.personaPrefix === 'string' ? value.personaPrefix : '',
33
57
  proxyPort: typeof value.proxyPort === 'number' ? String(value.proxyPort) : '',
58
+ mcpEnabled: boolOf(value.mcpEnabled, true),
59
+ skillEnabled: boolOf(value.skillEnabled, true),
60
+ reverseSkillEnabled: boolOf(value.reverseSkillEnabled, true),
34
61
  }
35
62
  }
36
63
 
@@ -49,7 +76,11 @@ export function parseProxyPort(text: string): number | null {
49
76
  /** 草稿 → 提交形状(只回写本卡片负责的字段)。 */
50
77
  export function toPatch(draft: Draft): Record<string, unknown> {
51
78
  return {
79
+ personaPrefixMode: draft.personaPrefixMode,
52
80
  personaPrefix: draft.personaPrefix,
53
81
  proxyPort: parseProxyPort(draft.proxyPort) ?? 0,
82
+ mcpEnabled: draft.mcpEnabled,
83
+ skillEnabled: draft.skillEnabled,
84
+ reverseSkillEnabled: draft.reverseSkillEnabled,
54
85
  }
55
86
  }
@@ -9,13 +9,21 @@ export const NS = 'dsh-plus-agent-preset-rea'
9
9
 
10
10
  const ownZh = {
11
11
  title: '逆向工程预设',
12
- description: 'REA 提示词与安装维护:提示词留空即空 persona,工具指引与运行时上下文照常注入。',
13
- summaryLine: '编辑「逆向工程」预设的提示词,并安装/更新 REA 与 skill',
12
+ description:
13
+ 'REA 提示词与安装维护:提示词默认取随包内置文本,也可切到自定义;工具指引与运行时上下文照常注入。',
14
+ summaryLine: '编辑「逆向工程」预设的提示词、开关 REA MCP 与两类 skill,并安装/更新',
14
15
  prompt: '系统提示词(persona 前缀)',
16
+ promptMode: '提示词来源',
17
+ promptModeDefault: '随包默认',
18
+ promptModeCustom: '自定义',
15
19
  promptHint:
16
- '写入 system-prompt 的 persona 前缀段,仅对「逆向工程」预设的新会话生效;留空 = 不注入 persona 段(官方工具指引、项目指令与运行时上下文不受影响)。保存后新建会话即用新值。',
20
+ '写入 system-prompt 的 persona 前缀段(order 0,早于全部工具指引),仅对「逆向工程」预设的新会话生效。默认取随包内置文本;选「自定义」才用下面输入框的正文。官方工具指引、项目指令与运行时上下文不受影响。保存后新建会话即用新值。',
21
+ promptDefaultHint: '当前使用随包默认:下方为只读预览,切到「自定义」可改写正文。',
22
+ promptLegacyHint: '自定义正文与内置默认不同:「改用随包默认」只改草稿,仍需点保存才生效。',
23
+ promptResetToDefault: '改用随包默认',
24
+ promptChars: '内置文本字符数:',
17
25
  promptPlaceholder: '例如:先做证据分级,再动手改二进制;每一步给出可复核的证据链……',
18
- promptEmpty: '当前为空:该预设不注入 persona 段。',
26
+ promptEmpty: '正文为空:保存后会回落随包内置文本,不会注入空 persona。',
19
27
  saveFailed: '保存失败:',
20
28
 
21
29
  installSection: 'REA 安装与更新',
@@ -58,6 +66,26 @@ const ownZh = {
58
66
  jobElapsed: '已用时',
59
67
  jobLogEmpty: '(暂无输出)',
60
68
 
69
+ toggleSection: '能力开关',
70
+ toggleMcp: 'REA MCP 工具(mcp__rea__*)',
71
+ toggleMcpHint:
72
+ '关掉即从本预设摘掉 REA MCP 行,模型面看不到 mcp__rea__* 工具;REA 仍留在磁盘上,随时可开回来(保存后新建会话生效)。',
73
+ toggleSkill: 'REA 官方 skill',
74
+ toggleSkillHint:
75
+ '关掉即不挂 REA 官方 skill 根(reverse-engineer-anything),其余 skill 根不受影响。',
76
+ toggleReverse: 'reverse-skill 技能包',
77
+ toggleReverseHint:
78
+ '关掉即不挂 zhaoxuya520/reverse-skill 的技能组(默认挂主包根:路由技能 + 各模块技能);安装副本仍在,可从下面重新更新。',
79
+ enabled: '已挂载',
80
+ disabled: '已关闭',
81
+ reverseSource: 'reverse-skill',
82
+ reverseCommit: '提交',
83
+ reverseGroups: '技能组',
84
+ reverseGroupsHint: '树内可选组:',
85
+ reversePath: '技能包目录',
86
+ reverseAction: '更新 reverse-skill',
87
+ jobReverse: '更新 reverse-skill',
88
+
61
89
  proxyPort: '安装代理端口',
62
90
  proxyPortHint:
63
91
  '安装/更新时供 npm 与原生依赖(node-pty)prebuild 下载使用的本机代理端口;0 或留空 = 直连。未保存也用于本次安装,保存后长期生效。',
@@ -67,14 +95,24 @@ const ownZh = {
67
95
  const ownEn = {
68
96
  title: 'Reverse-engineering preset',
69
97
  description:
70
- 'REA prompt and installation: an empty prompt means a blank persona; tool guidance and runtime context stay in place.',
71
- summaryLine: 'Edit the “逆向工程” prompt and install/update REA and its skill',
98
+ 'REA prompt and installation: the prompt defaults to the bundled text and can be switched to custom; tool guidance and runtime context stay in place.',
99
+ summaryLine: 'Edit the “逆向工程” prompt, toggle REA MCP/skills, install and update them',
72
100
  prompt: 'System prompt (persona prefix)',
101
+ promptMode: 'Prompt source',
102
+ promptModeDefault: 'Bundled default',
103
+ promptModeCustom: 'Custom',
73
104
  promptHint:
74
- 'Written to the persona-prefix section of the system prompt for new sessions of this preset only. Empty means no persona section (official tool guidance, project instructions and runtime context are unaffected). New sessions pick up the saved value.',
105
+ 'Written to the persona-prefix section of the system prompt (order 0, ahead of every tool-guidance section) for new sessions of this preset only. The default is the bundled text; the textarea below is used only in Custom mode. Official tool guidance, project instructions and runtime context are unaffected. New sessions pick up the saved value.',
106
+ promptDefaultHint:
107
+ 'Using the bundled default: the preview below is read-only; switch to Custom to rewrite it.',
108
+ promptLegacyHint:
109
+ 'The custom text differs from the bundled default; “Use bundled default” only edits the draft — save to apply.',
110
+ promptResetToDefault: 'Use bundled default',
111
+ promptChars: 'Bundled text characters: ',
75
112
  promptPlaceholder:
76
113
  'e.g. Grade the evidence first, then patch the binary; every step needs a checkable chain of evidence…',
77
- promptEmpty: 'Currently empty: this preset injects no persona section.',
114
+ promptEmpty:
115
+ 'Empty body: saving falls back to the bundled text, so no empty persona is injected.',
78
116
  saveFailed: 'Save failed: ',
79
117
 
80
118
  installSection: 'REA installation',
@@ -118,6 +156,26 @@ const ownEn = {
118
156
  jobElapsed: 'Elapsed',
119
157
  jobLogEmpty: '(no output yet)',
120
158
 
159
+ toggleSection: 'Capability switches',
160
+ toggleMcp: 'REA MCP tools (mcp__rea__*)',
161
+ toggleMcpHint:
162
+ 'Turning this off drops the REA MCP row from this preset, so mcp__rea__* tools disappear; REA stays on disk and can be switched back on. New sessions pick up the change.',
163
+ toggleSkill: 'REA official skill',
164
+ toggleSkillHint:
165
+ 'Turning this off unmounts the bundled REA skill root (reverse-engineer-anything); other skill roots are unaffected.',
166
+ toggleReverse: 'reverse-skill pack',
167
+ toggleReverseHint:
168
+ 'Turning this off unmounts the skill groups of zhaoxuya520/reverse-skill (the main pack root is mounted by default: router skill plus module skills). The installed copy stays on disk and can be updated again below.',
169
+ enabled: 'Mounted',
170
+ disabled: 'Off',
171
+ reverseSource: 'reverse-skill',
172
+ reverseCommit: 'Commit',
173
+ reverseGroups: 'Skill groups',
174
+ reverseGroupsHint: 'Available in tree: ',
175
+ reversePath: 'Pack directory',
176
+ reverseAction: 'Update reverse-skill',
177
+ jobReverse: 'Update reverse-skill',
178
+
121
179
  proxyPort: 'Install proxy port',
122
180
  proxyPortHint:
123
181
  'Local proxy port used by npm and by the native node-pty prebuild download during install/update; 0 or empty means direct. The unsaved value is used for the next install and applies permanently once saved.',