mcp-probe-kit 3.2.0 → 3.6.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.
Files changed (180) hide show
  1. package/README.md +25 -7
  2. package/build/index.js +45 -79
  3. package/build/lib/__tests__/agents-md-template.unit.test.js +1 -0
  4. package/build/lib/__tests__/dev-workflow.unit.test.js +22 -0
  5. package/build/lib/__tests__/handles.unit.test.js +19 -0
  6. package/build/lib/__tests__/mcp-apps.unit.test.d.ts +1 -0
  7. package/build/lib/__tests__/mcp-apps.unit.test.js +52 -0
  8. package/build/lib/__tests__/mcp-tool-skill-registry.unit.test.d.ts +1 -0
  9. package/build/lib/__tests__/mcp-tool-skill-registry.unit.test.js +18 -0
  10. package/build/lib/__tests__/memory-client.unit.test.js +105 -0
  11. package/build/lib/__tests__/memory-orchestration.unit.test.d.ts +1 -0
  12. package/build/lib/__tests__/memory-orchestration.unit.test.js +88 -0
  13. package/build/lib/__tests__/memory-payload.unit.test.d.ts +1 -0
  14. package/build/lib/__tests__/memory-payload.unit.test.js +35 -0
  15. package/build/lib/__tests__/quality-constraints.unit.test.d.ts +1 -0
  16. package/build/lib/__tests__/quality-constraints.unit.test.js +54 -0
  17. package/build/lib/__tests__/spec-gate.unit.test.d.ts +1 -0
  18. package/build/lib/__tests__/spec-gate.unit.test.js +54 -0
  19. package/build/lib/__tests__/spec-validator.unit.test.js +106 -74
  20. package/build/lib/__tests__/task-defaults.unit.test.d.ts +1 -0
  21. package/build/lib/__tests__/task-defaults.unit.test.js +27 -0
  22. package/build/lib/__tests__/workflow-skill-installer.unit.test.d.ts +1 -0
  23. package/build/lib/__tests__/workflow-skill-installer.unit.test.js +110 -0
  24. package/build/lib/agents-md-template.js +40 -32
  25. package/build/lib/cursor-history-client.d.ts +54 -0
  26. package/build/lib/cursor-history-client.js +240 -0
  27. package/build/lib/dev-workflow.d.ts +36 -0
  28. package/build/lib/dev-workflow.js +497 -0
  29. package/build/lib/handles.d.ts +31 -0
  30. package/build/lib/handles.js +36 -0
  31. package/build/lib/mcp-apps.d.ts +14 -0
  32. package/build/lib/mcp-apps.js +234 -0
  33. package/build/lib/mcp-tool-skill-registry.d.ts +46 -0
  34. package/build/lib/mcp-tool-skill-registry.js +256 -0
  35. package/build/lib/memory-client.d.ts +19 -0
  36. package/build/lib/memory-client.js +69 -0
  37. package/build/lib/memory-orchestration.d.ts +5 -0
  38. package/build/lib/memory-orchestration.js +20 -0
  39. package/build/lib/merge-agents-md.d.ts +2 -2
  40. package/build/lib/merge-agents-md.js +7 -4
  41. package/build/lib/output-schema-registry.d.ts +11 -0
  42. package/build/lib/output-schema-registry.js +80 -0
  43. package/build/lib/quality-constraints.d.ts +54 -0
  44. package/build/lib/quality-constraints.js +155 -0
  45. package/build/lib/skill-bridge.js +12 -12
  46. package/build/lib/spec-gate.d.ts +32 -0
  47. package/build/lib/spec-gate.js +83 -0
  48. package/build/lib/spec-validator.js +16 -3
  49. package/build/lib/task-defaults.d.ts +6 -0
  50. package/build/lib/task-defaults.js +20 -0
  51. package/build/lib/template-loader.js +83 -23
  52. package/build/lib/tool-annotations.js +3 -0
  53. package/build/lib/toolset-manager.js +2 -0
  54. package/build/lib/workflow-skill-installer.d.ts +38 -0
  55. package/build/lib/workflow-skill-installer.js +158 -0
  56. package/build/lib/workflow-skill-template.d.ts +9 -0
  57. package/build/lib/workflow-skill-template.js +85 -0
  58. package/build/lib/workflow-skill-version.d.ts +15 -0
  59. package/build/lib/workflow-skill-version.js +68 -0
  60. package/build/resources/ui-ux-data/guidelines/vercel-web-interface.json +1632 -1632
  61. package/build/resources/ui-ux-data/metadata.json +30 -30
  62. package/build/resources/ui-ux-data/shadcn/blocks.json +2541 -2541
  63. package/build/resources/ui-ux-data/shadcn/components.json +997 -997
  64. package/build/resources/ui-ux-data/themes/presets.json +483 -483
  65. package/build/schemas/index.d.ts +110 -0
  66. package/build/schemas/index.js +1 -0
  67. package/build/schemas/memory-tools.d.ts +83 -0
  68. package/build/schemas/memory-tools.js +43 -0
  69. package/build/schemas/orchestration-tools.d.ts +8 -0
  70. package/build/schemas/orchestration-tools.js +8 -0
  71. package/build/schemas/output/code-insight-tools.d.ts +65 -0
  72. package/build/schemas/output/code-insight-tools.js +42 -0
  73. package/build/schemas/output/memory-tools.d.ts +576 -0
  74. package/build/schemas/output/memory-tools.js +148 -0
  75. package/build/schemas/project-tools.d.ts +19 -0
  76. package/build/schemas/project-tools.js +20 -0
  77. package/build/tools/__tests__/cursor-history.unit.test.d.ts +1 -0
  78. package/build/tools/__tests__/cursor-history.unit.test.js +38 -0
  79. package/build/tools/__tests__/delete_memory_asset.unit.test.d.ts +1 -0
  80. package/build/tools/__tests__/delete_memory_asset.unit.test.js +87 -0
  81. package/build/tools/__tests__/search_memory.unit.test.js +1 -0
  82. package/build/tools/__tests__/start_bugfix.unit.test.js +34 -1
  83. package/build/tools/__tests__/update_memory_asset.unit.test.d.ts +1 -0
  84. package/build/tools/__tests__/update_memory_asset.unit.test.js +82 -0
  85. package/build/tools/__tests__/workflow.unit.test.d.ts +1 -0
  86. package/build/tools/__tests__/workflow.unit.test.js +24 -0
  87. package/build/tools/check_spec.js +16 -16
  88. package/build/tools/code_insight.js +46 -42
  89. package/build/tools/code_review.js +11 -4
  90. package/build/tools/cursor_read_conversation.d.ts +7 -0
  91. package/build/tools/cursor_read_conversation.js +36 -0
  92. package/build/tools/delete_memory_asset.d.ts +7 -0
  93. package/build/tools/delete_memory_asset.js +57 -0
  94. package/build/tools/fix_bug.js +161 -161
  95. package/build/tools/gencommit.js +60 -60
  96. package/build/tools/index.d.ts +3 -0
  97. package/build/tools/index.js +3 -0
  98. package/build/tools/init_project_context.js +432 -432
  99. package/build/tools/search_memory.js +5 -2
  100. package/build/tools/start_bugfix.js +37 -4
  101. package/build/tools/start_feature.js +4 -3
  102. package/build/tools/start_product.js +1 -1
  103. package/build/tools/start_ui.js +22 -4
  104. package/build/tools/ui-ux-tools.d.ts +3 -0
  105. package/build/tools/ui-ux-tools.js +302 -290
  106. package/build/tools/update_memory_asset.d.ts +7 -0
  107. package/build/tools/update_memory_asset.js +98 -0
  108. package/build/tools/workflow.d.ts +13 -0
  109. package/build/tools/workflow.js +69 -0
  110. package/build/utils/__tests__/vercel-guidelines-sync.unit.test.js +12 -12
  111. package/build/utils/design-reasoning-engine.d.ts +2 -0
  112. package/build/utils/design-reasoning-engine.js +3 -0
  113. package/build/utils/themes-sync.js +8 -8
  114. package/package.json +6 -3
  115. package/build/resources/index.d.ts +0 -4
  116. package/build/resources/index.js +0 -4
  117. package/build/resources/tool-params-guide.d.ts +0 -571
  118. package/build/resources/tool-params-guide.js +0 -488
  119. package/build/tools/analyze_project.d.ts +0 -1
  120. package/build/tools/analyze_project.js +0 -527
  121. package/build/tools/check_deps.d.ts +0 -13
  122. package/build/tools/check_deps.js +0 -204
  123. package/build/tools/convert.d.ts +0 -13
  124. package/build/tools/convert.js +0 -599
  125. package/build/tools/css_order.d.ts +0 -13
  126. package/build/tools/css_order.js +0 -81
  127. package/build/tools/debug.d.ts +0 -13
  128. package/build/tools/debug.js +0 -131
  129. package/build/tools/design2code.d.ts +0 -20
  130. package/build/tools/design2code.js +0 -426
  131. package/build/tools/detect_shell.d.ts +0 -6
  132. package/build/tools/detect_shell.js +0 -151
  133. package/build/tools/explain.d.ts +0 -13
  134. package/build/tools/explain.js +0 -390
  135. package/build/tools/fix.d.ts +0 -13
  136. package/build/tools/fix.js +0 -303
  137. package/build/tools/gen_mock.d.ts +0 -22
  138. package/build/tools/gen_mock.js +0 -269
  139. package/build/tools/gen_skill.d.ts +0 -13
  140. package/build/tools/gen_skill.js +0 -560
  141. package/build/tools/genapi.d.ts +0 -13
  142. package/build/tools/genapi.js +0 -174
  143. package/build/tools/genchangelog.d.ts +0 -13
  144. package/build/tools/genchangelog.js +0 -250
  145. package/build/tools/gendoc.d.ts +0 -13
  146. package/build/tools/gendoc.js +0 -232
  147. package/build/tools/genpr.d.ts +0 -13
  148. package/build/tools/genpr.js +0 -194
  149. package/build/tools/genreadme.d.ts +0 -13
  150. package/build/tools/genreadme.js +0 -626
  151. package/build/tools/gensql.d.ts +0 -13
  152. package/build/tools/gensql.js +0 -320
  153. package/build/tools/genui.d.ts +0 -13
  154. package/build/tools/genui.js +0 -803
  155. package/build/tools/init_component_catalog.d.ts +0 -22
  156. package/build/tools/init_component_catalog.js +0 -809
  157. package/build/tools/init_setting.d.ts +0 -13
  158. package/build/tools/init_setting.js +0 -47
  159. package/build/tools/perf.d.ts +0 -13
  160. package/build/tools/perf.js +0 -409
  161. package/build/tools/render_ui.d.ts +0 -22
  162. package/build/tools/render_ui.js +0 -384
  163. package/build/tools/resolve_conflict.d.ts +0 -13
  164. package/build/tools/resolve_conflict.js +0 -349
  165. package/build/tools/security_scan.d.ts +0 -22
  166. package/build/tools/security_scan.js +0 -323
  167. package/build/tools/split.d.ts +0 -13
  168. package/build/tools/split.js +0 -599
  169. package/build/tools/start_api.d.ts +0 -13
  170. package/build/tools/start_api.js +0 -193
  171. package/build/tools/start_doc.d.ts +0 -13
  172. package/build/tools/start_doc.js +0 -207
  173. package/build/tools/start_refactor.d.ts +0 -13
  174. package/build/tools/start_refactor.js +0 -188
  175. package/build/tools/start_release.d.ts +0 -13
  176. package/build/tools/start_release.js +0 -167
  177. package/build/tools/start_review.d.ts +0 -13
  178. package/build/tools/start_review.js +0 -175
  179. /package/build/{utils/design-docs-generator.d.ts → lib/__tests__/dev-workflow.unit.test.d.ts} +0 -0
  180. /package/build/{utils/design-docs-generator.js → lib/__tests__/handles.unit.test.d.ts} +0 -0
@@ -0,0 +1,54 @@
1
+ import { describe, test, expect } from 'vitest';
2
+ import { CODE_LIMITS, BANNED_CODE_PATTERNS, UI_HARD_RULES, UI_BANNED_LIST, renderCodeLimits, renderBannedPatterns, renderUiHardRules, renderUiBannedList, renderPreFlightChecklist, } from '../quality-constraints.js';
3
+ describe('quality-constraints(质量约束单一真相源)', () => {
4
+ test('CODE_LIMITS 数值符合预期(单文件 500 / 函数 50)', () => {
5
+ expect(CODE_LIMITS.maxFileLines).toBe(500);
6
+ expect(CODE_LIMITS.maxFunctionLines).toBe(50);
7
+ expect(CODE_LIMITS.maxNestingDepth).toBe(4);
8
+ expect(CODE_LIMITS.maxParameters).toBe(3);
9
+ });
10
+ test('黑名单与硬约束清单非空', () => {
11
+ expect(BANNED_CODE_PATTERNS.length).toBeGreaterThan(0);
12
+ expect(UI_HARD_RULES.length).toBeGreaterThan(0);
13
+ expect(UI_BANNED_LIST.length).toBeGreaterThan(0);
14
+ });
15
+ test('代码完整性黑名单含关键占位模式', () => {
16
+ expect(BANNED_CODE_PATTERNS).toContain('// TODO');
17
+ expect(BANNED_CODE_PATTERNS).toContain('// ...');
18
+ });
19
+ test('UI 黑名单含 em-dash 零容忍与 AI 紫蓝渐变', () => {
20
+ expect(UI_BANNED_LIST.some((b) => b.includes('em-dash'))).toBe(true);
21
+ expect(UI_BANNED_LIST.some((b) => b.includes('紫蓝渐变'))).toBe(true);
22
+ });
23
+ test('renderCodeLimits 输出含 500 行红线', () => {
24
+ const out = renderCodeLimits();
25
+ expect(out).toContain('500');
26
+ expect(out).toContain('HIGH');
27
+ });
28
+ test('renderBannedPatterns 输出含 CRITICAL 与二元规则', () => {
29
+ const out = renderBannedPatterns();
30
+ expect(out).toContain('CRITICAL');
31
+ expect(out).toContain('二元');
32
+ });
33
+ test('renderUiHardRules 含 4pt 间距阶梯与对比度阈值', () => {
34
+ const out = renderUiHardRules();
35
+ expect(out).toContain('4, 8, 12, 16, 24, 32, 48, 64, 96');
36
+ expect(out).toContain('4.5:1');
37
+ });
38
+ test('renderUiBannedList 输出每条以 ❌ 标记', () => {
39
+ const out = renderUiBannedList();
40
+ expect(out).toContain('❌');
41
+ });
42
+ test('renderPreFlightChecklist 含 Scope-lock 与完整性勾选项', () => {
43
+ const out = renderPreFlightChecklist();
44
+ expect(out).toContain('Pre-Flight');
45
+ expect(out).toContain('Scope-lock');
46
+ expect(out).toContain('占位符');
47
+ });
48
+ // 防回归:注入下游 prompt 的渲染输出自身不得含 em-dash,否则与「em-dash 零容忍」自相矛盾
49
+ test('代码类渲染输出不含 em-dash(避免规则自相矛盾)', () => {
50
+ expect(renderCodeLimits()).not.toContain('—');
51
+ expect(renderBannedPatterns()).not.toContain('—');
52
+ expect(renderPreFlightChecklist()).not.toContain('—');
53
+ });
54
+ });
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,54 @@
1
+ import * as fs from 'node:fs';
2
+ import * as os from 'node:os';
3
+ import * as path from 'node:path';
4
+ import { afterEach, describe, expect, test } from 'vitest';
5
+ import { resolveBugfixFeatureName, resolveBugfixSpecGate, specArtifactsExist, } from '../spec-gate.js';
6
+ const tempDirs = [];
7
+ afterEach(() => {
8
+ while (tempDirs.length > 0) {
9
+ const dir = tempDirs.pop();
10
+ if (dir) {
11
+ fs.rmSync(dir, { recursive: true, force: true });
12
+ }
13
+ }
14
+ });
15
+ function makeSpecTree(featureName) {
16
+ const root = fs.mkdtempSync(path.join(os.tmpdir(), 'spec-gate-'));
17
+ tempDirs.push(root);
18
+ const specDir = path.join(root, 'docs', 'specs', featureName);
19
+ fs.mkdirSync(specDir, { recursive: true });
20
+ fs.writeFileSync(path.join(specDir, 'requirements.md'), '# requirements\n');
21
+ return root;
22
+ }
23
+ describe('spec-gate', () => {
24
+ test('显式 feature_name 优先', () => {
25
+ const root = makeSpecTree('user-auth');
26
+ expect(resolveBugfixFeatureName('payment', root, 'docs', 'user-auth login failed')).toBe('payment');
27
+ });
28
+ test('仅一个 spec 目录时自动识别', () => {
29
+ const root = makeSpecTree('only-feature');
30
+ expect(resolveBugfixFeatureName('', root, 'docs', 'random error')).toBe('only-feature');
31
+ });
32
+ test('错误描述唯一匹配 spec 目录', () => {
33
+ const root = fs.mkdtempSync(path.join(os.tmpdir(), 'spec-gate-'));
34
+ tempDirs.push(root);
35
+ for (const name of ['user-auth', 'billing']) {
36
+ const specDir = path.join(root, 'docs', 'specs', name);
37
+ fs.mkdirSync(specDir, { recursive: true });
38
+ fs.writeFileSync(path.join(specDir, 'tasks.md'), '# tasks\n');
39
+ }
40
+ expect(resolveBugfixFeatureName('', root, 'docs', 'billing invoice total mismatch')).toBe('billing');
41
+ });
42
+ test('resolveBugfixSpecGate 在规格存在时返回上下文', () => {
43
+ const root = makeSpecTree('checkout-flow');
44
+ const gate = resolveBugfixSpecGate({
45
+ featureName: 'checkout-flow',
46
+ projectRoot: root,
47
+ docsDir: 'docs',
48
+ hintText: 'checkout failed',
49
+ });
50
+ expect(gate?.featureName).toBe('checkout-flow');
51
+ expect(gate?.specDir).toBe('docs/specs/checkout-flow');
52
+ expect(specArtifactsExist(root, 'docs', 'checkout-flow')).toBe(true);
53
+ });
54
+ });
@@ -1,75 +1,81 @@
1
1
  import { describe, test, expect } from 'vitest';
2
2
  import { validateSpecDocuments, extractFrIds } from '../spec-validator.js';
3
- const goodReq = `# 需求文档:demo
4
-
5
- ## 功能概述
6
- 做一个登录功能。
7
-
8
- ## 历史经验与坑(来自记忆库)
9
- - 可复用经验: 无
10
- - 必须规避的坑: 无
11
-
12
- ## 范围边界
13
- In Scope: 登录
14
- Out of Scope: 注册
15
-
16
- ## 需求列表
17
- ### FR-1: 登录
18
- **优先级:** Must
19
- **用户故事:** 作为用户,我想登录,以便访问系统。
20
- #### 验收标准(EARS)
21
- 1. WHEN 提交正确凭证 THEN 系统 SHALL 登录成功
22
-
23
- ## 非功能需求
24
- - NFR-1: 登录响应 < 1s
25
-
26
- ## 依赖关系
27
- - 无
3
+ const goodReq = `# 需求文档:demo
4
+
5
+ ## 功能概述
6
+ 做一个登录功能。
7
+
8
+ ## 历史经验与坑(来自记忆库)
9
+ - 可复用经验: 无
10
+ - 必须规避的坑: 无
11
+
12
+ ## 范围边界
13
+ In Scope: 登录
14
+ Out of Scope: 注册
15
+
16
+ ## 需求列表
17
+ ### FR-1: 登录
18
+ **优先级:** Must
19
+ **用户故事:** 作为用户,我想登录,以便访问系统。
20
+ #### 验收标准(EARS)
21
+ 1. WHEN 提交正确凭证 THEN 系统 SHALL 登录成功
22
+
23
+ ## 非功能需求
24
+ - NFR-1: 登录响应 < 1s
25
+
26
+ ## 依赖关系
27
+ - 无
28
28
  `;
29
- const goodDesign = `# 设计文档:demo
30
-
31
- ## 概述
32
- 登录设计。
33
- **对应需求:** FR-1
34
-
35
- ## 技术方案
36
- ### 技术选型
37
- 使用 JWT。
38
-
39
- ## 数据模型
40
- 不涉及。
41
-
42
- ## API 设计
43
- POST /api/login
44
-
45
- ## 文件结构
46
- src/login.ts
47
-
48
- ## 设计决策
49
- 决策 1:用 JWT。
50
-
51
- ## 风险评估
52
- 无。
29
+ const goodDesign = `# 设计文档:demo
30
+
31
+ ## 概述
32
+ 登录设计。
33
+ **对应需求:** FR-1
34
+
35
+ ## 技术方案
36
+ ### 技术选型
37
+ 使用 JWT。
38
+
39
+ ## 数据模型
40
+ 不涉及。
41
+
42
+ ## API 设计
43
+ POST /api/login
44
+
45
+ ## 文件结构
46
+ src/login.ts
47
+
48
+ ## 设计决策
49
+ 决策 1:用 JWT。
50
+
51
+ ## 风险评估
52
+ 无。
53
53
  `;
54
- const goodTasks = `# 任务清单:demo
55
-
56
- ## 概述
57
- 任务分解。
58
-
59
- ## 任务列表
60
- ### 阶段 2: 核心实现
61
- - [ ] 2.1 实现登录接口 — _需求: FR-1_ | _设计: API 设计_
62
-
63
- ## 检查点
64
- - [ ] 阶段 2 完成后:登录可用
65
-
66
- ## 需求覆盖矩阵
67
- | 需求 ID | 设计章节 | 任务编号 | 状态 |
68
- | FR-1 | API 设计 | 2.1 | 未开始 |
69
-
70
- ## 文件变更清单
71
- | 文件 | 操作 | 说明 |
72
- | src/login.ts | 新建 | 登录接口 |
54
+ const goodTasks = `# 任务清单:demo
55
+
56
+ ## 概述
57
+ 任务分解。
58
+
59
+ ## 交付物清单(Scope-lock)
60
+ - 预计新建文件数: 1
61
+ - 预计修改文件数: 0
62
+
63
+ ## 任务列表
64
+ ### 阶段 2: 核心实现
65
+ - [ ] 2.1 实现登录接口 POST /api/login,校验邮箱并返回 JWT
66
+ - 证据块: 先读 src/router.ts:1,确认路由注册方式
67
+ - _需求: FR-1_ _设计: API 设计_
68
+
69
+ ## 检查点
70
+ - [ ] 阶段 2 完成后:登录可用
71
+
72
+ ## 需求覆盖矩阵
73
+ | 需求 ID | 设计章节 | 任务编号 | 状态 |
74
+ | FR-1 | API 设计 | 2.1 | 未开始 |
75
+
76
+ ## 文件变更清单
77
+ | 文件 | 操作 | 说明 |
78
+ | src/login.ts | 新建 | 登录接口 |
73
79
  `;
74
80
  describe('spec-validator(P1 填写后校验)', () => {
75
81
  test('完整规格通过校验', () => {
@@ -98,12 +104,12 @@ describe('spec-validator(P1 填写后校验)', () => {
98
104
  expect(r.issues.some((i) => i.code === 'no_acceptance')).toBe(true);
99
105
  });
100
106
  test('FR 未进 tasks 覆盖矩阵 → 跨文档未覆盖', () => {
101
- const reqTwoFr = goodReq.replace('## 非功能需求', `### FR-2: 登出
102
- **优先级:** Should
103
- **用户故事:** 作为用户,我想登出。
104
- #### 验收标准(EARS)
105
- 1. WHEN 点击登出 THEN 系统 SHALL 退出登录
106
-
107
+ const reqTwoFr = goodReq.replace('## 非功能需求', `### FR-2: 登出
108
+ **优先级:** Should
109
+ **用户故事:** 作为用户,我想登出。
110
+ #### 验收标准(EARS)
111
+ 1. WHEN 点击登出 THEN 系统 SHALL 退出登录
112
+
107
113
  ## 非功能需求`);
108
114
  const r = validateSpecDocuments({ requirements: reqTwoFr, design: goodDesign, tasks: goodTasks });
109
115
  expect(r.passed).toBe(false);
@@ -112,4 +118,30 @@ describe('spec-validator(P1 填写后校验)', () => {
112
118
  test('extractFrIds 去重并保序', () => {
113
119
  expect(extractFrIds('FR-1 写了 FR-1 又写 FR-2')).toEqual(['FR-1', 'FR-2']);
114
120
  });
121
+ test('tasks 缺少「交付物清单」章节 → 未通过', () => {
122
+ const tasksNoScope = goodTasks.replace(/## 交付物清单(Scope-lock)[\s\S]*?\n\n/, '');
123
+ // 防 fixture 漂移导致替换失效造成假通过
124
+ expect(tasksNoScope).not.toContain('交付物清单');
125
+ const r = validateSpecDocuments({ requirements: goodReq, design: goodDesign, tasks: tasksNoScope });
126
+ expect(r.passed).toBe(false);
127
+ expect(r.issues.some((i) => i.file === 'tasks' && i.code === 'missing_section')).toBe(true);
128
+ });
129
+ test('任务无「证据块」→ thin_task 提醒(warning,不阻断)', () => {
130
+ const tasksThin = goodTasks.replace(' - 证据块: 先读 src/router.ts:1,确认路由注册方式\n', '');
131
+ expect(tasksThin).not.toBe(goodTasks);
132
+ const r = validateSpecDocuments({ requirements: goodReq, design: goodDesign, tasks: tasksThin });
133
+ expect(r.issues.some((i) => i.code === 'thin_task')).toBe(true);
134
+ expect(r.warningCount).toBeGreaterThan(0);
135
+ // 核心语义:thin_task 是 warning,不应阻断 passed
136
+ expect(r.passed).toBe(true);
137
+ });
138
+ test('裸 [填写] 占位(无冒号)也应被检出', () => {
139
+ const r = validateSpecDocuments({
140
+ requirements: goodReq + '\n- 备注: [填写]',
141
+ design: goodDesign,
142
+ tasks: goodTasks,
143
+ });
144
+ expect(r.passed).toBe(false);
145
+ expect(r.issues.some((i) => i.file === 'requirements' && i.code === 'placeholder')).toBe(true);
146
+ });
115
147
  });
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,27 @@
1
+ import { describe, expect, test, afterEach } from 'vitest';
2
+ import { isAutoTaskTool, shouldAutoEscalateToTask } from '../task-defaults.js';
3
+ const originalDisable = process.env.MCP_DISABLE_AUTO_TASK;
4
+ afterEach(() => {
5
+ if (originalDisable === undefined) {
6
+ delete process.env.MCP_DISABLE_AUTO_TASK;
7
+ }
8
+ else {
9
+ process.env.MCP_DISABLE_AUTO_TASK = originalDisable;
10
+ }
11
+ });
12
+ describe('task-defaults', () => {
13
+ test('code_insight 与 scan 属于自动 Task 工具', () => {
14
+ expect(isAutoTaskTool('code_insight')).toBe(true);
15
+ expect(isAutoTaskTool('scan_and_extract_patterns')).toBe(true);
16
+ expect(isAutoTaskTool('search_memory')).toBe(false);
17
+ });
18
+ test('默认对长耗时工具自动升级为 Task', () => {
19
+ delete process.env.MCP_DISABLE_AUTO_TASK;
20
+ expect(shouldAutoEscalateToTask('code_insight', false)).toBe(true);
21
+ expect(shouldAutoEscalateToTask('code_insight', true)).toBe(false);
22
+ });
23
+ test('MCP_DISABLE_AUTO_TASK=1 时关闭自动 Task', () => {
24
+ process.env.MCP_DISABLE_AUTO_TASK = '1';
25
+ expect(shouldAutoEscalateToTask('code_insight', false)).toBe(false);
26
+ });
27
+ });
@@ -0,0 +1,110 @@
1
+ import * as fs from "node:fs";
2
+ import * as os from "node:os";
3
+ import * as path from "node:path";
4
+ import { afterEach, describe, expect, test } from "vitest";
5
+ import { VERSION } from "../../version.js";
6
+ import { ensureAgentsMdSkillReference, ensureMcpProbeKitBootstrap, ensureMcpProbeSkill, resolveProjectRootFromToolArgs, } from "../workflow-skill-installer.js";
7
+ import { formatSkillVersionMarker, agentsContextNeedsUpgrade, compareSemver, skillContentNeedsUpgrade, } from "../workflow-skill-version.js";
8
+ import { LEGACY_WORKFLOW_SKILL_REL_PATH, MCP_PROBE_SKILL_REL_PATH, } from "../workflow-skill-template.js";
9
+ import { wrapMcpProbeBlock } from "../merge-agents-md.js";
10
+ const tempDirs = [];
11
+ afterEach(() => {
12
+ while (tempDirs.length > 0) {
13
+ const dir = tempDirs.pop();
14
+ if (dir) {
15
+ fs.rmSync(dir, { recursive: true, force: true });
16
+ }
17
+ }
18
+ });
19
+ describe("workflow-skill-version", () => {
20
+ test("compareSemver 比较主次补丁", () => {
21
+ expect(compareSemver("3.5.0", "3.5.1")).toBeLessThan(0);
22
+ expect(compareSemver("3.6.0", "3.5.9")).toBeGreaterThan(0);
23
+ expect(compareSemver("3.5.0", "3.5.0")).toBe(0);
24
+ });
25
+ test("无版本标记视为需要升级", () => {
26
+ expect(skillContentNeedsUpgrade("# custom", VERSION)).toBe(true);
27
+ expect(agentsContextNeedsUpgrade("<!-- mcp-probe:context begin -->", VERSION)).toBe(true);
28
+ });
29
+ });
30
+ describe("workflow-skill-installer", () => {
31
+ test("缺失时创建 mcp-probe-kit Skill", () => {
32
+ const root = fs.mkdtempSync(path.join(os.tmpdir(), "wf-skill-"));
33
+ tempDirs.push(root);
34
+ const result = ensureMcpProbeSkill(root);
35
+ expect(result.created).toBe(true);
36
+ expect(result.updated).toBe(false);
37
+ expect(result.version).toBe(VERSION);
38
+ const text = fs.readFileSync(path.join(root, MCP_PROBE_SKILL_REL_PATH), "utf8");
39
+ expect(text).toContain(formatSkillVersionMarker(VERSION));
40
+ expect(text).toContain("MCP 调用时机");
41
+ });
42
+ test("同版本 Skill 不覆盖", () => {
43
+ const root = fs.mkdtempSync(path.join(os.tmpdir(), "wf-skill-"));
44
+ tempDirs.push(root);
45
+ const skillPath = path.join(root, MCP_PROBE_SKILL_REL_PATH);
46
+ const content = `${formatSkillVersionMarker(VERSION)}\n# same version\n`;
47
+ fs.mkdirSync(path.dirname(skillPath), { recursive: true });
48
+ fs.writeFileSync(skillPath, content, "utf8");
49
+ const result = ensureMcpProbeSkill(root);
50
+ expect(result.created).toBe(false);
51
+ expect(result.updated).toBe(false);
52
+ expect(fs.readFileSync(skillPath, "utf8")).toBe(content);
53
+ });
54
+ test("旧版本 Skill 会升级覆盖", () => {
55
+ const root = fs.mkdtempSync(path.join(os.tmpdir(), "wf-skill-"));
56
+ tempDirs.push(root);
57
+ const skillPath = path.join(root, MCP_PROBE_SKILL_REL_PATH);
58
+ fs.mkdirSync(path.dirname(skillPath), { recursive: true });
59
+ fs.writeFileSync(skillPath, `${formatSkillVersionMarker("0.1.0")}\n# stale tools list\n`, "utf8");
60
+ const result = ensureMcpProbeSkill(root);
61
+ expect(result.updated).toBe(true);
62
+ expect(result.previousVersion).toBe("0.1.0");
63
+ const text = fs.readFileSync(skillPath, "utf8");
64
+ expect(text).toContain(formatSkillVersionMarker(VERSION));
65
+ expect(text).toContain("何时调用");
66
+ expect(text).not.toContain("stale tools list");
67
+ });
68
+ test("无 AGENTS.md 时创建并引用 Skill", () => {
69
+ const root = fs.mkdtempSync(path.join(os.tmpdir(), "wf-skill-"));
70
+ tempDirs.push(root);
71
+ const result = ensureAgentsMdSkillReference(root);
72
+ expect(result.created).toBe(true);
73
+ const agents = fs.readFileSync(path.join(root, "AGENTS.md"), "utf8");
74
+ expect(agents).toContain("mcp-probe:context-version");
75
+ expect(agents).toContain(MCP_PROBE_SKILL_REL_PATH);
76
+ });
77
+ test("已有 AGENTS.md 但缺 Skill 引用时更新", () => {
78
+ const root = fs.mkdtempSync(path.join(os.tmpdir(), "wf-skill-"));
79
+ tempDirs.push(root);
80
+ fs.writeFileSync(path.join(root, "AGENTS.md"), "# Custom rules\n", "utf8");
81
+ const result = ensureAgentsMdSkillReference(root);
82
+ expect(result.updated).toBe(true);
83
+ const agents = fs.readFileSync(path.join(root, "AGENTS.md"), "utf8");
84
+ expect(agents).toContain("# Custom rules");
85
+ expect(agents).toContain(MCP_PROBE_SKILL_REL_PATH);
86
+ });
87
+ test("旧 workflow Skill 路径会触发 AGENTS.md 更新", () => {
88
+ const root = fs.mkdtempSync(path.join(os.tmpdir(), "wf-skill-"));
89
+ tempDirs.push(root);
90
+ const legacyBlock = wrapMcpProbeBlock(`## MCP\nSee [skill](${LEGACY_WORKFLOW_SKILL_REL_PATH})`, "0.1.0");
91
+ fs.writeFileSync(path.join(root, "AGENTS.md"), `${legacyBlock}\n`, "utf8");
92
+ const result = ensureAgentsMdSkillReference(root);
93
+ expect(result.updated).toBe(true);
94
+ const agents = fs.readFileSync(path.join(root, "AGENTS.md"), "utf8");
95
+ expect(agents).toContain(MCP_PROBE_SKILL_REL_PATH);
96
+ expect(agents).toContain(`mcp-probe:context-version: ${VERSION}`);
97
+ });
98
+ test("bootstrap 同时处理 Skill 与 AGENTS.md", () => {
99
+ const root = fs.mkdtempSync(path.join(os.tmpdir(), "wf-skill-"));
100
+ tempDirs.push(root);
101
+ const result = ensureMcpProbeKitBootstrap(root);
102
+ expect(result.skill.created).toBe(true);
103
+ expect(result.agentsMd.created).toBe(true);
104
+ });
105
+ test("从 tool args 解析 project_root", () => {
106
+ const root = fs.mkdtempSync(path.join(os.tmpdir(), "wf-skill-"));
107
+ tempDirs.push(root);
108
+ expect(resolveProjectRootFromToolArgs({ project_root: root })).toBe(path.resolve(root));
109
+ });
110
+ });
@@ -1,21 +1,26 @@
1
1
  import { relativeLink } from "./project-context-layout.js";
2
+ import { MCP_PROBE_SKILL_REL_PATH } from "./workflow-skill-template.js";
2
3
  function link(layout, targetRel) {
3
4
  return relativeLink(layout.indexPath, targetRel);
4
5
  }
5
6
  function memorySection(locale) {
6
7
  if (locale === "zh-CN") {
7
- return `
8
- 记忆(需 MEMORY_QDRANT_URL 等已配置):
9
- - 检索:\`start_*\` 命中后**自动注入**历史经验全文;中途补查可用 \`search_memory\`;单条精读仍可用 \`read_memory_asset\`
10
- - 沉淀:跨仓库共享**勿填** source_project/source_path;路径写进 content;summary 写检索关键词
11
- - Bug 修完验证通过 → **必须** \`memorize_asset\` type=\`bugfix\` tags=\`bugfix,root-cause\`(content 含【现象】【根因】【修复】【验证】)
8
+ return `
9
+ 记忆(需 MEMORY_QDRANT_URL 等已配置):
10
+ - 检索:\`start_*\` 命中后**自动注入**历史经验全文;中途补查可用 \`search_memory\`;单条精读仍可用 \`read_memory_asset\`
11
+ - 沉淀:跨仓库共享**勿填** source_project/source_path;路径写进 content;summary 写检索关键词
12
+ - 修正:已有资产可用 \`update_memory_asset\` asset_id 原地更新(保留 ID)
13
+ - 清理:过时/错误/重复沉淀可用 \`delete_memory_asset\`(删除前建议 \`read_memory_asset\` 确认)
14
+ - Bug 修完验证通过 → **必须** \`memorize_asset\` type=\`bugfix\` tags=\`bugfix,root-cause\`(content 含【现象】【根因】【修复】【验证】)
12
15
  - 功能/UI 可复用产出 → \`memorize_asset\` type=\`pattern\`/\`component\``;
13
16
  }
14
- return `
15
- Memory (requires MEMORY_* env):
16
- - Search: \`start_*\` auto-injects full memory hits; use \`search_memory\` mid-task; \`read_memory_asset\` for a specific id
17
- - Store: do NOT use source_project/source_path for cross-repo pools; put paths in content; write keyword-rich summary
18
- - After verified bugfix MUST \`memorize_asset\` type=\`bugfix\` (sections: symptom, root cause, fix, verification)
17
+ return `
18
+ Memory (requires MEMORY_* env):
19
+ - Search: \`start_*\` auto-injects full memory hits; use \`search_memory\` mid-task; \`read_memory_asset\` for a specific id
20
+ - Store: do NOT use source_project/source_path for cross-repo pools; put paths in content; write keyword-rich summary
21
+ - Update: fix existing entries in place with \`update_memory_asset\` by asset_id (preserves ID)
22
+ - Cleanup: remove stale/wrong/duplicate entries with \`delete_memory_asset\` (confirm via \`read_memory_asset\` first)
23
+ - After verified bugfix → MUST \`memorize_asset\` type=\`bugfix\` (sections: symptom, root cause, fix, verification)
19
24
  - Reusable feature/UI → \`memorize_asset\` type=\`pattern\`/\`component\``;
20
25
  }
21
26
  /**
@@ -25,31 +30,34 @@ export function generateAgentsMdInner(input) {
25
30
  const { layout, locale } = input;
26
31
  const graph = link(layout, layout.latestMarkdownPath);
27
32
  const ctxIndex = link(layout, layout.legacyIndexPath);
33
+ const skillLink = link(layout, MCP_PROBE_SKILL_REL_PATH);
28
34
  if (locale === "zh-CN") {
29
- return `## MCP(必须先调)
30
- 需已配置 mcp-probe-kit。\`start_*\` 若返回 delegated plan,逐步执行完再结束。
31
-
32
- - 新功能 → \`start_feature\`(会先搜记忆)
33
- - Bug → \`start_bugfix\`(会先搜记忆)
34
- - UI → \`start_ui\`(会先搜记忆)
35
- - 不熟代码 / 影响面 → \`code_insight\`(context / impact / auto)
36
- - 缺上下文 → \`init_project_context\`
37
- - 提交 → \`gencommit\`
38
-
39
- 上下文:写代码前先读 [project-context](${ctxIndex})(链到 \`${layout.modularDir}/\` 各文档)
35
+ return `## MCP(必须先调)
36
+ 需已配置 mcp-probe-kit。写代码前先读 Skill:[MCP 调用时机](${skillLink})(\`${MCP_PROBE_SKILL_REL_PATH}\`,首次 MCP 调用自动创建)。
37
+
38
+ - 不确定用哪个 MCP → \`workflow\`(返回 firstTool)
39
+ - 新功能 → \`start_feature\`(会先搜记忆)
40
+ - Bug → \`start_bugfix\`(会先搜记忆)
41
+ - UI → \`start_ui\`(会先搜记忆)
42
+ - 不熟代码 / 影响面 → \`code_insight\`(context / impact / auto)
43
+ - 缺上下文 → \`init_project_context\`
44
+ - 提交 → \`gencommit\`
45
+
46
+ 上下文:写代码前先读 [project-context](${ctxIndex})(链到 \`${layout.modularDir}/\` 各文档)
40
47
  图谱:大改前读 [latest](${graph});过期 \`code_insight\` mode=auto save_to_docs=true${memorySection(locale)}`;
41
48
  }
42
- return `## MCP (call first)
43
- Requires mcp-probe-kit. Complete every \`start_*\` delegated plan step before done.
44
-
45
- - Feature → \`start_feature\` (searches memory first)
46
- - Bug → \`start_bugfix\` (searches memory first)
47
- - UI → \`start_ui\` (searches memory first)
48
- - Unfamiliar code / impact → \`code_insight\` (context / impact / auto)
49
- - Missing context → \`init_project_context\`
50
- - Commit → \`gencommit\`
51
-
52
- Context: before coding read [project-context](${ctxIndex}) (links to \`${layout.modularDir}/\`)
49
+ return `## MCP (call first)
50
+ Requires mcp-probe-kit. Before coding, read Skill: [When to call MCP](${skillLink}) (\`${MCP_PROBE_SKILL_REL_PATH}\`, auto-created on first MCP call).
51
+
52
+ - Unsure which MCP → \`workflow\` (returns firstTool)
53
+ - Feature → \`start_feature\` (searches memory first)
54
+ - Bug → \`start_bugfix\` (searches memory first)
55
+ - UI → \`start_ui\` (searches memory first)
56
+ - Unfamiliar code / impact → \`code_insight\` (context / impact / auto)
57
+ - Missing context → \`init_project_context\`
58
+ - Commit → \`gencommit\`
59
+
60
+ Context: before coding read [project-context](${ctxIndex}) (links to \`${layout.modularDir}/\`)
53
61
  Graph: read [latest](${graph}) before large changes; refresh \`code_insight\` mode=auto save_to_docs=true${memorySection(locale)}`;
54
62
  }
55
63
  export function generateAgentsMdTemplate(input) {
@@ -0,0 +1,54 @@
1
+ export interface CursorConversationSummary {
2
+ composerId: string;
3
+ name: string;
4
+ createdAt?: number;
5
+ lastUpdatedAt?: number;
6
+ workspaceId?: string;
7
+ workspacePath?: string;
8
+ mode?: string;
9
+ contextUsagePercent?: number;
10
+ subtitle?: string;
11
+ isArchived?: boolean;
12
+ source: 'composerHeaders';
13
+ }
14
+ export interface CursorConversationMessage {
15
+ bubbleId: string;
16
+ type: number;
17
+ text: string;
18
+ createdAt?: string;
19
+ requestId?: string;
20
+ }
21
+ export interface CursorConversationDetail {
22
+ composerId: string;
23
+ messages: CursorConversationMessage[];
24
+ }
25
+ export interface CursorHistorySearchResult {
26
+ composerId: string;
27
+ conversationName: string;
28
+ bubbleId: string;
29
+ type: number;
30
+ text: string;
31
+ createdAt?: string;
32
+ requestId?: string;
33
+ }
34
+ export declare class CursorHistoryClient {
35
+ private withDatabase;
36
+ private loadConversationIndex;
37
+ listConversations(params?: {
38
+ titleQuery?: string;
39
+ workspaceQuery?: string;
40
+ includeArchived?: boolean;
41
+ limit?: number;
42
+ }): Promise<CursorConversationSummary[]>;
43
+ searchHistory(params: {
44
+ query: string;
45
+ composerId?: string;
46
+ limit?: number;
47
+ }): Promise<CursorHistorySearchResult[]>;
48
+ readConversation(params: {
49
+ composerId: string;
50
+ limit?: number;
51
+ includeEmpty?: boolean;
52
+ }): Promise<CursorConversationDetail>;
53
+ }
54
+ export declare function createCursorHistoryClient(): CursorHistoryClient;