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,41 @@
1
+ /**
2
+ * 设计系统 JSON 格式化器
3
+ *
4
+ * 将设计系统推荐转换为机器可读的 JSON 格式
5
+ */
6
+ import { DesignSystemRecommendation } from './design-reasoning-engine.js';
7
+ export interface DesignSystemJson {
8
+ version: string;
9
+ productType: string;
10
+ stack?: string;
11
+ colors: {
12
+ primary: Record<string, string>;
13
+ secondary?: Record<string, string>;
14
+ neutral: Record<string, string>;
15
+ success: Record<string, string>;
16
+ warning: Record<string, string>;
17
+ error: Record<string, string>;
18
+ };
19
+ typography: {
20
+ fontFamily: {
21
+ sans: string[];
22
+ serif: string[];
23
+ mono: string[];
24
+ };
25
+ fontSize: Record<string, string>;
26
+ fontWeight: Record<string, number>;
27
+ lineHeight: Record<string, string>;
28
+ };
29
+ spacing: {
30
+ base: number;
31
+ scale: number[];
32
+ };
33
+ borderRadius: Record<string, string>;
34
+ shadows: Record<string, string>;
35
+ breakpoints: Record<string, string>;
36
+ zIndex: Record<string, number>;
37
+ }
38
+ /**
39
+ * 格式化设计系统为 JSON
40
+ */
41
+ export declare function formatDesignSystemJson(recommendation: DesignSystemRecommendation, productType: string, stack?: string): DesignSystemJson;
@@ -0,0 +1,165 @@
1
+ /**
2
+ * 设计系统 JSON 格式化器
3
+ *
4
+ * 将设计系统推荐转换为机器可读的 JSON 格式
5
+ */
6
+ /**
7
+ * 解析颜色字符串,生成色阶
8
+ */
9
+ function generateColorScale(baseColor) {
10
+ // 简化版:返回基础色阶
11
+ // 实际项目中可以使用 color 库生成完整色阶
12
+ return {
13
+ '50': lighten(baseColor, 0.95),
14
+ '100': lighten(baseColor, 0.9),
15
+ '200': lighten(baseColor, 0.8),
16
+ '300': lighten(baseColor, 0.6),
17
+ '400': lighten(baseColor, 0.4),
18
+ '500': baseColor,
19
+ '600': darken(baseColor, 0.2),
20
+ '700': darken(baseColor, 0.4),
21
+ '800': darken(baseColor, 0.6),
22
+ '900': darken(baseColor, 0.8),
23
+ };
24
+ }
25
+ /**
26
+ * 简单的颜色变亮函数
27
+ */
28
+ function lighten(color, _amount) {
29
+ // 简化实现:返回原色
30
+ // 实际项目中应该使用专业的颜色库
31
+ return color;
32
+ }
33
+ /**
34
+ * 简单的颜色变暗函数
35
+ */
36
+ function darken(color, _amount) {
37
+ // 简化实现:返回原色
38
+ // 实际项目中应该使用专业的颜色库
39
+ return color;
40
+ }
41
+ /**
42
+ * 从推荐中提取主色
43
+ */
44
+ function extractPrimaryColor(recommendation) {
45
+ // 从配色方案中提取主色
46
+ const colorPalette = recommendation.colors;
47
+ // 尝试从 primary 字段提取
48
+ if (colorPalette.primary) {
49
+ return colorPalette.primary;
50
+ }
51
+ // 默认蓝色
52
+ return '#3b82f6';
53
+ }
54
+ /**
55
+ * 从推荐中提取辅色
56
+ */
57
+ function extractSecondaryColor(recommendation) {
58
+ const colorPalette = recommendation.colors;
59
+ if (colorPalette.secondary) {
60
+ return colorPalette.secondary;
61
+ }
62
+ return undefined;
63
+ }
64
+ /**
65
+ * 从推荐中提取中性色
66
+ */
67
+ function extractNeutralColor(recommendation) {
68
+ const colorPalette = recommendation.colors;
69
+ // 使用 text 颜色作为中性色
70
+ if (colorPalette.text) {
71
+ return colorPalette.text;
72
+ }
73
+ return '#6b7280';
74
+ }
75
+ /**
76
+ * 格式化设计系统为 JSON
77
+ */
78
+ export function formatDesignSystemJson(recommendation, productType, stack) {
79
+ const primaryColor = extractPrimaryColor(recommendation);
80
+ const secondaryColor = extractSecondaryColor(recommendation);
81
+ const neutralColor = extractNeutralColor(recommendation);
82
+ return {
83
+ version: '1.0.0',
84
+ productType,
85
+ stack,
86
+ colors: {
87
+ primary: generateColorScale(primaryColor),
88
+ ...(secondaryColor && { secondary: generateColorScale(secondaryColor) }),
89
+ neutral: generateColorScale(neutralColor),
90
+ success: generateColorScale('#10b981'),
91
+ warning: generateColorScale('#f59e0b'),
92
+ error: generateColorScale('#ef4444'),
93
+ },
94
+ typography: {
95
+ fontFamily: {
96
+ sans: recommendation.typography.heading?.split(',').map((f) => f.trim()) || ['Inter', 'system-ui', 'sans-serif'],
97
+ serif: recommendation.typography.body?.split(',').map((f) => f.trim()) || ['Merriweather', 'Georgia', 'serif'],
98
+ mono: ['Fira Code', 'Consolas', 'monospace'],
99
+ },
100
+ fontSize: {
101
+ xs: '0.75rem',
102
+ sm: '0.875rem',
103
+ base: '1rem',
104
+ lg: '1.125rem',
105
+ xl: '1.25rem',
106
+ '2xl': '1.5rem',
107
+ '3xl': '1.875rem',
108
+ '4xl': '2.25rem',
109
+ '5xl': '3rem',
110
+ },
111
+ fontWeight: {
112
+ light: 300,
113
+ normal: 400,
114
+ medium: 500,
115
+ semibold: 600,
116
+ bold: 700,
117
+ extrabold: 800,
118
+ },
119
+ lineHeight: {
120
+ none: '1',
121
+ tight: '1.25',
122
+ snug: '1.375',
123
+ normal: '1.5',
124
+ relaxed: '1.625',
125
+ loose: '2',
126
+ },
127
+ },
128
+ spacing: {
129
+ base: 4,
130
+ scale: [0, 4, 8, 12, 16, 20, 24, 32, 40, 48, 64, 80, 96, 128],
131
+ },
132
+ borderRadius: {
133
+ none: '0',
134
+ sm: '0.125rem',
135
+ md: '0.375rem',
136
+ lg: '0.5rem',
137
+ xl: '0.75rem',
138
+ '2xl': '1rem',
139
+ full: '9999px',
140
+ },
141
+ shadows: {
142
+ sm: '0 1px 2px 0 rgb(0 0 0 / 0.05)',
143
+ md: '0 4px 6px -1px rgb(0 0 0 / 0.1)',
144
+ lg: '0 10px 15px -3px rgb(0 0 0 / 0.1)',
145
+ xl: '0 20px 25px -5px rgb(0 0 0 / 0.1)',
146
+ '2xl': '0 25px 50px -12px rgb(0 0 0 / 0.25)',
147
+ },
148
+ breakpoints: {
149
+ sm: '640px',
150
+ md: '768px',
151
+ lg: '1024px',
152
+ xl: '1280px',
153
+ '2xl': '1536px',
154
+ },
155
+ zIndex: {
156
+ dropdown: 1000,
157
+ sticky: 1020,
158
+ fixed: 1030,
159
+ modalBackdrop: 1040,
160
+ modal: 1050,
161
+ popover: 1060,
162
+ tooltip: 1070,
163
+ },
164
+ };
165
+ }
@@ -0,0 +1,56 @@
1
+ /**
2
+ * UI/UX 数据加载器
3
+ *
4
+ * 三层数据策略:
5
+ * 1. 内嵌数据(构建时同步)
6
+ * 2. 缓存数据(运行时更新)
7
+ * 3. 手动同步(用户触发)
8
+ */
9
+ import { CacheManager } from './cache-manager.js';
10
+ import { UISearchEngine } from './ui-search-engine.js';
11
+ export interface DataLoaderOptions {
12
+ useCache?: boolean;
13
+ autoUpdate?: boolean;
14
+ }
15
+ /**
16
+ * UI/UX 数据加载器
17
+ */
18
+ export declare class UIDataLoader {
19
+ private cacheManager;
20
+ private searchEngine;
21
+ private useCache;
22
+ private loaded;
23
+ constructor(options?: DataLoaderOptions);
24
+ /**
25
+ * 加载数据
26
+ */
27
+ load(): Promise<void>;
28
+ /**
29
+ * 从缓存加载数据
30
+ */
31
+ private loadFromCache;
32
+ /**
33
+ * 从内嵌数据加载
34
+ */
35
+ private loadFromEmbedded;
36
+ /**
37
+ * 提取类别名称
38
+ */
39
+ private extractCategory;
40
+ /**
41
+ * 后台检查更新
42
+ */
43
+ private checkUpdateInBackground;
44
+ /**
45
+ * 获取搜索引擎
46
+ */
47
+ getSearchEngine(): UISearchEngine;
48
+ /**
49
+ * 获取缓存管理器
50
+ */
51
+ getCacheManager(): CacheManager;
52
+ /**
53
+ * 重新加载数据
54
+ */
55
+ reload(): Promise<void>;
56
+ }
@@ -0,0 +1,164 @@
1
+ /**
2
+ * UI/UX 数据加载器
3
+ *
4
+ * 三层数据策略:
5
+ * 1. 内嵌数据(构建时同步)
6
+ * 2. 缓存数据(运行时更新)
7
+ * 3. 手动同步(用户触发)
8
+ */
9
+ import * as fs from 'fs';
10
+ import * as path from 'path';
11
+ import { fileURLToPath } from 'url';
12
+ import { CacheManager } from './cache-manager.js';
13
+ import { UISearchEngine } from './ui-search-engine.js';
14
+ const __filename = fileURLToPath(import.meta.url);
15
+ const __dirname = path.dirname(__filename);
16
+ /**
17
+ * UI/UX 数据加载器
18
+ */
19
+ export class UIDataLoader {
20
+ cacheManager;
21
+ searchEngine;
22
+ useCache;
23
+ loaded = false;
24
+ constructor(options = {}) {
25
+ this.useCache = options.useCache ?? true;
26
+ this.cacheManager = new CacheManager({
27
+ autoUpdate: options.autoUpdate ?? true,
28
+ });
29
+ this.searchEngine = new UISearchEngine();
30
+ }
31
+ /**
32
+ * 加载数据
33
+ */
34
+ async load() {
35
+ if (this.loaded) {
36
+ return;
37
+ }
38
+ // 尝试从缓存加载
39
+ if (this.useCache && this.cacheManager.hasCache()) {
40
+ try {
41
+ await this.loadFromCache();
42
+ this.loaded = true;
43
+ // 后台检查更新
44
+ this.checkUpdateInBackground();
45
+ return;
46
+ }
47
+ catch (error) {
48
+ console.error('Failed to load from cache, falling back to embedded data:', error);
49
+ }
50
+ }
51
+ // 从内嵌数据加载
52
+ await this.loadFromEmbedded();
53
+ this.loaded = true;
54
+ }
55
+ /**
56
+ * 从缓存加载数据
57
+ */
58
+ async loadFromCache() {
59
+ const files = this.cacheManager.listFiles();
60
+ const datasets = [];
61
+ for (const file of files) {
62
+ if (!file.endsWith('.json')) {
63
+ continue;
64
+ }
65
+ const data = this.cacheManager.readFile(file);
66
+ if (!data || !Array.isArray(data)) {
67
+ continue;
68
+ }
69
+ // 提取类别名称
70
+ const category = this.extractCategory(file);
71
+ datasets.push({
72
+ category,
73
+ data,
74
+ });
75
+ }
76
+ this.searchEngine.loadDatasets(datasets);
77
+ }
78
+ /**
79
+ * 从内嵌数据加载
80
+ */
81
+ async loadFromEmbedded() {
82
+ const dataDir = path.join(__dirname, '..', 'resources', 'ui-ux-data');
83
+ if (!fs.existsSync(dataDir)) {
84
+ throw new Error('Embedded UI/UX data not found. Please run "npm run sync-ui-data" first.');
85
+ }
86
+ const datasets = [];
87
+ const walk = (dir, prefix = '') => {
88
+ const entries = fs.readdirSync(dir, { withFileTypes: true });
89
+ for (const entry of entries) {
90
+ const fullPath = path.join(dir, entry.name);
91
+ const relativePath = prefix ? `${prefix}/${entry.name}` : entry.name;
92
+ if (entry.isDirectory()) {
93
+ walk(fullPath, relativePath);
94
+ }
95
+ else if (entry.isFile() && entry.name.endsWith('.json') && entry.name !== 'metadata.json') {
96
+ try {
97
+ const content = fs.readFileSync(fullPath, 'utf-8');
98
+ const data = JSON.parse(content);
99
+ if (Array.isArray(data)) {
100
+ const category = this.extractCategory(relativePath);
101
+ datasets.push({ category, data });
102
+ }
103
+ }
104
+ catch (error) {
105
+ console.error(`Failed to load ${relativePath}:`, error);
106
+ }
107
+ }
108
+ }
109
+ };
110
+ walk(dataDir);
111
+ this.searchEngine.loadDatasets(datasets);
112
+ }
113
+ /**
114
+ * 提取类别名称
115
+ */
116
+ extractCategory(filename) {
117
+ // 移除扩展名
118
+ let category = filename.replace(/\.json$/, '');
119
+ // 处理子目录(如 stacks/react.json -> react)
120
+ if (category.includes('/')) {
121
+ const parts = category.split('/');
122
+ category = parts[parts.length - 1];
123
+ }
124
+ return category;
125
+ }
126
+ /**
127
+ * 后台检查更新
128
+ */
129
+ async checkUpdateInBackground() {
130
+ try {
131
+ const updateInfo = await this.cacheManager.checkUpdate();
132
+ if (updateInfo.hasUpdate) {
133
+ console.log(`UI/UX data update available: ${updateInfo.currentVersion || 'none'} -> ${updateInfo.latestVersion}`);
134
+ console.log('Run "npm run sync-ui-data" to update.');
135
+ }
136
+ }
137
+ catch (error) {
138
+ // 静默失败,不影响主流程
139
+ }
140
+ }
141
+ /**
142
+ * 获取搜索引擎
143
+ */
144
+ getSearchEngine() {
145
+ if (!this.loaded) {
146
+ throw new Error('Data not loaded. Call load() first.');
147
+ }
148
+ return this.searchEngine;
149
+ }
150
+ /**
151
+ * 获取缓存管理器
152
+ */
153
+ getCacheManager() {
154
+ return this.cacheManager;
155
+ }
156
+ /**
157
+ * 重新加载数据
158
+ */
159
+ async reload() {
160
+ this.searchEngine.clear();
161
+ this.loaded = false;
162
+ await this.load();
163
+ }
164
+ }
@@ -0,0 +1,57 @@
1
+ /**
2
+ * UI/UX 搜索引擎
3
+ *
4
+ * 基于 BM25 算法的 UI/UX 数据搜索引擎
5
+ */
6
+ export interface UISearchOptions {
7
+ category?: string;
8
+ stack?: string;
9
+ limit?: number;
10
+ minScore?: number;
11
+ }
12
+ export interface UISearchResult {
13
+ id: string;
14
+ score: number;
15
+ category: string;
16
+ data: Record<string, any>;
17
+ }
18
+ export interface UIDataset {
19
+ category: string;
20
+ data: Record<string, any>[];
21
+ }
22
+ /**
23
+ * UI/UX 搜索引擎
24
+ */
25
+ export declare class UISearchEngine {
26
+ private bm25;
27
+ private datasets;
28
+ constructor();
29
+ /**
30
+ * 加载数据集
31
+ */
32
+ loadDataset(category: string, data: Record<string, any>[]): void;
33
+ /**
34
+ * 批量加载数据集
35
+ */
36
+ loadDatasets(datasets: UIDataset[]): void;
37
+ /**
38
+ * 构建搜索文本
39
+ */
40
+ private buildSearchText;
41
+ /**
42
+ * 搜索 UI/UX 数据
43
+ */
44
+ search(query: string, options?: UISearchOptions): UISearchResult[];
45
+ /**
46
+ * 获取所有类别
47
+ */
48
+ getCategories(): string[];
49
+ /**
50
+ * 获取类别数据
51
+ */
52
+ getCategoryData(category: string): Record<string, any>[] | undefined;
53
+ /**
54
+ * 清空索引
55
+ */
56
+ clear(): void;
57
+ }
@@ -0,0 +1,123 @@
1
+ /**
2
+ * UI/UX 搜索引擎
3
+ *
4
+ * 基于 BM25 算法的 UI/UX 数据搜索引擎
5
+ */
6
+ import { BM25 } from './bm25.js';
7
+ /**
8
+ * UI/UX 搜索引擎
9
+ */
10
+ export class UISearchEngine {
11
+ bm25;
12
+ datasets = new Map();
13
+ constructor() {
14
+ this.bm25 = new BM25({
15
+ k1: 1.5,
16
+ b: 0.75,
17
+ });
18
+ }
19
+ /**
20
+ * 加载数据集
21
+ */
22
+ loadDataset(category, data) {
23
+ this.datasets.set(category, data);
24
+ // 为每条数据创建 BM25 文档
25
+ for (let i = 0; i < data.length; i++) {
26
+ const item = data[i];
27
+ const docId = `${category}:${i}`;
28
+ // 构建搜索文本(包含所有字段)
29
+ const searchText = this.buildSearchText(item);
30
+ this.bm25.addDocument({
31
+ id: docId,
32
+ text: searchText,
33
+ metadata: {
34
+ category,
35
+ index: i,
36
+ },
37
+ });
38
+ }
39
+ }
40
+ /**
41
+ * 批量加载数据集
42
+ */
43
+ loadDatasets(datasets) {
44
+ for (const dataset of datasets) {
45
+ this.loadDataset(dataset.category, dataset.data);
46
+ }
47
+ }
48
+ /**
49
+ * 构建搜索文本
50
+ */
51
+ buildSearchText(item) {
52
+ const parts = [];
53
+ for (const [key, value] of Object.entries(item)) {
54
+ if (value == null)
55
+ continue;
56
+ if (typeof value === 'string') {
57
+ parts.push(value);
58
+ }
59
+ else if (typeof value === 'number') {
60
+ parts.push(String(value));
61
+ }
62
+ else if (Array.isArray(value)) {
63
+ parts.push(value.join(' '));
64
+ }
65
+ else if (typeof value === 'object') {
66
+ parts.push(JSON.stringify(value));
67
+ }
68
+ }
69
+ return parts.join(' ');
70
+ }
71
+ /**
72
+ * 搜索 UI/UX 数据
73
+ */
74
+ search(query, options = {}) {
75
+ const { category, limit = 10, minScore = 0, } = options;
76
+ // 执行 BM25 搜索
77
+ const bm25Results = this.bm25.search(query, limit * 2);
78
+ // 转换结果
79
+ const results = [];
80
+ for (const result of bm25Results) {
81
+ if (result.score < minScore)
82
+ continue;
83
+ const { category: resultCategory, index } = result.metadata;
84
+ // 过滤类别
85
+ if (category && resultCategory !== category) {
86
+ continue;
87
+ }
88
+ const dataset = this.datasets.get(resultCategory);
89
+ if (!dataset || index >= dataset.length) {
90
+ continue;
91
+ }
92
+ results.push({
93
+ id: result.id,
94
+ score: result.score,
95
+ category: resultCategory,
96
+ data: dataset[index],
97
+ });
98
+ if (results.length >= limit) {
99
+ break;
100
+ }
101
+ }
102
+ return results;
103
+ }
104
+ /**
105
+ * 获取所有类别
106
+ */
107
+ getCategories() {
108
+ return Array.from(this.datasets.keys());
109
+ }
110
+ /**
111
+ * 获取类别数据
112
+ */
113
+ getCategoryData(category) {
114
+ return this.datasets.get(category);
115
+ }
116
+ /**
117
+ * 清空索引
118
+ */
119
+ clear() {
120
+ this.bm25.clear();
121
+ this.datasets.clear();
122
+ }
123
+ }
@@ -0,0 +1,13 @@
1
+ /**
2
+ * UI/UX 数据同步工具
3
+ *
4
+ * 从 npm 包 uipro-cli 同步数据到缓存目录
5
+ */
6
+ /**
7
+ * 同步 UI/UX 数据到指定目录(通用函数)
8
+ */
9
+ export declare function syncUIDataTo(outputDir: string, verbose?: boolean): Promise<void>;
10
+ /**
11
+ * 同步 UI/UX 数据到缓存
12
+ */
13
+ export declare function syncUIDataToCache(force?: boolean, verbose?: boolean): Promise<void>;