mcp-probe-kit 3.0.14 → 3.0.16

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 (43) hide show
  1. package/README.md +17 -11
  2. package/build/lib/__tests__/gitnexus-bridge.unit.test.js +9 -1
  3. package/build/lib/gitnexus-bridge.d.ts +1 -0
  4. package/build/lib/gitnexus-bridge.js +29 -1
  5. package/build/lib/skill-bridge.d.ts +31 -0
  6. package/build/lib/skill-bridge.js +100 -0
  7. package/build/resources/ui-ux-data/charts.json +302 -0
  8. package/build/resources/ui-ux-data/colors.json +1058 -0
  9. package/build/resources/ui-ux-data/icons.json +1102 -0
  10. package/build/resources/ui-ux-data/landing.json +262 -0
  11. package/build/resources/ui-ux-data/metadata.json +6 -0
  12. package/build/resources/ui-ux-data/products.json +1058 -0
  13. package/build/resources/ui-ux-data/react-performance.json +574 -0
  14. package/build/resources/ui-ux-data/stacks/astro.json +266 -0
  15. package/build/resources/ui-ux-data/stacks/flutter.json +626 -0
  16. package/build/resources/ui-ux-data/stacks/html-tailwind.json +662 -0
  17. package/build/resources/ui-ux-data/stacks/jetpack-compose.json +626 -0
  18. package/build/resources/ui-ux-data/stacks/nextjs.json +218 -0
  19. package/build/resources/ui-ux-data/stacks/nuxt-ui.json +14 -0
  20. package/build/resources/ui-ux-data/stacks/nuxtjs.json +182 -0
  21. package/build/resources/ui-ux-data/stacks/react-native.json +350 -0
  22. package/build/resources/ui-ux-data/stacks/react.json +530 -0
  23. package/build/resources/ui-ux-data/stacks/shadcn.json +566 -0
  24. package/build/resources/ui-ux-data/stacks/svelte.json +134 -0
  25. package/build/resources/ui-ux-data/stacks/swiftui.json +26 -0
  26. package/build/resources/ui-ux-data/stacks/vue.json +170 -0
  27. package/build/resources/ui-ux-data/styles.json +1610 -0
  28. package/build/resources/ui-ux-data/typography.json +743 -0
  29. package/build/resources/ui-ux-data/ui-reasoning.json +1431 -0
  30. package/build/resources/ui-ux-data/ux-guidelines.json +1190 -0
  31. package/build/resources/ui-ux-data/web-interface.json +389 -0
  32. package/build/schemas/ui-ux-schemas.js +1 -1
  33. package/build/tools/start_product.js +8 -1
  34. package/build/tools/start_ui.js +14 -3
  35. package/build/tools/ui-ux-tools.js +21 -17
  36. package/build/utils/ui-data-loader.d.ts +18 -2
  37. package/build/utils/ui-data-loader.js +74 -12
  38. package/docs/i18n/en.json +4 -2
  39. package/docs/i18n/ja.json +4 -2
  40. package/docs/i18n/ko.json +4 -2
  41. package/docs/i18n/zh-CN.json +4 -2
  42. package/docs/pages/getting-started.html +3 -0
  43. package/package.json +2 -1
@@ -0,0 +1,389 @@
1
+ [
2
+ {
3
+ "No": "1",
4
+ "Category": "Accessibility",
5
+ "Issue": "Icon Button Labels",
6
+ "Keywords": "icon button aria-label",
7
+ "Platform": "Web",
8
+ "Description": "Icon-only buttons must have accessible names",
9
+ "Do": "Add aria-label to icon buttons",
10
+ "Don't": "Icon button without label",
11
+ "Code Example Good": "<button aria-label='Close'><XIcon /></button>",
12
+ "Code Example Bad": "<button><XIcon /></button>",
13
+ "Severity": "Critical"
14
+ },
15
+ {
16
+ "No": "2",
17
+ "Category": "Accessibility",
18
+ "Issue": "Form Control Labels",
19
+ "Keywords": "form input label aria",
20
+ "Platform": "Web",
21
+ "Description": "All form controls need labels or aria-label",
22
+ "Do": "Use label element or aria-label",
23
+ "Don't": "Input without accessible name",
24
+ "Code Example Good": "<label for='email'>Email</label><input id='email' />",
25
+ "Code Example Bad": "<input placeholder='Email' />",
26
+ "Severity": "Critical"
27
+ },
28
+ {
29
+ "No": "3",
30
+ "Category": "Accessibility",
31
+ "Issue": "Keyboard Handlers",
32
+ "Keywords": "keyboard onclick onkeydown",
33
+ "Platform": "Web",
34
+ "Description": "Interactive elements must support keyboard interaction",
35
+ "Do": "Add onKeyDown alongside onClick",
36
+ "Don't": "Click-only interaction",
37
+ "Code Example Good": "<div onClick={fn} onKeyDown={fn} tabIndex={0}>",
38
+ "Code Example Bad": "<div onClick={fn}>",
39
+ "Severity": "High"
40
+ },
41
+ {
42
+ "No": "4",
43
+ "Category": "Accessibility",
44
+ "Issue": "Semantic HTML",
45
+ "Keywords": "semantic button a label",
46
+ "Platform": "Web",
47
+ "Description": "Use semantic HTML before ARIA attributes",
48
+ "Do": "Use button/a/label elements",
49
+ "Don't": "Div with role attribute",
50
+ "Code Example Good": "<button onClick={fn}>Submit</button>",
51
+ "Code Example Bad": "<div role='button' onClick={fn}>Submit</div>",
52
+ "Severity": "High"
53
+ },
54
+ {
55
+ "No": "5",
56
+ "Category": "Accessibility",
57
+ "Issue": "Aria Live",
58
+ "Keywords": "aria-live polite async",
59
+ "Platform": "Web",
60
+ "Description": "Async updates need aria-live for screen readers",
61
+ "Do": "Add aria-live='polite' for dynamic content",
62
+ "Don't": "Silent async updates",
63
+ "Code Example Good": "<div aria-live='polite'>{status}</div>",
64
+ "Code Example Bad": "<div>{status}</div> // no announcement",
65
+ "Severity": "Medium"
66
+ },
67
+ {
68
+ "No": "6",
69
+ "Category": "Accessibility",
70
+ "Issue": "Decorative Icons",
71
+ "Keywords": "aria-hidden decorative icon",
72
+ "Platform": "Web",
73
+ "Description": "Decorative icons should be hidden from screen readers",
74
+ "Do": "Add aria-hidden='true' to decorative icons",
75
+ "Don't": "Decorative icon announced",
76
+ "Code Example Good": "<Icon aria-hidden='true' />",
77
+ "Code Example Bad": "<Icon /> // announced as 'image'",
78
+ "Severity": "Medium"
79
+ },
80
+ {
81
+ "No": "7",
82
+ "Category": "Focus",
83
+ "Issue": "Visible Focus States",
84
+ "Keywords": "focus-visible outline ring",
85
+ "Platform": "Web",
86
+ "Description": "All interactive elements need visible focus states",
87
+ "Do": "Use :focus-visible with ring/outline",
88
+ "Don't": "No focus indication",
89
+ "Code Example Good": "focus-visible:ring-2 focus-visible:ring-blue-500",
90
+ "Code Example Bad": "outline-none // no replacement",
91
+ "Severity": "Critical"
92
+ },
93
+ {
94
+ "No": "8",
95
+ "Category": "Focus",
96
+ "Issue": "Never Remove Outline",
97
+ "Keywords": "outline-none focus replacement",
98
+ "Platform": "Web",
99
+ "Description": "Never remove outline without providing replacement",
100
+ "Do": "Replace outline with visible alternative",
101
+ "Don't": "Remove outline completely",
102
+ "Code Example Good": "focus:outline-none focus:ring-2",
103
+ "Code Example Bad": "focus:outline-none // nothing else",
104
+ "Severity": "Critical"
105
+ },
106
+ {
107
+ "No": "9",
108
+ "Category": "Focus",
109
+ "Issue": "Checkbox Radio Hit Target",
110
+ "Keywords": "checkbox radio label target",
111
+ "Platform": "Web",
112
+ "Description": "Checkbox/radio must share hit target with label",
113
+ "Do": "Wrap input and label together",
114
+ "Don't": "Separate tiny checkbox",
115
+ "Code Example Good": "<label class='flex gap-2'><input type='checkbox' /><span>Option</span></label>",
116
+ "Code Example Bad": "<input type='checkbox' id='x' /><label for='x'>Option</label>",
117
+ "Severity": "Medium"
118
+ },
119
+ {
120
+ "No": "10",
121
+ "Category": "Forms",
122
+ "Issue": "Autocomplete Attribute",
123
+ "Keywords": "autocomplete input form",
124
+ "Platform": "Web",
125
+ "Description": "Inputs need autocomplete attribute for autofill",
126
+ "Do": "Add appropriate autocomplete value",
127
+ "Don't": "Missing autocomplete",
128
+ "Code Example Good": "<input autocomplete='email' type='email' />",
129
+ "Code Example Bad": "<input type='email' />",
130
+ "Severity": "High"
131
+ },
132
+ {
133
+ "No": "11",
134
+ "Category": "Forms",
135
+ "Issue": "Semantic Input Types",
136
+ "Keywords": "input type email tel url",
137
+ "Platform": "Web",
138
+ "Description": "Use semantic input type attributes",
139
+ "Do": "Use email/tel/url/number types",
140
+ "Don't": "text type for everything",
141
+ "Code Example Good": "<input type='email' />",
142
+ "Code Example Bad": "<input type='text' /> // for email",
143
+ "Severity": "Medium"
144
+ },
145
+ {
146
+ "No": "12",
147
+ "Category": "Forms",
148
+ "Issue": "Never Block Paste",
149
+ "Keywords": "paste onpaste password",
150
+ "Platform": "Web",
151
+ "Description": "Never prevent paste functionality",
152
+ "Do": "Allow paste on all inputs",
153
+ "Don't": "Block paste on password/code",
154
+ "Code Example Good": "<input type='password' />",
155
+ "Code Example Bad": "<input onPaste={e => e.preventDefault()} />",
156
+ "Severity": "High"
157
+ },
158
+ {
159
+ "No": "13",
160
+ "Category": "Forms",
161
+ "Issue": "Spellcheck Disable",
162
+ "Keywords": "spellcheck email code",
163
+ "Platform": "Web",
164
+ "Description": "Disable spellcheck on emails and codes",
165
+ "Do": "Set spellcheck='false' on codes",
166
+ "Don't": "Spellcheck on technical input",
167
+ "Code Example Good": "<input spellCheck='false' type='email' />",
168
+ "Code Example Bad": "<input type='email' /> // red squiggles",
169
+ "Severity": "Low"
170
+ },
171
+ {
172
+ "No": "14",
173
+ "Category": "Forms",
174
+ "Issue": "Submit Button Enabled",
175
+ "Keywords": "submit button disabled loading",
176
+ "Platform": "Web",
177
+ "Description": "Keep submit enabled and show spinner during requests",
178
+ "Do": "Show loading spinner keep enabled",
179
+ "Don't": "Disable button during submit",
180
+ "Code Example Good": "<button>{loading ? <Spinner /> : 'Submit'}</button>",
181
+ "Code Example Bad": "<button disabled={loading}>Submit</button>",
182
+ "Severity": "Medium"
183
+ },
184
+ {
185
+ "No": "15",
186
+ "Category": "Forms",
187
+ "Issue": "Inline Errors",
188
+ "Keywords": "error message inline focus",
189
+ "Platform": "Web",
190
+ "Description": "Show error messages inline near the problem field",
191
+ "Do": "Inline error with focus on first error",
192
+ "Don't": "Single error at top",
193
+ "Code Example Good": "<input /><span class='text-red-500'>{error}</span>",
194
+ "Code Example Bad": "<div class='error'>{allErrors}</div> // at top",
195
+ "Severity": "High"
196
+ },
197
+ {
198
+ "No": "16",
199
+ "Category": "Performance",
200
+ "Issue": "Virtualize Lists",
201
+ "Keywords": "virtualize list 50 items",
202
+ "Platform": "Web",
203
+ "Description": "Virtualize lists exceeding 50 items",
204
+ "Do": "Use virtual list for large datasets",
205
+ "Don't": "Render all items",
206
+ "Code Example Good": "<VirtualList items={items} />",
207
+ "Code Example Bad": "items.map(item => <Item />)",
208
+ "Severity": "High"
209
+ },
210
+ {
211
+ "No": "17",
212
+ "Category": "Performance",
213
+ "Issue": "Avoid Layout Reads",
214
+ "Keywords": "layout read render getboundingclientrect",
215
+ "Platform": "Web",
216
+ "Description": "Avoid layout reads during render phase",
217
+ "Do": "Read layout in effects or callbacks",
218
+ "Don't": "getBoundingClientRect in render",
219
+ "Code Example Good": "useEffect(() => { el.getBoundingClientRect() })",
220
+ "Code Example Bad": "const rect = el.getBoundingClientRect() // in render",
221
+ "Severity": "Medium"
222
+ },
223
+ {
224
+ "No": "18",
225
+ "Category": "Performance",
226
+ "Issue": "Batch DOM Operations",
227
+ "Keywords": "batch dom write read",
228
+ "Platform": "Web",
229
+ "Description": "Group DOM operations to minimize reflows",
230
+ "Do": "Batch writes then reads",
231
+ "Don't": "Interleave reads and writes",
232
+ "Code Example Good": "writes.forEach(w => w()); reads.forEach(r => r())",
233
+ "Code Example Bad": "write(); read(); write(); read(); // thrashing",
234
+ "Severity": "Medium"
235
+ },
236
+ {
237
+ "No": "19",
238
+ "Category": "Performance",
239
+ "Issue": "Preconnect CDN",
240
+ "Keywords": "preconnect link cdn",
241
+ "Platform": "Web",
242
+ "Description": "Add preconnect links for CDN domains",
243
+ "Do": "Preconnect to known domains",
244
+ "Don't": "<link rel='preconnect' href='https://cdn.example.com' />",
245
+ "Code Example Good": "// no preconnect hint",
246
+ "Code Example Bad": "Low"
247
+ },
248
+ {
249
+ "No": "20",
250
+ "Category": "Performance",
251
+ "Issue": "Lazy Load Images",
252
+ "Keywords": "lazy loading image below-fold",
253
+ "Platform": "Web",
254
+ "Description": "Lazy-load images below the fold",
255
+ "Do": "Use loading='lazy' for below-fold images",
256
+ "Don't": "Load all images eagerly",
257
+ "Code Example Good": "<img loading='lazy' src='...' />",
258
+ "Code Example Bad": "<img src='...' /> // above fold only",
259
+ "Severity": "Medium"
260
+ },
261
+ {
262
+ "No": "21",
263
+ "Category": "State",
264
+ "Issue": "URL Reflects State",
265
+ "Keywords": "url state query params",
266
+ "Platform": "Web",
267
+ "Description": "URL should reflect current UI state",
268
+ "Do": "Sync filters/tabs/pagination to URL",
269
+ "Don't": "State only in memory",
270
+ "Code Example Good": "?tab=settings&page=2",
271
+ "Code Example Bad": "useState only // lost on refresh",
272
+ "Severity": "High"
273
+ },
274
+ {
275
+ "No": "22",
276
+ "Category": "State",
277
+ "Issue": "Deep Linking",
278
+ "Keywords": "deep link stateful component",
279
+ "Platform": "Web",
280
+ "Description": "Stateful components should support deep-linking",
281
+ "Do": "Enable sharing current view via URL",
282
+ "Don't": "No shareable state",
283
+ "Code Example Good": "router.push({ query: { ...filters } })",
284
+ "Code Example Bad": "setFilters(f) // not in URL",
285
+ "Severity": "Medium"
286
+ },
287
+ {
288
+ "No": "23",
289
+ "Category": "State",
290
+ "Issue": "Confirm Destructive Actions",
291
+ "Keywords": "confirm destructive delete modal",
292
+ "Platform": "Web",
293
+ "Description": "Destructive actions require confirmation",
294
+ "Do": "Show confirmation dialog before delete",
295
+ "Don't": "Delete without confirmation",
296
+ "Code Example Good": "if (confirm('Delete?')) delete()",
297
+ "Code Example Bad": "onClick={delete} // no confirmation",
298
+ "Severity": "High"
299
+ },
300
+ {
301
+ "No": "24",
302
+ "Category": "Typography",
303
+ "Issue": "Proper Unicode",
304
+ "Keywords": "unicode ellipsis quotes",
305
+ "Platform": "Web",
306
+ "Description": "Use proper Unicode characters",
307
+ "Do": "Use ... curly quotes proper dashes",
308
+ "Don't": "ASCII approximations",
309
+ "Code Example Good": "'Hello...' with proper ellipsis",
310
+ "Code Example Bad": "'Hello...' with three dots",
311
+ "Severity": "Low"
312
+ },
313
+ {
314
+ "No": "25",
315
+ "Category": "Typography",
316
+ "Issue": "Text Overflow",
317
+ "Keywords": "truncate line-clamp overflow",
318
+ "Platform": "Web",
319
+ "Description": "Handle text overflow properly",
320
+ "Do": "Use truncate/line-clamp/break-words",
321
+ "Don't": "Text overflows container",
322
+ "Code Example Good": "<p class='truncate'>Long text...</p>",
323
+ "Code Example Bad": "<p>Long text...</p> // overflows",
324
+ "Severity": "Medium"
325
+ },
326
+ {
327
+ "No": "26",
328
+ "Category": "Typography",
329
+ "Issue": "Non-Breaking Spaces",
330
+ "Keywords": "nbsp unit brand",
331
+ "Platform": "Web",
332
+ "Description": "Use non-breaking spaces for units and brand names",
333
+ "Do": "Use &nbsp; between number and unit",
334
+ "Don't": "10&nbsp;kg or Next.js&nbsp;14",
335
+ "Code Example Good": "10 kg // may wrap",
336
+ "Code Example Bad": "Low"
337
+ },
338
+ {
339
+ "No": "27",
340
+ "Category": "Anti-Pattern",
341
+ "Issue": "No Zoom Disable",
342
+ "Keywords": "viewport zoom disable",
343
+ "Platform": "Web",
344
+ "Description": "Never disable zoom in viewport meta",
345
+ "Do": "Allow user zoom",
346
+ "Don't": "<meta name='viewport' content='width=device-width'>",
347
+ "Code Example Good": "<meta name='viewport' content='maximum-scale=1'>",
348
+ "Code Example Bad": "Critical"
349
+ },
350
+ {
351
+ "No": "28",
352
+ "Category": "Anti-Pattern",
353
+ "Issue": "No Transition All",
354
+ "Keywords": "transition all specific",
355
+ "Platform": "Web",
356
+ "Description": "Avoid transition: all - specify properties",
357
+ "Do": "Transition specific properties",
358
+ "Don't": "transition: all",
359
+ "Code Example Good": "transition-colors duration-200",
360
+ "Code Example Bad": "transition-all duration-200",
361
+ "Severity": "Medium"
362
+ },
363
+ {
364
+ "No": "29",
365
+ "Category": "Anti-Pattern",
366
+ "Issue": "Outline Replacement",
367
+ "Keywords": "outline-none ring focus",
368
+ "Platform": "Web",
369
+ "Description": "Never use outline-none without replacement",
370
+ "Do": "Provide visible focus replacement",
371
+ "Don't": "Remove outline with nothing",
372
+ "Code Example Good": "focus:outline-none focus:ring-2 focus:ring-blue-500",
373
+ "Code Example Bad": "focus:outline-none // alone",
374
+ "Severity": "Critical"
375
+ },
376
+ {
377
+ "No": "30",
378
+ "Category": "Anti-Pattern",
379
+ "Issue": "No Hardcoded Dates",
380
+ "Keywords": "date format intl locale",
381
+ "Platform": "Web",
382
+ "Description": "Use Intl for date/number formatting",
383
+ "Do": "Use Intl.DateTimeFormat",
384
+ "Don't": "Hardcoded date format",
385
+ "Code Example Good": "new Intl.DateTimeFormat('en').format(date)",
386
+ "Code Example Bad": "date.toLocaleDateString() // or manual format",
387
+ "Severity": "Medium"
388
+ }
389
+ ]
@@ -69,7 +69,7 @@ export const uiSearchSchema = {
69
69
  };
70
70
  export const syncUiDataSchema = {
71
71
  name: "sync_ui_data",
72
- description: "同步 UI/UX 数据到本地缓存。从 npm 包 uipro-cli 下载最新数据,支持自动检查更新和强制同步。数据存储在 ~/.mcp-probe-kit/ui-ux-data/。",
72
+ description: "同步 UI/UX 数据到本地缓存。从 npm 包 uipro-cli 下载最新数据,支持自动检查更新和强制同步。数据存储在 ~/.mcp-probe-kit/ui-ux-data/,默认在下次启动时生效以保证当前会话一致性。",
73
73
  inputSchema: {
74
74
  type: "object",
75
75
  properties: {
@@ -2,6 +2,7 @@ import { parseArgs, getString, getBoolean } from "../utils/parseArgs.js";
2
2
  import { promises as fs } from "fs";
3
3
  import { okStructured } from "../lib/response.js";
4
4
  import { renderOrchestrationHeader } from "../lib/orchestration-guidance.js";
5
+ import { buildSkillBridgePlanStep, buildSkillHeaderNote, detectSkillBridge, renderSkillBridgeSection, } from "../lib/skill-bridge.js";
5
6
  import { WorkflowReportSchema } from "../schemas/structured-output.js";
6
7
  import { reportToolProgress, throwIfAborted, } from "../lib/tool-execution-context.js";
7
8
  /**
@@ -76,6 +77,9 @@ export async function startProduct(args, context) {
76
77
  isError: true,
77
78
  };
78
79
  }
80
+ const skillBridge = detectSkillBridge('start_product');
81
+ const skillBridgeStep = buildSkillBridgePlanStep(skillBridge);
82
+ const skillBridgeSection = renderSkillBridgeSection(skillBridge);
79
83
  const header = renderOrchestrationHeader({
80
84
  tool: 'start_product',
81
85
  goal: `完成产品设计工作流:${productName}`,
@@ -83,8 +87,9 @@ export async function startProduct(args, context) {
83
87
  '按 delegated plan 顺序调用工具',
84
88
  '生成 PRD、原型、设计系统与 HTML 原型',
85
89
  ],
90
+ notes: [buildSkillHeaderNote(skillBridge)],
86
91
  });
87
- const guidanceText = header + `# 🚀 产品设计工作流执行指导
92
+ const guidanceText = header + skillBridgeSection + `# 🚀 产品设计工作流执行指导
88
93
 
89
94
  基于${requirementsSource},请按照以下步骤完成从需求到 HTML 原型的完整产品设计流程。
90
95
 
@@ -308,6 +313,7 @@ ${!skipDesignSystem ? `├── design-system.json # 设计系统配
308
313
  const plan = {
309
314
  mode: 'delegated',
310
315
  steps: [
316
+ skillBridgeStep,
311
317
  {
312
318
  id: 'context',
313
319
  tool: 'init_project_context',
@@ -473,6 +479,7 @@ ${!skipDesignSystem ? `├── design-system.json # 设计系统配
473
479
  ],
474
480
  metadata: {
475
481
  plan,
482
+ skills: skillBridge,
476
483
  },
477
484
  };
478
485
  await reportToolProgress(context, 95, "start_product: 工作流输出已生成");
@@ -11,6 +11,7 @@ import { parseArgs, getString, getNumber } from "../utils/parseArgs.js";
11
11
  import { getReasoningEngine } from "./ui-ux-tools.js";
12
12
  import { okStructured } from "../lib/response.js";
13
13
  import { renderOrchestrationHeader } from "../lib/orchestration-guidance.js";
14
+ import { buildSkillBridgePlanStep, buildSkillHeaderNote, detectSkillBridge, renderSkillBridgeSection, } from "../lib/skill-bridge.js";
14
15
  import { UIReportSchema, RequirementsLoopSchema } from "../schemas/structured-output.js";
15
16
  import { detectProjectType } from "../lib/project-detector.js";
16
17
  import { reportToolProgress, throwIfAborted, } from "../lib/tool-execution-context.js";
@@ -519,6 +520,10 @@ export async function startUi(args, context) {
519
520
  if (profileDecision.warning) {
520
521
  headerNotes.push(profileDecision.warning);
521
522
  }
523
+ const skillBridge = detectSkillBridge('start_ui');
524
+ const skillBridgeStep = buildSkillBridgePlanStep(skillBridge);
525
+ const skillBridgeSection = renderSkillBridgeSection(skillBridge);
526
+ headerNotes.push(buildSkillHeaderNote(skillBridge));
522
527
  // 验证 mode 参数
523
528
  const validModes = ["auto", "manual"];
524
529
  if (mode && !validModes.includes(mode)) {
@@ -583,6 +588,7 @@ start_ui <描述> --requirements_mode=loop
583
588
  const plan = {
584
589
  mode: 'delegated',
585
590
  steps: [
591
+ skillBridgeStep,
586
592
  {
587
593
  id: 'loop-1',
588
594
  tool: 'ask_user',
@@ -666,7 +672,7 @@ start_ui <描述> --requirements_mode=loop
666
672
  const loopTemplate = profileDecision.resolved === 'strict'
667
673
  ? LOOP_PROMPT_TEMPLATE_STRICT
668
674
  : LOOP_PROMPT_TEMPLATE_GUIDED;
669
- const guide = header + loopTemplate
675
+ const guide = header + skillBridgeSection + loopTemplate
670
676
  .replace(/{description}/g, description)
671
677
  .replace(/{question_budget}/g, String(questionBudget))
672
678
  .replace(/{assumption_cap}/g, String(assumptionCap));
@@ -696,6 +702,7 @@ start_ui <描述> --requirements_mode=loop
696
702
  metadata: {
697
703
  plan,
698
704
  template: templateMeta,
705
+ skills: skillBridge,
699
706
  },
700
707
  };
701
708
  await reportToolProgress(context, 95, "start_ui: loop 输出已生成");
@@ -808,6 +815,7 @@ ${recommendation.reasoning}
808
815
  const plan = {
809
816
  mode: 'delegated',
810
817
  steps: [
818
+ skillBridgeStep,
811
819
  {
812
820
  id: 'context',
813
821
  tool: 'init_project_context',
@@ -872,7 +880,7 @@ ${recommendation.reasoning}
872
880
  ],
873
881
  notes: headerNotes,
874
882
  });
875
- const smartPlan = header + (profileDecision.resolved === 'strict' ? smartPlanStrict : smartPlanGuided);
883
+ const smartPlan = header + skillBridgeSection + (profileDecision.resolved === 'strict' ? smartPlanStrict : smartPlanGuided);
876
884
  // Create structured UI report for auto mode
877
885
  const uiReport = {
878
886
  summary: `智能 UI 开发:${description}`,
@@ -941,6 +949,7 @@ ${recommendation.reasoning}
941
949
  metadata: {
942
950
  plan,
943
951
  template: templateMeta,
952
+ skills: skillBridge,
944
953
  },
945
954
  };
946
955
  await reportToolProgress(context, 95, "start_ui: auto 输出已生成");
@@ -1002,7 +1011,7 @@ start_ui "设置页面" --framework=react
1002
1011
  const baseTemplate = profileDecision.resolved === 'strict'
1003
1012
  ? PROMPT_TEMPLATE_STRICT
1004
1013
  : PROMPT_TEMPLATE_GUIDED;
1005
- let guide = header + baseTemplate;
1014
+ let guide = header + skillBridgeSection + baseTemplate;
1006
1015
  guide = safeReplace(guide, '{description}', escapeJson(description));
1007
1016
  guide = safeReplace(guide, '{productType}', productType);
1008
1017
  guide = safeReplace(guide, '{framework}', framework);
@@ -1010,6 +1019,7 @@ start_ui "设置页面" --framework=react
1010
1019
  const plan = {
1011
1020
  mode: 'delegated',
1012
1021
  steps: [
1022
+ skillBridgeStep,
1013
1023
  {
1014
1024
  id: 'context',
1015
1025
  tool: 'init_project_context',
@@ -1132,6 +1142,7 @@ start_ui "设置页面" --framework=react
1132
1142
  metadata: {
1133
1143
  plan,
1134
1144
  template: templateMeta,
1145
+ skills: skillBridge,
1135
1146
  },
1136
1147
  };
1137
1148
  await reportToolProgress(context, 95, "start_ui: manual 输出已生成");
@@ -774,7 +774,7 @@ export async function syncUiData(args, context) {
774
774
  console.log('Failed to check update, proceeding with sync...');
775
775
  }
776
776
  }
777
- // 执行同步
777
+ // 执行同步(下载并写入缓存,当前会话不热切换)
778
778
  throwIfAborted(context?.signal, 'sync_ui_data 已取消');
779
779
  await reportToolProgress(context, 30, 'sync_ui_data: 下载并处理数据');
780
780
  await syncUIDataToCache(force, verbose, {
@@ -783,16 +783,14 @@ export async function syncUiData(args, context) {
783
783
  await reportToolProgress(context, 30 + Math.round(progress * 0.6), `sync_ui_data: ${message}`);
784
784
  },
785
785
  });
786
- // 重新加载数据
787
786
  throwIfAborted(context?.signal, 'sync_ui_data 已取消');
788
- await reportToolProgress(context, 92, 'sync_ui_data: 重载本地缓存');
789
- if (dataLoader) {
790
- await dataLoader.reload();
791
- }
792
- const cacheDir = dataLoader?.getCacheManager().getCacheDir() || '';
787
+ await reportToolProgress(context, 92, 'sync_ui_data: 记录会话状态');
793
788
  // 获取同步的数据统计
794
789
  const loader = await getDataLoader();
790
+ const cacheDir = loader.getCacheManager().getCacheDir() || '';
791
+ const metadata = loader.getCacheManager().getMetadata();
795
792
  const searchEngine = loader.getSearchEngine();
793
+ const sessionInfo = loader.getSessionInfo();
796
794
  const syncedData = {
797
795
  summary: "UI/UX 数据同步成功",
798
796
  status: 'success',
@@ -802,20 +800,26 @@ export async function syncUiData(args, context) {
802
800
  components: (searchEngine.getCategoryData('products') || []).length,
803
801
  patterns: (searchEngine.getCategoryData('landing') || []).length,
804
802
  },
803
+ version: metadata?.version,
805
804
  timestamp: new Date().toISOString(),
806
805
  };
807
806
  await reportToolProgress(context, 100, 'sync_ui_data: 同步完成');
808
807
  return okStructured(`✅ UI/UX 数据同步成功
809
-
810
- 数据已更新到缓存目录: ${cacheDir}
811
-
812
- **同步统计:**
813
- - 颜色: ${syncedData.synced.colors} 条
814
- - 图标: ${syncedData.synced.icons} 条
815
- - 组件: ${syncedData.synced.components} 条
816
- - 模式: ${syncedData.synced.patterns} 条
817
-
818
- **提示:** 数据已自动重新加载,可以立即使用最新数据。
808
+
809
+ 数据已更新到缓存目录: ${cacheDir}
810
+ 下载版本: ${metadata?.version || 'unknown'}
811
+
812
+ **同步统计:**
813
+ - 颜色: ${syncedData.synced.colors} 条
814
+ - 图标: ${syncedData.synced.icons} 条
815
+ - 组件: ${syncedData.synced.components} 条
816
+ - 模式: ${syncedData.synced.patterns} 条
817
+
818
+ **会话状态:**
819
+ - 当前会话使用版本: ${sessionInfo.activeVersion || 'unknown'}(source: ${sessionInfo.source})
820
+ - 下次启动生效版本: ${sessionInfo.pendingVersion || metadata?.version || 'unknown'}
821
+
822
+ **提示:** 为保证会话内结果一致,新数据将在下次启动后生效。
819
823
  `, syncedData, {
820
824
  schema: (await import('../schemas/output/ui-ux-tools.js')).SyncReportSchema,
821
825
  });
@@ -4,7 +4,7 @@
4
4
  * 三层数据策略:
5
5
  * 1. 内嵌数据(构建时同步)
6
6
  * 2. 缓存数据(运行时更新)
7
- * 3. 手动同步(用户触发)
7
+ * 3. 自动后台同步(当前会话不热切换,下次启动生效)
8
8
  */
9
9
  import { CacheManager } from './cache-manager.js';
10
10
  import { UISearchEngine } from './ui-search-engine.js';
@@ -12,6 +12,13 @@ export interface DataLoaderOptions {
12
12
  useCache?: boolean;
13
13
  autoUpdate?: boolean;
14
14
  }
15
+ export interface UIDataSessionInfo {
16
+ source: 'cache' | 'embedded';
17
+ activeVersion?: string;
18
+ pendingVersion?: string;
19
+ lastCheckedAt?: string;
20
+ hasPendingUpdate: boolean;
21
+ }
15
22
  /**
16
23
  * UI/UX 数据加载器
17
24
  */
@@ -19,7 +26,11 @@ export declare class UIDataLoader {
19
26
  private cacheManager;
20
27
  private searchEngine;
21
28
  private useCache;
29
+ private autoUpdate;
22
30
  private loaded;
31
+ private autoSyncRunning;
32
+ private autoSyncFailureUntil;
33
+ private sessionInfo;
23
34
  constructor(options?: DataLoaderOptions);
24
35
  /**
25
36
  * 加载数据
@@ -33,6 +44,7 @@ export declare class UIDataLoader {
33
44
  * 从内嵌数据加载
34
45
  */
35
46
  private loadFromEmbedded;
47
+ private readEmbeddedVersion;
36
48
  /**
37
49
  * 提取类别名称
38
50
  */
@@ -50,7 +62,11 @@ export declare class UIDataLoader {
50
62
  */
51
63
  getCacheManager(): CacheManager;
52
64
  /**
53
- * 重新加载数据
65
+ * 获取当前会话的数据状态
66
+ */
67
+ getSessionInfo(): UIDataSessionInfo;
68
+ /**
69
+ * 重新加载数据(手动触发时使用)
54
70
  */
55
71
  reload(): Promise<void>;
56
72
  }