@devflow-tools/plugin-vue 0.12.6 → 0.13.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/dist/analyzers/debug-reactivity.d.ts +3 -0
- package/dist/analyzers/debug-reactivity.d.ts.map +1 -0
- package/dist/analyzers/debug-reactivity.js +68 -0
- package/dist/analyzers/debug-reactivity.js.map +1 -0
- package/dist/analyzers/diagnose-bug.d.ts +9 -0
- package/dist/analyzers/diagnose-bug.d.ts.map +1 -0
- package/dist/analyzers/diagnose-bug.js +86 -0
- package/dist/analyzers/diagnose-bug.js.map +1 -0
- package/dist/analyzers/types.d.ts +19 -0
- package/dist/analyzers/types.d.ts.map +1 -0
- package/dist/analyzers/types.js +2 -0
- package/dist/analyzers/types.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +1281 -0
- package/dist/index.js.map +1 -0
- package/package.json +2 -2
package/dist/index.js
ADDED
|
@@ -0,0 +1,1281 @@
|
|
|
1
|
+
export const vuePlugin = {
|
|
2
|
+
meta: {
|
|
3
|
+
name: "vue",
|
|
4
|
+
version: "0.1.0",
|
|
5
|
+
description: "Vue 3 专家 — Bug 诊断、Composition API、响应式调试、组件重构",
|
|
6
|
+
icon: "💚",
|
|
7
|
+
tags: ["frontend", "vue", "composition-api", "pinia", "reactive"],
|
|
8
|
+
},
|
|
9
|
+
knowledge: {
|
|
10
|
+
sources: [
|
|
11
|
+
{
|
|
12
|
+
name: "vue-docs",
|
|
13
|
+
urls: [
|
|
14
|
+
"https://vuejs.org/guide/introduction.html",
|
|
15
|
+
"https://vuejs.org/api/",
|
|
16
|
+
"https://pinia.vuejs.org/",
|
|
17
|
+
],
|
|
18
|
+
pluginName: "vue",
|
|
19
|
+
version: "3.4.0",
|
|
20
|
+
},
|
|
21
|
+
],
|
|
22
|
+
},
|
|
23
|
+
memory: {
|
|
24
|
+
project: {
|
|
25
|
+
stack: ["Vue 3", "Composition API", "Pinia", "Vue Router"],
|
|
26
|
+
conventions: [
|
|
27
|
+
{ key: "components", value: "使用 <script setup> 语法糖", source: "manual", confidence: 0.9 },
|
|
28
|
+
{ key: "state", value: "使用 Pinia 进行状态管理", source: "manual", confidence: 0.9 },
|
|
29
|
+
{ key: "naming", value: "组件名使用 PascalCase,文件名使用 kebab-case", source: "manual", confidence: 0.8 },
|
|
30
|
+
{ key: "composables", value: "可复用逻辑抽取为 composables,以 use 开头", source: "manual", confidence: 0.85 },
|
|
31
|
+
],
|
|
32
|
+
},
|
|
33
|
+
global: [
|
|
34
|
+
{
|
|
35
|
+
id: "vue:composition-api",
|
|
36
|
+
source: "vue",
|
|
37
|
+
title: "Composition API 最佳实践",
|
|
38
|
+
content: "使用 ref 管理基本类型,reactive 管理对象。computed 用于派生状态,watch 用于副作用。setup 语法糖中自动导入 ref、reactive 等。",
|
|
39
|
+
embedding: [],
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
id: "vue:reactivity",
|
|
43
|
+
source: "vue",
|
|
44
|
+
title: "响应式系统原理",
|
|
45
|
+
content: "Vue 3 使用 Proxy 实现响应式。ref 和 reactive 创建深层响应式对象。shallowRef 和 shallowReactive 只做浅层响应式。toRaw 获取原始对象。",
|
|
46
|
+
embedding: [],
|
|
47
|
+
},
|
|
48
|
+
{
|
|
49
|
+
id: "vue:performance",
|
|
50
|
+
source: "vue",
|
|
51
|
+
title: "Vue 3 性能优化",
|
|
52
|
+
content: "使用 v-memo 跳过子树更新,v-once 只渲染一次。异步组件减少首屏加载。KeepAlive 缓存组件状态。shallowRef 避免深层响应式开销。",
|
|
53
|
+
embedding: [],
|
|
54
|
+
},
|
|
55
|
+
{
|
|
56
|
+
id: "vue:reactivity-debug",
|
|
57
|
+
source: "vue",
|
|
58
|
+
title: "响应式调试技巧",
|
|
59
|
+
content: "使用 watchEffect 追踪依赖。onRenderTracked/onRenderTriggered 调试渲染。使用 Vue DevTools 查看组件状态和事件。computed 值变化可通过 watch 追踪来源。",
|
|
60
|
+
embedding: [],
|
|
61
|
+
},
|
|
62
|
+
],
|
|
63
|
+
},
|
|
64
|
+
workflow: {
|
|
65
|
+
steps: [],
|
|
66
|
+
templates: [
|
|
67
|
+
// ── Bug 诊断修复 ──
|
|
68
|
+
{
|
|
69
|
+
name: "bug-diagnosis",
|
|
70
|
+
description: "Vue Bug 诊断:报错定位 → 响应式排查 → 修复验证",
|
|
71
|
+
version: "2.0.0",
|
|
72
|
+
steps: [
|
|
73
|
+
{
|
|
74
|
+
id: "capture-error",
|
|
75
|
+
title: "收集错误信息",
|
|
76
|
+
instruction: [
|
|
77
|
+
"## 收集错误信息(堆栈、Vue DevTools 状态、Console)",
|
|
78
|
+
"",
|
|
79
|
+
"完整记录 Bug 的所有表象信息,这是后续诊断的基础。",
|
|
80
|
+
"",
|
|
81
|
+
"**执行动作**:",
|
|
82
|
+
"1. 复制完整的错误堆栈(包括 `message`、`stack`、组件树)",
|
|
83
|
+
"2. 打开浏览器 DevTools → Console,记录所有红色 Error 和黄色 Warning",
|
|
84
|
+
"3. 查看 Vue DevTools:",
|
|
85
|
+
" - **Components 面板**:找到出错组件,查看其 props、emits、state",
|
|
86
|
+
" - **Timeline 面板**:查看组件事件和性能数据",
|
|
87
|
+
" - **Pinia 面板**:查看 Store 状态快照",
|
|
88
|
+
"4. 查看 Network 面板,标记失败请求的 URL、状态码、响应体",
|
|
89
|
+
"5. 记录复现路径:从哪个页面、点击什么按钮、输入什么数据触发",
|
|
90
|
+
"",
|
|
91
|
+
"**产出格式**:",
|
|
92
|
+
"```",
|
|
93
|
+
"error_type: TypeError | ReferenceError | Warn | ...",
|
|
94
|
+
"error_message: <完整的错误消息>",
|
|
95
|
+
"stack_trace: <关键 3 帧>",
|
|
96
|
+
"affected_component: <组件名>",
|
|
97
|
+
"vue_devtools_state: { props: {...}, state: {...} }",
|
|
98
|
+
"repro_steps: [1. 进入页面, 2. 点击按钮, 3. 输入数据]",
|
|
99
|
+
"failed_requests: [{ url, status, response }]",
|
|
100
|
+
"```",
|
|
101
|
+
].join("\n"),
|
|
102
|
+
suggestedTools: ["Read", "Bash"],
|
|
103
|
+
output: "结构化的错误信息清单(error_type, stack_trace, component, repro_steps)",
|
|
104
|
+
},
|
|
105
|
+
{
|
|
106
|
+
id: "locate-component",
|
|
107
|
+
title: "定位出错组件",
|
|
108
|
+
instruction: [
|
|
109
|
+
"## 定位出错组件(通过堆栈和 Vue DevTools 组件树)",
|
|
110
|
+
"",
|
|
111
|
+
"根据上一步收集的堆栈信息,定位到具体的 Vue 组件文件和代码行。",
|
|
112
|
+
"",
|
|
113
|
+
"**执行动作**:",
|
|
114
|
+
"1. 从 `stack_trace` 中提取第一个属于本项目(非 `node_modules`)的帧",
|
|
115
|
+
"2. 解析出文件路径和行号,例如 `src/components/MyComponent.vue:42`",
|
|
116
|
+
"3. 使用 Read 工具读取该 `.vue` 文件,聚焦错误行附近的上下文",
|
|
117
|
+
"4. 在 Vue DevTools 组件树中找到对应组件,确认其父子关系",
|
|
118
|
+
"5. 如果堆栈指向编译产物(`dist/`),通过 sourcemap 或文件名反推源文件",
|
|
119
|
+
"6. 标记出问题函数 / 组件名和相关的 composable",
|
|
120
|
+
"",
|
|
121
|
+
"**判定标准**:",
|
|
122
|
+
"- 找到包含 Bug 触发逻辑的具体组件 / composable",
|
|
123
|
+
"- 能说出该组件在什么条件下走到错误分支",
|
|
124
|
+
"",
|
|
125
|
+
"**产出格式**:",
|
|
126
|
+
"```",
|
|
127
|
+
"source_file: src/components/MyComponent.vue",
|
|
128
|
+
"line_range: 30-50",
|
|
129
|
+
"component_name: MyComponent",
|
|
130
|
+
"script_section: '<script setup lang=\"ts\">'",
|
|
131
|
+
"suspected_cause: 解构了可能为 undefined 的 props.data",
|
|
132
|
+
"```",
|
|
133
|
+
].join("\n"),
|
|
134
|
+
suggestedTools: ["Read", "Bash"],
|
|
135
|
+
output: "问题源文件路径、组件名、可疑代码行",
|
|
136
|
+
depends: ["capture-error"],
|
|
137
|
+
},
|
|
138
|
+
{
|
|
139
|
+
id: "check-reactivity",
|
|
140
|
+
title: "检查响应式数据流",
|
|
141
|
+
instruction: [
|
|
142
|
+
"## 检查响应式数据流(ref/reactive 值是否正确更新)",
|
|
143
|
+
"",
|
|
144
|
+
"排查 Vue 3 响应式数据是否正确更新,这是 Vue Bug 最常见的根因。",
|
|
145
|
+
"",
|
|
146
|
+
"**执行动作**:",
|
|
147
|
+
"1. 检查 `ref` 的使用:",
|
|
148
|
+
" - 在 `<script setup>` 中访问 ref 值是否使用了 `.value`",
|
|
149
|
+
" - 在 `<template>` 中 ref 是否自动解包(不需要 `.value`)",
|
|
150
|
+
" ```bash",
|
|
151
|
+
" grep -n '\\.value' <component_file>",
|
|
152
|
+
" ```",
|
|
153
|
+
"2. 检查 `reactive` 的使用:",
|
|
154
|
+
" - 是否对 reactive 对象进行了破坏性解构(丢失响应式)",
|
|
155
|
+
" - 是否直接替换了 reactive 对象的引用(应该用 Object.assign)",
|
|
156
|
+
" ```bash",
|
|
157
|
+
" grep -n 'const { .* } = reactive\\|const { .* } = props' <component_file>",
|
|
158
|
+
" ```",
|
|
159
|
+
"3. 检查 `computed` 的依赖是否正确追踪:",
|
|
160
|
+
" - computed 内使用的 ref/reactive 是否都是响应式的",
|
|
161
|
+
" - computed 结果是否被意外修改(computed 是只读的)",
|
|
162
|
+
"4. 检查 `watch` / `watchEffect` 的依赖是否正确:",
|
|
163
|
+
" - watch 的 getter 是否返回了响应式引用",
|
|
164
|
+
" - watchEffect 是否追踪了所有需要的依赖",
|
|
165
|
+
"5. 在 Vue DevTools 中观察响应式数据的实时值",
|
|
166
|
+
"",
|
|
167
|
+
"**常见陷阱**:",
|
|
168
|
+
"- `const { count } = props` → 失去响应式,应用 `toRefs(props)`",
|
|
169
|
+
"- `let x = ref(0); x = 1` → 错误!应该 `x.value = 1`",
|
|
170
|
+
"- `reactive(obj) = newObj` → 错误!应该 `Object.assign(obj, newObj)`",
|
|
171
|
+
"",
|
|
172
|
+
"**产出格式**:",
|
|
173
|
+
"```",
|
|
174
|
+
"reactivity_issues: [",
|
|
175
|
+
" { variable: 'count', type: 'ref', issue: '模板中误用了 .value' }",
|
|
176
|
+
"]",
|
|
177
|
+
"data_flow: props → toRefs → localRef → computed → template",
|
|
178
|
+
"```",
|
|
179
|
+
].join("\n"),
|
|
180
|
+
suggestedTools: ["Read", "Bash"],
|
|
181
|
+
output: "响应式数据流问题清单",
|
|
182
|
+
depends: ["locate-component"],
|
|
183
|
+
},
|
|
184
|
+
{
|
|
185
|
+
id: "check-composables",
|
|
186
|
+
title: "排查相关 composable 函数逻辑",
|
|
187
|
+
instruction: [
|
|
188
|
+
"## 排查相关 composable 函数逻辑",
|
|
189
|
+
"",
|
|
190
|
+
"如果 Bug 涉及自定义 composable,深入排查其内部逻辑。",
|
|
191
|
+
"",
|
|
192
|
+
"**执行动作**:",
|
|
193
|
+
"1. 找到组件中使用的所有 composable:",
|
|
194
|
+
" ```bash",
|
|
195
|
+
" grep -n 'use[A-Z]' <component_file>",
|
|
196
|
+
" ```",
|
|
197
|
+
"2. 读取每个 composable 的源码:",
|
|
198
|
+
" ```bash",
|
|
199
|
+
" find src/ -name 'use*.ts' -o -name 'use*.js' | head -20",
|
|
200
|
+
" ```",
|
|
201
|
+
"3. 检查 composable 内部:",
|
|
202
|
+
" - 返回的 ref/reactive 是否保持了响应式",
|
|
203
|
+
" - 生命周期钩子(onMounted, onUnmounted)是否正确使用",
|
|
204
|
+
" - watch 是否在 onUnmounted 时清理",
|
|
205
|
+
" - 是否有竞态条件(异步请求未完成时组件已卸载)",
|
|
206
|
+
"4. 检查 composable 的参数传递是否正确",
|
|
207
|
+
"5. 检查 composable 是否依赖了外部状态(Store、Router)且是否正确注入",
|
|
208
|
+
"",
|
|
209
|
+
"**产出格式**:",
|
|
210
|
+
"```",
|
|
211
|
+
"composables_used: [{ name, file, line }]",
|
|
212
|
+
"composable_issues: [",
|
|
213
|
+
" { composable: 'useCounter', issue: '未在 onUnmounted 清理 watch' }",
|
|
214
|
+
"]",
|
|
215
|
+
"```",
|
|
216
|
+
].join("\n"),
|
|
217
|
+
suggestedTools: ["Read", "Bash"],
|
|
218
|
+
output: "composable 函数问题清单",
|
|
219
|
+
depends: ["locate-component"],
|
|
220
|
+
},
|
|
221
|
+
{
|
|
222
|
+
id: "search-docs",
|
|
223
|
+
title: "搜索 Vue 官方文档中相关 API 用法",
|
|
224
|
+
instruction: [
|
|
225
|
+
"## 搜索 Vue 官方文档中相关 API 用法",
|
|
226
|
+
"",
|
|
227
|
+
"查阅 Vue 官方文档和项目知识库,寻找涉及 API 的正确用法。",
|
|
228
|
+
"",
|
|
229
|
+
"**执行动作**:",
|
|
230
|
+
"1. 根据错误类型提取关键词(如 `watch deep`、`reactive destructuring`、`computed write`)",
|
|
231
|
+
"2. 搜索 Vue 官方文档:",
|
|
232
|
+
" - 响应式 API:ref, reactive, computed, watch, watchEffect",
|
|
233
|
+
" - 生命周期:onMounted, onUpdated, onUnmounted",
|
|
234
|
+
" - 组件通信:props, emits, provide/inject",
|
|
235
|
+
" - Pinia:defineStore, storeToRefs",
|
|
236
|
+
"3. 检查项目 `memory` 中是否有类似 Bug 的历史修复记录",
|
|
237
|
+
"4. 确认使用的 Vue 版本与 API 行为一致",
|
|
238
|
+
"",
|
|
239
|
+
"**产出格式**:",
|
|
240
|
+
"```",
|
|
241
|
+
"knowledge_hits: [",
|
|
242
|
+
" { source: vue-docs, title: '...', url: '...', relevant_section: '...' }",
|
|
243
|
+
"]",
|
|
244
|
+
"api_behavior: <相关 API 的正确行为描述>",
|
|
245
|
+
"```",
|
|
246
|
+
].join("\n"),
|
|
247
|
+
suggestedTools: ["Bash", "Read"],
|
|
248
|
+
output: "相关文档条目、API 正确行为",
|
|
249
|
+
depends: ["capture-error"],
|
|
250
|
+
},
|
|
251
|
+
{
|
|
252
|
+
id: "generate-fix",
|
|
253
|
+
title: "生成修复方案",
|
|
254
|
+
instruction: [
|
|
255
|
+
"## 生成修复方案",
|
|
256
|
+
"",
|
|
257
|
+
"综合所有诊断信息,生成最小化、精准的修复代码。",
|
|
258
|
+
"",
|
|
259
|
+
"**执行动作**:",
|
|
260
|
+
"1. 综合以下输入生成修复方案:",
|
|
261
|
+
" - `locate-component` 的可疑代码",
|
|
262
|
+
" - `check-reactivity` 的响应式问题",
|
|
263
|
+
" - `check-composables` 的 composable 问题",
|
|
264
|
+
" - `search-docs` 的 API 正确用法",
|
|
265
|
+
"2. 使用 Edit 工具精准修改代码(不要整文件重写)",
|
|
266
|
+
"3. 修复原则:",
|
|
267
|
+
" - **最小改动**:只改必须改的代码,不做附带重构",
|
|
268
|
+
" - **响应式正确**:确保 ref/reactive 使用方式正确",
|
|
269
|
+
" - **类型安全**:修复后不能有 `any` 或 `@ts-ignore`",
|
|
270
|
+
"4. 如果涉及多文件修改(组件 + composable),按依赖顺序依次修改",
|
|
271
|
+
"5. 保持 `<script setup>` 语法糖风格",
|
|
272
|
+
"",
|
|
273
|
+
"**产出格式**:",
|
|
274
|
+
"```",
|
|
275
|
+
"fix_summary: 在 useCounter 中修复 ref.value 访问方式",
|
|
276
|
+
"files_changed: [",
|
|
277
|
+
" { path: src/components/Counter.vue, changes: '第 42 行修复 ref 解包' }",
|
|
278
|
+
"]",
|
|
279
|
+
"diff_preview: -const count = props.count",
|
|
280
|
+
" +const count = toRef(props, 'count')",
|
|
281
|
+
"```",
|
|
282
|
+
].join("\n"),
|
|
283
|
+
suggestedTools: ["Read", "Edit"],
|
|
284
|
+
output: "修复代码 diff、修改文件列表、修复说明",
|
|
285
|
+
depends: ["check-reactivity", "check-composables", "search-docs"],
|
|
286
|
+
},
|
|
287
|
+
{
|
|
288
|
+
id: "type-check",
|
|
289
|
+
stepTemplate: "type-check",
|
|
290
|
+
overrides: {
|
|
291
|
+
title: "运行 vue-tsc 类型检查",
|
|
292
|
+
instruction: [
|
|
293
|
+
"## 运行 vue-tsc 类型检查",
|
|
294
|
+
"",
|
|
295
|
+
"验证修复后的代码在类型层面是正确的。",
|
|
296
|
+
"",
|
|
297
|
+
"**执行动作**:",
|
|
298
|
+
"1. 运行 Vue 项目的类型检查命令:",
|
|
299
|
+
" ```bash",
|
|
300
|
+
" npx vue-tsc --noEmit",
|
|
301
|
+
" ```",
|
|
302
|
+
"2. vue-tsc 会同时检查 `.ts` 和 `.vue` 文件的类型",
|
|
303
|
+
"3. 分析输出:",
|
|
304
|
+
" - **无错误**:✅ 类型检查通过",
|
|
305
|
+
" - **有错误**:记录错误位置,返回 `generate-fix` 步骤",
|
|
306
|
+
"4. 注意 `.vue` 文件的类型错误可能来自 template 部分(如 props 类型不匹配)",
|
|
307
|
+
].join("\n"),
|
|
308
|
+
},
|
|
309
|
+
depends: ["generate-fix"],
|
|
310
|
+
},
|
|
311
|
+
{
|
|
312
|
+
id: "verify",
|
|
313
|
+
stepTemplate: "human-review",
|
|
314
|
+
overrides: {
|
|
315
|
+
title: "人工审查确认修复",
|
|
316
|
+
instruction: [
|
|
317
|
+
"## 人工审查确认修复",
|
|
318
|
+
"",
|
|
319
|
+
"将所有诊断结果和修复方案呈现给用户,等待人工确认。",
|
|
320
|
+
"",
|
|
321
|
+
"**呈现给用户的摘要**:",
|
|
322
|
+
"",
|
|
323
|
+
"### 🐛 Vue Bug 诊断报告",
|
|
324
|
+
"",
|
|
325
|
+
"**问题**:<一句话描述 Bug>",
|
|
326
|
+
"**根因**:<响应式 / composable / 类型问题>",
|
|
327
|
+
"**影响范围**:<受影响的组件>",
|
|
328
|
+
"",
|
|
329
|
+
"### 🔧 修复方案",
|
|
330
|
+
"",
|
|
331
|
+
"**修改文件**:",
|
|
332
|
+
"- `src/components/MyComponent.vue` — <修改描述>",
|
|
333
|
+
"",
|
|
334
|
+
"**关键 diff**:",
|
|
335
|
+
"```diff",
|
|
336
|
+
"- const count = props.count",
|
|
337
|
+
"+ const count = toRef(props, 'count')",
|
|
338
|
+
"```",
|
|
339
|
+
"",
|
|
340
|
+
"### ✅ 验证结果",
|
|
341
|
+
"",
|
|
342
|
+
"- vue-tsc 类型检查:✅ 通过",
|
|
343
|
+
"",
|
|
344
|
+
"**等待用户操作**:",
|
|
345
|
+
"- 审查修复代码是否符合业务预期",
|
|
346
|
+
"- 确认后执行 `git commit`",
|
|
347
|
+
"",
|
|
348
|
+
"**注意**:此步骤必须等待用户明确确认后才能继续。",
|
|
349
|
+
].join("\n"),
|
|
350
|
+
},
|
|
351
|
+
depends: ["type-check"],
|
|
352
|
+
},
|
|
353
|
+
],
|
|
354
|
+
triggers: [
|
|
355
|
+
{ type: "cli", command: "bug" },
|
|
356
|
+
{ type: "mcp", tool: "diagnose_bug" },
|
|
357
|
+
],
|
|
358
|
+
},
|
|
359
|
+
// ── 新建组件 ──
|
|
360
|
+
{
|
|
361
|
+
name: "new-component",
|
|
362
|
+
description: "新建 Vue 3 组件(setup 语法 + 类型 + 测试)",
|
|
363
|
+
version: "2.0.0",
|
|
364
|
+
steps: [
|
|
365
|
+
{
|
|
366
|
+
id: "define-props-emits",
|
|
367
|
+
title: "定义 Props 和 Emits 类型接口",
|
|
368
|
+
instruction: [
|
|
369
|
+
"## 定义 Props 和 Emits 类型接口",
|
|
370
|
+
"",
|
|
371
|
+
"使用 TypeScript 的 `defineProps` 和 `defineEmits` 泛型语法定义类型。",
|
|
372
|
+
"",
|
|
373
|
+
"**执行动作**:",
|
|
374
|
+
"1. 分析组件需要的 Props:",
|
|
375
|
+
" - 数据 Props(传入组件的内容)",
|
|
376
|
+
" - 回调 Props(事件处理器,改用 emits)",
|
|
377
|
+
" - 样式 Props(class、style — Vue 自动合并)",
|
|
378
|
+
"2. 使用 `interface` 定义 Props 和 Emits:",
|
|
379
|
+
" ```typescript",
|
|
380
|
+
" interface Props {",
|
|
381
|
+
" /** 数据描述 */",
|
|
382
|
+
" data: DataType[];",
|
|
383
|
+
" /** 是否加载中 */",
|
|
384
|
+
" loading?: boolean;",
|
|
385
|
+
" }",
|
|
386
|
+
"",
|
|
387
|
+
" const props = withDefaults(defineProps<Props>(), {",
|
|
388
|
+
" loading: false,",
|
|
389
|
+
" });",
|
|
390
|
+
"",
|
|
391
|
+
" interface Emits {",
|
|
392
|
+
" (e: 'update', value: string): void;",
|
|
393
|
+
" (e: 'delete', id: number): void;",
|
|
394
|
+
" }",
|
|
395
|
+
"",
|
|
396
|
+
" const emit = defineEmits<Emits>();",
|
|
397
|
+
" ```",
|
|
398
|
+
"3. 必填 Props 在前,可选 Props 在后",
|
|
399
|
+
"4. 为每个 Prop 添加 JSDoc 注释",
|
|
400
|
+
"5. 使用 `withDefaults` 设置默认值",
|
|
401
|
+
"",
|
|
402
|
+
"**产出格式**:",
|
|
403
|
+
"```typescript",
|
|
404
|
+
"interface Props { ... }",
|
|
405
|
+
"interface Emits { ... }",
|
|
406
|
+
"```",
|
|
407
|
+
].join("\n"),
|
|
408
|
+
suggestedTools: ["Read", "Write"],
|
|
409
|
+
output: "TypeScript Props 和 Emits interface 定义",
|
|
410
|
+
},
|
|
411
|
+
{
|
|
412
|
+
id: "create-sfc",
|
|
413
|
+
title: "创建 .vue SFC 文件",
|
|
414
|
+
instruction: [
|
|
415
|
+
"## 创建 .vue SFC 文件(template + script setup + style scoped)",
|
|
416
|
+
"",
|
|
417
|
+
"**执行动作**:",
|
|
418
|
+
"1. 确认项目目录约定:",
|
|
419
|
+
" ```bash",
|
|
420
|
+
" ls -la src/components/ 2>/dev/null",
|
|
421
|
+
" ```",
|
|
422
|
+
"2. 创建 `.vue` 单文件组件,包含三个部分:",
|
|
423
|
+
" ```vue",
|
|
424
|
+
" <template>",
|
|
425
|
+
" <div class=\"my-component\">",
|
|
426
|
+
" <!-- 模板内容 -->",
|
|
427
|
+
" </div>",
|
|
428
|
+
" </template>",
|
|
429
|
+
"",
|
|
430
|
+
" <script setup lang=\"ts\">",
|
|
431
|
+
" // 类型定义",
|
|
432
|
+
" interface Props { ... }",
|
|
433
|
+
" const props = withDefaults(defineProps<Props>(), { ... });",
|
|
434
|
+
" const emit = defineEmits<Emits>();",
|
|
435
|
+
"",
|
|
436
|
+
" // 响应式状态",
|
|
437
|
+
" const count = ref(0);",
|
|
438
|
+
"",
|
|
439
|
+
" // 计算属性",
|
|
440
|
+
" const doubled = computed(() => count.value * 2);",
|
|
441
|
+
"",
|
|
442
|
+
" // 方法",
|
|
443
|
+
" function handleClick() { emit('update', 'clicked'); }",
|
|
444
|
+
"",
|
|
445
|
+
" // 生命周期",
|
|
446
|
+
" onMounted(() => { ... });",
|
|
447
|
+
" </script>",
|
|
448
|
+
"",
|
|
449
|
+
" <style scoped>",
|
|
450
|
+
" .my-component { ... }",
|
|
451
|
+
" </style>",
|
|
452
|
+
" ```",
|
|
453
|
+
"3. 必须使用 `<script setup lang=\"ts\">` 语法糖",
|
|
454
|
+
"4. 必须使用 `<style scoped>` 避免样式污染",
|
|
455
|
+
"5. 遵循 `kebab-case` 文件命名,`PascalCase` 组件名",
|
|
456
|
+
"",
|
|
457
|
+
"**产出格式**:",
|
|
458
|
+
"```",
|
|
459
|
+
"component_file: <path>",
|
|
460
|
+
"has_template: true",
|
|
461
|
+
"has_script_setup: true",
|
|
462
|
+
"has_style_scoped: true",
|
|
463
|
+
"```",
|
|
464
|
+
].join("\n"),
|
|
465
|
+
suggestedTools: ["Read", "Write", "Bash"],
|
|
466
|
+
output: "生成的 .vue SFC 文件",
|
|
467
|
+
depends: ["define-props-emits"],
|
|
468
|
+
},
|
|
469
|
+
{
|
|
470
|
+
id: "create-composable",
|
|
471
|
+
title: "抽取可复用逻辑到 composable",
|
|
472
|
+
instruction: [
|
|
473
|
+
"## 抽取可复用逻辑到 composable",
|
|
474
|
+
"",
|
|
475
|
+
"如果组件中有可复用的逻辑(数据获取、表单处理、UI 状态),抽取为 composable。",
|
|
476
|
+
"",
|
|
477
|
+
"**执行动作**:",
|
|
478
|
+
"1. 识别可抽取的逻辑:",
|
|
479
|
+
" - 数据获取 + loading/error 状态 → `useXxxData`",
|
|
480
|
+
" - 表单验证 + 提交 → `useXxxForm`",
|
|
481
|
+
" - UI 交互(拖拽、滚动) → `useXxxInteraction`",
|
|
482
|
+
"2. 创建 composable 文件:",
|
|
483
|
+
" ```typescript",
|
|
484
|
+
" // src/composables/useCounter.ts",
|
|
485
|
+
" import { ref, computed } from 'vue';",
|
|
486
|
+
"",
|
|
487
|
+
" export function useCounter(initial = 0) {",
|
|
488
|
+
" const count = ref(initial);",
|
|
489
|
+
" const doubled = computed(() => count.value * 2);",
|
|
490
|
+
" function increment() { count.value++; }",
|
|
491
|
+
" function decrement() { count.value--; }",
|
|
492
|
+
" return { count, doubled, increment, decrement };",
|
|
493
|
+
" }",
|
|
494
|
+
" ```",
|
|
495
|
+
"3. composable 命名以 `use` 开头",
|
|
496
|
+
"4. 返回值为对象,包含 ref、computed 和方法",
|
|
497
|
+
"5. 添加完整的 TypeScript 类型",
|
|
498
|
+
"6. 在组件中使用:`const { count, increment } = useCounter()`",
|
|
499
|
+
"",
|
|
500
|
+
"**产出格式**:",
|
|
501
|
+
"```",
|
|
502
|
+
"composables_created: [{ name, file_path, returns: {...} }]",
|
|
503
|
+
"```",
|
|
504
|
+
].join("\n"),
|
|
505
|
+
suggestedTools: ["Read", "Write", "Edit"],
|
|
506
|
+
output: "创建的 composable 函数清单",
|
|
507
|
+
depends: ["create-sfc"],
|
|
508
|
+
},
|
|
509
|
+
{
|
|
510
|
+
id: "type-check",
|
|
511
|
+
stepTemplate: "type-check",
|
|
512
|
+
overrides: {
|
|
513
|
+
title: "运行 vue-tsc 类型检查",
|
|
514
|
+
instruction: [
|
|
515
|
+
"## 运行 vue-tsc 类型检查",
|
|
516
|
+
"",
|
|
517
|
+
"**执行动作**:",
|
|
518
|
+
"1. 运行 `npx vue-tsc --noEmit`",
|
|
519
|
+
"2. 确认 `.vue` 文件的 template 和 script 部分都通过类型检查",
|
|
520
|
+
"3. 特别检查 Props 类型、Emits 类型、composable 返回值类型",
|
|
521
|
+
].join("\n"),
|
|
522
|
+
},
|
|
523
|
+
depends: ["create-sfc"],
|
|
524
|
+
},
|
|
525
|
+
{
|
|
526
|
+
id: "create-tests",
|
|
527
|
+
title: "生成 Vitest + @vue/test-utils 测试",
|
|
528
|
+
instruction: [
|
|
529
|
+
"## 生成 Vitest + @vue/test-utils 测试",
|
|
530
|
+
"",
|
|
531
|
+
"**执行动作**:",
|
|
532
|
+
"1. 确认测试框架配置:",
|
|
533
|
+
" ```bash",
|
|
534
|
+
" cat package.json | grep -i 'vitest\\|test-utils'",
|
|
535
|
+
" ```",
|
|
536
|
+
"2. 创建测试文件 `XxxComponent.test.ts`:",
|
|
537
|
+
" ```typescript",
|
|
538
|
+
" import { describe, it, expect } from 'vitest';",
|
|
539
|
+
" import { mount } from '@vue/test-utils';",
|
|
540
|
+
" import XxxComponent from './XxxComponent.vue';",
|
|
541
|
+
"",
|
|
542
|
+
" describe('XxxComponent', () => {",
|
|
543
|
+
" it('renders correctly with default props', () => {",
|
|
544
|
+
" const wrapper = mount(XxxComponent, { props: { data: [] } });",
|
|
545
|
+
" expect(wrapper.find('.my-component').exists()).toBe(true);",
|
|
546
|
+
" });",
|
|
547
|
+
" it('emits update event on click', async () => {",
|
|
548
|
+
" const wrapper = mount(XxxComponent, { props: { data: [] } });",
|
|
549
|
+
" await wrapper.find('button').trigger('click');",
|
|
550
|
+
" expect(wrapper.emitted('update')).toBeTruthy();",
|
|
551
|
+
" });",
|
|
552
|
+
" });",
|
|
553
|
+
" ```",
|
|
554
|
+
"3. 测试覆盖:",
|
|
555
|
+
" - **渲染测试**:默认 Props 下组件正确渲染",
|
|
556
|
+
" - **Props 测试**:不同 Props 组合的渲染结果",
|
|
557
|
+
" - **事件测试**:用户操作触发正确 emits",
|
|
558
|
+
" - **边界测试**:空数据、loading 状态",
|
|
559
|
+
"4. 使用 `mount` 完整挂载或 `shallowMount` 浅渲染",
|
|
560
|
+
"5. Mock 策略:Pinia Store 使用 `createTestingPinia`,Router 使用 `createRouter` + `createMemoryHistory`",
|
|
561
|
+
"",
|
|
562
|
+
"**产出格式**:",
|
|
563
|
+
"```",
|
|
564
|
+
"test_file: <path>",
|
|
565
|
+
"test_count: <N>",
|
|
566
|
+
"test_cases: [{ describe: '...', it: '...' }]",
|
|
567
|
+
"```",
|
|
568
|
+
].join("\n"),
|
|
569
|
+
suggestedTools: ["Bash", "Read", "Write"],
|
|
570
|
+
output: "创建的测试文件",
|
|
571
|
+
depends: ["create-sfc"],
|
|
572
|
+
},
|
|
573
|
+
{
|
|
574
|
+
id: "run-tests",
|
|
575
|
+
stepTemplate: "run-tests",
|
|
576
|
+
depends: ["create-tests", "type-check"],
|
|
577
|
+
},
|
|
578
|
+
],
|
|
579
|
+
triggers: [
|
|
580
|
+
{ type: "cli", command: "new:component" },
|
|
581
|
+
{ type: "mcp", tool: "new_component" },
|
|
582
|
+
],
|
|
583
|
+
},
|
|
584
|
+
// ── 响应式调试 ──
|
|
585
|
+
{
|
|
586
|
+
name: "reactivity-debug",
|
|
587
|
+
description: "响应式调试:追踪数据流 → 定位问题 → 修复",
|
|
588
|
+
version: "2.0.0",
|
|
589
|
+
steps: [
|
|
590
|
+
{
|
|
591
|
+
id: "trace-data-flow",
|
|
592
|
+
title: "通过 watchEffect / DevTools 追踪数据变更链路",
|
|
593
|
+
instruction: [
|
|
594
|
+
"## 通过 watchEffect / DevTools 追踪数据变更链路",
|
|
595
|
+
"",
|
|
596
|
+
"**执行动作**:",
|
|
597
|
+
"1. 使用 Vue DevTools 的 Timeline 面板:",
|
|
598
|
+
" - 观察组件的 `setup` 执行时间点",
|
|
599
|
+
" - 查看 `watch` 回调触发时间线",
|
|
600
|
+
" - 追踪 `computed` 重新计算的触发链",
|
|
601
|
+
"2. 在代码中添加临时 `watchEffect` 追踪数据变更:",
|
|
602
|
+
" ```typescript",
|
|
603
|
+
" // 临时追踪代码(调试后删除)",
|
|
604
|
+
" watchEffect(() => {",
|
|
605
|
+
" console.log('[trace] target value:', JSON.stringify(targetRef.value));",
|
|
606
|
+
" });",
|
|
607
|
+
" ```",
|
|
608
|
+
"3. 使用 `onRenderTriggered` 调试渲染触发:",
|
|
609
|
+
" ```typescript",
|
|
610
|
+
" onRenderTriggered((event) => {",
|
|
611
|
+
" console.log('[render-triggered]', event.key, event.type);",
|
|
612
|
+
" });",
|
|
613
|
+
" ```",
|
|
614
|
+
"4. 使用 `onRenderTracked` 查看渲染依赖:",
|
|
615
|
+
" ```typescript",
|
|
616
|
+
" onRenderTracked((event) => {",
|
|
617
|
+
" console.log('[render-tracked]', event.key, event.target);",
|
|
618
|
+
" });",
|
|
619
|
+
" ```",
|
|
620
|
+
"5. 检查 Pinia Store 中的数据流向:",
|
|
621
|
+
" ```bash",
|
|
622
|
+
" grep -rn 'useXxxStore' src/ --include='*.vue' --include='*.ts'",
|
|
623
|
+
" ```",
|
|
624
|
+
"",
|
|
625
|
+
"**产出格式**:",
|
|
626
|
+
"```",
|
|
627
|
+
"data_flow_trace: [",
|
|
628
|
+
" { source: 'Pinia Store → user.name', target: 'UserProfile.vue', reactivity: 'intact'|'broken' }",
|
|
629
|
+
"]",
|
|
630
|
+
"triggered_renders: [{ key, type, component }]",
|
|
631
|
+
"```",
|
|
632
|
+
].join("\n"),
|
|
633
|
+
suggestedTools: ["Read", "Bash"],
|
|
634
|
+
output: "数据变更追踪结果、渲染触发链",
|
|
635
|
+
},
|
|
636
|
+
{
|
|
637
|
+
id: "check-ref-unwrap",
|
|
638
|
+
title: "检查 ref 解包是否正确",
|
|
639
|
+
instruction: [
|
|
640
|
+
"## 检查 ref 解包是否正确(模板中自动解包,JS 中需要 .value)",
|
|
641
|
+
"",
|
|
642
|
+
"**检查项**:",
|
|
643
|
+
"1. 在 `<template>` 中:",
|
|
644
|
+
" - ref 自动解包,不需要 `.value`",
|
|
645
|
+
" - 错误:`{{ count.value }}` — template 中不需要 .value",
|
|
646
|
+
" - 正确:`{{ count }}`",
|
|
647
|
+
"2. 在 `<script setup>` 中:",
|
|
648
|
+
" - 必须使用 `.value` 访问 ref 值",
|
|
649
|
+
" - 错误:`console.log(count)` — 打印的是 Ref 对象",
|
|
650
|
+
" - 正确:`console.log(count.value)`",
|
|
651
|
+
"3. 在 `reactive` 对象中:",
|
|
652
|
+
" - ref 作为 reactive 属性时自动解包",
|
|
653
|
+
" - 但如果从 reactive 中解构出来,则失去 ref 特性",
|
|
654
|
+
"4. 在 `computed` 中:",
|
|
655
|
+
" - getter 中访问 ref 需要 `.value`",
|
|
656
|
+
" - 返回的 computed 本身是 ref",
|
|
657
|
+
"",
|
|
658
|
+
"**执行方式**:",
|
|
659
|
+
"```bash",
|
|
660
|
+
"grep -n '\\.value' <component_file>",
|
|
661
|
+
"```",
|
|
662
|
+
"",
|
|
663
|
+
"**产出格式**:",
|
|
664
|
+
"```",
|
|
665
|
+
"ref_issues: [",
|
|
666
|
+
" { file: '...', line: N, issue: 'template 中误用 .value', fix: '移除 .value' }",
|
|
667
|
+
"]",
|
|
668
|
+
"```",
|
|
669
|
+
].join("\n"),
|
|
670
|
+
suggestedTools: ["Read", "Bash"],
|
|
671
|
+
output: "ref 解包问题清单",
|
|
672
|
+
},
|
|
673
|
+
{
|
|
674
|
+
id: "check-computed-cache",
|
|
675
|
+
title: "检查 computed 缓存是否按预期工作",
|
|
676
|
+
instruction: [
|
|
677
|
+
"## 检查 computed 缓存是否按预期工作",
|
|
678
|
+
"",
|
|
679
|
+
"**检查项**:",
|
|
680
|
+
"1. computed 的依赖是否都是响应式的(非响应式依赖不会触发更新)",
|
|
681
|
+
"2. computed 是否有副作用(computed 应该是纯函数)",
|
|
682
|
+
"3. computed 的 getter 是否访问了正确的响应式引用",
|
|
683
|
+
"4. 检查是否有 computed 嵌套导致的性能问题",
|
|
684
|
+
"",
|
|
685
|
+
"**执行方式**:",
|
|
686
|
+
"```bash",
|
|
687
|
+
"# 找到所有 computed 定义",
|
|
688
|
+
"grep -n 'computed(' <component_file> -A 3",
|
|
689
|
+
"```",
|
|
690
|
+
"",
|
|
691
|
+
"**常见陷阱**:",
|
|
692
|
+
"- computed 内访问了非响应式变量(如普通 let)→ 不会更新",
|
|
693
|
+
"- computed 返回新对象 → 每次都是新引用,下游 watch 会重复触发",
|
|
694
|
+
"- computed 内修改了其他状态 → 违反纯函数原则",
|
|
695
|
+
"",
|
|
696
|
+
"**产出格式**:",
|
|
697
|
+
"```",
|
|
698
|
+
"computed_issues: [",
|
|
699
|
+
" { name: 'fullName', issue: '依赖了非响应式的 let 变量' }",
|
|
700
|
+
"]",
|
|
701
|
+
"```",
|
|
702
|
+
].join("\n"),
|
|
703
|
+
suggestedTools: ["Read", "Bash"],
|
|
704
|
+
output: "computed 缓存问题清单",
|
|
705
|
+
},
|
|
706
|
+
{
|
|
707
|
+
id: "check-watch-deps",
|
|
708
|
+
title: "检查 watch/watchEffect 依赖追踪是否正确",
|
|
709
|
+
instruction: [
|
|
710
|
+
"## 检查 watch/watchEffect 依赖追踪是否正确",
|
|
711
|
+
"",
|
|
712
|
+
"**检查项**:",
|
|
713
|
+
"1. `watch` 的源(source)是否正确:",
|
|
714
|
+
" - watch(ref) → 正确",
|
|
715
|
+
" - watch(() => obj.prop) → 正确(getter 函数)",
|
|
716
|
+
" - watch(obj.prop) → 错误!需要 getter 函数",
|
|
717
|
+
"2. `watch` 的 `deep` 选项是否合理:",
|
|
718
|
+
" - 监听深层对象变化需要 `{ deep: true }`",
|
|
719
|
+
" - 但 deep watch 性能开销大,考虑是否用 computed 替代",
|
|
720
|
+
"3. `watchEffect` 是否追踪了所有需要的依赖:",
|
|
721
|
+
" - watchEffect 自动追踪同步依赖",
|
|
722
|
+
" - 异步回调(setTimeout/Promise)中的依赖不会被追踪",
|
|
723
|
+
"4. `watch` 的 `immediate` 选项是否需要",
|
|
724
|
+
"5. `watch` 的清理函数是否在 `onCleanup` 中正确执行",
|
|
725
|
+
"",
|
|
726
|
+
"**执行方式**:",
|
|
727
|
+
"```bash",
|
|
728
|
+
"grep -n 'watch\\|watchEffect' <component_file> -A 5",
|
|
729
|
+
"```",
|
|
730
|
+
"",
|
|
731
|
+
"**产出格式**:",
|
|
732
|
+
"```",
|
|
733
|
+
"watch_issues: [",
|
|
734
|
+
" { line: N, type: 'watch', issue: '源是 obj.prop 而非 getter 函数', fix: '改为 () => obj.prop' }",
|
|
735
|
+
"]",
|
|
736
|
+
"```",
|
|
737
|
+
].join("\n"),
|
|
738
|
+
suggestedTools: ["Read", "Bash"],
|
|
739
|
+
output: "watch/watchEffect 依赖问题清单",
|
|
740
|
+
},
|
|
741
|
+
{
|
|
742
|
+
id: "diagnose",
|
|
743
|
+
title: "综合诊断响应式问题",
|
|
744
|
+
instruction: [
|
|
745
|
+
"## 综合诊断响应式问题",
|
|
746
|
+
"",
|
|
747
|
+
"汇总所有追踪和检查结果,确定响应式问题的根因。",
|
|
748
|
+
"",
|
|
749
|
+
"**诊断清单**:",
|
|
750
|
+
"1. 数据流追踪结果(`trace-data-flow`)",
|
|
751
|
+
"2. ref 解包问题(`check-ref-unwrap`)",
|
|
752
|
+
"3. computed 缓存问题(`check-computed-cache`)",
|
|
753
|
+
"4. watch 依赖问题(`check-watch-deps`)",
|
|
754
|
+
"",
|
|
755
|
+
"**产出格式**:",
|
|
756
|
+
"```",
|
|
757
|
+
"root_cause: <一句话描述>",
|
|
758
|
+
"affected_files: [{ path, issues: [...] }]",
|
|
759
|
+
"fix_strategy: <修复思路>",
|
|
760
|
+
"```",
|
|
761
|
+
].join("\n"),
|
|
762
|
+
suggestedTools: ["Read"],
|
|
763
|
+
output: "响应式问题根因分析",
|
|
764
|
+
depends: ["trace-data-flow", "check-ref-unwrap", "check-computed-cache", "check-watch-deps"],
|
|
765
|
+
},
|
|
766
|
+
{
|
|
767
|
+
id: "fix-reactivity",
|
|
768
|
+
title: "修复响应式问题",
|
|
769
|
+
instruction: [
|
|
770
|
+
"## 修复响应式问题",
|
|
771
|
+
"",
|
|
772
|
+
"根据 `diagnose` 的根因分析,精准修复响应式问题。",
|
|
773
|
+
"",
|
|
774
|
+
"**修复策略**:",
|
|
775
|
+
"1. **ref 解包问题** → 修正 `.value` 使用或改用 `toRefs`",
|
|
776
|
+
"2. **reactive 解构问题** → 使用 `toRefs(reactiveObj)` 后再解构",
|
|
777
|
+
"3. **computed 依赖问题** → 确保依赖为响应式引用",
|
|
778
|
+
"4. **watch 源问题** → 改用 getter 函数 `() => obj.prop`",
|
|
779
|
+
"5. **props 响应式丢失** → 使用 `toRef(props, 'name')` 或 `toRefs(props)`",
|
|
780
|
+
"",
|
|
781
|
+
"**执行方式**:使用 Edit 工具精准修改",
|
|
782
|
+
"",
|
|
783
|
+
"**产出格式**:",
|
|
784
|
+
"```",
|
|
785
|
+
"fixes_applied: [{ file, line, before: '...', after: '...' }]",
|
|
786
|
+
"```",
|
|
787
|
+
].join("\n"),
|
|
788
|
+
suggestedTools: ["Read", "Edit"],
|
|
789
|
+
output: "修复的 diff 列表",
|
|
790
|
+
depends: ["diagnose"],
|
|
791
|
+
},
|
|
792
|
+
{
|
|
793
|
+
id: "verify-fix",
|
|
794
|
+
title: "验证响应式行为恢复正常",
|
|
795
|
+
instruction: [
|
|
796
|
+
"## 验证响应式行为恢复正常",
|
|
797
|
+
"",
|
|
798
|
+
"**执行动作**:",
|
|
799
|
+
"1. 运行 `npx vue-tsc --noEmit` 确认类型正确",
|
|
800
|
+
"2. 删除调试用的 `watchEffect` / `onRenderTriggered` 代码",
|
|
801
|
+
"3. 运行测试确认无回归:`npm test`",
|
|
802
|
+
"4. 在浏览器中验证:",
|
|
803
|
+
" - 数据变更后 UI 是否正确更新",
|
|
804
|
+
" - Vue DevTools 中响应式数据是否正确",
|
|
805
|
+
" - 无多余的渲染触发(性能正常)",
|
|
806
|
+
"",
|
|
807
|
+
"**产出格式**:",
|
|
808
|
+
"```",
|
|
809
|
+
"type_check: passed | failed",
|
|
810
|
+
"tests: passed | failed",
|
|
811
|
+
"reactivity_restored: true | false",
|
|
812
|
+
"extra_renders_fixed: true | false",
|
|
813
|
+
"```",
|
|
814
|
+
].join("\n"),
|
|
815
|
+
suggestedTools: ["Bash", "Read"],
|
|
816
|
+
output: "验证结果",
|
|
817
|
+
depends: ["fix-reactivity"],
|
|
818
|
+
},
|
|
819
|
+
],
|
|
820
|
+
triggers: [
|
|
821
|
+
{ type: "cli", command: "debug:reactivity" },
|
|
822
|
+
{ type: "mcp", tool: "debug_reactivity" },
|
|
823
|
+
],
|
|
824
|
+
},
|
|
825
|
+
// ── Composable 提取 ──
|
|
826
|
+
{
|
|
827
|
+
name: "composable-extract",
|
|
828
|
+
description: "提取 Composable:识别重复逻辑 → 抽取 → 替换引用",
|
|
829
|
+
version: "2.0.0",
|
|
830
|
+
steps: [
|
|
831
|
+
{
|
|
832
|
+
id: "scan-duplication",
|
|
833
|
+
title: "扫描组件内可复用逻辑",
|
|
834
|
+
instruction: [
|
|
835
|
+
"## 扫描组件内可复用逻辑(重复的 ref/watch/computed 模式)",
|
|
836
|
+
"",
|
|
837
|
+
"**执行动作**:",
|
|
838
|
+
"1. 扫描所有组件文件,统计常见的逻辑模式:",
|
|
839
|
+
" ```bash",
|
|
840
|
+
" find src/ -name '*.vue' | head -50",
|
|
841
|
+
" ```",
|
|
842
|
+
"2. 查找重复的 ref 模式:",
|
|
843
|
+
" ```bash",
|
|
844
|
+
" # 数据加载模式",
|
|
845
|
+
" grep -rn 'const loading = ref(false)' src/ --include='*.vue'",
|
|
846
|
+
" grep -rn 'const error = ref(null)' src/ --include='*.vue'",
|
|
847
|
+
" grep -rn 'const data = ref(' src/ --include='*.vue'",
|
|
848
|
+
" ```",
|
|
849
|
+
"3. 查找重复的 watch 模式:",
|
|
850
|
+
" ```bash",
|
|
851
|
+
" # 表单验证模式",
|
|
852
|
+
" grep -rn 'watch(.*formData\\|watch(.*form' src/ --include='*.vue'",
|
|
853
|
+
" # 路由监听模式",
|
|
854
|
+
" grep -rn 'watch(.*route\\|watch(.*\\$route' src/ --include='*.vue'",
|
|
855
|
+
" ```",
|
|
856
|
+
"4. 查找重复的 computed 模式:",
|
|
857
|
+
" ```bash",
|
|
858
|
+
" grep -rn 'computed(' src/ --include='*.vue' | head -30",
|
|
859
|
+
" ```",
|
|
860
|
+
"5. 查找重复的生命周期模式:",
|
|
861
|
+
" ```bash",
|
|
862
|
+
" grep -rn 'onMounted\\|onUnmounted' src/ --include='*.vue' | head -30",
|
|
863
|
+
" ```",
|
|
864
|
+
"",
|
|
865
|
+
"**产出格式**:",
|
|
866
|
+
"```",
|
|
867
|
+
"duplicate_patterns: [",
|
|
868
|
+
" { pattern: 'data loading', count: 8, files: ['...'], logic: 'ref + onMounted + fetch' }",
|
|
869
|
+
"]",
|
|
870
|
+
"```",
|
|
871
|
+
].join("\n"),
|
|
872
|
+
suggestedTools: ["Bash", "Read"],
|
|
873
|
+
output: "重复逻辑模式清单",
|
|
874
|
+
},
|
|
875
|
+
{
|
|
876
|
+
id: "identify-candidates",
|
|
877
|
+
title: "识别可抽取为 composable 的逻辑块",
|
|
878
|
+
instruction: [
|
|
879
|
+
"## 识别可抽取为 composable 的逻辑块",
|
|
880
|
+
"",
|
|
881
|
+
"**判定标准**:",
|
|
882
|
+
"1. **出现次数 ≥ 2** — 至少在 2 个组件中有相同逻辑",
|
|
883
|
+
"2. **逻辑独立** — 可以独立于组件 UI 运行",
|
|
884
|
+
"3. **有明确的输入/输出** — 参数和返回值清晰",
|
|
885
|
+
"4. **包含响应式状态** — 使用了 ref、reactive、computed 等",
|
|
886
|
+
"",
|
|
887
|
+
"**常见可抽取模式**:",
|
|
888
|
+
"- `useDataFetch(url)` — 数据加载 + loading + error",
|
|
889
|
+
"- `useFormValidation(schema)` — 表单验证逻辑",
|
|
890
|
+
"- `useLocalStorage(key, default)` — 本地存储读写",
|
|
891
|
+
"- `useMediaQuery(query)` — 响应式媒体查询",
|
|
892
|
+
"- `useIntersectionObserver(target)` — 交叉观察器",
|
|
893
|
+
"- `useDebounce(value, delay)` — 防抖值",
|
|
894
|
+
"",
|
|
895
|
+
"**产出格式**:",
|
|
896
|
+
"```",
|
|
897
|
+
"composable_candidates: [",
|
|
898
|
+
" { name: 'useDataFetch', pattern: 'data loading', files: [...], params: 'url: string', returns: '{ data, loading, error, refetch }' }",
|
|
899
|
+
"]",
|
|
900
|
+
"```",
|
|
901
|
+
].join("\n"),
|
|
902
|
+
suggestedTools: ["Read", "Bash"],
|
|
903
|
+
output: "composable 抽取候选清单",
|
|
904
|
+
depends: ["scan-duplication"],
|
|
905
|
+
},
|
|
906
|
+
{
|
|
907
|
+
id: "extract-composable",
|
|
908
|
+
title: "生成 composable 函数",
|
|
909
|
+
instruction: [
|
|
910
|
+
"## 生成 composable 函数(类型安全、清理函数完整)",
|
|
911
|
+
"",
|
|
912
|
+
"**执行动作**:",
|
|
913
|
+
"1. 为每个候选创建 composable 文件:",
|
|
914
|
+
" ```bash",
|
|
915
|
+
" # 确认 composable 目录",
|
|
916
|
+
" ls -la src/composables/ 2>/dev/null || echo 'Create src/composables/'",
|
|
917
|
+
" ```",
|
|
918
|
+
"2. composable 编写规范:",
|
|
919
|
+
" ```typescript",
|
|
920
|
+
" // src/composables/useDataFetch.ts",
|
|
921
|
+
" import { ref, onMounted, onUnmounted } from 'vue';",
|
|
922
|
+
" import type { Ref } from 'vue';",
|
|
923
|
+
"",
|
|
924
|
+
" interface UseDataFetchOptions {",
|
|
925
|
+
" immediate?: boolean;",
|
|
926
|
+
" }",
|
|
927
|
+
"",
|
|
928
|
+
" export function useDataFetch<T>(url: string, options: UseDataFetchOptions = {}) {",
|
|
929
|
+
" const data = ref<T | null>(null) as Ref<T | null>;",
|
|
930
|
+
" const loading = ref(false);",
|
|
931
|
+
" const error = ref<Error | null>(null);",
|
|
932
|
+
" const controller = new AbortController();",
|
|
933
|
+
"",
|
|
934
|
+
" async function fetchData() {",
|
|
935
|
+
" loading.value = true;",
|
|
936
|
+
" error.value = null;",
|
|
937
|
+
" try {",
|
|
938
|
+
" const res = await fetch(url, { signal: controller.signal });",
|
|
939
|
+
" data.value = await res.json() as T;",
|
|
940
|
+
" } catch (e) {",
|
|
941
|
+
" error.value = e as Error;",
|
|
942
|
+
" } finally {",
|
|
943
|
+
" loading.value = false;",
|
|
944
|
+
" }",
|
|
945
|
+
" }",
|
|
946
|
+
"",
|
|
947
|
+
" onUnmounted(() => controller.abort());",
|
|
948
|
+
"",
|
|
949
|
+
" if (options.immediate !== false) onMounted(fetchData);",
|
|
950
|
+
"",
|
|
951
|
+
" return { data, loading, error, refetch: fetchData };",
|
|
952
|
+
" }",
|
|
953
|
+
" ```",
|
|
954
|
+
"3. 必须有完整的 TypeScript 泛型类型",
|
|
955
|
+
"4. 必须在 `onUnmounted` 中清理副作用",
|
|
956
|
+
"5. 返回值使用对象形式",
|
|
957
|
+
"",
|
|
958
|
+
"**产出格式**:",
|
|
959
|
+
"```",
|
|
960
|
+
"composables_created: [{ name, file_path, params: {...}, returns: {...} }]",
|
|
961
|
+
"```",
|
|
962
|
+
].join("\n"),
|
|
963
|
+
suggestedTools: ["Read", "Write", "Bash"],
|
|
964
|
+
output: "创建的 composable 函数",
|
|
965
|
+
depends: ["identify-candidates"],
|
|
966
|
+
},
|
|
967
|
+
{
|
|
968
|
+
id: "update-consumers",
|
|
969
|
+
title: "替换原有组件中的内联逻辑为 composable 调用",
|
|
970
|
+
instruction: [
|
|
971
|
+
"## 替换原有组件中的内联逻辑为 composable 调用",
|
|
972
|
+
"",
|
|
973
|
+
"**执行动作**:",
|
|
974
|
+
"1. 对每个使用了重复逻辑的组件:",
|
|
975
|
+
" - 使用 Edit 工具替换内联逻辑为 composable 调用",
|
|
976
|
+
" - 删除不再需要的 import(ref, onMounted 等,如果已不需要)",
|
|
977
|
+
" - 添加 composable 的 import",
|
|
978
|
+
"2. 替换示例:",
|
|
979
|
+
" ```typescript",
|
|
980
|
+
" // Before",
|
|
981
|
+
" const data = ref(null);",
|
|
982
|
+
" const loading = ref(false);",
|
|
983
|
+
" const error = ref(null);",
|
|
984
|
+
" onMounted(async () => { ... fetch logic ... });",
|
|
985
|
+
"",
|
|
986
|
+
" // After",
|
|
987
|
+
" const { data, loading, error } = useDataFetch('/api/items');",
|
|
988
|
+
" ```",
|
|
989
|
+
"3. 确保替换后组件行为不变",
|
|
990
|
+
"4. 更新 import 路径",
|
|
991
|
+
"",
|
|
992
|
+
"**产出格式**:",
|
|
993
|
+
"```",
|
|
994
|
+
"consumers_updated: [{ file, composable: 'useDataFetch', lines_changed: N }]",
|
|
995
|
+
"```",
|
|
996
|
+
].join("\n"),
|
|
997
|
+
suggestedTools: ["Read", "Edit"],
|
|
998
|
+
output: "更新的组件清单",
|
|
999
|
+
depends: ["extract-composable"],
|
|
1000
|
+
},
|
|
1001
|
+
{
|
|
1002
|
+
id: "type-check",
|
|
1003
|
+
stepTemplate: "type-check",
|
|
1004
|
+
overrides: {
|
|
1005
|
+
title: "运行 vue-tsc 类型检查",
|
|
1006
|
+
instruction: [
|
|
1007
|
+
"## 运行 vue-tsc 类型检查",
|
|
1008
|
+
"",
|
|
1009
|
+
"**执行动作**:",
|
|
1010
|
+
"1. 运行 `npx vue-tsc --noEmit`",
|
|
1011
|
+
"2. 确认 composable 泛型和组件调用处类型都正确",
|
|
1012
|
+
].join("\n"),
|
|
1013
|
+
},
|
|
1014
|
+
depends: ["update-consumers"],
|
|
1015
|
+
},
|
|
1016
|
+
{
|
|
1017
|
+
id: "regression-test",
|
|
1018
|
+
stepTemplate: "run-tests",
|
|
1019
|
+
overrides: {
|
|
1020
|
+
title: "运行回归测试",
|
|
1021
|
+
instruction: [
|
|
1022
|
+
"## 运行回归测试",
|
|
1023
|
+
"",
|
|
1024
|
+
"**执行动作**:",
|
|
1025
|
+
"1. 运行与修改组件相关的测试",
|
|
1026
|
+
"2. 运行完整测试套件确认无回归",
|
|
1027
|
+
"3. 如果 composable 有独立测试,也一并运行",
|
|
1028
|
+
].join("\n"),
|
|
1029
|
+
},
|
|
1030
|
+
depends: ["type-check"],
|
|
1031
|
+
},
|
|
1032
|
+
],
|
|
1033
|
+
triggers: [
|
|
1034
|
+
{ type: "cli", command: "extract:composable" },
|
|
1035
|
+
],
|
|
1036
|
+
},
|
|
1037
|
+
// ── Pinia Store 重构 ──
|
|
1038
|
+
{
|
|
1039
|
+
name: "pinia-refactor",
|
|
1040
|
+
description: "Pinia Store 重构:结构审查 → 拆分/合并 → 类型安全",
|
|
1041
|
+
version: "2.0.0",
|
|
1042
|
+
steps: [
|
|
1043
|
+
{
|
|
1044
|
+
id: "analyze-store",
|
|
1045
|
+
title: "分析 Store 大小、action 复杂度、getter 数量",
|
|
1046
|
+
instruction: [
|
|
1047
|
+
"## 分析 Store 大小、action 复杂度、getter 数量",
|
|
1048
|
+
"",
|
|
1049
|
+
"**执行动作**:",
|
|
1050
|
+
"1. 找到所有 Pinia Store 文件:",
|
|
1051
|
+
" ```bash",
|
|
1052
|
+
" find src/ -type f \\( -name '*store*' -o -name '*Store*' \\) \\( -name '*.ts' -o -name '*.js' \\) | head -30",
|
|
1053
|
+
" grep -rn 'defineStore' src/ --include='*.ts' --include='*.js'",
|
|
1054
|
+
" ```",
|
|
1055
|
+
"2. 统计每个 Store 的指标:",
|
|
1056
|
+
" ```bash",
|
|
1057
|
+
" # 文件行数",
|
|
1058
|
+
" wc -l <store_file>",
|
|
1059
|
+
" # state 属性数量",
|
|
1060
|
+
" grep -c 'ref(\\|:' <store_file>",
|
|
1061
|
+
" # getter 数量",
|
|
1062
|
+
" grep -c 'computed(' <store_file>",
|
|
1063
|
+
" # action 数量",
|
|
1064
|
+
" grep -c 'async function\\|function ' <store_file>",
|
|
1065
|
+
" ```",
|
|
1066
|
+
"3. 评估 Store 复杂度:",
|
|
1067
|
+
" - **简单**:< 100 行,< 5 个 state,< 3 个 action",
|
|
1068
|
+
" - **中等**:100-300 行,5-10 个 state,3-8 个 action",
|
|
1069
|
+
" - **复杂**:>300 行,>10 个 state,>8 个 action — 考虑拆分",
|
|
1070
|
+
"4. 检查 Store 之间是否有循环依赖",
|
|
1071
|
+
"",
|
|
1072
|
+
"**产出格式**:",
|
|
1073
|
+
"```",
|
|
1074
|
+
"stores: [",
|
|
1075
|
+
" { name: 'useUserStore', file: '...', lines: N, state_count: N, getter_count: N, action_count: N, complexity: 'simple'|'medium'|'complex' }",
|
|
1076
|
+
"]",
|
|
1077
|
+
"```",
|
|
1078
|
+
].join("\n"),
|
|
1079
|
+
suggestedTools: ["Bash", "Read"],
|
|
1080
|
+
output: "Store 指标分析报告",
|
|
1081
|
+
},
|
|
1082
|
+
{
|
|
1083
|
+
id: "check-types",
|
|
1084
|
+
title: "检查 Store 类型定义是否完整",
|
|
1085
|
+
instruction: [
|
|
1086
|
+
"## 检查 Store 类型定义是否完整",
|
|
1087
|
+
"",
|
|
1088
|
+
"**检查项**:",
|
|
1089
|
+
"1. state 属性是否都有 TypeScript 类型(而非 `any` 或无类型)",
|
|
1090
|
+
"2. action 参数和返回值是否有类型",
|
|
1091
|
+
"3. API 响应类型是否正确定义",
|
|
1092
|
+
"4. getter 返回值类型是否可推断",
|
|
1093
|
+
"",
|
|
1094
|
+
"**执行方式**:",
|
|
1095
|
+
"```bash",
|
|
1096
|
+
"# 查找 any 类型",
|
|
1097
|
+
"grep -n ': any\\|as any' <store_file>",
|
|
1098
|
+
"# 查找无类型的参数",
|
|
1099
|
+
"grep -n 'function.*(.*[^:].*) {' <store_file>",
|
|
1100
|
+
"```",
|
|
1101
|
+
"",
|
|
1102
|
+
"**产出格式**:",
|
|
1103
|
+
"```",
|
|
1104
|
+
"type_issues: [",
|
|
1105
|
+
" { store: 'useUserStore', field: 'user', issue: '类型为 any', fix: '定义 User interface' }",
|
|
1106
|
+
"]",
|
|
1107
|
+
"```",
|
|
1108
|
+
].join("\n"),
|
|
1109
|
+
suggestedTools: ["Read", "Bash"],
|
|
1110
|
+
output: "类型定义问题清单",
|
|
1111
|
+
},
|
|
1112
|
+
{
|
|
1113
|
+
id: "propose-refactor",
|
|
1114
|
+
title: "建议 Store 拆分或合并方案",
|
|
1115
|
+
instruction: [
|
|
1116
|
+
"## 建议 Store 拆分或合并方案(按业务领域)",
|
|
1117
|
+
"",
|
|
1118
|
+
"**拆分策略**:",
|
|
1119
|
+
"1. **按业务领域拆分** — 一个大 Store 拆为多个领域 Store:",
|
|
1120
|
+
" - `useUserStore` → `useAuthStore` + `useProfileStore`",
|
|
1121
|
+
" - `useAppStore` → `useLayoutStore` + `useThemeStore` + `useNotificationStore`",
|
|
1122
|
+
"2. **按功能职责拆分**:",
|
|
1123
|
+
" - 数据获取逻辑 → `useXxxDataStore`",
|
|
1124
|
+
" - UI 状态 → `useXxxUIStore`",
|
|
1125
|
+
" - 表单逻辑 → `useXxxFormStore`",
|
|
1126
|
+
"3. **合并相关小 Store** — 多个小 Store 合为一个:",
|
|
1127
|
+
" - 如果两个 Store 总是一起使用,考虑合并",
|
|
1128
|
+
"",
|
|
1129
|
+
"**执行动作**:",
|
|
1130
|
+
"1. 分析 Store 中各 state 的关联关系",
|
|
1131
|
+
"2. 分析哪些 action 操作哪些 state",
|
|
1132
|
+
"3. 按业务领域分组",
|
|
1133
|
+
"4. 设计新的 Store 结构",
|
|
1134
|
+
"",
|
|
1135
|
+
"**产出格式**:",
|
|
1136
|
+
"```",
|
|
1137
|
+
"refactor_plan: {",
|
|
1138
|
+
" strategy: 'split'|'merge'|'restructure',",
|
|
1139
|
+
" new_stores: [{ name: 'useAuthStore', responsibility: '...', state_from: '...' }],",
|
|
1140
|
+
" migration_steps: ['...']",
|
|
1141
|
+
"}",
|
|
1142
|
+
"```",
|
|
1143
|
+
].join("\n"),
|
|
1144
|
+
suggestedTools: ["Read", "Bash"],
|
|
1145
|
+
output: "Store 重构方案",
|
|
1146
|
+
depends: ["analyze-store", "check-types"],
|
|
1147
|
+
},
|
|
1148
|
+
{
|
|
1149
|
+
id: "refactor-store",
|
|
1150
|
+
title: "执行 Store 重构",
|
|
1151
|
+
instruction: [
|
|
1152
|
+
"## 执行 Store 重构",
|
|
1153
|
+
"",
|
|
1154
|
+
"**执行动作**:",
|
|
1155
|
+
"1. 按 `propose-refactor` 方案创建新 Store 文件:",
|
|
1156
|
+
" ```typescript",
|
|
1157
|
+
" // src/stores/auth.ts",
|
|
1158
|
+
" import { defineStore } from 'pinia';",
|
|
1159
|
+
" import { ref, computed } from 'vue';",
|
|
1160
|
+
"",
|
|
1161
|
+
" export const useAuthStore = defineStore('auth', () => {",
|
|
1162
|
+
" const token = ref<string | null>(null);",
|
|
1163
|
+
" const user = ref<User | null>(null);",
|
|
1164
|
+
" const isAuthenticated = computed(() => !!token.value);",
|
|
1165
|
+
"",
|
|
1166
|
+
" async function login(credentials: Credentials) { ... }",
|
|
1167
|
+
" function logout() { token.value = null; user.value = null; }",
|
|
1168
|
+
"",
|
|
1169
|
+
" return { token, user, isAuthenticated, login, logout };",
|
|
1170
|
+
" });",
|
|
1171
|
+
" ```",
|
|
1172
|
+
"2. 使用 Composition API 风格(`setup` 函数)定义 Store",
|
|
1173
|
+
"3. 确保类型完整(所有 ref 有泛型,所有 action 有参数/返回类型)",
|
|
1174
|
+
"4. 使用 Edit 工具精准修改,不重写整个文件",
|
|
1175
|
+
"5. 保持 Store 的 API 契约不变(或提供迁移方案)",
|
|
1176
|
+
"",
|
|
1177
|
+
"**产出格式**:",
|
|
1178
|
+
"```",
|
|
1179
|
+
"stores_created: [{ name, file_path }]",
|
|
1180
|
+
"stores_modified: [{ name, changes: '...' }]",
|
|
1181
|
+
"stores_removed: [{ name, reason: '...' }]",
|
|
1182
|
+
"```",
|
|
1183
|
+
].join("\n"),
|
|
1184
|
+
suggestedTools: ["Read", "Edit", "Write", "Bash"],
|
|
1185
|
+
output: "重构后的 Store 文件清单",
|
|
1186
|
+
depends: ["propose-refactor"],
|
|
1187
|
+
},
|
|
1188
|
+
{
|
|
1189
|
+
id: "update-references",
|
|
1190
|
+
title: "更新所有组件中的 Store 引用",
|
|
1191
|
+
instruction: [
|
|
1192
|
+
"## 更新所有组件中的 Store 引用",
|
|
1193
|
+
"",
|
|
1194
|
+
"**执行动作**:",
|
|
1195
|
+
"1. 查找所有使用了旧 Store 的组件:",
|
|
1196
|
+
" ```bash",
|
|
1197
|
+
" grep -rn 'useOldStore\\|useXxxStore' src/ --include='*.vue' --include='*.ts'",
|
|
1198
|
+
" ```",
|
|
1199
|
+
"2. 对每个引用文件:",
|
|
1200
|
+
" - 更新 import 路径",
|
|
1201
|
+
" - 更新 Store 调用(如 `useOldStore()` → `useNewStore()`)",
|
|
1202
|
+
" - 更新 `storeToRefs` 的使用",
|
|
1203
|
+
"3. 检查是否有跨 Store 依赖需要更新:",
|
|
1204
|
+
" ```bash",
|
|
1205
|
+
" grep -rn 'useXxxStore' src/stores/ --include='*.ts'",
|
|
1206
|
+
" ```",
|
|
1207
|
+
"4. 使用 Edit 工具精准修改每个引用",
|
|
1208
|
+
"",
|
|
1209
|
+
"**产出格式**:",
|
|
1210
|
+
"```",
|
|
1211
|
+
"references_updated: [{ file, old_store: '...', new_store: '...' }]",
|
|
1212
|
+
"```",
|
|
1213
|
+
].join("\n"),
|
|
1214
|
+
suggestedTools: ["Bash", "Read", "Edit"],
|
|
1215
|
+
output: "更新的 Store 引用清单",
|
|
1216
|
+
depends: ["refactor-store"],
|
|
1217
|
+
},
|
|
1218
|
+
{
|
|
1219
|
+
id: "verify-state",
|
|
1220
|
+
title: "验证重构后状态逻辑一致",
|
|
1221
|
+
instruction: [
|
|
1222
|
+
"## 验证重构后状态逻辑一致",
|
|
1223
|
+
"",
|
|
1224
|
+
"**执行动作**:",
|
|
1225
|
+
"1. 运行 `npx vue-tsc --noEmit` 确认类型正确",
|
|
1226
|
+
"2. 运行测试套件:`npm test`",
|
|
1227
|
+
"3. 检查 Store 之间的依赖是否正确:",
|
|
1228
|
+
" ```bash",
|
|
1229
|
+
" grep -rn 'useXxxStore' src/ --include='*.ts' --include='*.vue'",
|
|
1230
|
+
" ```",
|
|
1231
|
+
"4. 在 Pinia DevTools 中验证状态正确性",
|
|
1232
|
+
"5. 确认没有遗漏的旧 Store 引用",
|
|
1233
|
+
"",
|
|
1234
|
+
"**产出格式**:",
|
|
1235
|
+
"```",
|
|
1236
|
+
"type_check: passed | failed",
|
|
1237
|
+
"tests: passed | failed",
|
|
1238
|
+
"orphan_references: []",
|
|
1239
|
+
"state_consistency: verified",
|
|
1240
|
+
"```",
|
|
1241
|
+
].join("\n"),
|
|
1242
|
+
suggestedTools: ["Bash", "Read"],
|
|
1243
|
+
output: "验证结果",
|
|
1244
|
+
depends: ["update-references"],
|
|
1245
|
+
},
|
|
1246
|
+
],
|
|
1247
|
+
triggers: [
|
|
1248
|
+
{ type: "cli", command: "refactor:pinia" },
|
|
1249
|
+
],
|
|
1250
|
+
},
|
|
1251
|
+
],
|
|
1252
|
+
},
|
|
1253
|
+
prompt: {
|
|
1254
|
+
system: "你是一个 Vue 3 专家。使用 Composition API、<script setup> 和 TypeScript。遇到问题先查文档再给方案,不凭空猜测。",
|
|
1255
|
+
rules: [
|
|
1256
|
+
"使用 <script setup lang=\"ts\"> 语法糖",
|
|
1257
|
+
"使用 Composition API(ref、reactive、computed、watch)",
|
|
1258
|
+
"状态管理使用 Pinia",
|
|
1259
|
+
"可复用逻辑抽取为 composables",
|
|
1260
|
+
"遇到不确定的 API 时先查 Vue 官方文档再回答",
|
|
1261
|
+
"修复 Bug 前先排查响应式数据流",
|
|
1262
|
+
"生成代码后必须通过 vue-tsc 类型检查",
|
|
1263
|
+
"不能凭记忆猜测 API 行为,必须基于当前项目版本",
|
|
1264
|
+
],
|
|
1265
|
+
},
|
|
1266
|
+
tools: [
|
|
1267
|
+
{
|
|
1268
|
+
name: "vue_diagnose_bug",
|
|
1269
|
+
description: "Vue Bug 诊断:报错定位 → 响应式排查 → 修复验证",
|
|
1270
|
+
inputSchema: { type: "object", properties: { projectRoot: { type: "string" }, errorMessage: { type: "string" }, stackTrace: { type: "string" } }, required: ["projectRoot", "errorMessage"] },
|
|
1271
|
+
handler: async (input) => { const { diagnoseBug } = await import('./analyzers/diagnose-bug.js'); return diagnoseBug(input); },
|
|
1272
|
+
},
|
|
1273
|
+
{
|
|
1274
|
+
name: "vue_debug_reactivity",
|
|
1275
|
+
description: "响应式调试:追踪数据流 → 定位问题 → 修复",
|
|
1276
|
+
inputSchema: { type: "object", properties: { projectRoot: { type: "string" }, targetFile: { type: "string" } }, required: ["projectRoot"] },
|
|
1277
|
+
handler: async (input) => { const { debugReactivity } = await import('./analyzers/debug-reactivity.js'); return debugReactivity(input.projectRoot, input.targetFile); },
|
|
1278
|
+
},
|
|
1279
|
+
],
|
|
1280
|
+
};
|
|
1281
|
+
//# sourceMappingURL=index.js.map
|