@dsh-plus/agent-preset-rea 0.0.0-stage → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lib/index.d.ts ADDED
@@ -0,0 +1,145 @@
1
+ import { UnwrapVolatile } from "@dsh-plus/shared";
2
+ import z from "@deepseek-ai/schemastery";
3
+ import { Context } from "@deepseek-ai/cordis";
4
+ import { PresetDefinition } from "@deepseek-ai/dsh-agent-preset-registry";
5
+ //#region src/config.d.ts
6
+ /** settings 命名空间(字面量即合法命名空间;配置卡片与运行期读取同一份)。 */
7
+ declare const SETTINGS_NS = "dsh-plus-agent-preset-rea";
8
+ declare const Config: z<Schemastery.ObjectS<NoInfer<{
9
+ enabled: z<boolean, boolean, "defined">;
10
+ name: z<string, string, "defined">;
11
+ description: z<string, string, "defined">;
12
+ order: z<number, number, "defined">;
13
+ personaPrefix: z<string, string, "volatile-defined">;
14
+ mcpEnabled: z<boolean, boolean, "defined">;
15
+ mcpServerName: z<string, string, "defined">;
16
+ reaVersion: z<string, string, "defined">;
17
+ mcpCommand: z<string, string, "defined">;
18
+ mcpArgs: z<string[], string[], "defined">;
19
+ inputSchemaProfile: z<"compact" | "full", "compact" | "full", "defined">;
20
+ outputSchemaProfile: z<"full" | "off", "full" | "off", "defined">;
21
+ toolCallTimeoutMs: z<number, number, "defined">;
22
+ failOnStartupError: z<boolean, boolean, "defined">;
23
+ extraSkillDirs: z<string[], string[], "defined">;
24
+ }>>, Schemastery.ObjectT<NoInfer<{
25
+ enabled: z<boolean, boolean, "defined">;
26
+ name: z<string, string, "defined">;
27
+ description: z<string, string, "defined">;
28
+ order: z<number, number, "defined">;
29
+ personaPrefix: z<string, string, "volatile-defined">;
30
+ mcpEnabled: z<boolean, boolean, "defined">;
31
+ mcpServerName: z<string, string, "defined">;
32
+ reaVersion: z<string, string, "defined">;
33
+ mcpCommand: z<string, string, "defined">;
34
+ mcpArgs: z<string[], string[], "defined">;
35
+ inputSchemaProfile: z<"compact" | "full", "compact" | "full", "defined">;
36
+ outputSchemaProfile: z<"full" | "off", "full" | "off", "defined">;
37
+ toolCallTimeoutMs: z<number, number, "defined">;
38
+ failOnStartupError: z<boolean, boolean, "defined">;
39
+ extraSkillDirs: z<string[], string[], "defined">;
40
+ }>>, "plain">;
41
+ /** 活动字段形态(loader 解析产物:`personaPrefix` 为活动引用)。 */
42
+ type AgentPresetReaConfigFields = Schemastery.TypeT<typeof Config>;
43
+ /** 平面配置形态(消费面的读取形态,由活动引用解包得到)。 */
44
+ type AgentPresetReaConfig = UnwrapVolatile<AgentPresetReaConfigFields>;
45
+ //#endregion
46
+ //#region src/definition.d.ts
47
+ /** 预设注册表身份(改 id 等于换预设,default 等引用都会落空)。 */
48
+ declare const REA_PRESET_ID = "rea";
49
+ /** 相对上游 `standard` 新增的行 id(镜像测试按此白名单放行自造行)。 */
50
+ declare const ADDED_ROWS: readonly string[];
51
+ /**
52
+ * 已镜像行 → 允许偏离上游的字段名(其余字段必须逐字一致)。
53
+ * 删除某条等于把该行改回上游原文;改动上游不存在的字段会被测试拦下。
54
+ */
55
+ declare const CONFIG_DELTAS: Readonly<Record<string, readonly string[]>>;
56
+ /**
57
+ * 由配置拼出注册表声明。
58
+ * @param config - 已验证的插件配置。
59
+ * @returns id 固定为 `rea` 的预设声明。
60
+ */
61
+ declare function reaPresetDefinition(config: AgentPresetReaConfig): PresetDefinition;
62
+ //#endregion
63
+ //#region src/mcp.d.ts
64
+ /** 钉版基线:`rea-agents@6.5.0`(升级时同步测试断言、tests 清单与包文档)。 */
65
+ declare const REA_PINNED_VERSION = "6.5.0";
66
+ /** stdio 启动命令默认值:POSIX 用 `npx`;Windows 需 `cmd.exe /c npx`(见包文档)。 */
67
+ declare const DEFAULT_MCP_COMMAND = "npx";
68
+ /** REA 工具入参 schema 广告档位:`compact` 压请求前缀体积,`full` 与上游默认一致。 */
69
+ declare const INPUT_SCHEMA_PROFILES: readonly ['compact', 'full'];
70
+ /** REA 工具出参 schema 广告档位:`off` 不下发(结果仍由 REA 侧校验),`full` 与上游默认一致。 */
71
+ declare const OUTPUT_SCHEMA_PROFILES: readonly ['off', 'full'];
72
+ /** stdio 参数:显式配置优先(Windows/全局安装配方),否则按钉版版本派生。 */
73
+ declare function reaMcpArgs(config: AgentPresetReaConfig): string[];
74
+ /**
75
+ * 传给 REA 子进程的环境变量(并入被清洗过的宿主环境之上)。
76
+ *
77
+ * REA 有 207 个工具(`server.json` 同版的 skill 元数据 `tool_count`),工具定义
78
+ * 是每轮请求的固定开销,因此两个 schema 档位默认都取最省的一档;REA 自己仍按
79
+ * 规范契约校验结果,`full` 可逐项还原上游默认。
80
+ */
81
+ declare function reaMcpEnv(config: AgentPresetReaConfig): Record<string, string>;
82
+ //#endregion
83
+ //#region src/prompt.d.ts
84
+ /**
85
+ * 本包随包携带的上游提示词文本:`standard` 预设 `plan-mode` 行的 section 原文。
86
+ *
87
+ * `dsh-plan-mode` 要求 `config.section` 非空(部署方所有权),因此该文本必须随包;
88
+ * 逐字相等由 tests/upstream-mirror.test.ts 对着上游夹具守卫,上游一改即失败。
89
+ *
90
+ * persona 不在本文件:本预设的 persona 前缀默认为**空串**(见 config.ts 的
91
+ * `personaPrefix`),不随包任何自有 persona 文案;官方工具指引、项目指令
92
+ * (AGENTS.md)与运行时上下文照常装配。
93
+ * @module @dsh-plus/agent-preset-rea/prompt
94
+ */
95
+ /** 上游 `standard` 预设 `plan-mode` 行的 section 原文(逐字,勿手改)。 */
96
+ declare const PLAN_MODE_SECTION = "You are in plan mode. Stay in plan mode until the user approves your plan through exit_plan_mode or switches the session mode. Imperative language to implement changes means plan the implementation, not execute it. A user's conversational agreement — including an answer confirming something you asked — approves nothing and does not end plan mode; fold the confirmed decision into the plan and submit it through exit_plan_mode.\n\nExplore first. Use non-mutating reads, searches, static analysis, and checks to ground the plan in the actual repository. Do not edit or write files, change configuration, run formatters or code generation that rewrites tracked files, commit, or otherwise carry out the plan. Prefer existing functions and patterns over new machinery.\n\nThe tool catalog stays the same across modes for request-cache stability. These plan-mode rules override any later tool description or guidance that suggests using mutation tools; those tools remain listed to keep the tool catalog unchanged. Do not use todo_write to track this planning phase: it tracks implementation after an approved plan, while the plan itself belongs in exit_plan_mode.\n\nResolve discoverable facts by inspection. Use ask_user_question only for user-owned choices or material ambiguity that inspection cannot answer. Do not ask the user where code lives or how current behavior works when you can find out.\n\nMake the plan decision-complete: state the goal and success criteria; group implementation changes by subsystem; identify public API, schema, and data-flow changes; cover edge cases, failure modes, tests, acceptance criteria, and explicit assumptions. Keep it concise enough to review but detailed enough that another engineer can implement it without making design decisions.\n\nWhen ready, call exit_plan_mode with the complete plan markdown, starting with a # title. Make exit_plan_mode the only and final tool call in that assistant response: it presents the plan for approval, and implementation begins only in a later step after approval. Do not paste the final plan as a plain reply or ask \"should I proceed?\" through prose or ask_user_question. If review rejects it, incorporate the feedback and present again. If the review channel is unavailable or aborted, stay in plan mode and ask the user to switch modes manually; do not proceed with implementation.\n";
97
+ //#endregion
98
+ //#region src/registration.d.ts
99
+ /** 注册表返回的注销句柄。 */
100
+ type Unregister = () => Promise<void>;
101
+ interface PresetRegistrarOptions {
102
+ /** 注册一份声明,返回其注销句柄(即 `ctx.agentPresets.register`)。 */
103
+ register(definition: PresetDefinition): Promise<Unregister>;
104
+ /** 按当前配置构造声明(每次换代重新调用,读到的必须是活值)。 */
105
+ build(): PresetDefinition;
106
+ /** 注册/注销失败的上报口(不抛)。 */
107
+ onError(error: unknown): void;
108
+ }
109
+ /** 换代器:`refresh()` 触发一次换代,`dispose()` 停用并注销。 */
110
+ interface PresetRegistrar {
111
+ refresh(): void;
112
+ dispose(): void;
113
+ }
114
+ /**
115
+ * 建一个换代器并立即调度初始注册。
116
+ * 后台串行链不返回句柄:需要等待完成的是测试与调用方的关停流程,而不是业务路径。
117
+ */
118
+ declare function createPresetRegistrar(options: PresetRegistrarOptions): PresetRegistrar;
119
+ //#endregion
120
+ //#region src/skill.d.ts
121
+ /**
122
+ * 随包 REA 官方 skill 根(包内 `skills/`)。
123
+ *
124
+ * `src/` 与构建产物 `lib/` 同为包根下一级,`../skills` 在源码直跑测试与安装后
125
+ * 运行产物两种位置下解析到同一目录。
126
+ */
127
+ declare const BUNDLED_SKILL_ROOT: string;
128
+ /** skill-filesystem 的追加根清单:随包 REA skill 在前,配置追加目录随后。 */
129
+ declare function reaSkillDirs(config: AgentPresetReaConfig): string[];
130
+ //#endregion
131
+ //#region src/index.d.ts
132
+ declare const name = "dsh-plus-agent-preset-rea";
133
+ /** 无硬 inject:agentPresets 经 apply 内惰性 inject 接线(缺席即空转)。 */
134
+ declare const inject: readonly [];
135
+ /**
136
+ * 注册 rea 预设,并在 persona 热更后换代;卸载时注销当前一代。
137
+ *
138
+ * 注册与换代都在 effect 生命周期内完成:fiber 早于注册完成被卸下时,
139
+ * 换代器自己收掉晚到的 disposer,不泄漏预设子树。
140
+ * @param ctx - 宿主上下文。
141
+ * @param config - 已验证的插件配置(`personaPrefix` 为活动引用)。
142
+ */
143
+ declare function apply(ctx: Context, config: AgentPresetReaConfigFields): void;
144
+ //#endregion
145
+ export { ADDED_ROWS, type AgentPresetReaConfig, type AgentPresetReaConfigFields, BUNDLED_SKILL_ROOT, CONFIG_DELTAS, Config, DEFAULT_MCP_COMMAND, INPUT_SCHEMA_PROFILES, OUTPUT_SCHEMA_PROFILES, PLAN_MODE_SECTION, type PresetRegistrar, REA_PINNED_VERSION, REA_PRESET_ID, SETTINGS_NS, type Unregister, apply, createPresetRegistrar, inject, name, reaMcpArgs, reaMcpEnv, reaPresetDefinition, reaSkillDirs };
package/lib/index.js ADDED
@@ -0,0 +1,422 @@
1
+ import { unwrapVolatile } from "@dsh-plus/shared";
2
+ import z from "@deepseek-ai/schemastery";
3
+ import { fileURLToPath } from "node:url";
4
+ //#region src/mcp.ts
5
+ /** 钉版基线:`rea-agents@6.5.0`(升级时同步测试断言、tests 清单与包文档)。 */
6
+ const REA_PINNED_VERSION = "6.5.0";
7
+ /** stdio 启动命令默认值:POSIX 用 `npx`;Windows 需 `cmd.exe /c npx`(见包文档)。 */
8
+ const DEFAULT_MCP_COMMAND = "npx";
9
+ /** REA 工具入参 schema 广告档位:`compact` 压请求前缀体积,`full` 与上游默认一致。 */
10
+ const INPUT_SCHEMA_PROFILES = ["compact", "full"];
11
+ /** REA 工具出参 schema 广告档位:`off` 不下发(结果仍由 REA 侧校验),`full` 与上游默认一致。 */
12
+ const OUTPUT_SCHEMA_PROFILES = ["off", "full"];
13
+ /** stdio 参数:显式配置优先(Windows/全局安装配方),否则按钉版版本派生。 */
14
+ function reaMcpArgs(config) {
15
+ return config.mcpArgs.length > 0 ? [...config.mcpArgs] : [
16
+ "-y",
17
+ `rea-agents@${config.reaVersion}`,
18
+ "mcp"
19
+ ];
20
+ }
21
+ /**
22
+ * 传给 REA 子进程的环境变量(并入被清洗过的宿主环境之上)。
23
+ *
24
+ * REA 有 207 个工具(`server.json` 同版的 skill 元数据 `tool_count`),工具定义
25
+ * 是每轮请求的固定开销,因此两个 schema 档位默认都取最省的一档;REA 自己仍按
26
+ * 规范契约校验结果,`full` 可逐项还原上游默认。
27
+ */
28
+ function reaMcpEnv(config) {
29
+ return {
30
+ REA_MCP_INPUT_SCHEMA_PROFILE: config.inputSchemaProfile,
31
+ REA_MCP_OUTPUT_SCHEMA_PROFILE: config.outputSchemaProfile
32
+ };
33
+ }
34
+ //#endregion
35
+ //#region src/config.ts
36
+ /**
37
+ * 插件配置(schemastery):显示面、persona、REA MCP 行与 skill 根外部化。
38
+ *
39
+ * 单一事实源同时充当两处:cordis 行级 `Config`(组合默认,profile patch 层可覆盖)
40
+ * 与 settings 用户层(GUI 配置卡片写入 profile 行级覆盖层,loader 原位提交活动
41
+ * 引用,消费端 `unwrapVolatile` 现取即热)。
42
+ *
43
+ * **只有 `personaPrefix` 标 `.volatile()`**:它是对用户的承诺(配置卡片必须给出
44
+ * 编辑器,见 src/client/card.tsx),也是本预设里唯一需要热更的字段;其余字段是
45
+ * **部署方平面**(MCP 参数、超时、附加 skill 根等运维旋钮),由 `cordis.patch.yml`
46
+ * 整体覆盖,GUI 不提供入口。
47
+ *
48
+ * **persona 默认为空串**:`dsh-persona` 的空模板照样遮蔽部署级 persona 段,
49
+ * 渲染为空后在提示词里消失;官方装配(harness 身份、工具指引、项目指令、
50
+ * 运行时上下文)不受影响。
51
+ *
52
+ * 预设 id 固定为 `rea`(注册表身份,不开放覆盖——改 id 等于换预设,
53
+ * default/selectedDefault 等引用都会落空)。
54
+ * @module @dsh-plus/agent-preset-rea/config
55
+ */
56
+ /** settings 命名空间(字面量即合法命名空间;配置卡片与运行期读取同一份)。 */
57
+ const SETTINGS_NS = "dsh-plus-agent-preset-rea";
58
+ const Config = z.object({
59
+ enabled: z.boolean().description("总开关(false = 不注册 rea 预设,等价插件未安装)").default(true),
60
+ name: z.string().description("预设显示名(设置 → Agent 预设卡片标题)").default("逆向工程"),
61
+ description: z.string().description("预设说明(设置 → Agent 预设卡片描述)").default("逆向工程预设:官方 standard 全量行 + 仅本预设可见的 REA MCP 客户端(mcp__rea__*)与随包 REA 官方 skill;persona 默认为空,工具指引沿用官方装配。"),
62
+ order: z.number().description("预设名册排序位").default(6),
63
+ personaPrefix: z.string().description("persona 前缀(system-prompt 的 deployment:persona-prefix 段);留空 = 空 persona(该段渲染为空后消失),工具指引与运行时上下文保留").default("").volatile(),
64
+ mcpEnabled: z.boolean().description("是否挂 REA MCP 客户端行(false = 只保留预设其余能力)").default(true),
65
+ mcpServerName: z.string().pattern(/^[A-Za-z0-9_-]{1,32}$/).description("MCP 服务命名空间:模型面工具名为 mcp__<serverName>__<tool>,取值 [A-Za-z0-9_-]{1,32}").default("rea"),
66
+ reaVersion: z.string().description("钉版的 rea-agents 版本(npx 拉取)").default(REA_PINNED_VERSION),
67
+ mcpCommand: z.string().description("MCP stdio 可执行文件;Windows 需 cmd.exe 配方,见包文档").default("npx"),
68
+ mcpArgs: z.array(z.string()).description("MCP stdio 参数;留空 = 按 reaVersion 派生 [\"-y\",\"rea-agents@<version>\",\"mcp\"]").default([]),
69
+ inputSchemaProfile: z.union(INPUT_SCHEMA_PROFILES).description("REA 工具入参 schema 广告档位(REA_MCP_INPUT_SCHEMA_PROFILE):compact 压体积,full 与上游默认一致").default("compact"),
70
+ outputSchemaProfile: z.union(OUTPUT_SCHEMA_PROFILES).description("REA 工具出参 schema 广告档位(REA_MCP_OUTPUT_SCHEMA_PROFILE):off 不下发(结果仍由 REA 校验),full 与上游默认一致").default("off"),
71
+ toolCallTimeoutMs: z.number().description("单次 MCP 工具调用超时(毫秒);REA 分析类调用常超默认 60 秒").default(6e5),
72
+ failOnStartupError: z.boolean().description("MCP 初次连接/同步失败是否让本行激活失败;默认 false:只记日志并按退避重连,不拖垮 boot").default(false),
73
+ extraSkillDirs: z.array(z.string()).description("附加 skill 根目录(随本预设作用域生效,其他预设不可见)").default([])
74
+ });
75
+ //#endregion
76
+ //#region src/prompt.ts
77
+ /**
78
+ * 本包随包携带的上游提示词文本:`standard` 预设 `plan-mode` 行的 section 原文。
79
+ *
80
+ * `dsh-plan-mode` 要求 `config.section` 非空(部署方所有权),因此该文本必须随包;
81
+ * 逐字相等由 tests/upstream-mirror.test.ts 对着上游夹具守卫,上游一改即失败。
82
+ *
83
+ * persona 不在本文件:本预设的 persona 前缀默认为**空串**(见 config.ts 的
84
+ * `personaPrefix`),不随包任何自有 persona 文案;官方工具指引、项目指令
85
+ * (AGENTS.md)与运行时上下文照常装配。
86
+ * @module @dsh-plus/agent-preset-rea/prompt
87
+ */
88
+ /** 上游 `standard` 预设 `plan-mode` 行的 section 原文(逐字,勿手改)。 */
89
+ const PLAN_MODE_SECTION = `You are in plan mode. Stay in plan mode until the user approves your plan through exit_plan_mode or switches the session mode. Imperative language to implement changes means plan the implementation, not execute it. A user's conversational agreement — including an answer confirming something you asked — approves nothing and does not end plan mode; fold the confirmed decision into the plan and submit it through exit_plan_mode.
90
+
91
+ Explore first. Use non-mutating reads, searches, static analysis, and checks to ground the plan in the actual repository. Do not edit or write files, change configuration, run formatters or code generation that rewrites tracked files, commit, or otherwise carry out the plan. Prefer existing functions and patterns over new machinery.
92
+
93
+ The tool catalog stays the same across modes for request-cache stability. These plan-mode rules override any later tool description or guidance that suggests using mutation tools; those tools remain listed to keep the tool catalog unchanged. Do not use todo_write to track this planning phase: it tracks implementation after an approved plan, while the plan itself belongs in exit_plan_mode.
94
+
95
+ Resolve discoverable facts by inspection. Use ask_user_question only for user-owned choices or material ambiguity that inspection cannot answer. Do not ask the user where code lives or how current behavior works when you can find out.
96
+
97
+ Make the plan decision-complete: state the goal and success criteria; group implementation changes by subsystem; identify public API, schema, and data-flow changes; cover edge cases, failure modes, tests, acceptance criteria, and explicit assumptions. Keep it concise enough to review but detailed enough that another engineer can implement it without making design decisions.
98
+
99
+ When ready, call exit_plan_mode with the complete plan markdown, starting with a # title. Make exit_plan_mode the only and final tool call in that assistant response: it presents the plan for approval, and implementation begins only in a later step after approval. Do not paste the final plan as a plain reply or ask "should I proceed?" through prose or ask_user_question. If review rejects it, incorporate the feedback and present again. If the review channel is unavailable or aborted, stay in plan mode and ask the user to switch modes manually; do not proceed with implementation.
100
+ `;
101
+ //#endregion
102
+ //#region src/skill.ts
103
+ /**
104
+ * 预设作用域内的 skill 根解析:随包 REA 官方 skill + 配置追加目录。
105
+ *
106
+ * 两者都只加在本预设 `skill-filesystem` 行的 `customSkillDirs`(rank 300 的
107
+ * **追加**根)上,因此不会进入项目根 / 用户根 / `$DSH_BUNDLED_SKILL_DIR`,
108
+ * 其他预设的 skill 目录不受影响。
109
+ * @module @dsh-plus/agent-preset-rea/skill
110
+ */
111
+ /**
112
+ * 随包 REA 官方 skill 根(包内 `skills/`)。
113
+ *
114
+ * `src/` 与构建产物 `lib/` 同为包根下一级,`../skills` 在源码直跑测试与安装后
115
+ * 运行产物两种位置下解析到同一目录。
116
+ */
117
+ const BUNDLED_SKILL_ROOT = fileURLToPath(new URL("../skills", import.meta.url));
118
+ /** skill-filesystem 的追加根清单:随包 REA skill 在前,配置追加目录随后。 */
119
+ function reaSkillDirs(config) {
120
+ return [BUNDLED_SKILL_ROOT, ...config.extraSkillDirs];
121
+ }
122
+ //#endregion
123
+ //#region src/definition.ts
124
+ /** 预设注册表身份(改 id 等于换预设,default 等引用都会落空)。 */
125
+ const REA_PRESET_ID = "rea";
126
+ /** 相对上游 `standard` 新增的行 id(镜像测试按此白名单放行自造行)。 */
127
+ const ADDED_ROWS = ["mcp-rea"];
128
+ /**
129
+ * 已镜像行 → 允许偏离上游的字段名(其余字段必须逐字一致)。
130
+ * 删除某条等于把该行改回上游原文;改动上游不存在的字段会被测试拦下。
131
+ */
132
+ const CONFIG_DELTAS = {
133
+ persona: ["prefix"],
134
+ "skill-filesystem": ["customSkillDirs"]
135
+ };
136
+ /** 平台门控表达式:与上游 `standard` 预设逐字相同,Windows 上由 pwsh 顶替 bash。 */
137
+ const WINDOWS_ONLY = { __jsExpr: "process.platform === 'win32'" };
138
+ const POSIX_ONLY = { __jsExpr: "process.platform !== 'win32'" };
139
+ /** 官方 loader 的嵌套组行名。 */
140
+ const GROUP = "cordis:group";
141
+ /**
142
+ * 由配置拼出注册表声明。
143
+ * @param config - 已验证的插件配置。
144
+ * @returns id 固定为 `rea` 的预设声明。
145
+ */
146
+ function reaPresetDefinition(config) {
147
+ return {
148
+ id: "rea",
149
+ name: config.name,
150
+ description: config.description,
151
+ order: config.order,
152
+ plugins: [
153
+ {
154
+ id: "persona",
155
+ name: "@deepseek-ai/dsh-persona",
156
+ config: { prefix: config.personaPrefix }
157
+ },
158
+ {
159
+ id: "agent-instructions",
160
+ name: "@deepseek-ai/dsh-agent-instructions",
161
+ config: { maxBytes: 65536 }
162
+ },
163
+ {
164
+ id: "time-context",
165
+ name: "@deepseek-ai/dsh-time-context"
166
+ },
167
+ {
168
+ id: "tool-bash",
169
+ name: "@deepseek-ai/dsh-tool-bash",
170
+ disabled: WINDOWS_ONLY
171
+ },
172
+ {
173
+ id: "tool-pwsh",
174
+ name: "@deepseek-ai/dsh-tool-pwsh",
175
+ disabled: POSIX_ONLY
176
+ },
177
+ {
178
+ id: "tool-fs",
179
+ name: "@deepseek-ai/dsh-tool-fs"
180
+ },
181
+ {
182
+ id: "tool-fs-search",
183
+ name: "@deepseek-ai/dsh-tool-fs-search",
184
+ config: { sampleOverCapGlobResults: false }
185
+ },
186
+ {
187
+ id: "tool-jobs",
188
+ name: "@deepseek-ai/dsh-tool-jobs"
189
+ },
190
+ {
191
+ id: "tool-schedule",
192
+ name: "@deepseek-ai/dsh-tool-schedule"
193
+ },
194
+ {
195
+ id: "skill-filesystem",
196
+ name: "@deepseek-ai/dsh-skill-filesystem",
197
+ config: { customSkillDirs: reaSkillDirs(config) }
198
+ },
199
+ {
200
+ id: "tool-skill",
201
+ name: "@deepseek-ai/dsh-tool-skill"
202
+ },
203
+ {
204
+ id: "command-goal",
205
+ name: "@deepseek-ai/dsh-command-goal"
206
+ },
207
+ {
208
+ id: "tool-goal",
209
+ name: "@deepseek-ai/dsh-tool-goal"
210
+ },
211
+ {
212
+ id: "planning",
213
+ name: GROUP,
214
+ group: true,
215
+ isolate: { planMode: true },
216
+ config: [{
217
+ id: "plan-mode",
218
+ name: "@deepseek-ai/dsh-plan-mode",
219
+ config: { section: PLAN_MODE_SECTION }
220
+ }]
221
+ },
222
+ {
223
+ id: "compaction",
224
+ name: GROUP,
225
+ group: true,
226
+ isolate: {
227
+ compaction: true,
228
+ toolResultPruner: true
229
+ },
230
+ config: [
231
+ {
232
+ id: "compaction-basic",
233
+ name: "@deepseek-ai/dsh-compaction-basic"
234
+ },
235
+ {
236
+ id: "command-compact",
237
+ name: "@deepseek-ai/dsh-command-compact"
238
+ },
239
+ {
240
+ id: "tool-result-pruner",
241
+ name: "@deepseek-ai/dsh-compaction-tool-result-pruner",
242
+ config: {
243
+ thresholdChars: 8192,
244
+ headChars: 4096,
245
+ tailChars: 1024
246
+ }
247
+ }
248
+ ]
249
+ },
250
+ {
251
+ id: "delegation",
252
+ name: GROUP,
253
+ group: true,
254
+ isolate: { workflowEngine: true },
255
+ config: [
256
+ {
257
+ id: "tool-subagent-control",
258
+ name: "@deepseek-ai/dsh-tool-subagent-control"
259
+ },
260
+ {
261
+ id: "tool-subagent-list-agents",
262
+ name: "@deepseek-ai/dsh-tool-subagent-control/list-agents"
263
+ },
264
+ {
265
+ id: "tool-subagent",
266
+ name: "@deepseek-ai/dsh-tool-subagent",
267
+ config: {
268
+ provider: "spawn",
269
+ toolName: "subagent",
270
+ modelSelectionSettings: true
271
+ }
272
+ },
273
+ {
274
+ id: "tool-subagent-fork",
275
+ name: "@deepseek-ai/dsh-tool-subagent",
276
+ config: {
277
+ provider: "fork",
278
+ toolName: "subagent_fork"
279
+ }
280
+ },
281
+ {
282
+ id: "workflow-ptc",
283
+ name: "@deepseek-ai/dsh-workflow-ptc",
284
+ config: { provider: "spawn" }
285
+ },
286
+ {
287
+ id: "tool-workflow",
288
+ name: "@deepseek-ai/dsh-tool-workflow"
289
+ }
290
+ ]
291
+ },
292
+ {
293
+ id: "tool-ask-user",
294
+ name: "@deepseek-ai/dsh-tool-ask-user"
295
+ },
296
+ {
297
+ id: "tool-todo",
298
+ name: "@deepseek-ai/dsh-tool-todo",
299
+ config: { allowParallelInProgress: true }
300
+ },
301
+ {
302
+ id: "tool-web",
303
+ name: "@deepseek-ai/dsh-tool-web",
304
+ config: {
305
+ fetch: true,
306
+ searchTimeoutMs: 6e4
307
+ }
308
+ },
309
+ {
310
+ id: "mcp-rea",
311
+ name: "@deepseek-ai/dsh-mcp-client",
312
+ disabled: !config.mcpEnabled,
313
+ config: {
314
+ transport: "stdio",
315
+ serverName: config.mcpServerName,
316
+ command: config.mcpCommand,
317
+ args: reaMcpArgs(config),
318
+ env: reaMcpEnv(config),
319
+ toolCallTimeoutMs: config.toolCallTimeoutMs,
320
+ failOnStartupError: config.failOnStartupError
321
+ }
322
+ },
323
+ {
324
+ id: "present",
325
+ name: "@deepseek-ai/dsh-tool-present"
326
+ },
327
+ {
328
+ id: "tool-plugin-manager",
329
+ name: "@deepseek-ai/dsh-plugin-manager/tools",
330
+ disabled: true
331
+ }
332
+ ]
333
+ };
334
+ }
335
+ //#endregion
336
+ //#region src/registration.ts
337
+ /**
338
+ * 建一个换代器并立即调度初始注册。
339
+ * 后台串行链不返回句柄:需要等待完成的是测试与调用方的关停流程,而不是业务路径。
340
+ */
341
+ function createPresetRegistrar(options) {
342
+ let disposed = false;
343
+ let queued = false;
344
+ let unregister;
345
+ let chain = Promise.resolve();
346
+ const report = (error) => {
347
+ options.onError(error);
348
+ };
349
+ const settle = (task) => {
350
+ task.catch(report);
351
+ };
352
+ /** 换一代:先注销上一代,再注册按当前配置重建的声明。 */
353
+ const swap = async () => {
354
+ if (disposed) return;
355
+ const previous = unregister;
356
+ unregister = void 0;
357
+ if (previous !== void 0) await previous();
358
+ if (disposed) return;
359
+ const next = await options.register(options.build());
360
+ if (disposed) {
361
+ await next();
362
+ return;
363
+ }
364
+ unregister = next;
365
+ };
366
+ const schedule = () => {
367
+ if (queued) return;
368
+ queued = true;
369
+ chain = chain.then(async () => {
370
+ queued = false;
371
+ await swap();
372
+ }).catch(report);
373
+ };
374
+ schedule();
375
+ return {
376
+ refresh: schedule,
377
+ dispose: () => {
378
+ disposed = true;
379
+ const pending = unregister;
380
+ unregister = void 0;
381
+ if (pending !== void 0) settle(pending());
382
+ }
383
+ };
384
+ }
385
+ //#endregion
386
+ //#region src/index.ts
387
+ const name = "dsh-plus-agent-preset-rea";
388
+ /** 无硬 inject:agentPresets 经 apply 内惰性 inject 接线(缺席即空转)。 */
389
+ const inject = [];
390
+ /**
391
+ * 注册 rea 预设,并在 persona 热更后换代;卸载时注销当前一代。
392
+ *
393
+ * 注册与换代都在 effect 生命周期内完成:fiber 早于注册完成被卸下时,
394
+ * 换代器自己收掉晚到的 disposer,不泄漏预设子树。
395
+ * @param ctx - 宿主上下文。
396
+ * @param config - 已验证的插件配置(`personaPrefix` 为活动引用)。
397
+ */
398
+ function apply(ctx, config) {
399
+ const logger = ctx.logger("agent-preset-rea");
400
+ const current = () => unwrapVolatile(config);
401
+ if (current().enabled !== true) return;
402
+ const onError = (error) => {
403
+ const detail = error instanceof Error ? error.message : String(error);
404
+ logger.warn(`register rea preset failed: ${detail}`);
405
+ };
406
+ ctx.inject(["agentPresets"], (scope) => {
407
+ scope.effect(() => {
408
+ const registrar = createPresetRegistrar({
409
+ register: (definition) => scope.agentPresets.register(definition),
410
+ build: () => reaPresetDefinition(current()),
411
+ onError
412
+ });
413
+ const off = ctx.events.on("loader/volatile-update", () => registrar.refresh());
414
+ return () => {
415
+ off();
416
+ registrar.dispose();
417
+ };
418
+ }, "agent-preset-rea: register rea preset");
419
+ });
420
+ }
421
+ //#endregion
422
+ export { ADDED_ROWS, BUNDLED_SKILL_ROOT, CONFIG_DELTAS, Config, DEFAULT_MCP_COMMAND, INPUT_SCHEMA_PROFILES, OUTPUT_SCHEMA_PROFILES, PLAN_MODE_SECTION, REA_PINNED_VERSION, REA_PRESET_ID, SETTINGS_NS, apply, createPresetRegistrar, inject, name, reaMcpArgs, reaMcpEnv, reaPresetDefinition, reaSkillDirs };
package/package.json CHANGED
@@ -1,6 +1,63 @@
1
1
  {
2
2
  "name": "@dsh-plus/agent-preset-rea",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
3
+ "version": "0.1.0",
4
+ "description": "dsh-plus service + UI plugin: 注册逆向工程 agent preset(id=rea)——官方 standard 全量行镜像 + 预设作用域的 REA MCP 客户端(mcp__rea__*)、随包 REA 官方 skill 与 persona 提示词卡片",
5
+ "type": "module",
6
+ "main": "lib/index.js",
7
+ "types": "lib/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "types": "./lib/index.d.ts",
11
+ "default": "./lib/index.js"
12
+ },
13
+ "./client": {
14
+ "default": "./lib/client.js"
15
+ },
16
+ "./src/*": "./src/*",
17
+ "./package.json": "./package.json"
18
+ },
19
+ "files": [
20
+ "lib",
21
+ "src",
22
+ "skills"
23
+ ],
24
+ "dsh": {
25
+ "client": {
26
+ "inject": [
27
+ "@deepseek-ai/dsh-client-locale",
28
+ "@deepseek-ai/dsh-client-ui-renderer",
29
+ "@deepseek-ai/dsh-api-remotes"
30
+ ],
31
+ "platform": "web"
32
+ }
33
+ },
34
+ "dependencies": {
35
+ "@dsh-plus/shared": "0.1.40"
36
+ },
37
+ "peerDependencies": {
38
+ "@deepseek-ai/cordis": "^4.0.5-alpha.2",
39
+ "@deepseek-ai/dsh-agent-preset-registry": "^0.2.1-alpha.3",
40
+ "@deepseek-ai/schemastery": "^3.18.5-alpha.2"
41
+ },
42
+ "devDependencies": {
43
+ "@deepseek-ai/cordis": "4.0.5-alpha.2",
44
+ "@deepseek-ai/dsh-agent-preset-registry": "0.2.1-alpha.3",
45
+ "@deepseek-ai/schemastery": "3.18.5-alpha.2",
46
+ "@types/react": "~18.3.31",
47
+ "react": "^18.2.0",
48
+ "yaml": "^2.9.0"
49
+ },
50
+ "publishConfig": {
51
+ "access": "public"
52
+ },
53
+ "license": "MIT",
54
+ "repository": {
55
+ "type": "git",
56
+ "url": "git+https://github.com/A-G-guy/dsh-plus.git",
57
+ "directory": "packages/agent-preset-rea"
58
+ },
59
+ "scripts": {
60
+ "build": "tsdown",
61
+ "watch": "tsdown --watch"
62
+ }
6
63
  }
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 morluto
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.