mcp-probe-kit 3.2.0 → 3.3.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 (104) hide show
  1. package/README.md +10 -0
  2. package/build/lib/__tests__/memory-orchestration.unit.test.js +88 -0
  3. package/build/lib/__tests__/memory-payload.unit.test.js +35 -0
  4. package/build/lib/__tests__/quality-constraints.unit.test.d.ts +1 -0
  5. package/build/lib/__tests__/quality-constraints.unit.test.js +54 -0
  6. package/build/lib/__tests__/spec-validator.unit.test.js +106 -74
  7. package/build/lib/agents-md-template.js +32 -32
  8. package/build/lib/cursor-history-client.d.ts +54 -0
  9. package/build/lib/cursor-history-client.js +240 -0
  10. package/build/lib/quality-constraints.d.ts +54 -0
  11. package/build/lib/quality-constraints.js +155 -0
  12. package/build/lib/skill-bridge.js +12 -12
  13. package/build/lib/spec-validator.js +16 -3
  14. package/build/lib/template-loader.js +83 -23
  15. package/build/resources/ui-ux-data/guidelines/vercel-web-interface.json +1632 -1632
  16. package/build/resources/ui-ux-data/metadata.json +30 -30
  17. package/build/resources/ui-ux-data/shadcn/blocks.json +2541 -2541
  18. package/build/resources/ui-ux-data/shadcn/components.json +997 -997
  19. package/build/resources/ui-ux-data/themes/presets.json +483 -483
  20. package/build/tools/__tests__/cursor-history.unit.test.d.ts +1 -0
  21. package/build/tools/__tests__/cursor-history.unit.test.js +38 -0
  22. package/build/tools/check_spec.js +16 -16
  23. package/build/tools/code_insight.js +41 -41
  24. package/build/tools/code_review.js +11 -4
  25. package/build/tools/cursor_read_conversation.d.ts +7 -0
  26. package/build/tools/cursor_read_conversation.js +36 -0
  27. package/build/tools/fix_bug.js +161 -161
  28. package/build/tools/gencommit.js +60 -60
  29. package/build/tools/init_project_context.js +432 -432
  30. package/build/tools/start_product.js +1 -1
  31. package/build/tools/start_ui.js +17 -0
  32. package/build/tools/ui-ux-tools.d.ts +3 -0
  33. package/build/tools/ui-ux-tools.js +302 -290
  34. package/build/utils/__tests__/vercel-guidelines-sync.unit.test.js +12 -12
  35. package/build/utils/design-reasoning-engine.d.ts +2 -0
  36. package/build/utils/design-reasoning-engine.js +3 -0
  37. package/build/utils/themes-sync.js +8 -8
  38. package/package.json +3 -2
  39. package/build/resources/index.d.ts +0 -4
  40. package/build/resources/index.js +0 -4
  41. package/build/resources/tool-params-guide.d.ts +0 -571
  42. package/build/resources/tool-params-guide.js +0 -488
  43. package/build/tools/analyze_project.d.ts +0 -1
  44. package/build/tools/analyze_project.js +0 -527
  45. package/build/tools/check_deps.d.ts +0 -13
  46. package/build/tools/check_deps.js +0 -204
  47. package/build/tools/convert.d.ts +0 -13
  48. package/build/tools/convert.js +0 -599
  49. package/build/tools/css_order.d.ts +0 -13
  50. package/build/tools/css_order.js +0 -81
  51. package/build/tools/debug.d.ts +0 -13
  52. package/build/tools/debug.js +0 -131
  53. package/build/tools/design2code.d.ts +0 -20
  54. package/build/tools/design2code.js +0 -426
  55. package/build/tools/detect_shell.d.ts +0 -6
  56. package/build/tools/detect_shell.js +0 -151
  57. package/build/tools/explain.d.ts +0 -13
  58. package/build/tools/explain.js +0 -390
  59. package/build/tools/fix.d.ts +0 -13
  60. package/build/tools/fix.js +0 -303
  61. package/build/tools/gen_mock.d.ts +0 -22
  62. package/build/tools/gen_mock.js +0 -269
  63. package/build/tools/gen_skill.d.ts +0 -13
  64. package/build/tools/gen_skill.js +0 -560
  65. package/build/tools/genapi.d.ts +0 -13
  66. package/build/tools/genapi.js +0 -174
  67. package/build/tools/genchangelog.d.ts +0 -13
  68. package/build/tools/genchangelog.js +0 -250
  69. package/build/tools/gendoc.d.ts +0 -13
  70. package/build/tools/gendoc.js +0 -232
  71. package/build/tools/genpr.d.ts +0 -13
  72. package/build/tools/genpr.js +0 -194
  73. package/build/tools/genreadme.d.ts +0 -13
  74. package/build/tools/genreadme.js +0 -626
  75. package/build/tools/gensql.d.ts +0 -13
  76. package/build/tools/gensql.js +0 -320
  77. package/build/tools/genui.d.ts +0 -13
  78. package/build/tools/genui.js +0 -803
  79. package/build/tools/init_component_catalog.d.ts +0 -22
  80. package/build/tools/init_component_catalog.js +0 -809
  81. package/build/tools/init_setting.d.ts +0 -13
  82. package/build/tools/init_setting.js +0 -47
  83. package/build/tools/perf.d.ts +0 -13
  84. package/build/tools/perf.js +0 -409
  85. package/build/tools/render_ui.d.ts +0 -22
  86. package/build/tools/render_ui.js +0 -384
  87. package/build/tools/resolve_conflict.d.ts +0 -13
  88. package/build/tools/resolve_conflict.js +0 -349
  89. package/build/tools/security_scan.d.ts +0 -22
  90. package/build/tools/security_scan.js +0 -323
  91. package/build/tools/split.d.ts +0 -13
  92. package/build/tools/split.js +0 -599
  93. package/build/tools/start_api.d.ts +0 -13
  94. package/build/tools/start_api.js +0 -193
  95. package/build/tools/start_doc.d.ts +0 -13
  96. package/build/tools/start_doc.js +0 -207
  97. package/build/tools/start_refactor.d.ts +0 -13
  98. package/build/tools/start_refactor.js +0 -188
  99. package/build/tools/start_release.d.ts +0 -13
  100. package/build/tools/start_release.js +0 -167
  101. package/build/tools/start_review.d.ts +0 -13
  102. package/build/tools/start_review.js +0 -175
  103. /package/build/{utils/design-docs-generator.d.ts → lib/__tests__/memory-orchestration.unit.test.d.ts} +0 -0
  104. /package/build/{utils/design-docs-generator.js → lib/__tests__/memory-payload.unit.test.d.ts} +0 -0
package/README.md CHANGED
@@ -67,6 +67,16 @@ A powerful MCP (Model Context Protocol) server providing **27 tools** covering t
67
67
  - **🧠 Memory** (4 tools) - Reusable asset memory
68
68
  - `search_memory`, `read_memory_asset`, `memorize_asset`, `scan_and_extract_patterns`
69
69
 
70
+ ### 🛡️ Quality Constraints (single source of truth)
71
+
72
+ All hard quality rules live in one module (`src/lib/quality-constraints.ts`) and are injected into `code_review`, the `add_feature` task templates, and the UI tools. Change once, apply everywhere — inspired by [taste-skill](https://github.com/Leonxlnx/taste-skill) and [impeccable](https://github.com/pbakaus/impeccable).
73
+
74
+ - **Code limits**: single file ≤ 500 lines (split into modules/components when exceeded), function ≤ 50 lines, nesting ≤ 4, parameters ≤ 3.
75
+ - **Completeness blacklist**: `code_review` flags placeholder/elision patterns (`// ...`, `// TODO`, `// rest of code`, bare `...`) as CRITICAL — "a partial output is a broken output".
76
+ - **Anti-laziness task templates**: `add_feature` tasks now carry a Scope-lock deliverable count, a mandatory evidence block (read code before writing), a per-file line budget, and a binary zero-tolerance rule for placeholders. `check_spec` validates these (missing Scope-lock = error, thin task without evidence = warning).
77
+ - **UI hard red lines**: numeric, machine-checkable rules — 4pt spacing scale, WCAG contrast (4.5/3/3), type scale ≥ 1.25, hero font ≤ 6rem, OKLCH, eight interaction states, cognitive load ≤ 4, motion 150-300ms.
78
+ - **UI banned list + Pre-Flight checklist**: match-and-refuse blacklist for AI slop (default Inter/Roboto, AI purple-blue gradients, gradient text, cookie-cutter card grids, em-dash, cream/beige body backgrounds, nested cards) plus a delivery-gate self-check matrix.
79
+
70
80
  ### 🧠 Code Graph Bridge (GitNexus)
71
81
 
72
82
  - `code_insight` bridges GitNexus by default for query/context/impact analysis
@@ -0,0 +1,88 @@
1
+ import { afterEach, describe, expect, test, vi } from 'vitest';
2
+ import { renderMemoryGuideSection, shouldShowSourceInSearch, } from '../memory-orchestration.js';
3
+ afterEach(() => {
4
+ vi.unstubAllEnvs();
5
+ });
6
+ describe('memory-orchestration', () => {
7
+ test('does not show source path by default', () => {
8
+ vi.stubEnv('MEMORY_SEARCH_SHOW_SOURCE', '');
9
+ vi.stubEnv('MEMORY_REPO_ID', '');
10
+ const section = renderMemoryGuideSection({
11
+ enabled: true,
12
+ available: true,
13
+ degraded: false,
14
+ query: '404 submit',
15
+ results: [
16
+ {
17
+ id: '1',
18
+ score: 0.91,
19
+ name: 'purchase-create-submit-404',
20
+ type: 'bugfix',
21
+ description: 'desc',
22
+ summary: 'summary',
23
+ content: '',
24
+ tags: ['bugfix'],
25
+ sourceProject: 'zhixing/gongyingshang',
26
+ sourcePath: 'admin-api/app.js',
27
+ },
28
+ ],
29
+ assetsById: {},
30
+ });
31
+ expect(section).toContain('purchase-create-submit-404');
32
+ expect(section).not.toContain('admin-api/app.js');
33
+ expect(section).not.toContain('来源:');
34
+ });
35
+ test('shows source path when MEMORY_REPO_ID matches', () => {
36
+ vi.stubEnv('MEMORY_SEARCH_SHOW_SOURCE', '');
37
+ vi.stubEnv('MEMORY_REPO_ID', 'zhixing/gongyingshang');
38
+ expect(shouldShowSourceInSearch({
39
+ id: '1',
40
+ score: 0.9,
41
+ name: 'x',
42
+ type: 'bugfix',
43
+ description: '',
44
+ summary: '',
45
+ content: '',
46
+ tags: [],
47
+ sourceProject: 'zhixing/gongyingshang',
48
+ sourcePath: 'admin-api/app.js',
49
+ })).toBe(true);
50
+ expect(shouldShowSourceInSearch({
51
+ id: '2',
52
+ score: 0.9,
53
+ name: 'y',
54
+ type: 'bugfix',
55
+ description: '',
56
+ summary: '',
57
+ content: '',
58
+ tags: [],
59
+ sourceProject: 'other/repo',
60
+ sourcePath: 'src/index.ts',
61
+ })).toBe(false);
62
+ });
63
+ test('MEMORY_SEARCH_SHOW_SOURCE=true always shows source', () => {
64
+ vi.stubEnv('MEMORY_SEARCH_SHOW_SOURCE', 'true');
65
+ vi.stubEnv('MEMORY_REPO_ID', '');
66
+ const section = renderMemoryGuideSection({
67
+ enabled: true,
68
+ available: true,
69
+ degraded: false,
70
+ query: 'q',
71
+ results: [
72
+ {
73
+ id: '1',
74
+ score: 0.8,
75
+ name: 'n',
76
+ type: 'bugfix',
77
+ description: '',
78
+ summary: 's',
79
+ content: '',
80
+ tags: [],
81
+ sourcePath: 'admin-api/app.js',
82
+ },
83
+ ],
84
+ assetsById: {},
85
+ });
86
+ expect(section).toContain('来源: admin-api/app.js');
87
+ });
88
+ });
@@ -0,0 +1,35 @@
1
+ import { describe, expect, test } from 'vitest';
2
+ import { normalizeMemoryPayload, payloadToMemoryFields } from '../memory-payload.js';
3
+ describe('memory-payload', () => {
4
+ test('maps legacy kind/title/source fields to current schema', () => {
5
+ const normalized = normalizeMemoryPayload({
6
+ kind: 'extracted_pattern',
7
+ title: 'Feishu submit success but sync_failed',
8
+ source: 'scan_and_extract_patterns-fallback',
9
+ content: 'Pattern: proxy mismatch',
10
+ tags: ['feishu', 'pattern'],
11
+ created_at: '2026-05-25T11:20:06.705Z',
12
+ });
13
+ expect(normalized.name).toBe('Feishu submit success but sync_failed');
14
+ expect(normalized.type).toBe('pattern');
15
+ expect(normalized.summary).toContain('Pattern');
16
+ expect(normalized.createdAt).toBe('2026-05-25T11:20:06.705Z');
17
+ });
18
+ test('payloadToMemoryFields preserves standard asset fields', () => {
19
+ const fields = payloadToMemoryFields({
20
+ id: 'asset-1',
21
+ name: 'purchase-create-submit-404',
22
+ type: 'bugfix',
23
+ description: '送审 404',
24
+ summary: 'res.data.purchase.id',
25
+ content: '【现象】404',
26
+ tags: ['bugfix'],
27
+ confidence: 0.95,
28
+ createdAt: '2026-05-27T04:28:04.684Z',
29
+ updatedAt: '2026-05-27T04:28:04.684Z',
30
+ });
31
+ expect(fields.name).toBe('purchase-create-submit-404');
32
+ expect(fields.type).toBe('bugfix');
33
+ expect(fields.tags).toEqual(['bugfix']);
34
+ });
35
+ });
@@ -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
+ });
@@ -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
  });
@@ -4,18 +4,18 @@ function link(layout, targetRel) {
4
4
  }
5
5
  function memorySection(locale) {
6
6
  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 含【现象】【根因】【修复】【验证】)
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 含【现象】【根因】【修复】【验证】)
12
12
  - 功能/UI 可复用产出 → \`memorize_asset\` type=\`pattern\`/\`component\``;
13
13
  }
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)
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)
19
19
  - Reusable feature/UI → \`memorize_asset\` type=\`pattern\`/\`component\``;
20
20
  }
21
21
  /**
@@ -26,30 +26,30 @@ export function generateAgentsMdInner(input) {
26
26
  const graph = link(layout, layout.latestMarkdownPath);
27
27
  const ctxIndex = link(layout, layout.legacyIndexPath);
28
28
  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}/\` 各文档)
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}/\` 各文档)
40
40
  图谱:大改前读 [latest](${graph});过期 \`code_insight\` mode=auto save_to_docs=true${memorySection(locale)}`;
41
41
  }
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}/\`)
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}/\`)
53
53
  Graph: read [latest](${graph}) before large changes; refresh \`code_insight\` mode=auto save_to_docs=true${memorySection(locale)}`;
54
54
  }
55
55
  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;