mcp-probe-kit 1.13.0 → 1.15.1

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.
Files changed (46) hide show
  1. package/README.md +54 -3
  2. package/build/index.js +14 -1
  3. package/build/schemas/index.d.ts +108 -0
  4. package/build/schemas/index.js +2 -0
  5. package/build/schemas/ui-ux-schemas.d.ts +248 -0
  6. package/build/schemas/ui-ux-schemas.js +147 -0
  7. package/build/tools/__tests__/start_ui.integration.test.d.ts +6 -0
  8. package/build/tools/__tests__/start_ui.integration.test.js +179 -0
  9. package/build/tools/__tests__/start_ui.property.test.d.ts +6 -0
  10. package/build/tools/__tests__/start_ui.property.test.js +263 -0
  11. package/build/tools/__tests__/start_ui.unit.test.d.ts +6 -0
  12. package/build/tools/__tests__/start_ui.unit.test.js +109 -0
  13. package/build/tools/index.d.ts +4 -0
  14. package/build/tools/index.js +5 -0
  15. package/build/tools/init_component_catalog.d.ts +22 -0
  16. package/build/tools/init_component_catalog.js +809 -0
  17. package/build/tools/render_ui.d.ts +22 -0
  18. package/build/tools/render_ui.js +384 -0
  19. package/build/tools/start_ui.d.ts +25 -0
  20. package/build/tools/start_ui.js +299 -0
  21. package/build/tools/ui-ux-tools.d.ts +116 -0
  22. package/build/tools/ui-ux-tools.js +756 -0
  23. package/build/tools/ui-ux-tools.test.d.ts +6 -0
  24. package/build/tools/ui-ux-tools.test.js +132 -0
  25. package/build/utils/ascii-box-formatter.d.ts +29 -0
  26. package/build/utils/ascii-box-formatter.js +195 -0
  27. package/build/utils/bm25.d.ts +60 -0
  28. package/build/utils/bm25.js +139 -0
  29. package/build/utils/cache-manager.d.ts +65 -0
  30. package/build/utils/cache-manager.js +156 -0
  31. package/build/utils/design-reasoning-engine.d.ts +158 -0
  32. package/build/utils/design-reasoning-engine.js +363 -0
  33. package/build/utils/design-system-json-formatter.d.ts +41 -0
  34. package/build/utils/design-system-json-formatter.js +165 -0
  35. package/build/utils/ui-data-loader.d.ts +56 -0
  36. package/build/utils/ui-data-loader.js +164 -0
  37. package/build/utils/ui-search-engine.d.ts +57 -0
  38. package/build/utils/ui-search-engine.js +123 -0
  39. package/build/utils/ui-sync.d.ts +13 -0
  40. package/build/utils/ui-sync.js +241 -0
  41. package/docs/BEST_PRACTICES.md +257 -1
  42. package/docs/HOW_TO_TRIGGER.md +71 -1
  43. package/docs/MCP-Probe-Kit-/344/275/277/347/224/250/346/211/213/345/206/214.html +89 -29
  44. package/docs/MCP-Probe-Kit-/344/275/277/347/224/250/346/211/213/345/206/214.md +582 -1
  45. package/package.json +19 -6
  46. package/docs/HOW_TO_TRIGGER.html +0 -255
@@ -0,0 +1,179 @@
1
+ /**
2
+ * 集成测试:start_ui 工具
3
+ *
4
+ * 测试完整的工作流程和端到端场景
5
+ */
6
+ import { describe, test, expect } from 'vitest';
7
+ import { startUi } from '../start_ui.js';
8
+ describe('start_ui 集成测试', () => {
9
+ describe('任务 9.3: 完整的手动模式流程', () => {
10
+ test('生成可执行的工具调用指导', async () => {
11
+ const result = await startUi({
12
+ description: '登录页面',
13
+ framework: 'react'
14
+ });
15
+ expect(result.isError).not.toBe(true);
16
+ const text = result.content[0].text;
17
+ // 1. 应该包含快速开始部分
18
+ expect(text).toMatch(/^#\s+快速开始/m);
19
+ // 2. 应该包含 4 个步骤
20
+ expect(text).toMatch(/步骤 1.*生成设计系统/);
21
+ expect(text).toMatch(/步骤 2.*生成组件目录/);
22
+ expect(text).toMatch(/步骤 3.*搜索.*模板/);
23
+ expect(text).toMatch(/步骤 4.*渲染.*代码/);
24
+ // 3. 每个步骤应该包含工具名称
25
+ expect(text).toMatch(/ui_design_system/);
26
+ expect(text).toMatch(/init_component_catalog/);
27
+ expect(text).toMatch(/ui_search/);
28
+ expect(text).toMatch(/render_ui/);
29
+ // 4. 每个步骤应该包含 JSON 参数
30
+ const jsonBlocks = text.match(/```json[\s\S]*?```/g);
31
+ expect(jsonBlocks).toBeTruthy();
32
+ expect(jsonBlocks.length).toBeGreaterThanOrEqual(3);
33
+ // 5. 所有 JSON 应该是有效的
34
+ jsonBlocks.forEach(block => {
35
+ const jsonContent = block.replace(/```json\n/, '').replace(/\n```/, '');
36
+ expect(() => JSON.parse(jsonContent)).not.toThrow();
37
+ });
38
+ // 6. 应该包含预期输出
39
+ expect(text).toMatch(/预期输出/);
40
+ // 7. 应该包含失败处理
41
+ expect(text).toMatch(/失败处理/);
42
+ // 8. 应该包含高级选项
43
+ expect(text).toMatch(/高级选项/);
44
+ });
45
+ test('不同框架生成不同的指导', async () => {
46
+ const reactResult = await startUi({
47
+ description: '测试',
48
+ framework: 'react'
49
+ });
50
+ const vueResult = await startUi({
51
+ description: '测试',
52
+ framework: 'vue'
53
+ });
54
+ const htmlResult = await startUi({
55
+ description: '测试',
56
+ framework: 'html'
57
+ });
58
+ // 应该包含对应的框架名称
59
+ expect(reactResult.content[0].text).toMatch(/react/i);
60
+ expect(vueResult.content[0].text).toMatch(/vue/i);
61
+ expect(htmlResult.content[0].text).toMatch(/html/i);
62
+ // 应该是不同的内容
63
+ expect(reactResult.content[0].text).not.toBe(vueResult.content[0].text);
64
+ expect(vueResult.content[0].text).not.toBe(htmlResult.content[0].text);
65
+ });
66
+ test('复杂描述生成正确的指导', async () => {
67
+ const result = await startUi({
68
+ description: '带有用户认证和权限管理的管理后台',
69
+ framework: 'react'
70
+ });
71
+ expect(result.isError).not.toBe(true);
72
+ const text = result.content[0].text;
73
+ // 应该包含转义后的描述
74
+ expect(text).toMatch(/带有用户认证和权限管理的管理后台/);
75
+ // 所有 JSON 应该是有效的
76
+ const jsonBlocks = text.match(/```json[\s\S]*?```/g);
77
+ expect(jsonBlocks).toBeTruthy();
78
+ jsonBlocks.forEach(block => {
79
+ const jsonContent = block.replace(/```json\n/, '').replace(/\n```/, '');
80
+ expect(() => JSON.parse(jsonContent)).not.toThrow();
81
+ });
82
+ });
83
+ });
84
+ describe('任务 9.3: 错误恢复流程', () => {
85
+ test('缺少参数时提供清晰的恢复指导', async () => {
86
+ const result = await startUi({});
87
+ expect(result.isError).toBe(true);
88
+ const text = result.content[0].text;
89
+ // 应该说明问题
90
+ expect(text).toMatch(/缺少必要参数/);
91
+ // 应该提供用法示例
92
+ expect(text).toMatch(/用法/);
93
+ expect(text).toMatch(/start_ui/);
94
+ // 应该提供具体示例
95
+ expect(text).toMatch(/示例/);
96
+ });
97
+ test('无效模式时提供清晰的恢复指导', async () => {
98
+ const result = await startUi({
99
+ description: '测试',
100
+ mode: 'invalid'
101
+ });
102
+ expect(result.isError).toBe(true);
103
+ const text = result.content[0].text;
104
+ // 应该说明问题
105
+ expect(text).toMatch(/无效的模式/);
106
+ // 应该列出有效选项
107
+ expect(text).toMatch(/auto/);
108
+ expect(text).toMatch(/manual/);
109
+ // 应该提供示例
110
+ expect(text).toMatch(/示例/);
111
+ });
112
+ });
113
+ describe('任务 9.3: 工具调用可执行性', () => {
114
+ test('生成的 JSON 参数可以直接使用', async () => {
115
+ const result = await startUi({
116
+ description: '用户列表',
117
+ framework: 'vue'
118
+ });
119
+ const text = result.content[0].text;
120
+ // 提取所有 JSON 代码块
121
+ const jsonBlocks = text.match(/```json\n([\s\S]*?)\n```/g);
122
+ expect(jsonBlocks).toBeTruthy();
123
+ // 验证每个 JSON 都可以解析并包含有效参数
124
+ jsonBlocks.forEach(block => {
125
+ const jsonContent = block.replace(/```json\n/, '').replace(/\n```/, '');
126
+ const parsed = JSON.parse(jsonContent);
127
+ // 应该是一个对象
128
+ expect(typeof parsed).toBe('object');
129
+ expect(parsed).not.toBeNull();
130
+ // 不应该包含未替换的占位符
131
+ const jsonStr = JSON.stringify(parsed);
132
+ expect(jsonStr).not.toMatch(/\{description\}/);
133
+ expect(jsonStr).not.toMatch(/\{framework\}/);
134
+ expect(jsonStr).not.toMatch(/\{templateName\}/);
135
+ });
136
+ });
137
+ test('工具名称是有效的 MCP 工具', async () => {
138
+ const result = await startUi({
139
+ description: '测试',
140
+ framework: 'react'
141
+ });
142
+ const text = result.content[0].text;
143
+ // 定义有效的工具名称
144
+ const validTools = [
145
+ 'ui_design_system',
146
+ 'init_component_catalog',
147
+ 'ui_search',
148
+ 'render_ui'
149
+ ];
150
+ // 应该只包含有效的工具名称
151
+ validTools.forEach(tool => {
152
+ if (text.includes(tool)) {
153
+ // 工具名称应该在代码块或工具标记中
154
+ const toolPattern = new RegExp(`(\`${tool}\`|\\*\\*工具\\*\\*.*${tool})`);
155
+ expect(text).toMatch(toolPattern);
156
+ }
157
+ });
158
+ });
159
+ });
160
+ describe('向后兼容性', () => {
161
+ test('支持旧的调用方式', async () => {
162
+ // 只传描述字符串
163
+ const result1 = await startUi({ description: '测试' });
164
+ expect(result1.isError).not.toBe(true);
165
+ // 传描述和框架
166
+ const result2 = await startUi({
167
+ description: '测试',
168
+ framework: 'react'
169
+ });
170
+ expect(result2.isError).not.toBe(true);
171
+ // 使用别名
172
+ const result3 = await startUi({
173
+ desc: '测试',
174
+ stack: 'vue'
175
+ });
176
+ expect(result3.isError).not.toBe(true);
177
+ });
178
+ });
179
+ });
@@ -0,0 +1,6 @@
1
+ /**
2
+ * 属性测试:start_ui 工具
3
+ *
4
+ * 使用 fast-check 进行基于属性的测试,验证跨所有输入的通用正确性属性
5
+ */
6
+ export {};
@@ -0,0 +1,263 @@
1
+ /**
2
+ * 属性测试:start_ui 工具
3
+ *
4
+ * 使用 fast-check 进行基于属性的测试,验证跨所有输入的通用正确性属性
5
+ */
6
+ import { describe, test, expect } from 'vitest';
7
+ import * as fc from 'fast-check';
8
+ import { startUi } from '../start_ui.js';
9
+ describe('start_ui 属性测试', () => {
10
+ // Feature: ui-workflow-execution-issue, Property 11: Token 长度约束
11
+ test('任务 1.1: 指导少于 800 tokens', async () => {
12
+ await fc.assert(fc.asyncProperty(fc.record({
13
+ description: fc.string({ minLength: 1, maxLength: 100 }),
14
+ framework: fc.constantFrom('react', 'vue', 'html')
15
+ }), async (input) => {
16
+ const result = await startUi(input);
17
+ const text = result.content[0].text;
18
+ // 简单的 token 估算:按空格和标点分割
19
+ const tokenCount = text.split(/[\s\n]+/).length;
20
+ // 硬性约束:必须少于 800 tokens
21
+ expect(tokenCount).toBeLessThan(800);
22
+ }), { numRuns: 100 });
23
+ });
24
+ // Feature: ui-workflow-execution-issue, Property 18: 一致的 Markdown 结构
25
+ test('任务 1.2: 指导使用一致的 Markdown 结构', async () => {
26
+ await fc.assert(fc.asyncProperty(fc.record({
27
+ description: fc.string({ minLength: 1, maxLength: 100 }),
28
+ framework: fc.constantFrom('react', 'vue', 'html')
29
+ }), async (input) => {
30
+ const result = await startUi(input);
31
+ const text = result.content[0].text;
32
+ // 应该包含 H1 标题(快速开始)
33
+ expect(text).toMatch(/^#\s+快速开始/m);
34
+ // 应该包含 H2 标题(步骤)
35
+ expect(text).toMatch(/^##\s+步骤/m);
36
+ // 应该包含代码块
37
+ expect(text).toMatch(/```json/);
38
+ // 应该包含高级选项部分
39
+ expect(text).toMatch(/^##\s+高级选项/m);
40
+ }), { numRuns: 100 });
41
+ });
42
+ // Feature: ui-workflow-execution-issue, Property 2: 代码块中的工具调用
43
+ test('任务 2.2: 工具调用在代码块中', async () => {
44
+ await fc.assert(fc.asyncProperty(fc.record({
45
+ description: fc.string({ minLength: 1, maxLength: 100 }),
46
+ framework: fc.constantFrom('react', 'vue', 'html')
47
+ }), async (input) => {
48
+ const result = await startUi(input);
49
+ const text = result.content[0].text;
50
+ // 如果包含 JSON 参数,应该在代码块中
51
+ const jsonBlocks = text.match(/```json[\s\S]*?```/g);
52
+ expect(jsonBlocks).toBeTruthy();
53
+ expect(jsonBlocks.length).toBeGreaterThan(0);
54
+ }), { numRuns: 100 });
55
+ });
56
+ // Feature: ui-workflow-execution-issue, Property 3: 完整的工具调用参数
57
+ test('任务 2.2: 工具调用包含完整参数', async () => {
58
+ await fc.assert(fc.asyncProperty(fc.record({
59
+ description: fc.string({ minLength: 1, maxLength: 100 }),
60
+ framework: fc.constantFrom('react', 'vue', 'html')
61
+ }), async (input) => {
62
+ const result = await startUi(input);
63
+ const text = result.content[0].text;
64
+ // 提取所有 JSON 代码块
65
+ const jsonBlocks = text.match(/```json\n([\s\S]*?)\n```/g);
66
+ if (jsonBlocks) {
67
+ jsonBlocks.forEach(block => {
68
+ // 提取 JSON 内容
69
+ const jsonContent = block.replace(/```json\n/, '').replace(/\n```/, '');
70
+ // 应该是有效的 JSON
71
+ expect(() => JSON.parse(jsonContent)).not.toThrow();
72
+ const parsed = JSON.parse(jsonContent);
73
+ // 不应该包含模板占位符
74
+ const jsonStr = JSON.stringify(parsed);
75
+ // 检查特定的模板占位符,而不是所有花括号
76
+ expect(jsonStr).not.toMatch(/\{description\}/);
77
+ expect(jsonStr).not.toMatch(/\{framework\}/);
78
+ expect(jsonStr).not.toMatch(/\{templateName\}/);
79
+ });
80
+ }
81
+ }), { numRuns: 100 });
82
+ });
83
+ // Feature: ui-workflow-execution-issue, Property 13: 标准 MCP 工具语法
84
+ test('任务 2.2: 使用标准 MCP 工具语法', async () => {
85
+ await fc.assert(fc.asyncProperty(fc.record({
86
+ description: fc.string({ minLength: 1, maxLength: 100 }),
87
+ framework: fc.constantFrom('react', 'vue', 'html')
88
+ }), async (input) => {
89
+ const result = await startUi(input);
90
+ const text = result.content[0].text;
91
+ // 应该包含有效的工具名称
92
+ const validTools = [
93
+ 'ui_design_system',
94
+ 'init_component_catalog',
95
+ 'ui_search',
96
+ 'render_ui'
97
+ ];
98
+ let foundTool = false;
99
+ validTools.forEach(tool => {
100
+ if (text.includes(tool)) {
101
+ foundTool = true;
102
+ }
103
+ });
104
+ expect(foundTool).toBe(true);
105
+ }), { numRuns: 100 });
106
+ });
107
+ });
108
+ // Feature: ui-workflow-execution-issue, Property 4: 预期输出文档
109
+ test('任务 3.4: 每个步骤包含预期输出', async () => {
110
+ await fc.assert(fc.asyncProperty(fc.record({
111
+ description: fc.string({ minLength: 1, maxLength: 100 }),
112
+ framework: fc.constantFrom('react', 'vue', 'html')
113
+ }), async (input) => {
114
+ const result = await startUi(input);
115
+ const text = result.content[0].text;
116
+ // 应该包含"预期输出"部分
117
+ expect(text).toMatch(/预期输出|Expected Output/i);
118
+ // 每个步骤都应该有预期输出
119
+ const stepSections = text.match(/^##\s+步骤\s+\d+:/gm);
120
+ if (stepSections) {
121
+ // 至少应该有一些步骤有预期输出
122
+ const outputCount = (text.match(/预期输出|Expected Output/gi) || []).length;
123
+ expect(outputCount).toBeGreaterThan(0);
124
+ }
125
+ }), { numRuns: 100 });
126
+ });
127
+ // Feature: ui-workflow-execution-issue, Property 6: 显式依赖关系
128
+ test('任务 3.4: 步骤包含依赖关系说明', async () => {
129
+ await fc.assert(fc.asyncProperty(fc.record({
130
+ description: fc.string({ minLength: 1, maxLength: 100 }),
131
+ framework: fc.constantFrom('react', 'vue', 'html')
132
+ }), async (input) => {
133
+ const result = await startUi(input);
134
+ const text = result.content[0].text;
135
+ // 应该包含依赖关系的说明(如"确保步骤 1")
136
+ const hasDependency = text.includes('确保步骤') ||
137
+ text.includes('确保') ||
138
+ text.includes('依赖') ||
139
+ text.includes('需要');
140
+ expect(hasDependency).toBe(true);
141
+ }), { numRuns: 100 });
142
+ });
143
+ // Feature: ui-workflow-execution-issue, Property 8: 全面的错误处理
144
+ test('任务 3.4: 每个步骤包含失败处理', async () => {
145
+ await fc.assert(fc.asyncProperty(fc.record({
146
+ description: fc.string({ minLength: 1, maxLength: 100 }),
147
+ framework: fc.constantFrom('react', 'vue', 'html')
148
+ }), async (input) => {
149
+ const result = await startUi(input);
150
+ const text = result.content[0].text;
151
+ // 应该包含"失败处理"部分
152
+ expect(text).toMatch(/失败处理|Failure Handling|On Failure/i);
153
+ // 每个步骤都应该有失败处理
154
+ const stepSections = text.match(/^##\s+步骤\s+\d+:/gm);
155
+ if (stepSections) {
156
+ // 至少应该有一些步骤有失败处理
157
+ const failureCount = (text.match(/失败处理|Failure Handling|On Failure/gi) || []).length;
158
+ expect(failureCount).toBeGreaterThan(0);
159
+ }
160
+ }), { numRuns: 100 });
161
+ });
162
+ // Feature: ui-workflow-execution-issue, Property 22: 模式参数支持
163
+ test('任务 5.4: 接受模式参数', async () => {
164
+ await fc.assert(fc.asyncProperty(fc.record({
165
+ description: fc.string({ minLength: 1, maxLength: 100 }),
166
+ framework: fc.constantFrom('react', 'vue', 'html'),
167
+ mode: fc.constantFrom('auto', 'manual', undefined)
168
+ }), async (input) => {
169
+ // 不应该抛出错误
170
+ const result = await startUi(input);
171
+ // 应该返回有效的响应
172
+ expect(result.content).toBeDefined();
173
+ expect(result.content[0].text).toBeTruthy();
174
+ }), { numRuns: 100 });
175
+ });
176
+ // Feature: ui-workflow-execution-issue, Property 24: 手动模式指导
177
+ test('任务 5.4: 手动模式返回指导', async () => {
178
+ await fc.assert(fc.asyncProperty(fc.record({
179
+ description: fc.string({ minLength: 1, maxLength: 100 }),
180
+ framework: fc.constantFrom('react', 'vue', 'html')
181
+ }), async (input) => {
182
+ // 默认或显式 manual 模式
183
+ const result1 = await startUi(input);
184
+ const result2 = await startUi({ ...input, mode: 'manual' });
185
+ // 应该返回指导文本
186
+ expect(result1.content[0].text).toMatch(/快速开始|Quick Start/i);
187
+ expect(result2.content[0].text).toMatch(/快速开始|Quick Start/i);
188
+ // 应该包含工具调用
189
+ expect(result1.content[0].text).toMatch(/ui_design_system|init_component_catalog/);
190
+ expect(result2.content[0].text).toMatch(/ui_design_system|init_component_catalog/);
191
+ }), { numRuns: 100 });
192
+ });
193
+ // Feature: ui-workflow-execution-issue, Property 15: 无副作用
194
+ test('任务 5.5: start_ui 无副作用', async () => {
195
+ await fc.assert(fc.asyncProperty(fc.record({
196
+ description: fc.string({ minLength: 1, maxLength: 100 }),
197
+ framework: fc.constantFrom('react', 'vue', 'html')
198
+ }), async (input) => {
199
+ // 调用 start_ui
200
+ const result = await startUi(input);
201
+ // 应该只返回文本,不应该有 isError(除非是错误情况)
202
+ expect(result.content).toBeDefined();
203
+ expect(result.content[0].type).toBe('text');
204
+ // 不应该抛出异常
205
+ expect(result).toBeTruthy();
206
+ }), { numRuns: 100 });
207
+ });
208
+ // Feature: ui-workflow-execution-issue, Property 1: 显式工具调用规范
209
+ test('任务 6.4: 指导包含显式工具名称', async () => {
210
+ await fc.assert(fc.asyncProperty(fc.record({
211
+ description: fc.string({ minLength: 1, maxLength: 100 }),
212
+ framework: fc.constantFrom('react', 'vue', 'html')
213
+ }), async (input) => {
214
+ const result = await startUi(input);
215
+ const text = result.content[0].text;
216
+ // 应该包含明确的工具名称
217
+ const hasToolNames = text.includes('ui_design_system') ||
218
+ text.includes('init_component_catalog') ||
219
+ text.includes('ui_search') ||
220
+ text.includes('render_ui');
221
+ expect(hasToolNames).toBe(true);
222
+ // 应该有明确的调用指令
223
+ expect(text).toMatch(/调用|执行|运行|call|execute|run/i);
224
+ }), { numRuns: 100 });
225
+ });
226
+ // Feature: ui-workflow-execution-issue, Property 5: 无模糊语言
227
+ test('任务 6.4: 无模糊语言', async () => {
228
+ await fc.assert(fc.asyncProperty(fc.record({
229
+ description: fc.string({ minLength: 1, maxLength: 100 }),
230
+ framework: fc.constantFrom('react', 'vue', 'html')
231
+ }), async (input) => {
232
+ const result = await startUi(input);
233
+ const text = result.content[0].text;
234
+ // 不应该包含模糊的指令(没有具体工具名称或文件名)
235
+ // 如果包含"检查",应该伴随具体的文件名或工具名
236
+ const checkMatches = text.match(/检查[^。\n]*/g) || [];
237
+ checkMatches.forEach(match => {
238
+ // 应该包含具体的文件名、工具名或目录名
239
+ const hasSpecific = match.includes('.json') ||
240
+ match.includes('.md') ||
241
+ match.includes('ui_') ||
242
+ match.includes('文件') ||
243
+ match.includes('权限') ||
244
+ match.includes('docs/') ||
245
+ match.includes('目录');
246
+ expect(hasSpecific).toBe(true);
247
+ });
248
+ }), { numRuns: 100 });
249
+ });
250
+ // Feature: ui-workflow-execution-issue, Property 16: 范围声明
251
+ test('任务 6.4: 包含职责范围声明', async () => {
252
+ await fc.assert(fc.asyncProperty(fc.record({
253
+ description: fc.string({ minLength: 1, maxLength: 100 }),
254
+ framework: fc.constantFrom('react', 'vue', 'html')
255
+ }), async (input) => {
256
+ const result = await startUi(input);
257
+ const text = result.content[0].text;
258
+ // 应该包含职责说明
259
+ expect(text).toMatch(/职责说明|职责|Responsibility/i);
260
+ // 应该说明只提供指导
261
+ expect(text).toMatch(/仅提供|只提供|提供指导|provide guidance/i);
262
+ }), { numRuns: 100 });
263
+ });
@@ -0,0 +1,6 @@
1
+ /**
2
+ * 单元测试:start_ui 工具
3
+ *
4
+ * 测试具体的功能点、边界情况和错误条件
5
+ */
6
+ export {};
@@ -0,0 +1,109 @@
1
+ /**
2
+ * 单元测试:start_ui 工具
3
+ *
4
+ * 测试具体的功能点、边界情况和错误条件
5
+ */
6
+ import { describe, test, expect } from 'vitest';
7
+ import { startUi } from '../start_ui.js';
8
+ describe('start_ui 单元测试', () => {
9
+ describe('任务 7.3: 错误处理', () => {
10
+ test('缺少描述参数时返回错误', async () => {
11
+ const result = await startUi({});
12
+ expect(result.isError).toBe(true);
13
+ expect(result.content[0].text).toMatch(/缺少必要参数|Missing required parameter/i);
14
+ expect(result.content[0].text).toMatch(/用法|Usage/i);
15
+ });
16
+ test('空描述参数时返回错误', async () => {
17
+ const result = await startUi({ description: '' });
18
+ expect(result.isError).toBe(true);
19
+ expect(result.content[0].text).toMatch(/缺少必要参数|Missing required parameter/i);
20
+ });
21
+ test('无效 mode 值时返回错误', async () => {
22
+ const result = await startUi({
23
+ description: '测试',
24
+ mode: 'invalid'
25
+ });
26
+ expect(result.isError).toBe(true);
27
+ expect(result.content[0].text).toMatch(/无效的模式|Invalid mode/i);
28
+ expect(result.content[0].text).toMatch(/auto.*manual/i);
29
+ });
30
+ test('错误响应包含使用示例', async () => {
31
+ const result = await startUi({});
32
+ expect(result.isError).toBe(true);
33
+ expect(result.content[0].text).toMatch(/示例|Example/i);
34
+ expect(result.content[0].text).toMatch(/start_ui/);
35
+ });
36
+ });
37
+ describe('参数解析', () => {
38
+ test('默认 framework 为 react', async () => {
39
+ const result = await startUi({ description: '测试' });
40
+ expect(result.content[0].text).toMatch(/react/i);
41
+ });
42
+ test('支持 vue framework', async () => {
43
+ const result = await startUi({
44
+ description: '测试',
45
+ framework: 'vue'
46
+ });
47
+ expect(result.content[0].text).toMatch(/vue/i);
48
+ });
49
+ test('支持 html framework', async () => {
50
+ const result = await startUi({
51
+ description: '测试',
52
+ framework: 'html'
53
+ });
54
+ expect(result.content[0].text).toMatch(/html/i);
55
+ });
56
+ test('自动生成模板名称', async () => {
57
+ const result = await startUi({ description: '登录页面' });
58
+ // 应该生成类似 login 的模板名
59
+ expect(result.content[0].text).toMatch(/login|登录/i);
60
+ });
61
+ });
62
+ describe('模式参数', () => {
63
+ test('默认模式为 manual', async () => {
64
+ const result = await startUi({ description: '测试' });
65
+ expect(result.isError).not.toBe(true);
66
+ expect(result.content[0].text).toMatch(/快速开始|Quick Start/i);
67
+ });
68
+ test('显式 manual 模式返回指导', async () => {
69
+ const result = await startUi({
70
+ description: '测试',
71
+ mode: 'manual'
72
+ });
73
+ expect(result.isError).not.toBe(true);
74
+ expect(result.content[0].text).toMatch(/快速开始|Quick Start/i);
75
+ });
76
+ test('auto 模式返回未实现消息', async () => {
77
+ const result = await startUi({
78
+ description: '测试',
79
+ mode: 'auto'
80
+ });
81
+ expect(result.isError).toBe(false);
82
+ expect(result.content[0].text).toMatch(/尚未实现|not yet implemented/i);
83
+ });
84
+ });
85
+ describe('输出格式', () => {
86
+ test('返回有效的 markdown', async () => {
87
+ const result = await startUi({ description: '测试' });
88
+ const text = result.content[0].text;
89
+ // 应该包含 markdown 标题
90
+ expect(text).toMatch(/^#/m);
91
+ // 应该包含代码块
92
+ expect(text).toMatch(/```/);
93
+ });
94
+ test('包含所有必需的步骤', async () => {
95
+ const result = await startUi({ description: '测试' });
96
+ const text = result.content[0].text;
97
+ // 应该包含 4 个步骤
98
+ expect(text).toMatch(/步骤 1/);
99
+ expect(text).toMatch(/步骤 2/);
100
+ expect(text).toMatch(/步骤 3/);
101
+ expect(text).toMatch(/步骤 4/);
102
+ });
103
+ test('包含高级选项部分', async () => {
104
+ const result = await startUi({ description: '测试' });
105
+ const text = result.content[0].text;
106
+ expect(text).toMatch(/高级选项|Advanced Options/i);
107
+ });
108
+ });
109
+ });
@@ -41,3 +41,7 @@ export { genSkill } from "./gen_skill.js";
41
41
  export { startRalph } from "./start_ralph.js";
42
42
  export { interview } from "./interview.js";
43
43
  export { askUser } from "./ask_user.js";
44
+ export { uiDesignSystem, uiSearch, syncUiData } from "./ui-ux-tools.js";
45
+ export { initComponentCatalog } from "./init_component_catalog.js";
46
+ export { renderUi } from "./render_ui.js";
47
+ export { startUi } from "./start_ui.js";
@@ -43,3 +43,8 @@ export { startRalph } from "./start_ralph.js";
43
43
  // 访谈工具
44
44
  export { interview } from "./interview.js";
45
45
  export { askUser } from "./ask_user.js";
46
+ // UI/UX Pro Max 工具
47
+ export { uiDesignSystem, uiSearch, syncUiData } from "./ui-ux-tools.js";
48
+ export { initComponentCatalog } from "./init_component_catalog.js";
49
+ export { renderUi } from "./render_ui.js";
50
+ export { startUi } from "./start_ui.js";
@@ -0,0 +1,22 @@
1
+ /**
2
+ * 初始化组件目录工具
3
+ *
4
+ * 基于设计系统规范生成组件目录
5
+ * 组件定义包含占位符,渲染时自动替换为实际值
6
+ */
7
+ /**
8
+ * 初始化组件目录工具
9
+ */
10
+ export declare function initComponentCatalog(args: any): Promise<{
11
+ content: {
12
+ type: string;
13
+ text: string;
14
+ }[];
15
+ isError: boolean;
16
+ } | {
17
+ content: {
18
+ type: string;
19
+ text: string;
20
+ }[];
21
+ isError?: undefined;
22
+ }>;