@ghyper9023/pi-dev-workflow 0.1.7 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +172 -2
- package/agents/git-agent.md +16 -25
- package/agents/review-agent.md +5 -3
- package/extensions/dev-prompts.ts +864 -0
- package/extensions/git-commands.ts +5 -2
- package/extensions/grill-me-agent.ts +687 -0
- package/extensions/sub-agents.ts +54 -33
- package/package.json +1 -1
- package/skills/grill-with-docs/ADR-FORMAT.md +47 -0
- package/skills/grill-with-docs/CONTEXT-FORMAT.md +77 -0
- package/skills/grill-with-docs/SKILL.md +88 -0
- package/skills/review-html/SKILL.md +36 -25
- package/skills/to-prd/SKILL.md +74 -0
|
@@ -0,0 +1,864 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Dev Prompts Extension
|
|
3
|
+
*
|
|
4
|
+
* Registers /dev-* commands that interactively collect missing context for
|
|
5
|
+
* high-quality prompt templates (from ai提示词优化.md) and send the assembled
|
|
6
|
+
* prompt directly to the main agent.
|
|
7
|
+
*
|
|
8
|
+
* Commands:
|
|
9
|
+
* /dev-feat - New feature / creative generation
|
|
10
|
+
* /dev-fix - Bug fix / error troubleshooting
|
|
11
|
+
* /dev-doc - Documentation generation
|
|
12
|
+
* /dev-refactor - Code refactoring
|
|
13
|
+
* /dev-test - Test case generation
|
|
14
|
+
* /dev-chore - Maintenance / automation
|
|
15
|
+
* /dev-perf - Performance optimization
|
|
16
|
+
* /dev-style - Style / format adjustment
|
|
17
|
+
* /dev-security - Security review
|
|
18
|
+
* /dev-explain - Concept explanation
|
|
19
|
+
* /dev-compare - Comparison evaluation
|
|
20
|
+
*
|
|
21
|
+
* Usage: type /dev-<type> and follow the wizard.
|
|
22
|
+
* Leave a field empty (Enter) to skip its section.
|
|
23
|
+
* Press Esc to cancel the entire wizard.
|
|
24
|
+
*/
|
|
25
|
+
|
|
26
|
+
import type { ExtensionAPI, ExtensionCommandContext } from "@earendil-works/pi-coding-agent";
|
|
27
|
+
import { runGrillPhase, runPRDPhase, type AgentDef, type GrillOptions } from "./grill-me-agent";
|
|
28
|
+
|
|
29
|
+
// ── Helpers ──────────────────────────────────────────────────
|
|
30
|
+
|
|
31
|
+
/** Ask a single question. Returns `undefined` on cancel (Esc). */
|
|
32
|
+
async function ask(
|
|
33
|
+
ctx: ExtensionCommandContext,
|
|
34
|
+
label: string,
|
|
35
|
+
placeholder: string,
|
|
36
|
+
): Promise<string | undefined> {
|
|
37
|
+
return ctx.ui.input(label, { placeholder, required: false });
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/** Check if a field value is empty or explicitly "无". */
|
|
41
|
+
function isEmpty(val: string | undefined): boolean {
|
|
42
|
+
return !val || val.trim() === "" || val.trim() === "无";
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/** Wrap a non-empty value for template insertion. */
|
|
46
|
+
function wrap(val: string | undefined, fallback = "..."): string {
|
|
47
|
+
if (isEmpty(val)) return fallback;
|
|
48
|
+
return val!.trim();
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// ── Template Assemblers ──────────────────────────────────────
|
|
52
|
+
|
|
53
|
+
interface FeatFields {
|
|
54
|
+
language: string;
|
|
55
|
+
techStack: string;
|
|
56
|
+
module: string;
|
|
57
|
+
description: string;
|
|
58
|
+
painPoint: string;
|
|
59
|
+
testCmd: string;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
function assembleFeatPrompt(f: FeatFields): string {
|
|
63
|
+
const lines: string[] = [];
|
|
64
|
+
lines.push(`[feat] 在 ${wrap(f.module)} 中实现 ${wrap(f.description)}`);
|
|
65
|
+
lines.push("");
|
|
66
|
+
lines.push(`**角色**:你是一个资深 ${wrap(f.language)} 工程师。`);
|
|
67
|
+
if (!isEmpty(f.techStack) || !isEmpty(f.painPoint)) {
|
|
68
|
+
lines.push(
|
|
69
|
+
`**背景**:项目使用 ${wrap(f.techStack)},当前缺少 ${wrap(f.description)}` +
|
|
70
|
+
(isEmpty(f.painPoint) ? "。" : `,用户痛点是 ${f.painPoint!.trim()}。`),
|
|
71
|
+
);
|
|
72
|
+
}
|
|
73
|
+
lines.push("**任务**:");
|
|
74
|
+
lines.push("1. 先分析代码库结构,给出逐步实施计划(列出要修改/创建的文件、数据库迁移、对现有代码的假设)。");
|
|
75
|
+
lines.push("2. 计划经我确认后再编写代码。");
|
|
76
|
+
if (!isEmpty(f.testCmd)) {
|
|
77
|
+
lines.push(`3. 实现后编写测试用例验证核心逻辑,并运行 ${f.testCmd!.trim()} 确认通过。`);
|
|
78
|
+
} else {
|
|
79
|
+
lines.push("3. 实现后编写测试用例验证核心逻辑。");
|
|
80
|
+
}
|
|
81
|
+
lines.push("**输出**:提供 unified diff 和两句话的变更说明。");
|
|
82
|
+
lines.push("**约束**:禁止顺手重构无关代码;保持所有公共 API 签名兼容;不要为假设性需求添加抽象层。");
|
|
83
|
+
if (!isEmpty(f.testCmd)) {
|
|
84
|
+
lines.push(`**验证**:运行 ${f.testCmd!.trim()} 确保无回归。`);
|
|
85
|
+
}
|
|
86
|
+
return lines.join("\n");
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
interface FixFields {
|
|
90
|
+
filePath: string;
|
|
91
|
+
lineNumber: string;
|
|
92
|
+
bugDesc: string;
|
|
93
|
+
inputDesc: string;
|
|
94
|
+
expected: string;
|
|
95
|
+
actualError: string;
|
|
96
|
+
testCmd: string;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
function assembleFixPrompt(f: FixFields): string {
|
|
100
|
+
const lines: string[] = [];
|
|
101
|
+
const loc = isEmpty(f.lineNumber) ? f.filePath.trim() : `${f.filePath.trim()} #L${f.lineNumber!.trim()}`;
|
|
102
|
+
lines.push(`[fix] 修复 ${loc} 中的 ${wrap(f.bugDesc)}`);
|
|
103
|
+
lines.push("");
|
|
104
|
+
lines.push("**背景**:");
|
|
105
|
+
lines.push(`- 输入:${isEmpty(f.inputDesc) ? "见代码上下文" : f.inputDesc!.trim()}`);
|
|
106
|
+
lines.push(`- 预期行为:${wrap(f.expected, "请描述预期结果")}`);
|
|
107
|
+
lines.push(`- 当前错误:${wrap(f.actualError, "请描述当前错误")}`);
|
|
108
|
+
lines.push("**任务**:");
|
|
109
|
+
lines.push("1. 不要仅仅消除报错(Suppress),要解决根本原因。");
|
|
110
|
+
lines.push("2. 先读取相关代码和日志,诊断根因(多步推理,不要先给结论)。");
|
|
111
|
+
lines.push("3. 提供至少一种修复方案,并说明为什么这样做。");
|
|
112
|
+
lines.push("4. 编写测试用例复现该 Bug 并确认修复有效。");
|
|
113
|
+
lines.push("**输出**:提供 diff 和两句话的根因分析。");
|
|
114
|
+
lines.push("**约束**:只修 bug,不做重构;最小化改动;不要假设错误是微不足道的。");
|
|
115
|
+
if (!isEmpty(f.testCmd)) {
|
|
116
|
+
lines.push(`**验证**:运行 ${f.testCmd!.trim()} 确认修复。`);
|
|
117
|
+
}
|
|
118
|
+
return lines.join("\n");
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
interface DocFields {
|
|
122
|
+
moduleName: string;
|
|
123
|
+
audience: string;
|
|
124
|
+
keyInfo: string;
|
|
125
|
+
language: string;
|
|
126
|
+
existingMaterial: string;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
function assembleDocPrompt(f: DocFields): string {
|
|
130
|
+
const lines: string[] = [];
|
|
131
|
+
lines.push(`[doc] 为 ${wrap(f.moduleName)} 撰写一份文档`);
|
|
132
|
+
lines.push("");
|
|
133
|
+
lines.push("**角色**:你是一位技术文档工程师。");
|
|
134
|
+
if (!isEmpty(f.audience) || !isEmpty(f.keyInfo)) {
|
|
135
|
+
lines.push(`**背景**:目标受众是 ${wrap(f.audience)},他们需要了解 ${wrap(f.keyInfo)}。`);
|
|
136
|
+
}
|
|
137
|
+
lines.push("**任务**:");
|
|
138
|
+
lines.push("1. 提取核心要点,按逻辑结构重组(概述 → 快速开始 → 详细说明 → 常见问题)。");
|
|
139
|
+
lines.push(`2. 添加至少 1 个真实可运行的示例(使用 ${wrap(f.language)} 语法高亮)。`);
|
|
140
|
+
lines.push("3. 如存在争议点,列出不同观点并注明\"无共识\"。");
|
|
141
|
+
if (!isEmpty(f.existingMaterial)) {
|
|
142
|
+
lines.push(`**已有材料**:${f.existingMaterial!.trim()}`);
|
|
143
|
+
}
|
|
144
|
+
lines.push("**输出格式**:Markdown 层级标题,必要时插入表格/列表。");
|
|
145
|
+
lines.push("**约束**:避免空洞词汇(如\"细致入微\"\"深入探究\");每段都应有实质信息;保持原意,不添加原文没有的事实。");
|
|
146
|
+
lines.push("**验证**:请先提供大纲,经我确认后再扩展。");
|
|
147
|
+
return lines.join("\n");
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
interface RefactorFields {
|
|
151
|
+
filePath: string;
|
|
152
|
+
lineCount: string;
|
|
153
|
+
problems: string;
|
|
154
|
+
goal: string;
|
|
155
|
+
testCmd: string;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
function assembleRefactorPrompt(f: RefactorFields): string {
|
|
159
|
+
const lines: string[] = [];
|
|
160
|
+
const loc = isEmpty(f.lineCount) ? f.filePath.trim() : `${f.filePath.trim()}(约 ${f.lineCount!.trim()} 行)`;
|
|
161
|
+
lines.push(`[refactor] 对 ${loc} 进行重构,提升 ${wrap(f.goal, "可读性 / 可维护性")}`);
|
|
162
|
+
lines.push("");
|
|
163
|
+
lines.push(`**背景**:当前代码存在 ${wrap(f.problems)}。`);
|
|
164
|
+
lines.push("**任务**:");
|
|
165
|
+
lines.push("1. 识别主要问题。");
|
|
166
|
+
lines.push("2. 提出重构方案,说明改动前后差异。");
|
|
167
|
+
lines.push("3. 输出重构后的完整版本。");
|
|
168
|
+
lines.push("**硬性约束**:");
|
|
169
|
+
lines.push("- 不改变任何行为,保留所有公共 API 签名不变。");
|
|
170
|
+
lines.push("- 禁止顺手优化、禁止添加新功能、禁止修改业务逻辑。");
|
|
171
|
+
if (!isEmpty(f.testCmd)) {
|
|
172
|
+
lines.push(`- 拆分后运行 ${f.testCmd!.trim()} 确认无回归。`);
|
|
173
|
+
}
|
|
174
|
+
lines.push("**输出**:提供 diff 和新模块的依赖关系图。");
|
|
175
|
+
if (!isEmpty(f.testCmd)) {
|
|
176
|
+
lines.push(`**验证**:运行 ${f.testCmd!.trim()} 并确保全部通过。`);
|
|
177
|
+
}
|
|
178
|
+
return lines.join("\n");
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
interface TestFields {
|
|
182
|
+
filePath: string;
|
|
183
|
+
framework: string;
|
|
184
|
+
coverage: string;
|
|
185
|
+
edgeCases: string;
|
|
186
|
+
testCmd: string;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
function assembleTestPrompt(f: TestFields): string {
|
|
190
|
+
const lines: string[] = [];
|
|
191
|
+
lines.push(`[test] 为 ${wrap(f.filePath)} 中的变更生成表驱动测试`);
|
|
192
|
+
lines.push("");
|
|
193
|
+
lines.push(`**角色**:你是一个资深测试工程师。`);
|
|
194
|
+
lines.push(`**背景**:使用 ${wrap(f.framework)} 框架,追求 ≥${wrap(f.coverage, "90")}% 分支覆盖率。`);
|
|
195
|
+
lines.push("**任务**:");
|
|
196
|
+
lines.push(`1. 覆盖维度:${isEmpty(f.edgeCases) ? "null 值、空值、超时、幂等性、重试、成功路径、4xx/5xx 错误、边界条件" : f.edgeCases!.trim()}。`);
|
|
197
|
+
lines.push("2. 优先让测试先失败(红),再提供补丁使其通过(绿)。");
|
|
198
|
+
lines.push("**输出格式**:表格列出场景 → 预期结果 → 权重,末尾附评分模板。");
|
|
199
|
+
lines.push("**约束**:评分准则必须无歧义;不要假设输入总是合法的。");
|
|
200
|
+
if (!isEmpty(f.testCmd)) {
|
|
201
|
+
lines.push(`**验证**:运行 ${f.testCmd!.trim()} 并展示覆盖率报告。`);
|
|
202
|
+
}
|
|
203
|
+
return lines.join("\n");
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
interface ChoreFields {
|
|
207
|
+
configPath: string;
|
|
208
|
+
task: string;
|
|
209
|
+
envDesc: string;
|
|
210
|
+
targetVersion: string;
|
|
211
|
+
verifyCmd: string;
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
function assembleChorePrompt(f: ChoreFields): string {
|
|
215
|
+
const lines: string[] = [];
|
|
216
|
+
lines.push(`[chore] 在 ${wrap(f.configPath)} 中 ${wrap(f.task)}`);
|
|
217
|
+
lines.push("");
|
|
218
|
+
lines.push("**角色**:你是一个 DevOps 工程师。");
|
|
219
|
+
lines.push(`**背景**:当前环境 ${wrap(f.envDesc)},目标版本 ${wrap(f.targetVersion)}。`);
|
|
220
|
+
lines.push("**任务**:");
|
|
221
|
+
lines.push(`1. 只做 ${wrap(f.task)},不做任何其他改动。`);
|
|
222
|
+
if (!isEmpty(f.verifyCmd)) {
|
|
223
|
+
lines.push(`2. 改动后运行 ${f.verifyCmd!.trim()} 确认无破坏性变更。`);
|
|
224
|
+
}
|
|
225
|
+
lines.push("**硬性约束**:");
|
|
226
|
+
lines.push("- NEVER 修改生产环境配置文件(如 config/production.yml)。");
|
|
227
|
+
lines.push("- NEVER 运行任何部署命令(除非用户明确要求)。");
|
|
228
|
+
lines.push("- 禁止顺手升级无关依赖、禁止修改代码逻辑。");
|
|
229
|
+
lines.push("**输出**:提供变更前后对比和影响说明。");
|
|
230
|
+
if (!isEmpty(f.verifyCmd)) {
|
|
231
|
+
lines.push(`**验证**:运行 ${f.verifyCmd!.trim()} 并展示结果。`);
|
|
232
|
+
}
|
|
233
|
+
return lines.join("\n");
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
interface PerfFields {
|
|
237
|
+
filePath: string;
|
|
238
|
+
bottleneck: string;
|
|
239
|
+
currentCost: string;
|
|
240
|
+
targetLatency: string;
|
|
241
|
+
benchCmd: string;
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
function assemblePerfPrompt(f: PerfFields): string {
|
|
245
|
+
const lines: string[] = [];
|
|
246
|
+
lines.push(`[perf] 优化 ${wrap(f.filePath)} 中的 ${wrap(f.bottleneck)}`);
|
|
247
|
+
lines.push("");
|
|
248
|
+
lines.push("**角色**:你是一位性能优化专家。");
|
|
249
|
+
lines.push(`**背景**:当前执行耗时约 ${wrap(f.currentCost)},用户可接受的延迟为 ${wrap(f.targetLatency)}。`);
|
|
250
|
+
lines.push("**任务**:");
|
|
251
|
+
lines.push("1. Think deeply about this performance issue.");
|
|
252
|
+
lines.push("2. 先分析当前性能数据,给出基准指标。");
|
|
253
|
+
lines.push("3. 列出 ≥2 种优化方案,分析每个方案的预估提升幅度、实现复杂度、潜在风险。");
|
|
254
|
+
if (!isEmpty(f.benchCmd)) {
|
|
255
|
+
lines.push(`4. 选择推荐方案并实现。优化后运行 ${f.benchCmd!.trim()} 对比前后数据。`);
|
|
256
|
+
} else {
|
|
257
|
+
lines.push("4. 选择推荐方案并实现。优化后运行基准测试对比前后数据。");
|
|
258
|
+
}
|
|
259
|
+
lines.push("**输出**:提供 before/after 性能对比表格。");
|
|
260
|
+
lines.push("**约束**:不要牺牲核心准确性;优先给出低风险改动;不为了微优化牺牲可读性。");
|
|
261
|
+
return lines.join("\n");
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
interface StyleFields {
|
|
265
|
+
targetStyle: string;
|
|
266
|
+
description: string;
|
|
267
|
+
terms: string;
|
|
268
|
+
lintCmd: string;
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
function assembleStylePrompt(f: StyleFields): string {
|
|
272
|
+
const lines: string[] = [];
|
|
273
|
+
lines.push(`[style] 将以下内容调整为 ${wrap(f.targetStyle)}`);
|
|
274
|
+
lines.push("");
|
|
275
|
+
lines.push("**角色**:你是一个代码风格专家。");
|
|
276
|
+
lines.push(`**原文**:${wrap(f.description, "(见当前上下文)")}`);
|
|
277
|
+
lines.push("**任务**:");
|
|
278
|
+
lines.push("1. 保持原意和信息完整,仅改变表达风格/代码格式。");
|
|
279
|
+
if (!isEmpty(f.terms)) {
|
|
280
|
+
lines.push(`2. 术语统一为:${f.terms!.trim()}。`);
|
|
281
|
+
lines.push("3. 输出两种备选风格供我对比。");
|
|
282
|
+
} else {
|
|
283
|
+
lines.push("2. 输出两种备选风格供我对比。");
|
|
284
|
+
}
|
|
285
|
+
lines.push("**约束**:不要添加原文没有的新事实,不要改变关键数据和逻辑;同时指出原文中可能存在的歧义表达。");
|
|
286
|
+
if (!isEmpty(f.lintCmd)) {
|
|
287
|
+
lines.push(`**验证**:对代码运行 ${f.lintCmd!.trim()} 确保符合规范。`);
|
|
288
|
+
}
|
|
289
|
+
return lines.join("\n");
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
interface SecurityFields {
|
|
293
|
+
filePath: string;
|
|
294
|
+
focus: string;
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
function assembleSecurityPrompt(f: SecurityFields): string {
|
|
298
|
+
const lines: string[] = [];
|
|
299
|
+
lines.push(`[security] 对 ${wrap(f.filePath)} 运行安全审查`);
|
|
300
|
+
lines.push("");
|
|
301
|
+
lines.push("**角色**:你是一名安全审计专家(独立于编写代码的 Agent)。");
|
|
302
|
+
lines.push("**任务**:");
|
|
303
|
+
lines.push(`1. 审查清单:${isEmpty(f.focus) ? "认证边界、注入漏洞、敏感数据暴露、CSRF/CORS 配置、权限校验缺失" : f.focus!.trim()}。`);
|
|
304
|
+
lines.push("2. 提供带行号的修复方案及理由。");
|
|
305
|
+
lines.push("3. 只审查不修改,输出审查报告。");
|
|
306
|
+
lines.push("**硬性约束**:在隔离上下文中运行,不继承主 Agent 的记忆。");
|
|
307
|
+
lines.push("**输出**:Markdown 报告,每个问题包含严重级别、行号、风险描述、修复建议。");
|
|
308
|
+
return lines.join("\n");
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
interface ExplainFields {
|
|
312
|
+
concept: string;
|
|
313
|
+
audience: string;
|
|
314
|
+
depth: string;
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
function assembleExplainPrompt(f: ExplainFields): string {
|
|
318
|
+
const lines: string[] = [];
|
|
319
|
+
lines.push(`[explain] 解释 ${wrap(f.concept)}`);
|
|
320
|
+
lines.push("");
|
|
321
|
+
lines.push("**角色**:你是一位资深技术导师,擅长用类比引导初学者理解复杂概念。");
|
|
322
|
+
lines.push(`**背景**:目标受众是 ${wrap(f.audience)},需要理解 ${wrap(f.concept)} 的 ${wrap(f.depth, "基础")} 层面。`);
|
|
323
|
+
lines.push("**任务**:");
|
|
324
|
+
lines.push("1. 用生活化的类比引入概念,建立直觉。");
|
|
325
|
+
lines.push("2. 由浅入深逐步展开,先给大局观再进入细节。");
|
|
326
|
+
lines.push("3. 提供至少一个真实世界的应用场景。");
|
|
327
|
+
lines.push("4. 如有常见误区,明确指出。");
|
|
328
|
+
lines.push("**输出格式**:Markdown,必要时插入图示描述。");
|
|
329
|
+
lines.push("**验证**:请先给出一句话总结,经我确认后再展开。");
|
|
330
|
+
return lines.join("\n");
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
interface CompareFields {
|
|
334
|
+
itemA: string;
|
|
335
|
+
itemB: string;
|
|
336
|
+
dimensions: string;
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
function assembleComparePrompt(f: CompareFields): string {
|
|
340
|
+
const lines: string[] = [];
|
|
341
|
+
lines.push(`[compare] 对比 ${wrap(f.itemA)} 与 ${wrap(f.itemB)}`);
|
|
342
|
+
lines.push("");
|
|
343
|
+
lines.push("**角色**:你是一位客观中立的评测专家。");
|
|
344
|
+
lines.push(`**背景**:需要从 ${wrap(f.dimensions, "多个方面")} 对 ${wrap(f.itemA)} 和 ${wrap(f.itemB)} 进行全面对比。`);
|
|
345
|
+
lines.push("**任务**:");
|
|
346
|
+
lines.push("1. 构建多维度评估矩阵,量化或半量化评分。");
|
|
347
|
+
lines.push("2. 分析各维度的权衡(Trade-offs),说明在什么场景下哪个更优。");
|
|
348
|
+
lines.push("3. 给出综合结论和建议。");
|
|
349
|
+
lines.push("**输出格式**:Markdown 表格 + 简短分析。");
|
|
350
|
+
lines.push("**约束**:客观中立,不偏袒任何一方,明确标注不确定的结论。");
|
|
351
|
+
return lines.join("\n");
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
// ── Specialized Agent Definitions for Grill ─────────────────
|
|
355
|
+
|
|
356
|
+
/** Bug fix root cause analysis & reproduction review. */
|
|
357
|
+
const FIX_GRILL_AGENT_DEF: AgentDef = {
|
|
358
|
+
name: "fix-grill-agent",
|
|
359
|
+
description: "Bug fix review agent — challenges the developer on understanding the bug root cause",
|
|
360
|
+
tools: ["read", "bash"],
|
|
361
|
+
systemPrompt: [
|
|
362
|
+
"You are an expert debugger reviewing a bug fix plan. Interview the developer relentlessly.",
|
|
363
|
+
"",
|
|
364
|
+
"## Rules",
|
|
365
|
+
"- For EACH question, provide recommended answer OPTIONS (a/b/c format)",
|
|
366
|
+
"- Focus on: reproduction steps, environment conditions, input variations, error messages, logs, attempted fixes",
|
|
367
|
+
"- Push for precise root cause identification — ask 'why' at least 3 levels deep",
|
|
368
|
+
"- Check if the developer has considered: edge cases in inputs, race conditions, state leakage, timeout, memory",
|
|
369
|
+
"- Verify the proposed fix addresses the root cause, not just the symptom",
|
|
370
|
+
"- If the codebase has logs/metrics available, suggest checking specific patterns",
|
|
371
|
+
"- Stress-test regression risk: could the fix break other parts of the system?",
|
|
372
|
+
"- Explore the codebase (use read/bash tools) when a question can be answered by looking at existing code",
|
|
373
|
+
"",
|
|
374
|
+
"## Output format",
|
|
375
|
+
"Output ALL questions in ONE JSON response. No preamble or explanation.",
|
|
376
|
+
'Only output the JSON object: { "questions": [{ "id": 1, "question": "...", "options": ["..."] }] }',
|
|
377
|
+
"",
|
|
378
|
+
"## Quantity",
|
|
379
|
+
"Ask 5-15 questions — enough to thoroughly understand the root cause before committing to a fix.",
|
|
380
|
+
"",
|
|
381
|
+
"## Language",
|
|
382
|
+
"Questions and options should be in the same language as the bug report (default: Chinese).",
|
|
383
|
+
].join("\n"),
|
|
384
|
+
timeoutMs: 300_000,
|
|
385
|
+
};
|
|
386
|
+
|
|
387
|
+
/** Document outline & structure review. */
|
|
388
|
+
const DOC_GRILL_AGENT_DEF: AgentDef = {
|
|
389
|
+
name: "doc-grill-agent",
|
|
390
|
+
description: "Documentation review agent — reviews document outline before writing",
|
|
391
|
+
tools: ["read", "bash"],
|
|
392
|
+
systemPrompt: [
|
|
393
|
+
"You are an expert technical writer reviewing a documentation plan. Interview the developer.",
|
|
394
|
+
"",
|
|
395
|
+
"## Rules",
|
|
396
|
+
"- For EACH question, provide recommended answer OPTIONS (a/b/c format)",
|
|
397
|
+
"- Focus on: target audience level, document structure, what examples to include, what NOT to cover",
|
|
398
|
+
"- Check if the proposed outline covers: overview → quick start → detailed usage → FAQ/troubleshooting",
|
|
399
|
+
"- Ask about existing documentation that should be linked or consolidated",
|
|
400
|
+
"- Clarify terminology preferences and API naming conventions",
|
|
401
|
+
"- Identify potential gaps: error handling, security considerations, performance notes, deprecation notices",
|
|
402
|
+
"- Explore the codebase (use read/bash tools) to see existing docs for consistency",
|
|
403
|
+
"",
|
|
404
|
+
"## Output format",
|
|
405
|
+
"Output ALL questions in ONE JSON response. No preamble or explanation.",
|
|
406
|
+
'Only output the JSON object: { "questions": [{ "id": 1, "question": "...", "options": ["..."] }] }',
|
|
407
|
+
"",
|
|
408
|
+
"## Quantity",
|
|
409
|
+
"Ask 3-10 questions — enough to define the scope and structure.",
|
|
410
|
+
"",
|
|
411
|
+
"## Language",
|
|
412
|
+
"Questions and options should be in the same language as the documentation request (default: Chinese).",
|
|
413
|
+
].join("\n"),
|
|
414
|
+
timeoutMs: 300_000,
|
|
415
|
+
};
|
|
416
|
+
|
|
417
|
+
/** Refactoring plan review. */
|
|
418
|
+
const REFACTOR_GRILL_AGENT_DEF: AgentDef = {
|
|
419
|
+
name: "refactor-grill-agent",
|
|
420
|
+
description: "Refactoring review agent — reviews refactoring plan before implementation",
|
|
421
|
+
tools: ["read", "bash"],
|
|
422
|
+
systemPrompt: [
|
|
423
|
+
"You are an expert software architect reviewing a refactoring plan. Interview the developer.",
|
|
424
|
+
"",
|
|
425
|
+
"## Rules",
|
|
426
|
+
"- For EACH question, provide recommended answer OPTIONS (a/b/c format)",
|
|
427
|
+
"- Focus on: module boundaries, API compatibility, dependency inversion, test strategy, migration steps",
|
|
428
|
+
"- Verify that behavior is preserved — no hidden logic changes disguised as refactoring",
|
|
429
|
+
"- Ask about: interface contracts, error handling behavior, logging behavior, side effects",
|
|
430
|
+
"- Check for risk: what's the rollback plan? Can we refactor incrementally?",
|
|
431
|
+
"- Ask about test coverage: are existing tests sufficient to catch regressions?",
|
|
432
|
+
"- Explore the codebase (use read/bash tools) to understand current module coupling",
|
|
433
|
+
"- Identify potential performance impact of the refactoring",
|
|
434
|
+
"- Check if there are circular dependency issues that should be addressed",
|
|
435
|
+
"",
|
|
436
|
+
"## Output format",
|
|
437
|
+
"Output ALL questions in ONE JSON response. No preamble or explanation.",
|
|
438
|
+
'Only output the JSON object: { "questions": [{ "id": 1, "question": "...", "options": ["..."] }] }',
|
|
439
|
+
"",
|
|
440
|
+
"## Quantity",
|
|
441
|
+
"Ask 5-15 questions — thorough enough to catch hidden coupling issues.",
|
|
442
|
+
"",
|
|
443
|
+
"## Language",
|
|
444
|
+
"Questions and options should be in the same language as the refactoring request (default: Chinese).",
|
|
445
|
+
].join("\n"),
|
|
446
|
+
timeoutMs: 300_000,
|
|
447
|
+
};
|
|
448
|
+
|
|
449
|
+
/** Test plan coverage review. */
|
|
450
|
+
const TEST_GRILL_AGENT_DEF: AgentDef = {
|
|
451
|
+
name: "test-grill-agent",
|
|
452
|
+
description: "Test plan review agent — reviews test coverage and approach before writing tests",
|
|
453
|
+
tools: ["read", "bash"],
|
|
454
|
+
systemPrompt: [
|
|
455
|
+
"You are an expert QA engineer reviewing a test plan. Interview the developer.",
|
|
456
|
+
"",
|
|
457
|
+
"## Rules",
|
|
458
|
+
"- For EACH question, provide recommended answer OPTIONS (a/b/c format)",
|
|
459
|
+
"- Focus on: coverage dimensions, edge cases not yet considered, mocking strategy, test isolation",
|
|
460
|
+
"- Ask about: null/empty inputs, timeouts, idempotency, retry logic, success/failure paths",
|
|
461
|
+
"- Check if the developer has considered: 4xx/5xx HTTP responses, concurrent access, partial failures",
|
|
462
|
+
"- Ask about testing infrastructure: how to run tests, CI integration, test data management",
|
|
463
|
+
"- Verify testability: are dependencies injected? Can we mock external services?",
|
|
464
|
+
"- Explore the codebase (use read/bash tools) to understand existing test patterns",
|
|
465
|
+
"- Ask about coverage thresholds and whether branch coverage is needed",
|
|
466
|
+
"",
|
|
467
|
+
"## Output format",
|
|
468
|
+
"Output ALL questions in ONE JSON response. No preamble or explanation.",
|
|
469
|
+
'Only output the JSON object: { "questions": [{ "id": 1, "question": "...", "options": ["..."] }] }',
|
|
470
|
+
"",
|
|
471
|
+
"## Quantity",
|
|
472
|
+
"Ask 5-12 questions — enough to define a thorough test strategy.",
|
|
473
|
+
"",
|
|
474
|
+
"## Language",
|
|
475
|
+
"Questions and options should be in the same language as the test request (default: Chinese).",
|
|
476
|
+
].join("\n"),
|
|
477
|
+
timeoutMs: 300_000,
|
|
478
|
+
};
|
|
479
|
+
|
|
480
|
+
/** Performance optimization plan review. */
|
|
481
|
+
const PERF_GRILL_AGENT_DEF: AgentDef = {
|
|
482
|
+
name: "perf-grill-agent",
|
|
483
|
+
description: "Performance review agent — reviews optimization approach and benchmarking strategy",
|
|
484
|
+
tools: ["read", "bash"],
|
|
485
|
+
systemPrompt: [
|
|
486
|
+
"You are an expert performance engineer reviewing an optimization plan. Interview the developer.",
|
|
487
|
+
"",
|
|
488
|
+
"## Rules",
|
|
489
|
+
"- For EACH question, provide recommended answer OPTIONS (a/b/c format)",
|
|
490
|
+
"- Focus on: benchmarking methodology, measurement tools, baseline metrics, optimization approaches",
|
|
491
|
+
"- Verify the bottleneck identification: is it really the bottleneck? What's the evidence?",
|
|
492
|
+
"- Ask about: existing profiling data, hot paths, memory vs CPU trade-offs",
|
|
493
|
+
"- Check if simpler solutions exist (e.g., caching before algorithm rewrite)",
|
|
494
|
+
"- Ask about regression risk: could the optimization introduce correctness issues?",
|
|
495
|
+
"- Explore the codebase (use read/bash tools) to understand current implementation",
|
|
496
|
+
"- Ask about monitoring: how will we measure the improvement in production?",
|
|
497
|
+
"- Challenge assumptions: is this optimization premature? What's the user-facing impact?",
|
|
498
|
+
"",
|
|
499
|
+
"## Output format",
|
|
500
|
+
"Output ALL questions in ONE JSON response. No preamble or explanation.",
|
|
501
|
+
'Only output the JSON object: { "questions": [{ "id": 1, "question": "...", "options": ["..."] }] }',
|
|
502
|
+
"",
|
|
503
|
+
"## Quantity",
|
|
504
|
+
"Ask 5-12 questions — enough to validate the approach before implementation.",
|
|
505
|
+
"",
|
|
506
|
+
"## Language",
|
|
507
|
+
"Questions and options should be in the same language as the optimization request (default: Chinese).",
|
|
508
|
+
].join("\n"),
|
|
509
|
+
timeoutMs: 300_000,
|
|
510
|
+
};
|
|
511
|
+
|
|
512
|
+
// ── Command runner ───────────────────────────────────────────
|
|
513
|
+
|
|
514
|
+
/**
|
|
515
|
+
* Run a wizard with an optional Grill phase:
|
|
516
|
+
* Wizard → Assemble → (Grill?) → Send
|
|
517
|
+
*/
|
|
518
|
+
async function runWizardWithGrill(
|
|
519
|
+
ctx: ExtensionCommandContext,
|
|
520
|
+
pi: ExtensionAPI,
|
|
521
|
+
type: string,
|
|
522
|
+
label: string,
|
|
523
|
+
questions: Array<{ label: string; placeholder: string; key: string }>,
|
|
524
|
+
assembler: (answers: Record<string, string>) => string,
|
|
525
|
+
grillOptions?: GrillOptions,
|
|
526
|
+
): Promise<void> {
|
|
527
|
+
ctx.ui.notify(`📋 /dev-${type} — ${label},请逐项填写以下信息(留空跳过对应段落,Esc 取消)`, "info");
|
|
528
|
+
|
|
529
|
+
const answers: Record<string, string> = {};
|
|
530
|
+
for (const q of questions) {
|
|
531
|
+
const val = await ask(ctx, q.label, q.placeholder);
|
|
532
|
+
if (val === undefined) {
|
|
533
|
+
ctx.ui.notify("❌ 已取消", "warning");
|
|
534
|
+
return;
|
|
535
|
+
}
|
|
536
|
+
answers[q.key] = val;
|
|
537
|
+
}
|
|
538
|
+
|
|
539
|
+
const basePrompt = assembler(answers);
|
|
540
|
+
|
|
541
|
+
// ── Grill phase (if agentDef provided) ────────────────────
|
|
542
|
+
let finalPrompt = basePrompt;
|
|
543
|
+
if (grillOptions) {
|
|
544
|
+
const grillResult = await runGrillPhase(basePrompt, ctx, {
|
|
545
|
+
agentDef: grillOptions.agentDef,
|
|
546
|
+
title: grillOptions.title,
|
|
547
|
+
description: grillOptions.description,
|
|
548
|
+
questionTitle: grillOptions.questionTitle,
|
|
549
|
+
loaderLabel: grillOptions.loaderLabel,
|
|
550
|
+
});
|
|
551
|
+
if (grillResult.cancelled) {
|
|
552
|
+
ctx.ui.notify("❌ 操作已取消", "warning");
|
|
553
|
+
return;
|
|
554
|
+
}
|
|
555
|
+
finalPrompt = grillResult.enhancedPrompt;
|
|
556
|
+
}
|
|
557
|
+
|
|
558
|
+
ctx.ui.notify(`✅ 提示词已组装完成,正在发送给主代理...`, "success");
|
|
559
|
+
pi.sendUserMessage(finalPrompt);
|
|
560
|
+
ctx.ui.notify(`📝 /dev-${type} 提示词已投递,主代理正在处理`, "info");
|
|
561
|
+
}
|
|
562
|
+
|
|
563
|
+
/**
|
|
564
|
+
* Run a wizard: ask questions, assemble prompt, send to agent.
|
|
565
|
+
* @param ctx Command context
|
|
566
|
+
* @param pi Extension API (for sendUserMessage)
|
|
567
|
+
* @param type Display name of the prompt type (e.g. "feat")
|
|
568
|
+
* @param label Friendly label (e.g. "新功能/创意生成")
|
|
569
|
+
* @param questions Array of [label, placeholder] pairs
|
|
570
|
+
* @param assembler Function that takes answers and returns the prompt string
|
|
571
|
+
*/
|
|
572
|
+
async function runWizard(
|
|
573
|
+
ctx: ExtensionCommandContext,
|
|
574
|
+
pi: ExtensionAPI,
|
|
575
|
+
type: string,
|
|
576
|
+
label: string,
|
|
577
|
+
questions: Array<{ label: string; placeholder: string; key: string }>,
|
|
578
|
+
assembler: (answers: Record<string, string>) => string,
|
|
579
|
+
): Promise<void> {
|
|
580
|
+
ctx.ui.notify(`📋 /dev-${type} — ${label},请逐项填写以下信息(留空跳过对应段落,Esc 取消)`, "info");
|
|
581
|
+
|
|
582
|
+
const answers: Record<string, string> = {};
|
|
583
|
+
|
|
584
|
+
for (const q of questions) {
|
|
585
|
+
const val = await ask(ctx, q.label, q.placeholder);
|
|
586
|
+
if (val === undefined) {
|
|
587
|
+
ctx.ui.notify("❌ 已取消", "warning");
|
|
588
|
+
return;
|
|
589
|
+
}
|
|
590
|
+
answers[q.key] = val;
|
|
591
|
+
}
|
|
592
|
+
|
|
593
|
+
const prompt = assembler(answers);
|
|
594
|
+
ctx.ui.notify(`✅ 提示词已组装完成,正在发送给主代理...`, "success");
|
|
595
|
+
|
|
596
|
+
// Send the assembled prompt to the main agent
|
|
597
|
+
pi.sendUserMessage(prompt);
|
|
598
|
+
|
|
599
|
+
// Also show the prompt in a notification for reference
|
|
600
|
+
ctx.ui.notify(`📝 /dev-${type} 提示词已投递,主代理正在处理`, "info");
|
|
601
|
+
}
|
|
602
|
+
|
|
603
|
+
// ── Questions for each command ────────────────────────────────
|
|
604
|
+
|
|
605
|
+
const FEAT_QUESTIONS = [
|
|
606
|
+
{ label: "编程语言/框架", placeholder: "如 TypeScript, Python, Rust...", key: "language" },
|
|
607
|
+
{ label: "技术栈", placeholder: "如 NestJS + Prisma, React + Express...", key: "techStack" },
|
|
608
|
+
{ label: "目标模块/文件名", placeholder: "如 src/auth/login.ts", key: "module" },
|
|
609
|
+
{ label: "核心功能描述", placeholder: "用户可以通过邮箱+密码注册并登录", key: "description" },
|
|
610
|
+
{ label: "用户痛点/当前缺少", placeholder: "当前缺少用户认证系统,每次手动校验身份", key: "painPoint" },
|
|
611
|
+
{ label: "测试命令(可选)", placeholder: "如 npm test, cargo test, go test...", key: "testCmd" },
|
|
612
|
+
];
|
|
613
|
+
|
|
614
|
+
const FIX_QUESTIONS = [
|
|
615
|
+
{ label: "文件路径", placeholder: "如 src/auth/login.ts", key: "filePath" },
|
|
616
|
+
{ label: "行号(可选)", placeholder: "如 42,留空则扫描整个文件", key: "lineNumber" },
|
|
617
|
+
{ label: "Bug 描述", placeholder: "登录接口在密码正确时返回 401", key: "bugDesc" },
|
|
618
|
+
{ label: "输入/现象", placeholder: "输入正确邮箱和密码,返回 401 错误", key: "inputDesc" },
|
|
619
|
+
{ label: "预期行为", placeholder: "应返回 200 和 token", key: "expected" },
|
|
620
|
+
{ label: "当前错误信息", placeholder: "Unauthorized (401) - 不符合预期的输出", key: "actualError" },
|
|
621
|
+
{ label: "测试命令(可选)", placeholder: "如 npm test, go test...", key: "testCmd" },
|
|
622
|
+
];
|
|
623
|
+
|
|
624
|
+
const DOC_QUESTIONS = [
|
|
625
|
+
{ label: "模块/API/doc 名称", placeholder: "如 AuthService, REST API v2...", key: "moduleName" },
|
|
626
|
+
{ label: "目标受众", placeholder: "如 小白 / 前端开发者 / 架构师", key: "audience" },
|
|
627
|
+
{ label: "关键信息点", placeholder: "他们需要了解如何使用认证接口", key: "keyInfo" },
|
|
628
|
+
{ label: "示例语言", placeholder: "如 TypeScript, Python, curl...", key: "language" },
|
|
629
|
+
{ label: "已有材料(可选)", placeholder: "现有 README、笔记、文件路径等,留空则从零生成", key: "existingMaterial" },
|
|
630
|
+
];
|
|
631
|
+
|
|
632
|
+
const REFACTOR_QUESTIONS = [
|
|
633
|
+
{ label: "文件路径", placeholder: "如 src/auth/login.ts", key: "filePath" },
|
|
634
|
+
{ label: "代码行数(可选)", placeholder: "如 200 行", key: "lineCount" },
|
|
635
|
+
{ label: "具体问题", placeholder: "如 重复逻辑、耦合度高、可读性差", key: "problems" },
|
|
636
|
+
{ label: "重构目标", placeholder: "如 可读性 / 可维护性 / 模块化", key: "goal" },
|
|
637
|
+
{ label: "测试命令(可选)", placeholder: "如 npm test, cargo test...", key: "testCmd" },
|
|
638
|
+
];
|
|
639
|
+
|
|
640
|
+
const TEST_QUESTIONS = [
|
|
641
|
+
{ label: "文件路径", placeholder: "如 src/auth/login.ts", key: "filePath" },
|
|
642
|
+
{ label: "测试框架", placeholder: "如 Jest / Vitest / pytest / Go test", key: "framework" },
|
|
643
|
+
{ label: "目标覆盖率", placeholder: "如 90,留空默认 90%", key: "coverage" },
|
|
644
|
+
{ label: "边界条件", placeholder: "如 null 值、空值、超时、幂等性、4xx/5xx 错误", key: "edgeCases" },
|
|
645
|
+
{ label: "测试命令(可选)", placeholder: "如 npm test -- --coverage", key: "testCmd" },
|
|
646
|
+
];
|
|
647
|
+
|
|
648
|
+
const CHORE_QUESTIONS = [
|
|
649
|
+
{ label: "配置文件/目标路径", placeholder: "如 package.json, .github/workflows/ci.yml", key: "configPath" },
|
|
650
|
+
{ label: "具体任务", placeholder: "如 更新依赖、修改构建脚本、调整 CI 配置", key: "task" },
|
|
651
|
+
{ label: "当前环境描述", placeholder: "如 Node 18, pnpm 8", key: "envDesc" },
|
|
652
|
+
{ label: "目标版本", placeholder: "如 Node 20, pnpm 9", key: "targetVersion" },
|
|
653
|
+
{ label: "验证命令(可选)", placeholder: "如 npm run build, pnpm test...", key: "verifyCmd" },
|
|
654
|
+
];
|
|
655
|
+
|
|
656
|
+
const PERF_QUESTIONS = [
|
|
657
|
+
{ label: "文件路径", placeholder: "如 src/services/query.ts", key: "filePath" },
|
|
658
|
+
{ label: "瓶颈描述", placeholder: "如 数据库查询延迟过高、内存泄漏", key: "bottleneck" },
|
|
659
|
+
{ label: "当前执行耗时", placeholder: "如 5 秒 / 成本 $0.02/次", key: "currentCost" },
|
|
660
|
+
{ label: "目标延迟", placeholder: "如 200ms", key: "targetLatency" },
|
|
661
|
+
{ label: "基准测试命令(可选)", placeholder: "如 npm run bench, go test -bench=.", key: "benchCmd" },
|
|
662
|
+
];
|
|
663
|
+
|
|
664
|
+
const STYLE_QUESTIONS = [
|
|
665
|
+
{ label: "目标风格", placeholder: "如 正式商务 / 幽默 / 简洁要点式 / Prettier 规范", key: "targetStyle" },
|
|
666
|
+
{ label: "待调整内容描述", placeholder: "如 以下函数需要调整命名风格,或粘贴文本", key: "description" },
|
|
667
|
+
{ label: "术语统一(可选)", placeholder: "如 API → 接口, user → 用户", key: "terms" },
|
|
668
|
+
{ label: "Linter/格式化命令(可选)", placeholder: "如 npx prettier --check, npm run lint", key: "lintCmd" },
|
|
669
|
+
];
|
|
670
|
+
|
|
671
|
+
const SECURITY_QUESTIONS = [
|
|
672
|
+
{ label: "文件路径", placeholder: "如 src/api/auth.ts", key: "filePath" },
|
|
673
|
+
{ label: "审查重点(可选)", placeholder: "如 认证边界、注入漏洞、敏感数据暴露、CSRF/CORS、权限校验", key: "focus" },
|
|
674
|
+
];
|
|
675
|
+
|
|
676
|
+
const EXPLAIN_QUESTIONS = [
|
|
677
|
+
{ label: "概念名称", placeholder: "如 React Server Component, HTTP/3", key: "concept" },
|
|
678
|
+
{ label: "目标受众", placeholder: "如 小白 / 开发者 / 架构师", key: "audience" },
|
|
679
|
+
{ label: "理解深度(可选)", placeholder: "如 基础 / 进阶,留空默认基础", key: "depth" },
|
|
680
|
+
];
|
|
681
|
+
|
|
682
|
+
const COMPARE_QUESTIONS = [
|
|
683
|
+
{ label: "对比对象 A", placeholder: "如 Vue 3, Next.js, PostgreSQL...", key: "itemA" },
|
|
684
|
+
{ label: "对比对象 B", placeholder: "如 React 18, Nuxt 3, MySQL...", key: "itemB" },
|
|
685
|
+
{ label: "评估维度(可选)", placeholder: "如 性能、生态、学习曲线、社区支持", key: "dimensions" },
|
|
686
|
+
];
|
|
687
|
+
|
|
688
|
+
// ── Extension ────────────────────────────────────────────────
|
|
689
|
+
|
|
690
|
+
export default function (pi: ExtensionAPI) {
|
|
691
|
+
// ── /dev-feat ──────────────────────────────────────────────
|
|
692
|
+
pi.registerCommand("dev-feat", {
|
|
693
|
+
description: "(prompt wizard) 新功能/创意生成 — 支持设计评审 (Grill) + PRD 生成",
|
|
694
|
+
handler: async (_args, ctx) => {
|
|
695
|
+
// ── Phase 1: Wizard ──────────────────────────────────
|
|
696
|
+
ctx.ui.notify("📋 /dev-feat — 新功能/创意生成,请逐项填写以下信息(留空跳过对应段落,Esc 取消)", "info");
|
|
697
|
+
|
|
698
|
+
const answers: Record<string, string> = {};
|
|
699
|
+
for (const q of FEAT_QUESTIONS) {
|
|
700
|
+
const val = await ask(ctx, q.label, q.placeholder);
|
|
701
|
+
if (val === undefined) {
|
|
702
|
+
ctx.ui.notify("❌ 已取消", "warning");
|
|
703
|
+
return;
|
|
704
|
+
}
|
|
705
|
+
answers[q.key] = val;
|
|
706
|
+
}
|
|
707
|
+
|
|
708
|
+
// ── Phase 2: Assemble base prompt ───────────────────
|
|
709
|
+
const basePrompt = assembleFeatPrompt(answers as FeatFields);
|
|
710
|
+
ctx.ui.notify(`✅ 基本信息已收集,共 ${FEAT_QUESTIONS.length} 项`, "success");
|
|
711
|
+
|
|
712
|
+
// ── Phase 3: Grill (设计评审) ───────────────────────
|
|
713
|
+
const grillResult = await runGrillPhase(basePrompt, ctx);
|
|
714
|
+
if (grillResult.cancelled) {
|
|
715
|
+
ctx.ui.notify("❌ 操作已取消", "warning");
|
|
716
|
+
return;
|
|
717
|
+
}
|
|
718
|
+
const finalPrompt = grillResult.enhancedPrompt;
|
|
719
|
+
|
|
720
|
+
// ── Phase 4: Send to main agent ─────────────────────
|
|
721
|
+
ctx.ui.notify(`✅ 提示词已组装完成,正在发送给主代理...`, "success");
|
|
722
|
+
pi.sendUserMessage(finalPrompt);
|
|
723
|
+
ctx.ui.notify(`📝 /dev-feat 提示词已投递,主代理正在处理`, "info");
|
|
724
|
+
|
|
725
|
+
// ── Phase 5: Wait for agent to finish ───────────────
|
|
726
|
+
await ctx.waitForIdle();
|
|
727
|
+
|
|
728
|
+
// ── Phase 6: PRD generation ─────────────────────────
|
|
729
|
+
const moduleHint = (answers as FeatFields).module || "feature";
|
|
730
|
+
const grillContext = finalPrompt;
|
|
731
|
+
await runPRDPhase(grillContext, moduleHint, pi, ctx);
|
|
732
|
+
},
|
|
733
|
+
});
|
|
734
|
+
|
|
735
|
+
// ── /dev-fix ───────────────────────────────────────────────
|
|
736
|
+
pi.registerCommand("dev-fix", {
|
|
737
|
+
description: "(prompt wizard) 问题排查/错误修正 — 支持根因分析评审 (Grill)",
|
|
738
|
+
handler: async (_args, ctx) => {
|
|
739
|
+
await runWizardWithGrill(
|
|
740
|
+
ctx, pi, "fix", "问题排查/错误修正",
|
|
741
|
+
FIX_QUESTIONS, assembleFixPrompt,
|
|
742
|
+
{
|
|
743
|
+
agentDef: FIX_GRILL_AGENT_DEF,
|
|
744
|
+
title: "🐛 Bug 根因分析评审",
|
|
745
|
+
description: "是否进入 Bug 根因分析评审 (Grill) 模式?\nAI 会从复现条件、根因推理、修复方案、回归风险等维度挑战你的理解。",
|
|
746
|
+
questionTitle: "Bug 根因分析",
|
|
747
|
+
loaderLabel: "🧠 AI 正在分析代码并生成根因评审问题...",
|
|
748
|
+
},
|
|
749
|
+
);
|
|
750
|
+
},
|
|
751
|
+
});
|
|
752
|
+
|
|
753
|
+
// ── /dev-doc ───────────────────────────────────────────────
|
|
754
|
+
pi.registerCommand("dev-doc", {
|
|
755
|
+
description: "(prompt wizard) 文档生成/总结 — 支持大纲评审 (Grill)",
|
|
756
|
+
handler: async (_args, ctx) => {
|
|
757
|
+
await runWizardWithGrill(
|
|
758
|
+
ctx, pi, "doc", "文档生成/总结",
|
|
759
|
+
DOC_QUESTIONS, assembleDocPrompt,
|
|
760
|
+
{
|
|
761
|
+
agentDef: DOC_GRILL_AGENT_DEF,
|
|
762
|
+
title: "📄 文档大纲评审",
|
|
763
|
+
description: "是否进入文档大纲评审 (Grill) 模式?\nAI 会从受众定位、结构安排、示例选择等维度审视你的文档计划。",
|
|
764
|
+
questionTitle: "文档大纲评审",
|
|
765
|
+
loaderLabel: "🧠 AI 正在分析并生成文档大纲评审问题...",
|
|
766
|
+
},
|
|
767
|
+
);
|
|
768
|
+
},
|
|
769
|
+
});
|
|
770
|
+
|
|
771
|
+
// ── /dev-refactor ──────────────────────────────────────────
|
|
772
|
+
pi.registerCommand("dev-refactor", {
|
|
773
|
+
description: "(prompt wizard) 重构/优化现有结构 — 支持重构计划评审 (Grill)",
|
|
774
|
+
handler: async (_args, ctx) => {
|
|
775
|
+
await runWizardWithGrill(
|
|
776
|
+
ctx, pi, "refactor", "重构/优化",
|
|
777
|
+
REFACTOR_QUESTIONS, assembleRefactorPrompt,
|
|
778
|
+
{
|
|
779
|
+
agentDef: REFACTOR_GRILL_AGENT_DEF,
|
|
780
|
+
title: "🔧 重构方案评审",
|
|
781
|
+
description: "是否进入重构方案评审 (Grill) 模式?\nAI 会从模块边界、API 兼容性、测试策略、迁移风险等维度审视你的重构计划。",
|
|
782
|
+
questionTitle: "重构方案评审",
|
|
783
|
+
loaderLabel: "🧠 AI 正在分析代码并生成重构评审问题...",
|
|
784
|
+
},
|
|
785
|
+
);
|
|
786
|
+
},
|
|
787
|
+
});
|
|
788
|
+
|
|
789
|
+
// ── /dev-test ──────────────────────────────────────────────
|
|
790
|
+
pi.registerCommand("dev-test", {
|
|
791
|
+
description: "(prompt wizard) 测试用例生成 — 支持测试计划评审 (Grill)",
|
|
792
|
+
handler: async (_args, ctx) => {
|
|
793
|
+
await runWizardWithGrill(
|
|
794
|
+
ctx, pi, "test", "测试用例/评估",
|
|
795
|
+
TEST_QUESTIONS, assembleTestPrompt,
|
|
796
|
+
{
|
|
797
|
+
agentDef: TEST_GRILL_AGENT_DEF,
|
|
798
|
+
title: "🧪 测试计划评审",
|
|
799
|
+
description: "是否进入测试计划评审 (Grill) 模式?\nAI 会从覆盖维度、边界条件、模拟策略等角度审视你的测试方案。",
|
|
800
|
+
questionTitle: "测试计划评审",
|
|
801
|
+
loaderLabel: "🧠 AI 正在分析并生成测试评审问题...",
|
|
802
|
+
},
|
|
803
|
+
);
|
|
804
|
+
},
|
|
805
|
+
});
|
|
806
|
+
|
|
807
|
+
// ── /dev-chore ─────────────────────────────────────────────
|
|
808
|
+
pi.registerCommand("dev-chore", {
|
|
809
|
+
description: "(prompt wizard) 日常维护/杂项自动化 — 交互填写后发送优化提示词给主代理",
|
|
810
|
+
handler: async (_args, ctx) => {
|
|
811
|
+
await runWizard(ctx, pi, "chore", "日常维护/自动化", CHORE_QUESTIONS, assembleChorePrompt);
|
|
812
|
+
},
|
|
813
|
+
});
|
|
814
|
+
|
|
815
|
+
// ── /dev-perf ──────────────────────────────────────────────
|
|
816
|
+
pi.registerCommand("dev-perf", {
|
|
817
|
+
description: "(prompt wizard) 性能优化 — 支持优化方案评审 (Grill)",
|
|
818
|
+
handler: async (_args, ctx) => {
|
|
819
|
+
await runWizardWithGrill(
|
|
820
|
+
ctx, pi, "perf", "性能优化",
|
|
821
|
+
PERF_QUESTIONS, assemblePerfPrompt,
|
|
822
|
+
{
|
|
823
|
+
agentDef: PERF_GRILL_AGENT_DEF,
|
|
824
|
+
title: "⚡ 性能优化方案评审",
|
|
825
|
+
description: "是否进入性能优化方案评审 (Grill) 模式?\nAI 会从基准测试方法、优化方向、回归风险等维度审视你的方案。",
|
|
826
|
+
questionTitle: "性能优化方案评审",
|
|
827
|
+
loaderLabel: "🧠 AI 正在分析并生成性能优化评审问题...",
|
|
828
|
+
},
|
|
829
|
+
);
|
|
830
|
+
},
|
|
831
|
+
});
|
|
832
|
+
|
|
833
|
+
// ── /dev-style ─────────────────────────────────────────────
|
|
834
|
+
pi.registerCommand("dev-style", {
|
|
835
|
+
description: "(prompt wizard) 风格/格式调整 — 交互填写后发送优化提示词给主代理",
|
|
836
|
+
handler: async (_args, ctx) => {
|
|
837
|
+
await runWizard(ctx, pi, "style", "风格/格式调整", STYLE_QUESTIONS, assembleStylePrompt);
|
|
838
|
+
},
|
|
839
|
+
});
|
|
840
|
+
|
|
841
|
+
// ── /dev-security ──────────────────────────────────────────
|
|
842
|
+
pi.registerCommand("dev-security", {
|
|
843
|
+
description: "(prompt wizard) 安全审查 — 交互填写后发送优化提示词给主代理",
|
|
844
|
+
handler: async (_args, ctx) => {
|
|
845
|
+
await runWizard(ctx, pi, "security", "安全审查", SECURITY_QUESTIONS, assembleSecurityPrompt);
|
|
846
|
+
},
|
|
847
|
+
});
|
|
848
|
+
|
|
849
|
+
// ── /dev-explain ───────────────────────────────────────────
|
|
850
|
+
pi.registerCommand("dev-explain", {
|
|
851
|
+
description: "(prompt wizard) 概念解释 — 交互填写后发送优化提示词给主代理",
|
|
852
|
+
handler: async (_args, ctx) => {
|
|
853
|
+
await runWizard(ctx, pi, "explain", "概念解释", EXPLAIN_QUESTIONS, assembleExplainPrompt);
|
|
854
|
+
},
|
|
855
|
+
});
|
|
856
|
+
|
|
857
|
+
// ── /dev-compare ───────────────────────────────────────────
|
|
858
|
+
pi.registerCommand("dev-compare", {
|
|
859
|
+
description: "(prompt wizard) 对比评估 — 交互填写后发送优化提示词给主代理",
|
|
860
|
+
handler: async (_args, ctx) => {
|
|
861
|
+
await runWizard(ctx, pi, "compare", "对比评估", COMPARE_QUESTIONS, assembleComparePrompt);
|
|
862
|
+
},
|
|
863
|
+
});
|
|
864
|
+
}
|