@jdzhang225gmail/fontend-prompt 0.1.0 → 0.2.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 +38 -182
- package/dist/cli.js +76 -1
- package/dist/index.js +5 -750
- package/dist/skills/optimize.js +442 -0
- package/dist/skills/scan.js +80 -0
- package/dist/skills/score.js +60 -0
- package/dist/types.js +1 -0
- package/dist/utils.js +38 -0
- package/package.json +4 -4
package/dist/index.js
CHANGED
|
@@ -1,750 +1,5 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
function asNonEmptyString(value) {
|
|
7
|
-
if (typeof value !== "string")
|
|
8
|
-
return undefined;
|
|
9
|
-
const s = value.trim();
|
|
10
|
-
return s.length ? s : undefined;
|
|
11
|
-
}
|
|
12
|
-
function clamp(n, min, max) {
|
|
13
|
-
return Math.max(min, Math.min(max, n));
|
|
14
|
-
}
|
|
15
|
-
function includesAny(haystack, needles) {
|
|
16
|
-
const h = haystack.toLowerCase();
|
|
17
|
-
return needles.some((n) => h.includes(n.toLowerCase()));
|
|
18
|
-
}
|
|
19
|
-
function safeResolveUnderCwd(p) {
|
|
20
|
-
const cwd = process.cwd();
|
|
21
|
-
const target = path.resolve(cwd, p ?? ".");
|
|
22
|
-
const rel = path.relative(cwd, target);
|
|
23
|
-
if (rel.startsWith("..") || path.isAbsolute(rel) && rel.includes(":")) {
|
|
24
|
-
throw new Error("scan_project: rootDir must be within the server working directory");
|
|
25
|
-
}
|
|
26
|
-
return target;
|
|
27
|
-
}
|
|
28
|
-
async function scanProject(args) {
|
|
29
|
-
const root = safeResolveUnderCwd(args.rootDir);
|
|
30
|
-
const maxDepth = typeof args.maxDepth === "number" ? clamp(Math.floor(args.maxDepth), 0, 10) : 4;
|
|
31
|
-
const maxEntries = typeof args.maxEntries === "number" ? clamp(Math.floor(args.maxEntries), 50, 5000) : 1200;
|
|
32
|
-
const ignoreNames = new Set(["node_modules", ".git", "dist", "build", ".next", ".nuxt", ".turbo"]);
|
|
33
|
-
const treeLines = [];
|
|
34
|
-
const filesIndex = [];
|
|
35
|
-
let entriesCount = 0;
|
|
36
|
-
async function walk(dir, depth, prefix) {
|
|
37
|
-
if (entriesCount >= maxEntries)
|
|
38
|
-
return;
|
|
39
|
-
let dirents;
|
|
40
|
-
try {
|
|
41
|
-
dirents = await fs.readdir(dir, { withFileTypes: true });
|
|
42
|
-
}
|
|
43
|
-
catch {
|
|
44
|
-
return;
|
|
45
|
-
}
|
|
46
|
-
const filtered = dirents
|
|
47
|
-
.filter((d) => !ignoreNames.has(d.name))
|
|
48
|
-
.sort((a, b) => {
|
|
49
|
-
if (a.isDirectory() && !b.isDirectory())
|
|
50
|
-
return -1;
|
|
51
|
-
if (!a.isDirectory() && b.isDirectory())
|
|
52
|
-
return 1;
|
|
53
|
-
return a.name.localeCompare(b.name);
|
|
54
|
-
});
|
|
55
|
-
for (let i = 0; i < filtered.length; i++) {
|
|
56
|
-
if (entriesCount >= maxEntries)
|
|
57
|
-
return;
|
|
58
|
-
const d = filtered[i];
|
|
59
|
-
const isLast = i === filtered.length - 1;
|
|
60
|
-
const connector = isLast ? "└─" : "├─";
|
|
61
|
-
const rel = path.relative(root, path.join(dir, d.name)).replace(/\\/g, "/");
|
|
62
|
-
treeLines.push(`${prefix}${connector} ${d.name}${d.isDirectory() ? "/" : ""}`);
|
|
63
|
-
entriesCount++;
|
|
64
|
-
if (!d.isDirectory())
|
|
65
|
-
filesIndex.push(rel);
|
|
66
|
-
if (d.isDirectory() && depth < maxDepth) {
|
|
67
|
-
await walk(path.join(dir, d.name), depth + 1, `${prefix}${isLast ? " " : "│ "}`);
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
treeLines.push(`${path.basename(root) || "."}/`);
|
|
72
|
-
await walk(root, 0, "");
|
|
73
|
-
const claudeCandidates = filesIndex.filter((p) => p.toLowerCase().endsWith("claude.md"));
|
|
74
|
-
const suggestedFiles = [
|
|
75
|
-
"package.json",
|
|
76
|
-
"pnpm-lock.yaml",
|
|
77
|
-
"yarn.lock",
|
|
78
|
-
"package-lock.json",
|
|
79
|
-
"tsconfig.json",
|
|
80
|
-
"vite.config.ts",
|
|
81
|
-
"vite.config.js",
|
|
82
|
-
"next.config.js",
|
|
83
|
-
"nuxt.config.ts",
|
|
84
|
-
"eslint.config.js",
|
|
85
|
-
".eslintrc",
|
|
86
|
-
".prettierrc",
|
|
87
|
-
"README.md",
|
|
88
|
-
"CLAUDE.md",
|
|
89
|
-
].filter((f) => filesIndex.some((p) => p.toLowerCase() === f.toLowerCase()));
|
|
90
|
-
return {
|
|
91
|
-
rootDir: root,
|
|
92
|
-
maxDepth,
|
|
93
|
-
maxEntries,
|
|
94
|
-
truncated: entriesCount >= maxEntries,
|
|
95
|
-
tree: treeLines.join("\n"),
|
|
96
|
-
hasClaudeMd: claudeCandidates.length > 0,
|
|
97
|
-
claudeMdPaths: claudeCandidates,
|
|
98
|
-
suggestedFiles,
|
|
99
|
-
};
|
|
100
|
-
}
|
|
101
|
-
function buildFrontendGuardrails(args) {
|
|
102
|
-
const guardrails = [
|
|
103
|
-
"输出必须面向前端开发实践(UI、交互、状态、路由、可访问性、性能、工程化),不要泛泛而谈。",
|
|
104
|
-
"如果关键信息不足,先提出澄清问题,不要凭空编造业务规则或接口字段。",
|
|
105
|
-
"除非明确要求,否则不要引入新的第三方依赖;如果必须引入,要说明原因与替代方案。",
|
|
106
|
-
"给出可执行的交付物(代码/文件结构/命令/步骤),避免只给概念。",
|
|
107
|
-
"优先考虑可维护性:类型、安全边界、错误处理、可测试性与可扩展性。",
|
|
108
|
-
"遵循安全与隐私:不要输出或要求提供密钥、token、个人敏感信息。",
|
|
109
|
-
"严格按要求的结构化模板输出;必须在需要审批的 gate 停止并等待用户确认。",
|
|
110
|
-
];
|
|
111
|
-
if (args.language === "ts") {
|
|
112
|
-
guardrails.push("默认使用 TypeScript,类型定义清晰,避免 any;必要时用类型收窄。 ");
|
|
113
|
-
}
|
|
114
|
-
if (args.framework) {
|
|
115
|
-
guardrails.push(`优先使用 ${args.framework} 的最佳实践与官方推荐写法。`);
|
|
116
|
-
}
|
|
117
|
-
if (args.styling) {
|
|
118
|
-
guardrails.push(`样式实现需符合:${args.styling}。`);
|
|
119
|
-
}
|
|
120
|
-
if (args.constraints?.length) {
|
|
121
|
-
guardrails.push(...args.constraints);
|
|
122
|
-
}
|
|
123
|
-
return guardrails;
|
|
124
|
-
}
|
|
125
|
-
function buildWorkflowDefinition(args) {
|
|
126
|
-
const taskType = args.taskType ?? "new_feature";
|
|
127
|
-
const requireApprovalGates = args.requireApprovalGates ?? true;
|
|
128
|
-
const gateMarker = "<<<MCP:GATE";
|
|
129
|
-
const gatesByType = {
|
|
130
|
-
new_feature: [
|
|
131
|
-
{ id: "new_feature_design", title: "新功能设计方案", when: "设计方案完成后,开始开发方案/实现之前" },
|
|
132
|
-
{ id: "new_feature_plan", title: "开发方案与 TODO", when: "开发步骤与 TODO 列表输出后,开始写代码之前" },
|
|
133
|
-
{ id: "new_feature_accept", title: "交付与验收", when: "TS 校验/实现完成后,等待用户验收" },
|
|
134
|
-
],
|
|
135
|
-
optimize_existing: [
|
|
136
|
-
{ id: "opt_change_doc", title: "变更说明文档", when: "Before/After/Scope 文档输出后,开始改代码之前" },
|
|
137
|
-
{ id: "opt_plan", title: "实施计划与 TODO", when: "实施计划输出后,开始改代码之前" },
|
|
138
|
-
],
|
|
139
|
-
refactor: [
|
|
140
|
-
{ id: "refactor_doc", title: "重构说明文档", when: "映射表与原则确定后,执行迁移之前" },
|
|
141
|
-
{ id: "refactor_migration", title: "迁移脚本/迁移方案", when: "脚本与运行方式确认后,执行迁移之前" },
|
|
142
|
-
],
|
|
143
|
-
bugfix: [{ id: "bugfix_plan", title: "修复方案", when: "根因定位后,开始改代码之前" }],
|
|
144
|
-
performance: [{ id: "perf_plan", title: "性能优化方案", when: "指标与瓶颈确认后,开始改代码之前" }],
|
|
145
|
-
ui_polish: [{ id: "ui_polish_plan", title: "UI 调整方案", when: "问题清单确认后,开始改代码之前" }],
|
|
146
|
-
dependency_upgrade: [{ id: "dep_upgrade_plan", title: "升级方案与回滚计划", when: "风险评估后,开始升级之前" }],
|
|
147
|
-
test_addition: [{ id: "test_plan", title: "测试补充方案", when: "用例范围确认后,开始写测试之前" }],
|
|
148
|
-
};
|
|
149
|
-
const gates = gatesByType[taskType] ?? gatesByType.new_feature;
|
|
150
|
-
const steps = [
|
|
151
|
-
{ id: "task_classification", title: "任务分类" },
|
|
152
|
-
{ id: "project_understanding", title: "项目理解" },
|
|
153
|
-
{ id: "risk_constraints", title: "风险与约束确认" },
|
|
154
|
-
];
|
|
155
|
-
if (taskType === "new_feature") {
|
|
156
|
-
steps.push({ id: "design", title: "新功能设计方案", gateId: "new_feature_design" }, { id: "plan", title: "开发方案与 TODO", gateId: "new_feature_plan" }, { id: "implementation", title: "开发实现" }, { id: "typecheck", title: "TypeScript 校验(如适用)" }, { id: "acceptance", title: "交付与验收", gateId: "new_feature_accept" }, { id: "docs", title: "文档更新(条件触发:claude.md 存在)" });
|
|
157
|
-
}
|
|
158
|
-
else if (taskType === "optimize_existing") {
|
|
159
|
-
steps.push({ id: "current_understanding", title: "现状理解(老功能逻辑)" }, { id: "change_doc", title: "变更说明文档(Markdown)", gateId: "opt_change_doc" }, { id: "plan", title: "实施计划与 TODO", gateId: "opt_plan" }, { id: "implementation", title: "实施与验证" });
|
|
160
|
-
}
|
|
161
|
-
else if (taskType === "refactor") {
|
|
162
|
-
steps.push({ id: "scope_understanding", title: "重构范围与现状理解" }, { id: "refactor_doc", title: "重构说明文档(Markdown)", gateId: "refactor_doc" }, { id: "migration", title: "迁移方案与脚本", gateId: "refactor_migration" }, { id: "execution", title: "执行重构" });
|
|
163
|
-
}
|
|
164
|
-
else if (taskType === "bugfix") {
|
|
165
|
-
steps.push({ id: "repro_rootcause", title: "复现与根因定位" }, { id: "plan", title: "修复方案", gateId: "bugfix_plan" }, { id: "implementation", title: "实施与验证" });
|
|
166
|
-
}
|
|
167
|
-
else if (taskType === "performance") {
|
|
168
|
-
steps.push({ id: "metrics", title: "性能目标与指标" }, { id: "plan", title: "优化方案", gateId: "perf_plan" }, { id: "implementation", title: "实施与对比" });
|
|
169
|
-
}
|
|
170
|
-
else if (taskType === "ui_polish") {
|
|
171
|
-
steps.push({ id: "issues", title: "体验问题清单" }, { id: "plan", title: "调整方案", gateId: "ui_polish_plan" }, { id: "implementation", title: "实施与验收" });
|
|
172
|
-
}
|
|
173
|
-
else if (taskType === "dependency_upgrade") {
|
|
174
|
-
steps.push({ id: "risk", title: "升级范围与风险评估" }, { id: "plan", title: "升级方案与回滚计划", gateId: "dep_upgrade_plan" }, { id: "implementation", title: "实施与验证" });
|
|
175
|
-
}
|
|
176
|
-
else {
|
|
177
|
-
steps.push({ id: "plan", title: "测试补充方案", gateId: "test_plan" }, { id: "implementation", title: "实施与验证" });
|
|
178
|
-
}
|
|
179
|
-
return {
|
|
180
|
-
taskType,
|
|
181
|
-
requireApprovalGates,
|
|
182
|
-
gateMarker,
|
|
183
|
-
gates,
|
|
184
|
-
steps,
|
|
185
|
-
};
|
|
186
|
-
}
|
|
187
|
-
function buildStructuredTemplate(args) {
|
|
188
|
-
const taskType = args.taskType ?? "new_feature";
|
|
189
|
-
const requireApprovalGates = args.requireApprovalGates ?? true;
|
|
190
|
-
const language = args.language ?? "ts";
|
|
191
|
-
const workflow = buildWorkflowDefinition(args);
|
|
192
|
-
const gateLine = requireApprovalGates
|
|
193
|
-
? "- 在标注为 **[GATE: NEED USER APPROVAL]** 的位置必须停止输出后续内容,等待用户明确回复“同意/调整”。"
|
|
194
|
-
: "- 允许一次性输出完整内容,但仍需标注原本的 gate 节点。";
|
|
195
|
-
const base = [
|
|
196
|
-
"# 输出结构(必须严格遵守)",
|
|
197
|
-
"## - Machine readable workflow",
|
|
198
|
-
`- mcp_workflow: ${JSON.stringify({ task_type: workflow.taskType, require_approval_gates: workflow.requireApprovalGates, gates: workflow.gates }, null, 0)}`,
|
|
199
|
-
`- gate_marker_prefix: ${workflow.gateMarker} id=\"...\" action=\"WAIT_FOR_USER_APPROVAL\">>>`,
|
|
200
|
-
"## 0. 任务分类",
|
|
201
|
-
"- task_type: <new_feature|optimize_existing|refactor|bugfix|performance|ui_polish|dependency_upgrade|test_addition>",
|
|
202
|
-
"- 目标: <一句话>",
|
|
203
|
-
"- 非目标: <明确不做什么>",
|
|
204
|
-
"",
|
|
205
|
-
"## 1. 项目理解(必须先做)",
|
|
206
|
-
"- 如果你还不了解项目结构:先调用工具 `scan_project` 获取目录树与关键文件,然后基于结果总结架构。",
|
|
207
|
-
"- 列出与你要改动最相关的文件/目录(最多 10 个)。",
|
|
208
|
-
"- 如需进一步定位:提出要用户提供的入口文件/路由/组件/接口契约。",
|
|
209
|
-
"",
|
|
210
|
-
"## 2. 风险与约束确认",
|
|
211
|
-
"- 兼容性: 浏览器范围/移动端/SSR/SEO(如适用)",
|
|
212
|
-
"- 依赖限制: 是否允许新增依赖",
|
|
213
|
-
"- 质量门槛: a11y/性能/测试要求",
|
|
214
|
-
"",
|
|
215
|
-
gateLine,
|
|
216
|
-
"- 当你到达 gate 节点并完成该章节后,输出一行:`<<<MCP:WAIT gate_id=\"<id>\" action=\"WAIT_FOR_USER_APPROVAL\">>>`,然后立刻停止。",
|
|
217
|
-
];
|
|
218
|
-
if (taskType === "new_feature") {
|
|
219
|
-
return [
|
|
220
|
-
...base,
|
|
221
|
-
"",
|
|
222
|
-
"<<<MCP:GATE id=\"new_feature_design\" action=\"WAIT_FOR_USER_APPROVAL\">>>",
|
|
223
|
-
"## 3. 新功能设计方案 **[GATE: NEED USER APPROVAL]**",
|
|
224
|
-
"- 用户故事/验收标准(可测试、可验收)",
|
|
225
|
-
"- UI/交互说明(状态:loading/empty/error/success)",
|
|
226
|
-
"- 状态设计(本地/全局/服务端状态)",
|
|
227
|
-
"- 路由与导航(如适用)",
|
|
228
|
-
"- 数据流与接口契约(如适用:字段、错误码、鉴权、缓存策略)",
|
|
229
|
-
"- 文件变更预告(新增/修改的文件路径清单)",
|
|
230
|
-
"- 关键决策与备选方案(trade-offs)",
|
|
231
|
-
"<<<MCP:WAIT gate_id=\"new_feature_design\" action=\"WAIT_FOR_USER_APPROVAL\">>>",
|
|
232
|
-
"",
|
|
233
|
-
"<<<MCP:GATE id=\"new_feature_plan\" action=\"WAIT_FOR_USER_APPROVAL\">>>",
|
|
234
|
-
"## 4. 开发方案与 TODO 流程 **[GATE: NEED USER APPROVAL]**",
|
|
235
|
-
"- 开发步骤(可分 PR/commit 阶段)",
|
|
236
|
-
"- TODO 列表(使用 Markdown checklist)",
|
|
237
|
-
"- 验证计划(本地运行/手动测试点/测试用例)",
|
|
238
|
-
"<<<MCP:WAIT gate_id=\"new_feature_plan\" action=\"WAIT_FOR_USER_APPROVAL\">>>",
|
|
239
|
-
"",
|
|
240
|
-
"## 5. 开发实现(通过 gate 后才输出)",
|
|
241
|
-
"- 按你在第 4 步承诺的方式输出代码(diff/full_files/snippets)",
|
|
242
|
-
"",
|
|
243
|
-
"## 6. TypeScript 校验与问题修复(如适用)",
|
|
244
|
-
language === "ts"
|
|
245
|
-
? "- 先执行 TS 校验(例如 tsc --noEmit 或 npm script),贴出关键错误并修复后再继续。"
|
|
246
|
-
: "- 如非 TS 项目则跳过此步骤。",
|
|
247
|
-
"",
|
|
248
|
-
"<<<MCP:GATE id=\"new_feature_accept\" action=\"WAIT_FOR_USER_APPROVAL\">>>",
|
|
249
|
-
"## 7. 交付与验收 **[GATE: NEED USER APPROVAL]**",
|
|
250
|
-
"- 给出验收清单(按验收标准逐条核对)",
|
|
251
|
-
"- 提示用户验收:通过/不通过/需要调整",
|
|
252
|
-
"<<<MCP:WAIT gate_id=\"new_feature_accept\" action=\"WAIT_FOR_USER_APPROVAL\">>>",
|
|
253
|
-
"",
|
|
254
|
-
"## 8. 文档更新(条件触发)",
|
|
255
|
-
"- 若 `scan_project` 显示存在 `claude.md/CLAUDE.md`:将本次新功能的描述追加到对应文档的合适位置。",
|
|
256
|
-
"- 若不存在:跳过文档更新。",
|
|
257
|
-
].join("\n");
|
|
258
|
-
}
|
|
259
|
-
if (taskType === "optimize_existing") {
|
|
260
|
-
return [
|
|
261
|
-
...base,
|
|
262
|
-
"",
|
|
263
|
-
"## 3. 现状理解(老功能逻辑)",
|
|
264
|
-
"- 描述当前功能的输入/输出/关键分支/异常路径",
|
|
265
|
-
"- 列出当前痛点(性能/可维护性/体验/bug 风险)",
|
|
266
|
-
"",
|
|
267
|
-
"<<<MCP:GATE id=\"opt_change_doc\" action=\"WAIT_FOR_USER_APPROVAL\">>>",
|
|
268
|
-
"## 4. 变更说明文档(Markdown) **[GATE: NEED USER APPROVAL]**",
|
|
269
|
-
"- 标题:<优化主题>",
|
|
270
|
-
"- Before:当前行为与问题点",
|
|
271
|
-
"- After:目标行为与改动收益",
|
|
272
|
-
"- Scope:改动范围(文件、模块、接口)",
|
|
273
|
-
"- Out of Scope:明确不改哪些",
|
|
274
|
-
"- 风险与回滚:可能风险、回滚策略",
|
|
275
|
-
"- 验收点:如何验证优化确实生效",
|
|
276
|
-
"<<<MCP:WAIT gate_id=\"opt_change_doc\" action=\"WAIT_FOR_USER_APPROVAL\">>>",
|
|
277
|
-
"",
|
|
278
|
-
"<<<MCP:GATE id=\"opt_plan\" action=\"WAIT_FOR_USER_APPROVAL\">>>",
|
|
279
|
-
"## 5. 实施计划与 TODO **[GATE: NEED USER APPROVAL]**",
|
|
280
|
-
"- TODO checklist",
|
|
281
|
-
"- 测试/验证计划",
|
|
282
|
-
"<<<MCP:WAIT gate_id=\"opt_plan\" action=\"WAIT_FOR_USER_APPROVAL\">>>",
|
|
283
|
-
"",
|
|
284
|
-
"## 6. 实施与验证(通过 gate 后才输出)",
|
|
285
|
-
"- 输出代码变更",
|
|
286
|
-
"- 如果是 TS 项目:执行 TS 校验并修复",
|
|
287
|
-
"- 输出对比结果(Before/After,包含指标/体验变化)",
|
|
288
|
-
].join("\n");
|
|
289
|
-
}
|
|
290
|
-
if (taskType === "refactor") {
|
|
291
|
-
return [
|
|
292
|
-
...base,
|
|
293
|
-
"",
|
|
294
|
-
"## 3. 重构范围与现状理解",
|
|
295
|
-
"- 列出重构范围内的模块/目录/入口",
|
|
296
|
-
"- 描述现有结构与主要依赖关系(数据流、组件层级、耦合点)",
|
|
297
|
-
"",
|
|
298
|
-
"<<<MCP:GATE id=\"refactor_doc\" action=\"WAIT_FOR_USER_APPROVAL\">>>",
|
|
299
|
-
"## 4. 重构说明文档(Markdown) **[GATE: NEED USER APPROVAL]**",
|
|
300
|
-
"- Before:当前结构、主要问题",
|
|
301
|
-
"- After:目标结构、约束与原则",
|
|
302
|
-
"- 目录/文件迁移映射表:old_path -> new_path(详细)",
|
|
303
|
-
"- 兼容策略:过渡层/adapter/别名/弃用计划(如需要)",
|
|
304
|
-
"- 风险与回滚:如何逐步落地",
|
|
305
|
-
"<<<MCP:WAIT gate_id=\"refactor_doc\" action=\"WAIT_FOR_USER_APPROVAL\">>>",
|
|
306
|
-
"",
|
|
307
|
-
"<<<MCP:GATE id=\"refactor_migration\" action=\"WAIT_FOR_USER_APPROVAL\">>>",
|
|
308
|
-
"## 5. 迁移方案与脚本(如涉及大范围移动) **[GATE: NEED USER APPROVAL]**",
|
|
309
|
-
"- 提供一个一次性迁移脚本(js/ts/py)方案:做文件移动、import 路径更新(或至少生成迁移清单)",
|
|
310
|
-
"- 说明脚本运行方式与注意事项",
|
|
311
|
-
"<<<MCP:WAIT gate_id=\"refactor_migration\" action=\"WAIT_FOR_USER_APPROVAL\">>>",
|
|
312
|
-
"",
|
|
313
|
-
"## 6. 执行重构(通过 gate 后才输出)",
|
|
314
|
-
"- 按映射表实施变更",
|
|
315
|
-
"- 运行 TS 校验/构建/测试(如存在)并修复",
|
|
316
|
-
"- 输出最终结构与关键文件变化摘要",
|
|
317
|
-
].join("\n");
|
|
318
|
-
}
|
|
319
|
-
if (taskType === "bugfix") {
|
|
320
|
-
return [
|
|
321
|
-
...base,
|
|
322
|
-
"",
|
|
323
|
-
"## 3. 复现与根因定位",
|
|
324
|
-
"- 复现步骤、预期 vs 实际",
|
|
325
|
-
"- 根因分析(涉及代码位置)",
|
|
326
|
-
"",
|
|
327
|
-
"<<<MCP:GATE id=\"bugfix_plan\" action=\"WAIT_FOR_USER_APPROVAL\">>>",
|
|
328
|
-
"## 4. 修复方案 **[GATE: NEED USER APPROVAL]**",
|
|
329
|
-
"- 修复点与影响范围",
|
|
330
|
-
"- 是否需要补充测试用例",
|
|
331
|
-
"<<<MCP:WAIT gate_id=\"bugfix_plan\" action=\"WAIT_FOR_USER_APPROVAL\">>>",
|
|
332
|
-
"",
|
|
333
|
-
"## 5. 实施与验证(通过 gate 后才输出)",
|
|
334
|
-
"- 输出代码变更",
|
|
335
|
-
"- 验证结果与回归检查点",
|
|
336
|
-
].join("\n");
|
|
337
|
-
}
|
|
338
|
-
if (taskType === "performance") {
|
|
339
|
-
return [
|
|
340
|
-
...base,
|
|
341
|
-
"",
|
|
342
|
-
"## 3. 性能目标与指标",
|
|
343
|
-
"- 明确指标:LCP/CLS/INP/TTI、bundle size、渲染次数、接口耗时等",
|
|
344
|
-
"",
|
|
345
|
-
"<<<MCP:GATE id=\"perf_plan\" action=\"WAIT_FOR_USER_APPROVAL\">>>",
|
|
346
|
-
"## 4. 优化方案 **[GATE: NEED USER APPROVAL]**",
|
|
347
|
-
"- 瓶颈假设与验证方法",
|
|
348
|
-
"- 改动点与预期收益",
|
|
349
|
-
"<<<MCP:WAIT gate_id=\"perf_plan\" action=\"WAIT_FOR_USER_APPROVAL\">>>",
|
|
350
|
-
"",
|
|
351
|
-
"## 5. 实施与对比(通过 gate 后才输出)",
|
|
352
|
-
"- 输出代码变更",
|
|
353
|
-
"- Before/After 数据对比",
|
|
354
|
-
].join("\n");
|
|
355
|
-
}
|
|
356
|
-
if (taskType === "ui_polish") {
|
|
357
|
-
return [
|
|
358
|
-
...base,
|
|
359
|
-
"",
|
|
360
|
-
"## 3. 体验问题清单",
|
|
361
|
-
"- 视觉/布局/交互/动效/可访问性问题",
|
|
362
|
-
"",
|
|
363
|
-
"<<<MCP:GATE id=\"ui_polish_plan\" action=\"WAIT_FOR_USER_APPROVAL\">>>",
|
|
364
|
-
"## 4. 调整方案(含截图/描述) **[GATE: NEED USER APPROVAL]**",
|
|
365
|
-
"- 每个问题的改法与验收点",
|
|
366
|
-
"<<<MCP:WAIT gate_id=\"ui_polish_plan\" action=\"WAIT_FOR_USER_APPROVAL\">>>",
|
|
367
|
-
"",
|
|
368
|
-
"## 5. 实施与验收(通过 gate 后才输出)",
|
|
369
|
-
"- 输出代码变更",
|
|
370
|
-
"- 验收清单",
|
|
371
|
-
].join("\n");
|
|
372
|
-
}
|
|
373
|
-
if (taskType === "dependency_upgrade") {
|
|
374
|
-
return [
|
|
375
|
-
...base,
|
|
376
|
-
"",
|
|
377
|
-
"## 3. 升级范围与风险评估",
|
|
378
|
-
"- 目标依赖/版本区间",
|
|
379
|
-
"- Breaking changes 风险与迁移成本",
|
|
380
|
-
"",
|
|
381
|
-
"<<<MCP:GATE id=\"dep_upgrade_plan\" action=\"WAIT_FOR_USER_APPROVAL\">>>",
|
|
382
|
-
"## 4. 升级方案与回滚计划 **[GATE: NEED USER APPROVAL]**",
|
|
383
|
-
"- 升级步骤与验证方式",
|
|
384
|
-
"- 回滚方案",
|
|
385
|
-
"<<<MCP:WAIT gate_id=\"dep_upgrade_plan\" action=\"WAIT_FOR_USER_APPROVAL\">>>",
|
|
386
|
-
"",
|
|
387
|
-
"## 5. 实施与验证(通过 gate 后才输出)",
|
|
388
|
-
"- 输出代码变更",
|
|
389
|
-
"- 构建/测试/TS 校验结果",
|
|
390
|
-
].join("\n");
|
|
391
|
-
}
|
|
392
|
-
return [
|
|
393
|
-
...base,
|
|
394
|
-
"",
|
|
395
|
-
"<<<MCP:GATE id=\"test_plan\" action=\"WAIT_FOR_USER_APPROVAL\">>>",
|
|
396
|
-
"## 3. 测试补充方案 **[GATE: NEED USER APPROVAL]**",
|
|
397
|
-
"- 测试范围与优先级(单测/组件/E2E)",
|
|
398
|
-
"- 用例列表与覆盖目标",
|
|
399
|
-
"<<<MCP:WAIT gate_id=\"test_plan\" action=\"WAIT_FOR_USER_APPROVAL\">>>",
|
|
400
|
-
"",
|
|
401
|
-
"## 4. 实施与验证(通过 gate 后才输出)",
|
|
402
|
-
"- 输出测试代码与必要的轻量重构",
|
|
403
|
-
"- 运行结果与覆盖说明",
|
|
404
|
-
].join("\n");
|
|
405
|
-
}
|
|
406
|
-
function buildClarifyingQuestions(args) {
|
|
407
|
-
const questions = [];
|
|
408
|
-
const prompt = (args.userPrompt ?? "").trim();
|
|
409
|
-
const ctx = (args.projectContext ?? "").trim();
|
|
410
|
-
const combined = `${prompt}\n${ctx}`.trim();
|
|
411
|
-
if (!args.framework && !includesAny(combined, ["react", "vue", "angular", "svelte", "next", "nuxt"])) {
|
|
412
|
-
questions.push("你使用的前端框架/运行环境是什么?(React/Vue/Angular/Svelte/Next.js/Nuxt 等)");
|
|
413
|
-
}
|
|
414
|
-
if (!args.techStack) {
|
|
415
|
-
questions.push("项目技术栈有哪些约束?(Vite/Webpack/Next、Node 版本、包管理器、Monorepo 等)");
|
|
416
|
-
}
|
|
417
|
-
if (!args.language && !includesAny(combined, ["typescript", "ts"])) {
|
|
418
|
-
questions.push("代码希望用 TypeScript 还是 JavaScript?");
|
|
419
|
-
}
|
|
420
|
-
if (!args.styling && !includesAny(combined, ["tailwind", "scss", "sass", "css modules", "styled-components", "emotion", "antd", "mui", "chakra"])) {
|
|
421
|
-
questions.push("样式/组件库有要求吗?(Tailwind/CSS Modules/SCSS/Styled-Components/Antd/MUI 等)");
|
|
422
|
-
}
|
|
423
|
-
if (!args.stateManagement && !includesAny(combined, ["redux", "zustand", "recoil", "pinia", "vuex", "mobx"])) {
|
|
424
|
-
questions.push("状态管理方案是什么?(Redux/Zustand/Context/Pinia 等,或无需全局状态)");
|
|
425
|
-
}
|
|
426
|
-
if (!args.router && !includesAny(combined, ["react router", "next", "nuxt", "vue-router"])) {
|
|
427
|
-
questions.push("路由方案是什么?(React Router/Next App Router/Vue Router 等)");
|
|
428
|
-
}
|
|
429
|
-
if (!includesAny(combined, ["api", "接口", "endpoint", "graphql", "rest"])) {
|
|
430
|
-
questions.push("是否需要对接接口?若需要:接口协议(REST/GraphQL)、关键字段、错误码、鉴权方式是什么?");
|
|
431
|
-
}
|
|
432
|
-
if (!includesAny(combined, ["a11y", "accessibility", "无障碍", "aria"])) {
|
|
433
|
-
questions.push("是否需要无障碍(a11y)要求?例如键盘可用、ARIA、对比度、读屏支持等。");
|
|
434
|
-
}
|
|
435
|
-
if (!includesAny(combined, ["responsive", "mobile", "适配", "breakpoint"])) {
|
|
436
|
-
questions.push("需要响应式/移动端适配吗?支持哪些断点与浏览器范围?");
|
|
437
|
-
}
|
|
438
|
-
if (!includesAny(combined, ["test", "jest", "vitest", "cypress", "playwright"])) {
|
|
439
|
-
questions.push("需要测试吗?(单测/组件测试/E2E)使用什么测试框架?");
|
|
440
|
-
}
|
|
441
|
-
if (!args.taskType && !includesAny(combined, ["新功能", "优化", "重构", "bug", "修复", "性能", "ui", "升级", "依赖", "test"])) {
|
|
442
|
-
questions.push("本次属于哪种任务类型?(新功能开发/老功能优化/重构/修复 bug/性能优化/UI 打磨/依赖升级/补测试)");
|
|
443
|
-
}
|
|
444
|
-
return questions;
|
|
445
|
-
}
|
|
446
|
-
function buildOptimizedPromptPackage(args) {
|
|
447
|
-
const outputLanguage = args.outputLanguage ?? "zh";
|
|
448
|
-
const outputFormat = args.outputFormat ?? "both";
|
|
449
|
-
const codeStyle = args.codeStyle ?? "diff";
|
|
450
|
-
const mustAskClarifyingQuestions = args.mustAskClarifyingQuestions ?? true;
|
|
451
|
-
const taskType = args.taskType ?? "new_feature";
|
|
452
|
-
const requireApprovalGates = args.requireApprovalGates ?? true;
|
|
453
|
-
const workflow = buildWorkflowDefinition(args);
|
|
454
|
-
const guardrails = buildFrontendGuardrails(args);
|
|
455
|
-
const clarifyingQuestions = buildClarifyingQuestions(args);
|
|
456
|
-
const system = [];
|
|
457
|
-
system.push(outputLanguage === "zh"
|
|
458
|
-
? "你是资深前端工程师与技术负责人。你的任务是把需求落地为高质量、可维护、可测试的实现方案与代码。"
|
|
459
|
-
: "You are a senior frontend engineer/tech lead. Turn requirements into high-quality, maintainable, testable plans and code.");
|
|
460
|
-
system.push(outputLanguage === "zh"
|
|
461
|
-
? "你必须遵守以下约束:"
|
|
462
|
-
: "You must follow these constraints:");
|
|
463
|
-
for (const g of guardrails)
|
|
464
|
-
system.push(`- ${g}`);
|
|
465
|
-
system.push(outputLanguage === "zh" ? `- 任务类型: ${taskType}` : `- Task type: ${taskType}`);
|
|
466
|
-
system.push(outputLanguage === "zh"
|
|
467
|
-
? `- 审批 gate: ${requireApprovalGates ? "启用(必须停在 gate 等用户同意)" : "关闭(可一次性输出但仍标注 gate)"}`
|
|
468
|
-
: `- Approval gates: ${requireApprovalGates ? "enabled" : "disabled"}`);
|
|
469
|
-
const user = [];
|
|
470
|
-
user.push("## 原始问题");
|
|
471
|
-
user.push(args.userPrompt.trim());
|
|
472
|
-
if (args.projectContext?.trim()) {
|
|
473
|
-
user.push("\n## 项目上下文");
|
|
474
|
-
user.push(args.projectContext.trim());
|
|
475
|
-
}
|
|
476
|
-
user.push("\n## 期望输出");
|
|
477
|
-
user.push(outputLanguage === "zh"
|
|
478
|
-
? "请先产出澄清问题(如果需要),再给出方案与实现。"
|
|
479
|
-
: "Ask clarifying questions if needed, then provide plan and implementation.");
|
|
480
|
-
user.push("\n## 输出格式要求");
|
|
481
|
-
user.push(`- 输出模式: ${outputFormat}`);
|
|
482
|
-
user.push(`- 代码输出方式: ${codeStyle}`);
|
|
483
|
-
user.push("- 必须包含:方案/关键决策/边界情况/错误处理/可访问性/性能注意事项");
|
|
484
|
-
user.push("- 如果需要新增/修改文件:给出文件路径与内容(或给出清晰 diff)");
|
|
485
|
-
user.push("\n## 强制结构化模板");
|
|
486
|
-
user.push(buildStructuredTemplate(args));
|
|
487
|
-
if (mustAskClarifyingQuestions && clarifyingQuestions.length) {
|
|
488
|
-
user.push("\n## 需要你先确认的问题");
|
|
489
|
-
for (const q of clarifyingQuestions)
|
|
490
|
-
user.push(`- ${q}`);
|
|
491
|
-
}
|
|
492
|
-
const messages = [
|
|
493
|
-
{ role: "system", content: system.join("\n") },
|
|
494
|
-
{ role: "user", content: user.join("\n") },
|
|
495
|
-
];
|
|
496
|
-
const optimizedPrompt = messages
|
|
497
|
-
.map((m) => `[${m.role.toUpperCase()}]\n${m.content}`)
|
|
498
|
-
.join("\n\n");
|
|
499
|
-
const checklist = [
|
|
500
|
-
"信息完整性:技术栈/框架/样式方案/状态/路由/接口/兼容性/测试要求",
|
|
501
|
-
"交付物可执行:代码、文件结构、命令、步骤",
|
|
502
|
-
"质量保障:类型/错误处理/边界情况/可访问性/性能",
|
|
503
|
-
"变更控制:不引入不必要依赖;说明权衡与替代方案",
|
|
504
|
-
];
|
|
505
|
-
return {
|
|
506
|
-
optimizedPrompt,
|
|
507
|
-
messages,
|
|
508
|
-
workflow,
|
|
509
|
-
guardrails,
|
|
510
|
-
clarifyingQuestions,
|
|
511
|
-
checklist,
|
|
512
|
-
meta: {
|
|
513
|
-
framework: args.framework ?? null,
|
|
514
|
-
techStack: args.techStack ?? null,
|
|
515
|
-
language: args.language ?? null,
|
|
516
|
-
styling: args.styling ?? null,
|
|
517
|
-
stateManagement: args.stateManagement ?? null,
|
|
518
|
-
router: args.router ?? null,
|
|
519
|
-
taskType,
|
|
520
|
-
requireApprovalGates,
|
|
521
|
-
outputLanguage,
|
|
522
|
-
outputFormat,
|
|
523
|
-
codeStyle,
|
|
524
|
-
},
|
|
525
|
-
};
|
|
526
|
-
}
|
|
527
|
-
function scoreFrontendPrompt(args) {
|
|
528
|
-
const prompt = args.prompt.trim();
|
|
529
|
-
const lower = prompt.toLowerCase();
|
|
530
|
-
const signals = {
|
|
531
|
-
hasContext: prompt.length >= 200 || includesAny(lower, ["背景", "上下文", "context", "existing", "现有"]),
|
|
532
|
-
hasStack: includesAny(lower, ["react", "vue", "angular", "svelte", "next", "nuxt", "vite", "webpack"]),
|
|
533
|
-
hasConstraints: includesAny(lower, ["必须", "禁止", "约束", "constraint", "don\u2019t", "do not", "avoid"]),
|
|
534
|
-
hasDeliverables: includesAny(lower, ["输出", "deliver", "code", "diff", "文件", "file", "目录", "structure"]),
|
|
535
|
-
hasEdgeCases: includesAny(lower, ["边界", "edge", "error", "异常", "fallback", "loading"]),
|
|
536
|
-
hasA11y: includesAny(lower, ["a11y", "accessibility", "aria", "无障碍"]),
|
|
537
|
-
hasPerformance: includesAny(lower, ["performance", "性能", "lcp", "cls", "memo", "virtualize", "debounce"]),
|
|
538
|
-
hasTesting: includesAny(lower, ["test", "jest", "vitest", "cypress", "playwright"]),
|
|
539
|
-
hasGates: includesAny(lower, ["<<<mcp:gate", "<<<mcp:wait", "[gate", "need user approval", "审批", "等待用户", "同意后"]),
|
|
540
|
-
hasScanProject: includesAny(lower, ["scan_project", "项目理解", "目录树", "架构"]),
|
|
541
|
-
hasTemplateSections: includesAny(lower, ["## 0.", "## 1.", "## 2.", "## 3."])
|
|
542
|
-
|| includesAny(lower, ["输出结构(必须严格遵守)"]),
|
|
543
|
-
};
|
|
544
|
-
const breakdown = {
|
|
545
|
-
clarity: clamp((prompt.length >= 80 ? 20 : 10) + (signals.hasDeliverables ? 10 : 0), 0, 30),
|
|
546
|
-
context: clamp((signals.hasContext ? 20 : 8) + (signals.hasStack ? 10 : 0), 0, 30),
|
|
547
|
-
constraints: clamp((signals.hasConstraints ? 18 : 6) + (signals.hasEdgeCases ? 6 : 0), 0, 30),
|
|
548
|
-
qualityBars: clamp((signals.hasA11y ? 5 : 0) + (signals.hasPerformance ? 5 : 0) + (signals.hasTesting ? 5 : 0), 0, 15),
|
|
549
|
-
process: clamp((signals.hasGates ? 8 : 0) + (signals.hasScanProject ? 6 : 0) + (signals.hasTemplateSections ? 6 : 0), 0, 20),
|
|
550
|
-
};
|
|
551
|
-
const score = clamp(breakdown.clarity + breakdown.context + breakdown.constraints + breakdown.qualityBars + breakdown.process, 0, 100);
|
|
552
|
-
const missing = [];
|
|
553
|
-
if (!signals.hasStack)
|
|
554
|
-
missing.push("框架/构建工具/运行环境(React/Vue/Next/Vite 等)");
|
|
555
|
-
if (!signals.hasConstraints)
|
|
556
|
-
missing.push("明确约束(必须/禁止/依赖限制/兼容性范围)");
|
|
557
|
-
if (!signals.hasDeliverables)
|
|
558
|
-
missing.push("明确交付物(要代码/要 diff/要文件结构/要步骤)");
|
|
559
|
-
if (!signals.hasEdgeCases)
|
|
560
|
-
missing.push("边界情况与错误处理(加载态/空态/失败态)");
|
|
561
|
-
if (!signals.hasA11y)
|
|
562
|
-
missing.push("可访问性要求(键盘/ARIA/对比度等)");
|
|
563
|
-
if (!signals.hasPerformance)
|
|
564
|
-
missing.push("性能要求(首屏、列表虚拟化、缓存、避免重复渲染等)");
|
|
565
|
-
if (!signals.hasScanProject)
|
|
566
|
-
missing.push("项目理解步骤(调用 scan_project/总结目录结构/定位相关文件)");
|
|
567
|
-
if (!signals.hasGates)
|
|
568
|
-
missing.push("审批 gate(设计方案/实施计划/验收等节点必须等待用户同意)");
|
|
569
|
-
if (!signals.hasTemplateSections)
|
|
570
|
-
missing.push("结构化模板章节(0/1/2/3... 的固定结构)");
|
|
571
|
-
const suggestions = [
|
|
572
|
-
"补充项目上下文:现有目录结构、关键组件/页面、接口契约、约定(lint/format)",
|
|
573
|
-
"把需求拆成可验收条目:功能点、交互细节、状态流转、异常路径",
|
|
574
|
-
"增加强约束:不新增依赖/必须 TS/必须支持移动端/必须兼容哪些浏览器",
|
|
575
|
-
"指定输出格式:先问澄清问题,再给方案,然后给代码(diff 或文件内容)",
|
|
576
|
-
];
|
|
577
|
-
return {
|
|
578
|
-
score,
|
|
579
|
-
breakdown,
|
|
580
|
-
missing,
|
|
581
|
-
suggestions,
|
|
582
|
-
};
|
|
583
|
-
}
|
|
584
|
-
const server = new Server({
|
|
585
|
-
name: "frontend-prompt-workflow-mcp",
|
|
586
|
-
version: "0.1.0",
|
|
587
|
-
}, {
|
|
588
|
-
capabilities: {
|
|
589
|
-
tools: {},
|
|
590
|
-
},
|
|
591
|
-
});
|
|
592
|
-
server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
593
|
-
return {
|
|
594
|
-
tools: [
|
|
595
|
-
{
|
|
596
|
-
name: "echo",
|
|
597
|
-
description: "Echo back the provided text",
|
|
598
|
-
inputSchema: {
|
|
599
|
-
type: "object",
|
|
600
|
-
properties: {
|
|
601
|
-
text: { type: "string" },
|
|
602
|
-
},
|
|
603
|
-
required: ["text"],
|
|
604
|
-
},
|
|
605
|
-
},
|
|
606
|
-
{
|
|
607
|
-
name: "scan_project",
|
|
608
|
-
description: "Scan project directory tree (read-only) and detect claude.md/CLAUDE.md. Intended for initial architecture understanding.",
|
|
609
|
-
inputSchema: {
|
|
610
|
-
type: "object",
|
|
611
|
-
properties: {
|
|
612
|
-
rootDir: { type: "string" },
|
|
613
|
-
maxDepth: { type: "number" },
|
|
614
|
-
maxEntries: { type: "number" },
|
|
615
|
-
},
|
|
616
|
-
},
|
|
617
|
-
},
|
|
618
|
-
{
|
|
619
|
-
name: "optimize_frontend_prompt",
|
|
620
|
-
description: "Standardize/optimize a raw user question into a frontend-dev prompt package (messages + guardrails + clarifying questions).",
|
|
621
|
-
inputSchema: {
|
|
622
|
-
type: "object",
|
|
623
|
-
properties: {
|
|
624
|
-
userPrompt: { type: "string" },
|
|
625
|
-
projectContext: { type: "string" },
|
|
626
|
-
techStack: { type: "string" },
|
|
627
|
-
framework: { type: "string" },
|
|
628
|
-
language: { type: "string", enum: ["ts", "js"] },
|
|
629
|
-
styling: { type: "string" },
|
|
630
|
-
stateManagement: { type: "string" },
|
|
631
|
-
router: { type: "string" },
|
|
632
|
-
constraints: { type: "array", items: { type: "string" } },
|
|
633
|
-
taskType: {
|
|
634
|
-
type: "string",
|
|
635
|
-
enum: [
|
|
636
|
-
"new_feature",
|
|
637
|
-
"optimize_existing",
|
|
638
|
-
"refactor",
|
|
639
|
-
"bugfix",
|
|
640
|
-
"performance",
|
|
641
|
-
"ui_polish",
|
|
642
|
-
"dependency_upgrade",
|
|
643
|
-
"test_addition",
|
|
644
|
-
],
|
|
645
|
-
},
|
|
646
|
-
outputLanguage: { type: "string", enum: ["zh", "en"] },
|
|
647
|
-
outputFormat: { type: "string", enum: ["step_by_step", "direct", "both"] },
|
|
648
|
-
codeStyle: { type: "string", enum: ["diff", "full_files", "snippets"] },
|
|
649
|
-
mustAskClarifyingQuestions: { type: "boolean" },
|
|
650
|
-
requireApprovalGates: { type: "boolean" },
|
|
651
|
-
},
|
|
652
|
-
required: ["userPrompt"],
|
|
653
|
-
},
|
|
654
|
-
},
|
|
655
|
-
{
|
|
656
|
-
name: "score_frontend_prompt",
|
|
657
|
-
description: "Score a frontend prompt quality and suggest missing info / improvements.",
|
|
658
|
-
inputSchema: {
|
|
659
|
-
type: "object",
|
|
660
|
-
properties: {
|
|
661
|
-
prompt: { type: "string" },
|
|
662
|
-
},
|
|
663
|
-
required: ["prompt"],
|
|
664
|
-
},
|
|
665
|
-
},
|
|
666
|
-
],
|
|
667
|
-
};
|
|
668
|
-
});
|
|
669
|
-
server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
670
|
-
if (request.params.name === "echo") {
|
|
671
|
-
const text = String(request.params.arguments?.text ?? "");
|
|
672
|
-
return {
|
|
673
|
-
content: [
|
|
674
|
-
{
|
|
675
|
-
type: "text",
|
|
676
|
-
text,
|
|
677
|
-
},
|
|
678
|
-
],
|
|
679
|
-
};
|
|
680
|
-
}
|
|
681
|
-
if (request.params.name === "scan_project") {
|
|
682
|
-
const rawArgs = (request.params.arguments ?? {});
|
|
683
|
-
const rootDir = asNonEmptyString(rawArgs.rootDir);
|
|
684
|
-
const maxDepth = typeof rawArgs.maxDepth === "number" ? rawArgs.maxDepth : undefined;
|
|
685
|
-
const maxEntries = typeof rawArgs.maxEntries === "number" ? rawArgs.maxEntries : undefined;
|
|
686
|
-
const result = await scanProject({ rootDir, maxDepth, maxEntries });
|
|
687
|
-
return {
|
|
688
|
-
content: [
|
|
689
|
-
{
|
|
690
|
-
type: "text",
|
|
691
|
-
text: JSON.stringify(result, null, 2),
|
|
692
|
-
},
|
|
693
|
-
],
|
|
694
|
-
};
|
|
695
|
-
}
|
|
696
|
-
if (request.params.name === "optimize_frontend_prompt") {
|
|
697
|
-
const rawArgs = (request.params.arguments ?? {});
|
|
698
|
-
const userPrompt = asNonEmptyString(rawArgs.userPrompt);
|
|
699
|
-
if (!userPrompt) {
|
|
700
|
-
throw new Error("optimize_frontend_prompt: missing required argument 'userPrompt'");
|
|
701
|
-
}
|
|
702
|
-
const args = {
|
|
703
|
-
userPrompt,
|
|
704
|
-
projectContext: asNonEmptyString(rawArgs.projectContext),
|
|
705
|
-
techStack: asNonEmptyString(rawArgs.techStack),
|
|
706
|
-
framework: asNonEmptyString(rawArgs.framework),
|
|
707
|
-
language: asNonEmptyString(rawArgs.language) ?? undefined,
|
|
708
|
-
styling: asNonEmptyString(rawArgs.styling),
|
|
709
|
-
stateManagement: asNonEmptyString(rawArgs.stateManagement),
|
|
710
|
-
router: asNonEmptyString(rawArgs.router),
|
|
711
|
-
constraints: Array.isArray(rawArgs.constraints)
|
|
712
|
-
? rawArgs.constraints.map((x) => String(x)).filter((x) => x.trim().length)
|
|
713
|
-
: undefined,
|
|
714
|
-
taskType: asNonEmptyString(rawArgs.taskType) ?? undefined,
|
|
715
|
-
outputLanguage: asNonEmptyString(rawArgs.outputLanguage) ?? undefined,
|
|
716
|
-
outputFormat: asNonEmptyString(rawArgs.outputFormat) ?? undefined,
|
|
717
|
-
codeStyle: asNonEmptyString(rawArgs.codeStyle) ?? undefined,
|
|
718
|
-
mustAskClarifyingQuestions: typeof rawArgs.mustAskClarifyingQuestions === "boolean" ? rawArgs.mustAskClarifyingQuestions : undefined,
|
|
719
|
-
requireApprovalGates: typeof rawArgs.requireApprovalGates === "boolean" ? rawArgs.requireApprovalGates : undefined,
|
|
720
|
-
};
|
|
721
|
-
const result = buildOptimizedPromptPackage(args);
|
|
722
|
-
return {
|
|
723
|
-
content: [
|
|
724
|
-
{
|
|
725
|
-
type: "text",
|
|
726
|
-
text: JSON.stringify(result, null, 2),
|
|
727
|
-
},
|
|
728
|
-
],
|
|
729
|
-
};
|
|
730
|
-
}
|
|
731
|
-
if (request.params.name === "score_frontend_prompt") {
|
|
732
|
-
const rawArgs = (request.params.arguments ?? {});
|
|
733
|
-
const prompt = asNonEmptyString(rawArgs.prompt);
|
|
734
|
-
if (!prompt) {
|
|
735
|
-
throw new Error("score_frontend_prompt: missing required argument 'prompt'");
|
|
736
|
-
}
|
|
737
|
-
const result = scoreFrontendPrompt({ prompt });
|
|
738
|
-
return {
|
|
739
|
-
content: [
|
|
740
|
-
{
|
|
741
|
-
type: "text",
|
|
742
|
-
text: JSON.stringify(result, null, 2),
|
|
743
|
-
},
|
|
744
|
-
],
|
|
745
|
-
};
|
|
746
|
-
}
|
|
747
|
-
throw new Error(`Unknown tool: ${request.params.name}`);
|
|
748
|
-
});
|
|
749
|
-
const transport = new StdioServerTransport();
|
|
750
|
-
await server.connect(transport);
|
|
1
|
+
export * from "./types.js";
|
|
2
|
+
export * from "./utils.js";
|
|
3
|
+
export { scanProject } from "./skills/scan.js";
|
|
4
|
+
export { buildOptimizedPromptPackage as optimizeFrontendPrompt } from "./skills/optimize.js";
|
|
5
|
+
export { scoreFrontendPrompt } from "./skills/score.js";
|