specforge-mcp 0.1.1 → 0.2.2

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 (287) hide show
  1. package/README.md +31 -1
  2. package/dist/config/version.d.ts +2 -0
  3. package/dist/config/version.d.ts.map +1 -0
  4. package/dist/config/version.js +9 -0
  5. package/dist/config/version.js.map +1 -0
  6. package/dist/config/version.ts +11 -0
  7. package/dist/engine/detectors/library-detector-langs2.d.ts.map +1 -1
  8. package/dist/engine/detectors/library-detector-langs2.js.map +1 -1
  9. package/dist/engine/mermaid-generator.d.ts.map +1 -1
  10. package/dist/engine/mermaid-generator.js +12 -2
  11. package/dist/engine/mermaid-generator.js.map +1 -1
  12. package/dist/index.js +2 -1
  13. package/dist/index.js.map +1 -1
  14. package/dist/tools/create-spec-hu/hu-body-generators.d.ts.map +1 -1
  15. package/dist/tools/create-spec-hu/hu-body-generators.js +7 -1
  16. package/dist/tools/create-spec-hu/hu-body-generators.js.map +1 -1
  17. package/dist/tools/create-spec-tech/ficha-content.d.ts.map +1 -1
  18. package/dist/tools/create-spec-tech/ficha-content.js +4 -2
  19. package/dist/tools/create-spec-tech/ficha-content.js.map +1 -1
  20. package/dist/tools/create-spec.d.ts.map +1 -1
  21. package/dist/tools/create-spec.js +4 -3
  22. package/dist/tools/create-spec.js.map +1 -1
  23. package/dist/tools/register-spec-tools/core-spec-tools.d.ts.map +1 -1
  24. package/dist/tools/register-spec-tools/core-spec-tools.js +4 -0
  25. package/dist/tools/register-spec-tools/core-spec-tools.js.map +1 -1
  26. package/dist/types/spec/core.d.ts +1 -0
  27. package/dist/types/spec/core.d.ts.map +1 -1
  28. package/dist/types/spec/inputs.d.ts +1 -0
  29. package/dist/types/spec/inputs.d.ts.map +1 -1
  30. package/package.json +27 -18
  31. package/src/config/version.ts +11 -0
  32. package/dist/engine/agent-generator.test.d.ts +0 -2
  33. package/dist/engine/agent-generator.test.d.ts.map +0 -1
  34. package/dist/engine/agent-generator.test.js +0 -556
  35. package/dist/engine/agent-generator.test.js.map +0 -1
  36. package/dist/engine/analyzer.test.d.ts +0 -2
  37. package/dist/engine/analyzer.test.d.ts.map +0 -1
  38. package/dist/engine/analyzer.test.js +0 -1461
  39. package/dist/engine/analyzer.test.js.map +0 -1
  40. package/dist/engine/auditor.test.d.ts +0 -2
  41. package/dist/engine/auditor.test.d.ts.map +0 -1
  42. package/dist/engine/auditor.test.js +0 -2075
  43. package/dist/engine/auditor.test.js.map +0 -1
  44. package/dist/engine/doc-generator.test.d.ts +0 -2
  45. package/dist/engine/doc-generator.test.d.ts.map +0 -1
  46. package/dist/engine/doc-generator.test.js +0 -961
  47. package/dist/engine/doc-generator.test.js.map +0 -1
  48. package/dist/engine/estimator.test.d.ts +0 -2
  49. package/dist/engine/estimator.test.d.ts.map +0 -1
  50. package/dist/engine/estimator.test.js +0 -334
  51. package/dist/engine/estimator.test.js.map +0 -1
  52. package/dist/engine/skill-generator.test.d.ts +0 -2
  53. package/dist/engine/skill-generator.test.d.ts.map +0 -1
  54. package/dist/engine/skill-generator.test.js +0 -742
  55. package/dist/engine/skill-generator.test.js.map +0 -1
  56. package/dist/engine/validator.test.d.ts +0 -2
  57. package/dist/engine/validator.test.d.ts.map +0 -1
  58. package/dist/engine/validator.test.js +0 -2371
  59. package/dist/engine/validator.test.js.map +0 -1
  60. package/dist/engine/web-fetcher.test.d.ts +0 -2
  61. package/dist/engine/web-fetcher.test.d.ts.map +0 -1
  62. package/dist/engine/web-fetcher.test.js +0 -360
  63. package/dist/engine/web-fetcher.test.js.map +0 -1
  64. package/dist/i18n/index.test.d.ts +0 -2
  65. package/dist/i18n/index.test.d.ts.map +0 -1
  66. package/dist/i18n/index.test.js +0 -375
  67. package/dist/i18n/index.test.js.map +0 -1
  68. package/dist/index.test.d.ts +0 -2
  69. package/dist/index.test.d.ts.map +0 -1
  70. package/dist/index.test.js +0 -124
  71. package/dist/index.test.js.map +0 -1
  72. package/dist/resources/patterns.test.d.ts +0 -2
  73. package/dist/resources/patterns.test.d.ts.map +0 -1
  74. package/dist/resources/patterns.test.js +0 -142
  75. package/dist/resources/patterns.test.js.map +0 -1
  76. package/dist/resources/process.test.d.ts +0 -2
  77. package/dist/resources/process.test.d.ts.map +0 -1
  78. package/dist/resources/process.test.js +0 -48
  79. package/dist/resources/process.test.js.map +0 -1
  80. package/dist/resources/registry.test.d.ts +0 -2
  81. package/dist/resources/registry.test.d.ts.map +0 -1
  82. package/dist/resources/registry.test.js +0 -138
  83. package/dist/resources/registry.test.js.map +0 -1
  84. package/dist/resources/specs.test.d.ts +0 -2
  85. package/dist/resources/specs.test.d.ts.map +0 -1
  86. package/dist/resources/specs.test.js +0 -130
  87. package/dist/resources/specs.test.js.map +0 -1
  88. package/dist/resources/templates.test.d.ts +0 -2
  89. package/dist/resources/templates.test.d.ts.map +0 -1
  90. package/dist/resources/templates.test.js +0 -119
  91. package/dist/resources/templates.test.js.map +0 -1
  92. package/dist/smoke.test.d.ts +0 -2
  93. package/dist/smoke.test.d.ts.map +0 -1
  94. package/dist/smoke.test.js +0 -229
  95. package/dist/smoke.test.js.map +0 -1
  96. package/dist/storage/base-store.test.d.ts +0 -2
  97. package/dist/storage/base-store.test.d.ts.map +0 -1
  98. package/dist/storage/base-store.test.js +0 -180
  99. package/dist/storage/base-store.test.js.map +0 -1
  100. package/dist/storage/global-store.test.d.ts +0 -2
  101. package/dist/storage/global-store.test.d.ts.map +0 -1
  102. package/dist/storage/global-store.test.js +0 -327
  103. package/dist/storage/global-store.test.js.map +0 -1
  104. package/dist/storage/index.test.d.ts +0 -2
  105. package/dist/storage/index.test.d.ts.map +0 -1
  106. package/dist/storage/index.test.js +0 -56
  107. package/dist/storage/index.test.js.map +0 -1
  108. package/dist/storage/knowledge-store.test.d.ts +0 -2
  109. package/dist/storage/knowledge-store.test.d.ts.map +0 -1
  110. package/dist/storage/knowledge-store.test.js +0 -368
  111. package/dist/storage/knowledge-store.test.js.map +0 -1
  112. package/dist/storage/metrics-store.test.d.ts +0 -2
  113. package/dist/storage/metrics-store.test.d.ts.map +0 -1
  114. package/dist/storage/metrics-store.test.js +0 -212
  115. package/dist/storage/metrics-store.test.js.map +0 -1
  116. package/dist/storage/pattern-store.test.d.ts +0 -2
  117. package/dist/storage/pattern-store.test.d.ts.map +0 -1
  118. package/dist/storage/pattern-store.test.js +0 -224
  119. package/dist/storage/pattern-store.test.js.map +0 -1
  120. package/dist/storage/spec-store.test.d.ts +0 -2
  121. package/dist/storage/spec-store.test.d.ts.map +0 -1
  122. package/dist/storage/spec-store.test.js +0 -227
  123. package/dist/storage/spec-store.test.js.map +0 -1
  124. package/dist/tools/audit.test.d.ts +0 -2
  125. package/dist/tools/audit.test.d.ts.map +0 -1
  126. package/dist/tools/audit.test.js +0 -169
  127. package/dist/tools/audit.test.js.map +0 -1
  128. package/dist/tools/challenge-spec.test.d.ts +0 -2
  129. package/dist/tools/challenge-spec.test.d.ts.map +0 -1
  130. package/dist/tools/challenge-spec.test.js +0 -782
  131. package/dist/tools/challenge-spec.test.js.map +0 -1
  132. package/dist/tools/check-versions.test.d.ts +0 -2
  133. package/dist/tools/check-versions.test.d.ts.map +0 -1
  134. package/dist/tools/check-versions.test.js +0 -214
  135. package/dist/tools/check-versions.test.js.map +0 -1
  136. package/dist/tools/clarify-requirements.test.d.ts +0 -2
  137. package/dist/tools/clarify-requirements.test.d.ts.map +0 -1
  138. package/dist/tools/clarify-requirements.test.js +0 -161
  139. package/dist/tools/clarify-requirements.test.js.map +0 -1
  140. package/dist/tools/consult-docs.test.d.ts +0 -2
  141. package/dist/tools/consult-docs.test.d.ts.map +0 -1
  142. package/dist/tools/consult-docs.test.js +0 -140
  143. package/dist/tools/consult-docs.test.js.map +0 -1
  144. package/dist/tools/create-spec.test.d.ts +0 -2
  145. package/dist/tools/create-spec.test.d.ts.map +0 -1
  146. package/dist/tools/create-spec.test.js +0 -233
  147. package/dist/tools/create-spec.test.js.map +0 -1
  148. package/dist/tools/define-ui-contract.test.d.ts +0 -2
  149. package/dist/tools/define-ui-contract.test.d.ts.map +0 -1
  150. package/dist/tools/define-ui-contract.test.js +0 -479
  151. package/dist/tools/define-ui-contract.test.js.map +0 -1
  152. package/dist/tools/design-schema.test.d.ts +0 -2
  153. package/dist/tools/design-schema.test.d.ts.map +0 -1
  154. package/dist/tools/design-schema.test.js +0 -301
  155. package/dist/tools/design-schema.test.js.map +0 -1
  156. package/dist/tools/detect-agent.test.d.ts +0 -2
  157. package/dist/tools/detect-agent.test.d.ts.map +0 -1
  158. package/dist/tools/detect-agent.test.js +0 -133
  159. package/dist/tools/detect-agent.test.js.map +0 -1
  160. package/dist/tools/detect-drift.test.d.ts +0 -2
  161. package/dist/tools/detect-drift.test.d.ts.map +0 -1
  162. package/dist/tools/detect-drift.test.js +0 -312
  163. package/dist/tools/detect-drift.test.js.map +0 -1
  164. package/dist/tools/discover-mcps.test.d.ts +0 -2
  165. package/dist/tools/discover-mcps.test.d.ts.map +0 -1
  166. package/dist/tools/discover-mcps.test.js +0 -345
  167. package/dist/tools/discover-mcps.test.js.map +0 -1
  168. package/dist/tools/estimate.test.d.ts +0 -2
  169. package/dist/tools/estimate.test.d.ts.map +0 -1
  170. package/dist/tools/estimate.test.js +0 -137
  171. package/dist/tools/estimate.test.js.map +0 -1
  172. package/dist/tools/generate-adr.test.d.ts +0 -2
  173. package/dist/tools/generate-adr.test.d.ts.map +0 -1
  174. package/dist/tools/generate-adr.test.js +0 -206
  175. package/dist/tools/generate-adr.test.js.map +0 -1
  176. package/dist/tools/generate-checklist.test.d.ts +0 -2
  177. package/dist/tools/generate-checklist.test.d.ts.map +0 -1
  178. package/dist/tools/generate-checklist.test.js +0 -201
  179. package/dist/tools/generate-checklist.test.js.map +0 -1
  180. package/dist/tools/generate-docs.test.d.ts +0 -2
  181. package/dist/tools/generate-docs.test.d.ts.map +0 -1
  182. package/dist/tools/generate-docs.test.js +0 -183
  183. package/dist/tools/generate-docs.test.js.map +0 -1
  184. package/dist/tools/generate-execution-plan.test.d.ts +0 -2
  185. package/dist/tools/generate-execution-plan.test.d.ts.map +0 -1
  186. package/dist/tools/generate-execution-plan.test.js +0 -643
  187. package/dist/tools/generate-execution-plan.test.js.map +0 -1
  188. package/dist/tools/generate-rules.test.d.ts +0 -2
  189. package/dist/tools/generate-rules.test.d.ts.map +0 -1
  190. package/dist/tools/generate-rules.test.js +0 -148
  191. package/dist/tools/generate-rules.test.js.map +0 -1
  192. package/dist/tools/generate-skill.test.d.ts +0 -2
  193. package/dist/tools/generate-skill.test.d.ts.map +0 -1
  194. package/dist/tools/generate-skill.test.js +0 -138
  195. package/dist/tools/generate-skill.test.js.map +0 -1
  196. package/dist/tools/generate-sub-agent.test.d.ts +0 -2
  197. package/dist/tools/generate-sub-agent.test.d.ts.map +0 -1
  198. package/dist/tools/generate-sub-agent.test.js +0 -162
  199. package/dist/tools/generate-sub-agent.test.js.map +0 -1
  200. package/dist/tools/generate-tests.test.d.ts +0 -2
  201. package/dist/tools/generate-tests.test.d.ts.map +0 -1
  202. package/dist/tools/generate-tests.test.js +0 -222
  203. package/dist/tools/generate-tests.test.js.map +0 -1
  204. package/dist/tools/init-constitution.test.d.ts +0 -2
  205. package/dist/tools/init-constitution.test.d.ts.map +0 -1
  206. package/dist/tools/init-constitution.test.js +0 -398
  207. package/dist/tools/init-constitution.test.js.map +0 -1
  208. package/dist/tools/init-project.test.d.ts +0 -2
  209. package/dist/tools/init-project.test.d.ts.map +0 -1
  210. package/dist/tools/init-project.test.js +0 -158
  211. package/dist/tools/init-project.test.js.map +0 -1
  212. package/dist/tools/integrate-pm.test.d.ts +0 -2
  213. package/dist/tools/integrate-pm.test.d.ts.map +0 -1
  214. package/dist/tools/integrate-pm.test.js +0 -558
  215. package/dist/tools/integrate-pm.test.js.map +0 -1
  216. package/dist/tools/learn.test.d.ts +0 -2
  217. package/dist/tools/learn.test.d.ts.map +0 -1
  218. package/dist/tools/learn.test.js +0 -123
  219. package/dist/tools/learn.test.js.map +0 -1
  220. package/dist/tools/list-specs.test.d.ts +0 -2
  221. package/dist/tools/list-specs.test.d.ts.map +0 -1
  222. package/dist/tools/list-specs.test.js +0 -110
  223. package/dist/tools/list-specs.test.js.map +0 -1
  224. package/dist/tools/manage-context.test.d.ts +0 -2
  225. package/dist/tools/manage-context.test.d.ts.map +0 -1
  226. package/dist/tools/manage-context.test.js +0 -359
  227. package/dist/tools/manage-context.test.js.map +0 -1
  228. package/dist/tools/manage-git.test.d.ts +0 -2
  229. package/dist/tools/manage-git.test.d.ts.map +0 -1
  230. package/dist/tools/manage-git.test.js +0 -882
  231. package/dist/tools/manage-git.test.js.map +0 -1
  232. package/dist/tools/orchestrate.test.d.ts +0 -2
  233. package/dist/tools/orchestrate.test.d.ts.map +0 -1
  234. package/dist/tools/orchestrate.test.js +0 -1117
  235. package/dist/tools/orchestrate.test.js.map +0 -1
  236. package/dist/tools/reconcile-spec.test.d.ts +0 -2
  237. package/dist/tools/reconcile-spec.test.d.ts.map +0 -1
  238. package/dist/tools/reconcile-spec.test.js +0 -259
  239. package/dist/tools/reconcile-spec.test.js.map +0 -1
  240. package/dist/tools/register-platform-tools.test.d.ts +0 -2
  241. package/dist/tools/register-platform-tools.test.d.ts.map +0 -1
  242. package/dist/tools/register-platform-tools.test.js +0 -404
  243. package/dist/tools/register-platform-tools.test.js.map +0 -1
  244. package/dist/tools/register-spec-tools.test.d.ts +0 -2
  245. package/dist/tools/register-spec-tools.test.d.ts.map +0 -1
  246. package/dist/tools/register-spec-tools.test.js +0 -407
  247. package/dist/tools/register-spec-tools.test.js.map +0 -1
  248. package/dist/tools/reverse-engineer.test.d.ts +0 -2
  249. package/dist/tools/reverse-engineer.test.d.ts.map +0 -1
  250. package/dist/tools/reverse-engineer.test.js +0 -206
  251. package/dist/tools/reverse-engineer.test.js.map +0 -1
  252. package/dist/tools/schemas.d.ts +0 -20
  253. package/dist/tools/schemas.d.ts.map +0 -1
  254. package/dist/tools/schemas.js +0 -133
  255. package/dist/tools/schemas.js.map +0 -1
  256. package/dist/tools/schemas.test.d.ts +0 -2
  257. package/dist/tools/schemas.test.d.ts.map +0 -1
  258. package/dist/tools/schemas.test.js +0 -245
  259. package/dist/tools/schemas.test.js.map +0 -1
  260. package/dist/tools/set-locale.test.d.ts +0 -2
  261. package/dist/tools/set-locale.test.d.ts.map +0 -1
  262. package/dist/tools/set-locale.test.js +0 -74
  263. package/dist/tools/set-locale.test.js.map +0 -1
  264. package/dist/tools/suggest-mcps.test.d.ts +0 -2
  265. package/dist/tools/suggest-mcps.test.d.ts.map +0 -1
  266. package/dist/tools/suggest-mcps.test.js +0 -198
  267. package/dist/tools/suggest-mcps.test.js.map +0 -1
  268. package/dist/tools/suggest-stack.test.d.ts +0 -2
  269. package/dist/tools/suggest-stack.test.d.ts.map +0 -1
  270. package/dist/tools/suggest-stack.test.js +0 -181
  271. package/dist/tools/suggest-stack.test.js.map +0 -1
  272. package/dist/tools/suggest-tooling.test.d.ts +0 -2
  273. package/dist/tools/suggest-tooling.test.d.ts.map +0 -1
  274. package/dist/tools/suggest-tooling.test.js +0 -213
  275. package/dist/tools/suggest-tooling.test.js.map +0 -1
  276. package/dist/tools/summarize-spec.test.d.ts +0 -2
  277. package/dist/tools/summarize-spec.test.d.ts.map +0 -1
  278. package/dist/tools/summarize-spec.test.js +0 -180
  279. package/dist/tools/summarize-spec.test.js.map +0 -1
  280. package/dist/tools/update-status.test.d.ts +0 -2
  281. package/dist/tools/update-status.test.d.ts.map +0 -1
  282. package/dist/tools/update-status.test.js +0 -142
  283. package/dist/tools/update-status.test.js.map +0 -1
  284. package/dist/tools/validate.test.d.ts +0 -2
  285. package/dist/tools/validate.test.d.ts.map +0 -1
  286. package/dist/tools/validate.test.js +0 -137
  287. package/dist/tools/validate.test.js.map +0 -1
@@ -1,123 +0,0 @@
1
- import { describe, it, expect, vi, beforeEach } from 'vitest';
2
- vi.mock('../i18n/index.js', () => ({
3
- t: vi.fn((key) => `t:${key}`),
4
- ti: vi.fn((_key, params) => `translated:${JSON.stringify(params)}`),
5
- }));
6
- vi.mock('../storage/index.js', () => ({
7
- patternStore: {
8
- listPatterns: vi.fn(),
9
- addPattern: vi.fn(),
10
- incrementPatternUsage: vi.fn(),
11
- },
12
- knowledgeStore: {
13
- getKnowledge: vi.fn(),
14
- },
15
- }));
16
- import { handleLearn } from './learn.js';
17
- import { patternStore, knowledgeStore } from '../storage/index.js';
18
- beforeEach(() => {
19
- vi.clearAllMocks();
20
- });
21
- describe('handleLearn', () => {
22
- it('should return error when project not found', async () => {
23
- vi.mocked(knowledgeStore.getKnowledge).mockResolvedValue(null);
24
- const result = await handleLearn({
25
- projectId: 'proj-123',
26
- type: 'architecture',
27
- pattern: 'Use repository pattern',
28
- });
29
- expect(result.isError).toBe(true);
30
- });
31
- it('should create new pattern successfully', async () => {
32
- vi.mocked(knowledgeStore.getKnowledge).mockResolvedValue({});
33
- vi.mocked(patternStore.listPatterns).mockResolvedValue([]);
34
- vi.mocked(patternStore.addPattern).mockResolvedValue(undefined);
35
- const result = await handleLearn({
36
- projectId: 'proj-123',
37
- type: 'architecture',
38
- pattern: 'Use repository pattern',
39
- });
40
- expect(result.isError).toBeUndefined();
41
- expect(result.content).toHaveLength(2);
42
- const parsed = JSON.parse(result.content[1].text);
43
- expect(parsed.action).toBe('created');
44
- expect(parsed.type).toBe('architecture');
45
- expect(parsed.pattern).toBe('Use repository pattern');
46
- expect(parsed.totalPatterns).toBe(1);
47
- expect(patternStore.addPattern).toHaveBeenCalled();
48
- });
49
- it('should increment usage count for duplicate pattern', async () => {
50
- vi.mocked(knowledgeStore.getKnowledge).mockResolvedValue({});
51
- vi.mocked(patternStore.listPatterns).mockResolvedValue([
52
- {
53
- id: 'PAT-ARC-123',
54
- projectId: 'proj-123',
55
- type: 'architecture',
56
- pattern: 'Use repository pattern',
57
- source: 'user-defined',
58
- learnedAt: '2024-01-01',
59
- confidence: 0.8,
60
- usageCount: 3,
61
- },
62
- ]);
63
- vi.mocked(patternStore.incrementPatternUsage).mockResolvedValue({
64
- usageCount: 4,
65
- });
66
- const result = await handleLearn({
67
- projectId: 'proj-123',
68
- type: 'architecture',
69
- pattern: 'Use repository pattern',
70
- });
71
- expect(result.isError).toBeUndefined();
72
- const parsed = JSON.parse(result.content[1].text);
73
- expect(parsed.action).toBe('incremented');
74
- expect(parsed.usageCount).toBe(4);
75
- expect(patternStore.addPattern).not.toHaveBeenCalled();
76
- });
77
- it('should use default source when not provided', async () => {
78
- vi.mocked(knowledgeStore.getKnowledge).mockResolvedValue({});
79
- vi.mocked(patternStore.listPatterns).mockResolvedValue([]);
80
- vi.mocked(patternStore.addPattern).mockResolvedValue(undefined);
81
- await handleLearn({
82
- projectId: 'proj-123',
83
- type: 'convention',
84
- pattern: 'Use camelCase',
85
- });
86
- const addCall = vi.mocked(patternStore.addPattern).mock.calls[0];
87
- const savedPattern = addCall[1];
88
- expect(savedPattern.source).toBe('user-defined');
89
- });
90
- it('should use custom source when provided', async () => {
91
- vi.mocked(knowledgeStore.getKnowledge).mockResolvedValue({});
92
- vi.mocked(patternStore.listPatterns).mockResolvedValue([]);
93
- vi.mocked(patternStore.addPattern).mockResolvedValue(undefined);
94
- await handleLearn({
95
- projectId: 'proj-123',
96
- type: 'quality',
97
- pattern: 'Always write tests',
98
- source: 'code-review',
99
- });
100
- const addCall = vi.mocked(patternStore.addPattern).mock.calls[0];
101
- const savedPattern = addCall[1];
102
- expect(savedPattern.source).toBe('code-review');
103
- });
104
- it('should build pattern summary correctly', async () => {
105
- vi.mocked(knowledgeStore.getKnowledge).mockResolvedValue({});
106
- vi.mocked(patternStore.listPatterns).mockResolvedValue([
107
- { type: 'architecture', pattern: 'Layered' },
108
- { type: 'architecture', pattern: 'Repository' },
109
- { type: 'convention', pattern: 'CamelCase' },
110
- ]);
111
- vi.mocked(patternStore.addPattern).mockResolvedValue(undefined);
112
- const result = await handleLearn({
113
- projectId: 'proj-123',
114
- type: 'stack',
115
- pattern: 'Use TypeScript',
116
- });
117
- const parsed = JSON.parse(result.content[1].text);
118
- expect(parsed.patternsByType.architecture).toBe(2);
119
- expect(parsed.patternsByType.convention).toBe(1);
120
- expect(parsed.patternsByType.stack).toBe(1);
121
- });
122
- });
123
- //# sourceMappingURL=learn.test.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"learn.test.js","sourceRoot":"","sources":["../../src/tools/learn.test.ts"],"names":[],"mappings":"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"}
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=list-specs.test.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"list-specs.test.d.ts","sourceRoot":"","sources":["../../src/tools/list-specs.test.ts"],"names":[],"mappings":""}
@@ -1,110 +0,0 @@
1
- import { describe, it, expect, vi, beforeEach } from 'vitest';
2
- vi.mock('../i18n/index.js', () => ({
3
- ti: vi.fn((_key, params) => `translated:${JSON.stringify(params)}`),
4
- }));
5
- vi.mock('../storage/index.js', () => ({
6
- specStore: {
7
- listSpecs: vi.fn(),
8
- },
9
- knowledgeStore: {
10
- getKnowledge: vi.fn(),
11
- },
12
- }));
13
- import { handleListSpecs } from './list-specs.js';
14
- import { specStore, knowledgeStore } from '../storage/index.js';
15
- const makeSpec = (overrides = {}) => ({
16
- id: 'SPEC-001',
17
- title: 'Test Spec',
18
- type: 'feature',
19
- scope: 'feature',
20
- status: 'draft',
21
- difficulty: 3,
22
- risk: 'medium',
23
- target: 'fullstack',
24
- tags: ['test'],
25
- gitBranch: 'feat/spec-001-test',
26
- estimation: {
27
- devHours: 8,
28
- reviewHours: 2,
29
- totalCostUsd: 500,
30
- recommendedModel: 'sonnet',
31
- tokenOptimization: { mode: 'local' },
32
- },
33
- createdAt: '2024-01-01',
34
- updatedAt: '2024-01-02',
35
- ...overrides,
36
- });
37
- beforeEach(() => {
38
- vi.clearAllMocks();
39
- });
40
- describe('handleListSpecs', () => {
41
- it('should return error when project not found', async () => {
42
- vi.mocked(knowledgeStore.getKnowledge).mockResolvedValue(null);
43
- const result = await handleListSpecs({ projectId: 'proj-123' });
44
- expect(result.isError).toBe(true);
45
- });
46
- it('should list all specs without filters', async () => {
47
- vi.mocked(knowledgeStore.getKnowledge).mockResolvedValue({});
48
- vi.mocked(specStore.listSpecs).mockResolvedValue([
49
- makeSpec({ id: 'SPEC-001', status: 'draft', type: 'feature' }),
50
- makeSpec({ id: 'SPEC-002', status: 'approved', type: 'bugfix' }),
51
- ]);
52
- const result = await handleListSpecs({ projectId: 'proj-123' });
53
- expect(result.isError).toBeUndefined();
54
- const parsed = JSON.parse(result.content[0].text);
55
- expect(parsed.count).toBe(2);
56
- expect(parsed.totalCount).toBe(2);
57
- expect(parsed.specs).toHaveLength(2);
58
- expect(parsed.filters.status).toBe('all');
59
- expect(parsed.filters.type).toBe('all');
60
- });
61
- it('should filter by status', async () => {
62
- vi.mocked(knowledgeStore.getKnowledge).mockResolvedValue({});
63
- vi.mocked(specStore.listSpecs).mockResolvedValue([
64
- makeSpec({ id: 'SPEC-001', status: 'draft', type: 'feature' }),
65
- makeSpec({ id: 'SPEC-002', status: 'approved', type: 'bugfix' }),
66
- ]);
67
- const result = await handleListSpecs({ projectId: 'proj-123', status: 'draft' });
68
- const parsed = JSON.parse(result.content[0].text);
69
- expect(parsed.count).toBe(1);
70
- expect(parsed.specs[0].id).toBe('SPEC-001');
71
- });
72
- it('should filter by type', async () => {
73
- vi.mocked(knowledgeStore.getKnowledge).mockResolvedValue({});
74
- vi.mocked(specStore.listSpecs).mockResolvedValue([
75
- makeSpec({ id: 'SPEC-001', status: 'draft', type: 'feature' }),
76
- makeSpec({ id: 'SPEC-002', status: 'approved', type: 'bugfix' }),
77
- ]);
78
- const result = await handleListSpecs({ projectId: 'proj-123', type: 'bugfix' });
79
- const parsed = JSON.parse(result.content[0].text);
80
- expect(parsed.count).toBe(1);
81
- expect(parsed.specs[0].id).toBe('SPEC-002');
82
- });
83
- it('should return empty list when no specs', async () => {
84
- vi.mocked(knowledgeStore.getKnowledge).mockResolvedValue({});
85
- vi.mocked(specStore.listSpecs).mockResolvedValue([]);
86
- const result = await handleListSpecs({ projectId: 'proj-123' });
87
- const parsed = JSON.parse(result.content[0].text);
88
- expect(parsed.count).toBe(0);
89
- expect(parsed.specs).toHaveLength(0);
90
- expect(parsed.summary.totalDevHours).toBe(0);
91
- });
92
- it('should calculate aggregated estimation totals', async () => {
93
- vi.mocked(knowledgeStore.getKnowledge).mockResolvedValue({});
94
- vi.mocked(specStore.listSpecs).mockResolvedValue([
95
- makeSpec({ estimation: { devHours: 8, reviewHours: 2, totalCostUsd: 500 } }),
96
- makeSpec({ estimation: { devHours: 16, reviewHours: 4, totalCostUsd: 1000 } }),
97
- ]);
98
- const result = await handleListSpecs({ projectId: 'proj-123' });
99
- const parsed = JSON.parse(result.content[0].text);
100
- expect(parsed.summary.totalDevHours).toBe(24);
101
- expect(parsed.summary.totalReviewHours).toBe(6);
102
- expect(parsed.summary.totalCostUsd).toBe(1500);
103
- });
104
- it('should handle errors gracefully', async () => {
105
- vi.mocked(knowledgeStore.getKnowledge).mockRejectedValue(new Error('Storage fail'));
106
- const result = await handleListSpecs({ projectId: 'proj-123' });
107
- expect(result.isError).toBe(true);
108
- });
109
- });
110
- //# sourceMappingURL=list-specs.test.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"list-specs.test.js","sourceRoot":"","sources":["../../src/tools/list-specs.test.ts"],"names":[],"mappings":"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"}
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=manage-context.test.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"manage-context.test.d.ts","sourceRoot":"","sources":["../../src/tools/manage-context.test.ts"],"names":[],"mappings":""}
@@ -1,359 +0,0 @@
1
- // Tests for handleManageContext
2
- import { describe, it, expect, vi, beforeEach } from 'vitest';
3
- vi.mock('../i18n/index.js', () => ({
4
- t: (key) => key,
5
- ti: (key, vars) => `${key}:${JSON.stringify(vars)}`,
6
- }));
7
- vi.mock('../storage/base-store.js', () => ({
8
- projectDataDir: (projectId) => `data/projects/${projectId}`,
9
- }));
10
- vi.mock('node:fs/promises', () => ({
11
- readFile: vi.fn(),
12
- writeFile: vi.fn(),
13
- readdir: vi.fn(),
14
- unlink: vi.fn(),
15
- mkdir: vi.fn(),
16
- }));
17
- import { handleManageContext } from './manage-context.js';
18
- import { readFile, writeFile, readdir, unlink, mkdir } from 'node:fs/promises';
19
- const mockReadFile = vi.mocked(readFile);
20
- const mockWriteFile = vi.mocked(writeFile);
21
- const mockReaddir = vi.mocked(readdir);
22
- const mockUnlink = vi.mocked(unlink);
23
- const mockMkdir = vi.mocked(mkdir);
24
- beforeEach(() => {
25
- vi.clearAllMocks();
26
- mockMkdir.mockResolvedValue(undefined);
27
- mockWriteFile.mockResolvedValue(undefined);
28
- mockUnlink.mockResolvedValue(undefined);
29
- });
30
- describe('handleManageContext', () => {
31
- // === save action ===
32
- it('should error when save called without key', async () => {
33
- const result = await handleManageContext({
34
- projectId: 'proj-1',
35
- action: 'save',
36
- content: 'hello',
37
- });
38
- expect(result.isError).toBe(true);
39
- expect(result.content[0].text).toContain('key');
40
- });
41
- it('should error when save called without content', async () => {
42
- const result = await handleManageContext({
43
- projectId: 'proj-1',
44
- action: 'save',
45
- key: 'test-note',
46
- });
47
- expect(result.isError).toBe(true);
48
- expect(result.content[0].text).toContain('content');
49
- });
50
- it('should save a context note successfully', async () => {
51
- const result = await handleManageContext({
52
- projectId: 'proj-1',
53
- action: 'save',
54
- key: 'meeting-notes',
55
- content: '# Meeting Notes\nDiscussed architecture.',
56
- });
57
- expect(result.isError).toBeUndefined();
58
- const data = JSON.parse(result.content[0].text);
59
- expect(data.action).toBe('save');
60
- expect(data.key).toBe('meeting-notes');
61
- expect(mockWriteFile).toHaveBeenCalledTimes(2); // .md and .meta.json
62
- expect(mockMkdir).toHaveBeenCalled();
63
- });
64
- it('should save with TTL when ttlDays provided', async () => {
65
- const result = await handleManageContext({
66
- projectId: 'proj-1',
67
- action: 'save',
68
- key: 'temp-note',
69
- content: 'Temporary content',
70
- ttlDays: 7,
71
- });
72
- const data = JSON.parse(result.content[0].text);
73
- expect(data.action).toBe('save');
74
- // Verify meta includes expiresAt
75
- const metaCall = mockWriteFile.mock.calls.find((c) => c[0].includes('.meta.json'));
76
- expect(metaCall).toBeDefined();
77
- const meta = JSON.parse(metaCall[1]);
78
- expect(meta.expiresAt).toBeDefined();
79
- });
80
- // === load action ===
81
- it('should error when load called without key', async () => {
82
- const result = await handleManageContext({
83
- projectId: 'proj-1',
84
- action: 'load',
85
- });
86
- expect(result.isError).toBe(true);
87
- });
88
- it('should load a context note', async () => {
89
- mockReadFile.mockImplementation(((path) => {
90
- if (path.endsWith('.md')) {
91
- return Promise.resolve('# Notes\nSome content');
92
- }
93
- if (path.endsWith('.meta.json')) {
94
- return Promise.resolve(JSON.stringify({ key: 'notes', createdAt: '2025-01-01' }));
95
- }
96
- return Promise.reject(new Error('not found'));
97
- }));
98
- const result = await handleManageContext({
99
- projectId: 'proj-1',
100
- action: 'load',
101
- key: 'notes',
102
- });
103
- expect(result.isError).toBeUndefined();
104
- const data = JSON.parse(result.content[0].text);
105
- expect(data.action).toBe('load');
106
- expect(data.content).toContain('Some content');
107
- });
108
- it('should return error when note not found on load', async () => {
109
- mockReadFile.mockRejectedValue(new Error('ENOENT'));
110
- const result = await handleManageContext({
111
- projectId: 'proj-1',
112
- action: 'load',
113
- key: 'nonexistent',
114
- });
115
- expect(result.isError).toBe(true);
116
- expect(result.content[0].text).toContain('not found');
117
- });
118
- it('should delete and return error for expired note on load', async () => {
119
- const expiredDate = new Date(Date.now() - 86400000).toISOString();
120
- mockReadFile.mockImplementation(((path) => {
121
- if (path.endsWith('.md')) {
122
- return Promise.resolve('old content');
123
- }
124
- if (path.endsWith('.meta.json')) {
125
- return Promise.resolve(JSON.stringify({
126
- key: 'expired',
127
- createdAt: '2025-01-01',
128
- expiresAt: expiredDate,
129
- }));
130
- }
131
- return Promise.reject(new Error('not found'));
132
- }));
133
- const result = await handleManageContext({
134
- projectId: 'proj-1',
135
- action: 'load',
136
- key: 'expired',
137
- });
138
- expect(result.isError).toBe(true);
139
- expect(result.content[0].text).toContain('expired');
140
- expect(mockUnlink).toHaveBeenCalled();
141
- });
142
- // === list action ===
143
- it('should list context notes', async () => {
144
- mockReaddir.mockResolvedValue(['note1.md', 'note2.md', 'note1.meta.json']);
145
- mockReadFile.mockImplementation(((path) => {
146
- if (path.endsWith('.md')) {
147
- return Promise.resolve('# Title\nContent here');
148
- }
149
- if (path.endsWith('.meta.json')) {
150
- return Promise.resolve(JSON.stringify({ key: 'note', createdAt: '2025-01-01' }));
151
- }
152
- return Promise.reject(new Error('not found'));
153
- }));
154
- const result = await handleManageContext({
155
- projectId: 'proj-1',
156
- action: 'list',
157
- });
158
- const data = JSON.parse(result.content[0].text);
159
- expect(data.action).toBe('list');
160
- expect(data.notes.length).toBeGreaterThan(0);
161
- });
162
- it('should return empty list when no notes', async () => {
163
- mockReaddir.mockRejectedValue(new Error('ENOENT'));
164
- const result = await handleManageContext({
165
- projectId: 'proj-1',
166
- action: 'list',
167
- });
168
- const data = JSON.parse(result.content[0].text);
169
- expect(data.notes).toHaveLength(0);
170
- });
171
- // === delete action ===
172
- it('should error when delete called without key', async () => {
173
- const result = await handleManageContext({
174
- projectId: 'proj-1',
175
- action: 'delete',
176
- });
177
- expect(result.isError).toBe(true);
178
- });
179
- it('should delete a note', async () => {
180
- mockReadFile.mockResolvedValue(JSON.stringify({ key: 'old-note', createdAt: '2025-01-01' }));
181
- const result = await handleManageContext({
182
- projectId: 'proj-1',
183
- action: 'delete',
184
- key: 'old-note',
185
- });
186
- const data = JSON.parse(result.content[0].text);
187
- expect(data.action).toBe('delete');
188
- expect(mockUnlink).toHaveBeenCalled();
189
- });
190
- it('should return error when deleting non-existent note', async () => {
191
- mockReadFile.mockRejectedValue(new Error('not found'));
192
- const result = await handleManageContext({
193
- projectId: 'proj-1',
194
- action: 'delete',
195
- key: 'nonexistent',
196
- });
197
- expect(result.isError).toBe(true);
198
- });
199
- // === cleanup action ===
200
- it('should clean up expired notes', async () => {
201
- const expiredDate = new Date(Date.now() - 86400000).toISOString();
202
- mockReaddir.mockResolvedValue(['expired.md', 'valid.md']);
203
- mockReadFile.mockImplementation(((path) => {
204
- if (path.includes('expired') && path.endsWith('.meta.json')) {
205
- return Promise.resolve(JSON.stringify({
206
- key: 'expired',
207
- createdAt: '2025-01-01',
208
- expiresAt: expiredDate,
209
- }));
210
- }
211
- if (path.includes('valid') && path.endsWith('.meta.json')) {
212
- return Promise.resolve(JSON.stringify({ key: 'valid', createdAt: '2025-01-01' }));
213
- }
214
- return Promise.reject(new Error('not found'));
215
- }));
216
- const result = await handleManageContext({
217
- projectId: 'proj-1',
218
- action: 'cleanup',
219
- });
220
- const data = JSON.parse(result.content[0].text);
221
- expect(data.action).toBe('cleanup');
222
- expect(data.message).toContain('removed');
223
- });
224
- // === list: skip expired notes ===
225
- it('should skip expired notes in list', async () => {
226
- const expiredDate = new Date(Date.now() - 86400000).toISOString();
227
- const validDate = new Date(Date.now() + 86400000).toISOString();
228
- mockReaddir.mockResolvedValue(['expired.md', 'valid.md']);
229
- mockReadFile.mockImplementation(((path) => {
230
- if (path.includes('expired') && path.endsWith('.meta.json')) {
231
- return Promise.resolve(JSON.stringify({
232
- key: 'expired',
233
- createdAt: '2025-01-01',
234
- expiresAt: expiredDate,
235
- }));
236
- }
237
- if (path.includes('valid') && path.endsWith('.meta.json')) {
238
- return Promise.resolve(JSON.stringify({
239
- key: 'valid',
240
- createdAt: '2025-06-01',
241
- expiresAt: validDate,
242
- }));
243
- }
244
- if (path.endsWith('.md')) {
245
- return Promise.resolve('# Valid note content');
246
- }
247
- return Promise.reject(new Error('not found'));
248
- }));
249
- const result = await handleManageContext({
250
- projectId: 'proj-1',
251
- action: 'list',
252
- });
253
- const data = JSON.parse(result.content[0].text);
254
- // Expired note should be skipped, only valid note remains
255
- expect(data.notes).toHaveLength(1);
256
- expect(data.notes[0].key).toBe('valid');
257
- });
258
- // === list: content preview fallback when file read fails ===
259
- it('should show fallback preview when content file read fails', async () => {
260
- mockReaddir.mockResolvedValue(['broken.md']);
261
- mockReadFile.mockImplementation(((path) => {
262
- if (path.endsWith('.meta.json')) {
263
- return Promise.resolve(JSON.stringify({ key: 'broken', createdAt: '2025-01-01' }));
264
- }
265
- // .md file always fails
266
- return Promise.reject(new Error('read error'));
267
- }));
268
- const result = await handleManageContext({
269
- projectId: 'proj-1',
270
- action: 'list',
271
- });
272
- const data = JSON.parse(result.content[0].text);
273
- expect(data.notes).toHaveLength(1);
274
- expect(data.notes[0].preview).toBe('(unable to read)');
275
- });
276
- // === list: sort comparator for unknown timestamps ===
277
- it('should sort notes with unknown createdAt to the end', async () => {
278
- mockReaddir.mockResolvedValue(['old.md', 'unknown.md', 'recent.md']);
279
- mockReadFile.mockImplementation(((path) => {
280
- if (path.includes('old') && path.endsWith('.meta.json')) {
281
- return Promise.resolve(JSON.stringify({ key: 'old', createdAt: '2024-01-01' }));
282
- }
283
- if (path.includes('unknown') && path.endsWith('.meta.json')) {
284
- // No meta file -> createdAt will be 'unknown'
285
- return Promise.reject(new Error('no meta'));
286
- }
287
- if (path.includes('recent') && path.endsWith('.meta.json')) {
288
- return Promise.resolve(JSON.stringify({ key: 'recent', createdAt: '2025-06-01' }));
289
- }
290
- if (path.endsWith('.md')) {
291
- return Promise.resolve('some content');
292
- }
293
- return Promise.reject(new Error('not found'));
294
- }));
295
- const result = await handleManageContext({
296
- projectId: 'proj-1',
297
- action: 'list',
298
- });
299
- const data = JSON.parse(result.content[0].text);
300
- // Notes with known dates come first (newest first), unknown last
301
- const keys = data.notes.map((n) => n.key);
302
- expect(keys[keys.length - 1]).toBe('unknown');
303
- });
304
- it('should sort when first note has unknown createdAt', async () => {
305
- mockReaddir.mockResolvedValue(['a.md', 'b.md']);
306
- mockReadFile.mockImplementation(((path) => {
307
- if (path.includes('/a') && path.endsWith('.meta.json')) {
308
- return Promise.reject(new Error('no meta'));
309
- }
310
- if (path.includes('/b') && path.endsWith('.meta.json')) {
311
- return Promise.resolve(JSON.stringify({ key: 'b-note', createdAt: '2025-06-01' }));
312
- }
313
- if (path.endsWith('.md')) {
314
- return Promise.resolve('content');
315
- }
316
- return Promise.reject(new Error('not found'));
317
- }));
318
- const result = await handleManageContext({
319
- projectId: 'proj-1',
320
- action: 'list',
321
- });
322
- const data = JSON.parse(result.content[0].text);
323
- // The note with a known date should come first
324
- expect(data.notes[0].createdAt).not.toBe('unknown');
325
- });
326
- // === list: preview truncation for long content (lines 92-94) ===
327
- it('should truncate preview to 120 chars with ellipsis for long content', async () => {
328
- const longLine = 'A'.repeat(200);
329
- mockReaddir.mockResolvedValue(['long-note.md']);
330
- mockReadFile.mockImplementation(((path) => {
331
- if (path.endsWith('.meta.json')) {
332
- return Promise.resolve(JSON.stringify({ key: 'long-note', createdAt: '2025-01-01' }));
333
- }
334
- if (path.endsWith('.md')) {
335
- return Promise.resolve(longLine);
336
- }
337
- return Promise.reject(new Error('not found'));
338
- }));
339
- const result = await handleManageContext({
340
- projectId: 'proj-1',
341
- action: 'list',
342
- });
343
- const data = JSON.parse(result.content[0].text);
344
- expect(data.notes).toHaveLength(1);
345
- // Preview should be truncated: 117 chars + '...'
346
- expect(data.notes[0].preview.length).toBe(120);
347
- expect(data.notes[0].preview).toMatch(/\.\.\.$/);
348
- });
349
- // === unknown action ===
350
- it('should return error for unknown action', async () => {
351
- const result = await handleManageContext({
352
- projectId: 'proj-1',
353
- action: 'unknown',
354
- });
355
- expect(result.isError).toBe(true);
356
- expect(result.content[0].text).toContain('Unknown action');
357
- });
358
- });
359
- //# sourceMappingURL=manage-context.test.js.map