mcp-probe-kit 3.0.19 → 3.0.22

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 (81) hide show
  1. package/README.md +12 -5
  2. package/build/index.js +3 -1
  3. package/build/lib/__tests__/agents-md-template.unit.test.js +2 -0
  4. package/build/lib/__tests__/memory-config.unit.test.js +9 -0
  5. package/build/lib/__tests__/memory-injection.unit.test.d.ts +1 -0
  6. package/build/lib/__tests__/memory-injection.unit.test.js +51 -0
  7. package/build/lib/__tests__/memory-orchestration.unit.test.d.ts +1 -0
  8. package/build/lib/__tests__/memory-orchestration.unit.test.js +84 -0
  9. package/build/lib/__tests__/memory-payload.unit.test.d.ts +1 -0
  10. package/build/lib/__tests__/memory-payload.unit.test.js +35 -0
  11. package/build/lib/agents-md-template.js +7 -5
  12. package/build/lib/memory-client.d.ts +8 -1
  13. package/build/lib/memory-client.js +53 -44
  14. package/build/lib/memory-config.d.ts +8 -0
  15. package/build/lib/memory-config.js +19 -0
  16. package/build/lib/memory-orchestration.d.ts +7 -2
  17. package/build/lib/memory-orchestration.js +81 -8
  18. package/build/lib/memory-payload.d.ts +21 -0
  19. package/build/lib/memory-payload.js +65 -0
  20. package/build/lib/shadcn-ui.d.ts +11 -0
  21. package/build/lib/shadcn-ui.js +78 -0
  22. package/build/resources/ui-ux-data/guidelines/vercel-web-interface.json +1632 -0
  23. package/build/resources/ui-ux-data/metadata.json +27 -3
  24. package/build/resources/ui-ux-data/shadcn/blocks.json +2541 -0
  25. package/build/resources/ui-ux-data/shadcn/components.json +997 -0
  26. package/build/resources/ui-ux-data/themes/presets.json +483 -0
  27. package/build/schemas/index.d.ts +38 -9
  28. package/build/schemas/memory-tools.d.ts +38 -9
  29. package/build/schemas/memory-tools.js +24 -9
  30. package/build/schemas/output/ui-ux-tools.d.ts +16 -0
  31. package/build/schemas/output/ui-ux-tools.js +4 -0
  32. package/build/schemas/ui-ux-schemas.js +3 -3
  33. package/build/tools/__tests__/start_ui.property.test.js +4 -3
  34. package/build/tools/index.d.ts +1 -0
  35. package/build/tools/index.js +1 -0
  36. package/build/tools/memorize_asset.js +12 -0
  37. package/build/tools/scan_and_extract_patterns.js +7 -7
  38. package/build/tools/search_memory.d.ts +7 -0
  39. package/build/tools/search_memory.js +57 -0
  40. package/build/tools/start_bugfix.js +3 -3
  41. package/build/tools/start_feature.js +3 -3
  42. package/build/tools/start_ui.js +33 -6
  43. package/build/tools/ui-ux-tools.js +322 -244
  44. package/build/utils/__tests__/shadcn-sync.unit.test.d.ts +1 -0
  45. package/build/utils/__tests__/shadcn-sync.unit.test.js +49 -0
  46. package/build/utils/__tests__/theme-pick.unit.test.d.ts +1 -0
  47. package/build/utils/__tests__/theme-pick.unit.test.js +9 -0
  48. package/build/utils/__tests__/themes-sync.unit.test.d.ts +1 -0
  49. package/build/utils/__tests__/themes-sync.unit.test.js +21 -0
  50. package/build/utils/__tests__/ui-metadata.unit.test.d.ts +1 -0
  51. package/build/utils/__tests__/ui-metadata.unit.test.js +35 -0
  52. package/build/utils/__tests__/vercel-guidelines-sync.unit.test.d.ts +1 -0
  53. package/build/utils/__tests__/vercel-guidelines-sync.unit.test.js +34 -0
  54. package/build/utils/bm25.d.ts +2 -1
  55. package/build/utils/bm25.js +17 -5
  56. package/build/utils/shadcn-sync.d.ts +55 -0
  57. package/build/utils/shadcn-sync.js +146 -0
  58. package/build/utils/themes-sync.d.ts +32 -0
  59. package/build/utils/themes-sync.js +201 -0
  60. package/build/utils/ui-data-loader.js +13 -2
  61. package/build/utils/ui-metadata.d.ts +27 -0
  62. package/build/utils/ui-metadata.js +39 -0
  63. package/build/utils/ui-search-engine.d.ts +1 -0
  64. package/build/utils/ui-search-engine.js +20 -6
  65. package/build/utils/ui-sync.d.ts +24 -2
  66. package/build/utils/ui-sync.js +152 -86
  67. package/build/utils/vercel-guidelines-sync.d.ts +30 -0
  68. package/build/utils/vercel-guidelines-sync.js +133 -0
  69. package/docs/data/tools.js +18 -0
  70. package/docs/i18n/all-tools/en.json +6 -1
  71. package/docs/i18n/all-tools/ja.json +2 -1
  72. package/docs/i18n/all-tools/ko.json +2 -1
  73. package/docs/i18n/all-tools/zh-CN.json +7 -2
  74. package/docs/i18n/en.json +5 -5
  75. package/docs/i18n/ja.json +2 -2
  76. package/docs/i18n/ko.json +2 -2
  77. package/docs/i18n/zh-CN.json +7 -7
  78. package/docs/memory-local-setup.md +1 -1
  79. package/docs/memory-local-setup.zh-CN.md +5 -2
  80. package/docs/pages/getting-started.html +3 -2
  81. package/package.json +2 -2
@@ -1,5 +1,35 @@
1
1
  import { createMemoryClient } from './memory-client.js';
2
- export async function loadMemoryInjectionContext(query) {
2
+ import { getMemoryConfig } from './memory-config.js';
3
+ function kindSearchPreferences(kind) {
4
+ switch (kind) {
5
+ case 'bugfix':
6
+ return { preferTypes: ['bugfix'], preferTags: ['bugfix', 'root-cause'] };
7
+ case 'ui':
8
+ return { preferTypes: ['component', 'pattern'], preferTags: ['ui', 'pattern'] };
9
+ case 'feature':
10
+ return { preferTypes: ['pattern', 'code'], preferTags: ['feature', 'pattern'] };
11
+ default:
12
+ return { preferTypes: [], preferTags: [] };
13
+ }
14
+ }
15
+ export function truncateInjectionText(value, maxChars) {
16
+ if (value.length <= maxChars) {
17
+ return value;
18
+ }
19
+ return `${value.slice(0, Math.max(0, maxChars - 3))}...`;
20
+ }
21
+ async function loadFullAssets(results) {
22
+ const client = createMemoryClient();
23
+ if (!client.isReadEnabled() || results.length === 0) {
24
+ return {};
25
+ }
26
+ const entries = await Promise.all(results.map(async (item) => {
27
+ const asset = await client.getAsset(item.id);
28
+ return asset ? [item.id, asset] : null;
29
+ }));
30
+ return Object.fromEntries(entries.filter((entry) => entry !== null));
31
+ }
32
+ export async function loadMemoryInjectionContext(query, kind = 'default') {
3
33
  const client = createMemoryClient();
4
34
  if (!client.isEnabled()) {
5
35
  return {
@@ -8,16 +38,23 @@ export async function loadMemoryInjectionContext(query) {
8
38
  degraded: false,
9
39
  query,
10
40
  results: [],
41
+ assetsById: {},
11
42
  };
12
43
  }
13
44
  try {
14
- const results = await client.search(query);
45
+ const prefs = kindSearchPreferences(kind);
46
+ const results = await client.search(query, {
47
+ preferTypes: prefs.preferTypes,
48
+ preferTags: prefs.preferTags,
49
+ });
50
+ const assetsById = await loadFullAssets(results);
15
51
  return {
16
52
  enabled: true,
17
53
  available: true,
18
54
  degraded: false,
19
55
  query,
20
56
  results,
57
+ assetsById,
21
58
  };
22
59
  }
23
60
  catch (error) {
@@ -27,6 +64,7 @@ export async function loadMemoryInjectionContext(query) {
27
64
  degraded: true,
28
65
  query,
29
66
  results: [],
67
+ assetsById: {},
30
68
  error: error instanceof Error ? error.message : String(error),
31
69
  };
32
70
  }
@@ -39,7 +77,44 @@ function formatMemoryResultLabel(item) {
39
77
  : '历史资产';
40
78
  return `${item.name} [${item.type}] (${kind})`;
41
79
  }
80
+ export function shouldShowSourceInSearch(item, config = getMemoryConfig()) {
81
+ if (config.searchShowSource) {
82
+ return Boolean(item.sourcePath);
83
+ }
84
+ if (!config.repoId || !item.sourceProject || !item.sourcePath) {
85
+ return false;
86
+ }
87
+ return item.sourceProject === config.repoId;
88
+ }
89
+ function formatSourceHint(item, config) {
90
+ if (!shouldShowSourceInSearch(item, config)) {
91
+ return '';
92
+ }
93
+ return `\n - 来源: ${item.sourcePath}`;
94
+ }
95
+ function formatAssetBody(asset, config) {
96
+ const lines = [
97
+ `### ${asset.name}`,
98
+ `- asset_id: ${asset.id}`,
99
+ asset.description ? `- 描述: ${asset.description}` : '',
100
+ asset.usage ? `- 适用: ${asset.usage}` : '',
101
+ asset.tags.length > 0 ? `- 标签: ${asset.tags.join(', ')}` : '',
102
+ '',
103
+ truncateInjectionText(asset.content, config.injectionContentMaxChars),
104
+ ].filter(Boolean);
105
+ return lines.join('\n');
106
+ }
107
+ function formatResultBlock(item, index, context, config) {
108
+ const label = formatMemoryResultLabel(item);
109
+ const asset = context.assetsById[item.id];
110
+ const header = `${index + 1}. ${label} score=${item.score.toFixed(3)}\n - 摘要: ${item.summary}${formatSourceHint(item, config)}`;
111
+ if (asset?.content) {
112
+ return `${header}\n\n${formatAssetBody(asset, config)}\n`;
113
+ }
114
+ return `${header}\n - 全文加载失败,可手动: read_memory_asset {"asset_id": "${item.id}"}\n`;
115
+ }
42
116
  export function renderMemoryGuideSection(context) {
117
+ const config = getMemoryConfig();
43
118
  if (!context.enabled) {
44
119
  return '';
45
120
  }
@@ -49,13 +124,11 @@ export function renderMemoryGuideSection(context) {
49
124
  if (context.results.length === 0) {
50
125
  return `\n\n## 🧠 记忆系统\n- 状态: 已启用\n- 检索结果: 未找到高相关记录(含历史 Bug 修复与可复用模式)\n- 处理: 继续主流程;Bug 修复验证通过后必须 \`memorize_asset\` 沉淀;功能/UI 有可复用产出再沉淀\n`;
51
126
  }
127
+ const loadedCount = context.results.filter((item) => context.assetsById[item.id]?.content).length;
52
128
  const items = context.results
53
- .map((item, index) => {
54
- const label = formatMemoryResultLabel(item);
55
- return `${index + 1}. ${label} score=${item.score.toFixed(3)}\n - 摘要: ${item.summary}\n - 读取: read_memory_asset {\"asset_id\": \"${item.id}\"}${item.sourcePath ? `\n - 来源: ${item.sourcePath}` : ''}`;
56
- })
129
+ .map((item, index) => formatResultBlock(item, index, context, config))
57
130
  .join('\n');
58
- return `\n\n## 🧠 记忆系统\n- 状态: 已启用\n- 指令: 开干前先复用下列记录(含历史 Bug 现象/根因/改法);相关条目用 \`read_memory_asset\` 读全文,避免重复踩坑\n- 检索结果:\n${items}\n`;
131
+ return `\n\n## 🧠 记忆系统\n- 状态: 已启用\n- 指令: 下列为已自动加载的历史经验全文(${loadedCount}/${context.results.length} 条);开干前直接复用,无需再调 \`read_memory_asset\`\n- 检索结果:\n${items}`;
59
132
  }
60
133
  export function buildMemoryPlanStep(kind = 'default') {
61
134
  if (kind === 'bugfix') {
@@ -68,7 +141,7 @@ export function buildMemoryPlanStep(kind = 'default') {
68
141
  type: 'bugfix',
69
142
  description: '[现象、报错信息、复现条件]',
70
143
  summary: '[检索用:关键词 + 根因 + 修复要点,一句话]',
71
- content: '【现象】...\n【根因】...\n【修复】具体改动文件与关键代码/配置\n【验证】如何确认已修好',
144
+ content: '【现象】...\n【根因】...\n【修复】具体改动与关键代码/配置\n【验证】如何确认已修好',
72
145
  usage: '[再次遇到何种症状时可参考]',
73
146
  tags: ['bugfix', 'root-cause'],
74
147
  confidence: 0.85,
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Unify legacy Qdrant payloads (kind/title/source) with the current asset schema.
3
+ */
4
+ export declare function normalizeMemoryPayload(payload: Record<string, unknown>): Record<string, unknown>;
5
+ export declare function payloadToMemoryFields(payload: Record<string, unknown>): {
6
+ id: string;
7
+ name: string;
8
+ type: string;
9
+ description: string;
10
+ summary: string;
11
+ content: string;
12
+ tags: string[];
13
+ confidence: number;
14
+ sourceProject?: string;
15
+ sourcePath?: string;
16
+ usage?: string;
17
+ contentHash?: string;
18
+ normalizedContentHash?: string;
19
+ createdAt: string;
20
+ updatedAt: string;
21
+ };
@@ -0,0 +1,65 @@
1
+ function truncate(value, maxChars) {
2
+ if (value.length <= maxChars) {
3
+ return value;
4
+ }
5
+ return `${value.slice(0, Math.max(0, maxChars - 3))}...`;
6
+ }
7
+ /**
8
+ * Unify legacy Qdrant payloads (kind/title/source) with the current asset schema.
9
+ */
10
+ export function normalizeMemoryPayload(payload) {
11
+ const normalized = { ...payload };
12
+ if (!normalized.name && typeof normalized.title === 'string') {
13
+ normalized.name = normalized.title;
14
+ }
15
+ if (!normalized.type && typeof normalized.kind === 'string') {
16
+ const kind = normalized.kind;
17
+ normalized.type = kind === 'extracted_pattern' ? 'pattern' : kind;
18
+ }
19
+ if (!normalized.description) {
20
+ if (typeof normalized.title === 'string') {
21
+ normalized.description = normalized.title;
22
+ }
23
+ else if (typeof normalized.source === 'string') {
24
+ normalized.description = `Legacy memory from ${normalized.source}`;
25
+ }
26
+ }
27
+ if (!normalized.summary && typeof normalized.content === 'string') {
28
+ normalized.summary = truncate(normalized.content, 280);
29
+ }
30
+ if (!normalized.createdAt && typeof normalized.created_at === 'string') {
31
+ normalized.createdAt = normalized.created_at;
32
+ }
33
+ if (!normalized.updatedAt) {
34
+ if (typeof normalized.updated_at === 'string') {
35
+ normalized.updatedAt = normalized.updated_at;
36
+ }
37
+ else if (typeof normalized.createdAt === 'string') {
38
+ normalized.updatedAt = normalized.createdAt;
39
+ }
40
+ }
41
+ return normalized;
42
+ }
43
+ export function payloadToMemoryFields(payload) {
44
+ const p = normalizeMemoryPayload(payload);
45
+ const tags = Array.isArray(p.tags)
46
+ ? p.tags.filter((item) => typeof item === 'string' && item.trim().length > 0)
47
+ : [];
48
+ return {
49
+ id: String(p.id || ''),
50
+ name: String(p.name || ''),
51
+ type: String(p.type || ''),
52
+ description: String(p.description || ''),
53
+ summary: String(p.summary || ''),
54
+ content: String(p.content || ''),
55
+ tags,
56
+ confidence: typeof p.confidence === 'number' && Number.isFinite(p.confidence) ? p.confidence : 0.5,
57
+ sourceProject: typeof p.sourceProject === 'string' ? p.sourceProject : undefined,
58
+ sourcePath: typeof p.sourcePath === 'string' ? p.sourcePath : undefined,
59
+ usage: typeof p.usage === 'string' ? p.usage : undefined,
60
+ contentHash: typeof p.contentHash === 'string' ? p.contentHash : undefined,
61
+ normalizedContentHash: typeof p.normalizedContentHash === 'string' ? p.normalizedContentHash : undefined,
62
+ createdAt: String(p.createdAt || ''),
63
+ updatedAt: String(p.updatedAt || ''),
64
+ };
65
+ }
@@ -0,0 +1,11 @@
1
+ /**
2
+ * 判断是否适合使用 shadcn/ui 实现路径
3
+ */
4
+ export declare function isShadcnStack(stack?: string): boolean;
5
+ export declare function isShadcnCategory(category?: string): boolean;
6
+ export declare function isThemeCategory(category?: string): boolean;
7
+ export declare function isGuidelineCategory(category?: string): boolean;
8
+ export declare function formatShadcnResult(data: Record<string, any>): string;
9
+ export declare function formatThemeResult(data: Record<string, any>): string;
10
+ export declare function formatGuidelineResult(data: Record<string, any>): string;
11
+ export declare function pickThemeForProductType(themes: Record<string, any>[], productType: string): Record<string, any> | undefined;
@@ -0,0 +1,78 @@
1
+ /**
2
+ * 判断是否适合使用 shadcn/ui 实现路径
3
+ */
4
+ export function isShadcnStack(stack) {
5
+ if (!stack)
6
+ return false;
7
+ const normalized = stack.toLowerCase();
8
+ return (normalized.includes('react') ||
9
+ normalized.includes('next') ||
10
+ normalized.includes('shadcn') ||
11
+ normalized.includes('tailwind'));
12
+ }
13
+ export function isShadcnCategory(category) {
14
+ return Boolean(category?.startsWith('shadcn-'));
15
+ }
16
+ export function isThemeCategory(category) {
17
+ return category === 'ui-themes';
18
+ }
19
+ export function isGuidelineCategory(category) {
20
+ return category === 'ui-guidelines-vercel';
21
+ }
22
+ export function formatShadcnResult(data) {
23
+ const lines = [
24
+ `- **名称**: ${data.name || data.title}`,
25
+ `- **类型**: ${data.type || 'unknown'}`,
26
+ `- **描述**: ${data.description || '—'}`,
27
+ `- **安装**: \`${data.installCommand || `npx shadcn@latest add ${data.name}`}\``,
28
+ ];
29
+ if (Array.isArray(data.registryDependencies) && data.registryDependencies.length > 0) {
30
+ lines.push(`- **依赖组件**: ${data.registryDependencies.join(', ')}`);
31
+ }
32
+ if (Array.isArray(data.files) && data.files.length > 0) {
33
+ lines.push(`- **文件**: ${data.files.slice(0, 5).join(', ')}${data.files.length > 5 ? '…' : ''}`);
34
+ }
35
+ return lines.join('\n');
36
+ }
37
+ export function formatThemeResult(data) {
38
+ const lines = [
39
+ `- **主题**: ${data.title || data.name}`,
40
+ `- **描述**: ${data.description || '—'}`,
41
+ `- **基色**: ${data.baseColor || '—'}`,
42
+ `- **适合**: ${Array.isArray(data.bestFor) ? data.bestFor.join(', ') : '—'}`,
43
+ `- **用法**: 将 \`globalsCssSnippet\` 粘贴到 \`app/globals.css\`(shadcn new-york)`,
44
+ ];
45
+ return lines.join('\n');
46
+ }
47
+ export function formatGuidelineResult(data) {
48
+ return [
49
+ `- **级别**: ${data.level || '—'}`,
50
+ `- **章节**: ${data.section || '—'} / ${data.subsection || '—'}`,
51
+ `- **规则**: ${data.rule || data.description || '—'}`,
52
+ `- **来源**: Vercel Web Interface Guidelines`,
53
+ ].join('\n');
54
+ }
55
+ export function pickThemeForProductType(themes, productType) {
56
+ if (themes.length === 0)
57
+ return undefined;
58
+ const normalized = productType.toLowerCase();
59
+ const scored = themes.map((theme) => {
60
+ const bestFor = Array.isArray(theme.bestFor) ? theme.bestFor : [];
61
+ const score = bestFor.reduce((acc, item) => {
62
+ const token = item.toLowerCase();
63
+ if (normalized.includes(token) || token.includes(normalized)) {
64
+ return acc + 2;
65
+ }
66
+ if (normalized.split(/\s+/).some((part) => token.includes(part) && part.length > 2)) {
67
+ return acc + 1;
68
+ }
69
+ return acc;
70
+ }, 0);
71
+ return { theme, score };
72
+ });
73
+ scored.sort((a, b) => b.score - a.score);
74
+ if (scored[0]?.score > 0) {
75
+ return scored[0].theme;
76
+ }
77
+ return themes.find((theme) => theme.name === 'zinc-neutral') || themes[0];
78
+ }