specforge-mcp 0.12.0 → 0.13.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 (258) hide show
  1. package/dist/index.js +0 -0
  2. package/package.json +1 -1
  3. package/dist/engine/agent-generator.test.d.ts +0 -2
  4. package/dist/engine/agent-generator.test.d.ts.map +0 -1
  5. package/dist/engine/agent-generator.test.js +0 -556
  6. package/dist/engine/agent-generator.test.js.map +0 -1
  7. package/dist/engine/analyzer.test.d.ts +0 -2
  8. package/dist/engine/analyzer.test.d.ts.map +0 -1
  9. package/dist/engine/analyzer.test.js +0 -1461
  10. package/dist/engine/analyzer.test.js.map +0 -1
  11. package/dist/engine/auditor.test.d.ts +0 -2
  12. package/dist/engine/auditor.test.d.ts.map +0 -1
  13. package/dist/engine/auditor.test.js +0 -2075
  14. package/dist/engine/auditor.test.js.map +0 -1
  15. package/dist/engine/doc-generator.test.d.ts +0 -2
  16. package/dist/engine/doc-generator.test.d.ts.map +0 -1
  17. package/dist/engine/doc-generator.test.js +0 -961
  18. package/dist/engine/doc-generator.test.js.map +0 -1
  19. package/dist/engine/estimator.test.d.ts +0 -2
  20. package/dist/engine/estimator.test.d.ts.map +0 -1
  21. package/dist/engine/estimator.test.js +0 -334
  22. package/dist/engine/estimator.test.js.map +0 -1
  23. package/dist/engine/skill-generator.test.d.ts +0 -2
  24. package/dist/engine/skill-generator.test.d.ts.map +0 -1
  25. package/dist/engine/skill-generator.test.js +0 -742
  26. package/dist/engine/skill-generator.test.js.map +0 -1
  27. package/dist/engine/validator.test.d.ts +0 -2
  28. package/dist/engine/validator.test.d.ts.map +0 -1
  29. package/dist/engine/validator.test.js +0 -2371
  30. package/dist/engine/validator.test.js.map +0 -1
  31. package/dist/engine/web-fetcher.test.d.ts +0 -2
  32. package/dist/engine/web-fetcher.test.d.ts.map +0 -1
  33. package/dist/engine/web-fetcher.test.js +0 -360
  34. package/dist/engine/web-fetcher.test.js.map +0 -1
  35. package/dist/i18n/index.test.d.ts +0 -2
  36. package/dist/i18n/index.test.d.ts.map +0 -1
  37. package/dist/i18n/index.test.js +0 -375
  38. package/dist/i18n/index.test.js.map +0 -1
  39. package/dist/index.test.d.ts +0 -2
  40. package/dist/index.test.d.ts.map +0 -1
  41. package/dist/index.test.js +0 -124
  42. package/dist/index.test.js.map +0 -1
  43. package/dist/resources/patterns.test.d.ts +0 -2
  44. package/dist/resources/patterns.test.d.ts.map +0 -1
  45. package/dist/resources/patterns.test.js +0 -142
  46. package/dist/resources/patterns.test.js.map +0 -1
  47. package/dist/resources/process.test.d.ts +0 -2
  48. package/dist/resources/process.test.d.ts.map +0 -1
  49. package/dist/resources/process.test.js +0 -48
  50. package/dist/resources/process.test.js.map +0 -1
  51. package/dist/resources/registry.test.d.ts +0 -2
  52. package/dist/resources/registry.test.d.ts.map +0 -1
  53. package/dist/resources/registry.test.js +0 -138
  54. package/dist/resources/registry.test.js.map +0 -1
  55. package/dist/resources/specs.test.d.ts +0 -2
  56. package/dist/resources/specs.test.d.ts.map +0 -1
  57. package/dist/resources/specs.test.js +0 -130
  58. package/dist/resources/specs.test.js.map +0 -1
  59. package/dist/resources/templates.test.d.ts +0 -2
  60. package/dist/resources/templates.test.d.ts.map +0 -1
  61. package/dist/resources/templates.test.js +0 -119
  62. package/dist/resources/templates.test.js.map +0 -1
  63. package/dist/smoke.test.d.ts +0 -2
  64. package/dist/smoke.test.d.ts.map +0 -1
  65. package/dist/smoke.test.js +0 -229
  66. package/dist/smoke.test.js.map +0 -1
  67. package/dist/storage/base-store.test.d.ts +0 -2
  68. package/dist/storage/base-store.test.d.ts.map +0 -1
  69. package/dist/storage/base-store.test.js +0 -180
  70. package/dist/storage/base-store.test.js.map +0 -1
  71. package/dist/storage/global-store.test.d.ts +0 -2
  72. package/dist/storage/global-store.test.d.ts.map +0 -1
  73. package/dist/storage/global-store.test.js +0 -327
  74. package/dist/storage/global-store.test.js.map +0 -1
  75. package/dist/storage/index.test.d.ts +0 -2
  76. package/dist/storage/index.test.d.ts.map +0 -1
  77. package/dist/storage/index.test.js +0 -56
  78. package/dist/storage/index.test.js.map +0 -1
  79. package/dist/storage/knowledge-store.test.d.ts +0 -2
  80. package/dist/storage/knowledge-store.test.d.ts.map +0 -1
  81. package/dist/storage/knowledge-store.test.js +0 -368
  82. package/dist/storage/knowledge-store.test.js.map +0 -1
  83. package/dist/storage/metrics-store.test.d.ts +0 -2
  84. package/dist/storage/metrics-store.test.d.ts.map +0 -1
  85. package/dist/storage/metrics-store.test.js +0 -212
  86. package/dist/storage/metrics-store.test.js.map +0 -1
  87. package/dist/storage/pattern-store.test.d.ts +0 -2
  88. package/dist/storage/pattern-store.test.d.ts.map +0 -1
  89. package/dist/storage/pattern-store.test.js +0 -224
  90. package/dist/storage/pattern-store.test.js.map +0 -1
  91. package/dist/storage/spec-store.test.d.ts +0 -2
  92. package/dist/storage/spec-store.test.d.ts.map +0 -1
  93. package/dist/storage/spec-store.test.js +0 -227
  94. package/dist/storage/spec-store.test.js.map +0 -1
  95. package/dist/tools/audit.test.d.ts +0 -2
  96. package/dist/tools/audit.test.d.ts.map +0 -1
  97. package/dist/tools/audit.test.js +0 -169
  98. package/dist/tools/audit.test.js.map +0 -1
  99. package/dist/tools/challenge-spec.test.d.ts +0 -2
  100. package/dist/tools/challenge-spec.test.d.ts.map +0 -1
  101. package/dist/tools/challenge-spec.test.js +0 -782
  102. package/dist/tools/challenge-spec.test.js.map +0 -1
  103. package/dist/tools/check-versions.test.d.ts +0 -2
  104. package/dist/tools/check-versions.test.d.ts.map +0 -1
  105. package/dist/tools/check-versions.test.js +0 -214
  106. package/dist/tools/check-versions.test.js.map +0 -1
  107. package/dist/tools/clarify-requirements.test.d.ts +0 -2
  108. package/dist/tools/clarify-requirements.test.d.ts.map +0 -1
  109. package/dist/tools/clarify-requirements.test.js +0 -161
  110. package/dist/tools/clarify-requirements.test.js.map +0 -1
  111. package/dist/tools/consult-docs.test.d.ts +0 -2
  112. package/dist/tools/consult-docs.test.d.ts.map +0 -1
  113. package/dist/tools/consult-docs.test.js +0 -140
  114. package/dist/tools/consult-docs.test.js.map +0 -1
  115. package/dist/tools/create-spec.test.d.ts +0 -2
  116. package/dist/tools/create-spec.test.d.ts.map +0 -1
  117. package/dist/tools/create-spec.test.js +0 -233
  118. package/dist/tools/create-spec.test.js.map +0 -1
  119. package/dist/tools/define-ui-contract.test.d.ts +0 -2
  120. package/dist/tools/define-ui-contract.test.d.ts.map +0 -1
  121. package/dist/tools/define-ui-contract.test.js +0 -479
  122. package/dist/tools/define-ui-contract.test.js.map +0 -1
  123. package/dist/tools/design-schema.test.d.ts +0 -2
  124. package/dist/tools/design-schema.test.d.ts.map +0 -1
  125. package/dist/tools/design-schema.test.js +0 -301
  126. package/dist/tools/design-schema.test.js.map +0 -1
  127. package/dist/tools/detect-agent.test.d.ts +0 -2
  128. package/dist/tools/detect-agent.test.d.ts.map +0 -1
  129. package/dist/tools/detect-agent.test.js +0 -133
  130. package/dist/tools/detect-agent.test.js.map +0 -1
  131. package/dist/tools/detect-drift.test.d.ts +0 -2
  132. package/dist/tools/detect-drift.test.d.ts.map +0 -1
  133. package/dist/tools/detect-drift.test.js +0 -312
  134. package/dist/tools/detect-drift.test.js.map +0 -1
  135. package/dist/tools/discover-mcps.test.d.ts +0 -2
  136. package/dist/tools/discover-mcps.test.d.ts.map +0 -1
  137. package/dist/tools/discover-mcps.test.js +0 -345
  138. package/dist/tools/discover-mcps.test.js.map +0 -1
  139. package/dist/tools/estimate.test.d.ts +0 -2
  140. package/dist/tools/estimate.test.d.ts.map +0 -1
  141. package/dist/tools/estimate.test.js +0 -137
  142. package/dist/tools/estimate.test.js.map +0 -1
  143. package/dist/tools/generate-adr.test.d.ts +0 -2
  144. package/dist/tools/generate-adr.test.d.ts.map +0 -1
  145. package/dist/tools/generate-adr.test.js +0 -206
  146. package/dist/tools/generate-adr.test.js.map +0 -1
  147. package/dist/tools/generate-checklist.test.d.ts +0 -2
  148. package/dist/tools/generate-checklist.test.d.ts.map +0 -1
  149. package/dist/tools/generate-checklist.test.js +0 -201
  150. package/dist/tools/generate-checklist.test.js.map +0 -1
  151. package/dist/tools/generate-docs.test.d.ts +0 -2
  152. package/dist/tools/generate-docs.test.d.ts.map +0 -1
  153. package/dist/tools/generate-docs.test.js +0 -183
  154. package/dist/tools/generate-docs.test.js.map +0 -1
  155. package/dist/tools/generate-execution-plan.test.d.ts +0 -2
  156. package/dist/tools/generate-execution-plan.test.d.ts.map +0 -1
  157. package/dist/tools/generate-execution-plan.test.js +0 -643
  158. package/dist/tools/generate-execution-plan.test.js.map +0 -1
  159. package/dist/tools/generate-rules.test.d.ts +0 -2
  160. package/dist/tools/generate-rules.test.d.ts.map +0 -1
  161. package/dist/tools/generate-rules.test.js +0 -148
  162. package/dist/tools/generate-rules.test.js.map +0 -1
  163. package/dist/tools/generate-skill.test.d.ts +0 -2
  164. package/dist/tools/generate-skill.test.d.ts.map +0 -1
  165. package/dist/tools/generate-skill.test.js +0 -138
  166. package/dist/tools/generate-skill.test.js.map +0 -1
  167. package/dist/tools/generate-sub-agent.test.d.ts +0 -2
  168. package/dist/tools/generate-sub-agent.test.d.ts.map +0 -1
  169. package/dist/tools/generate-sub-agent.test.js +0 -162
  170. package/dist/tools/generate-sub-agent.test.js.map +0 -1
  171. package/dist/tools/generate-tests.test.d.ts +0 -2
  172. package/dist/tools/generate-tests.test.d.ts.map +0 -1
  173. package/dist/tools/generate-tests.test.js +0 -222
  174. package/dist/tools/generate-tests.test.js.map +0 -1
  175. package/dist/tools/init-constitution.test.d.ts +0 -2
  176. package/dist/tools/init-constitution.test.d.ts.map +0 -1
  177. package/dist/tools/init-constitution.test.js +0 -398
  178. package/dist/tools/init-constitution.test.js.map +0 -1
  179. package/dist/tools/init-project.test.d.ts +0 -2
  180. package/dist/tools/init-project.test.d.ts.map +0 -1
  181. package/dist/tools/init-project.test.js +0 -158
  182. package/dist/tools/init-project.test.js.map +0 -1
  183. package/dist/tools/integrate-pm.test.d.ts +0 -2
  184. package/dist/tools/integrate-pm.test.d.ts.map +0 -1
  185. package/dist/tools/integrate-pm.test.js +0 -558
  186. package/dist/tools/integrate-pm.test.js.map +0 -1
  187. package/dist/tools/learn.test.d.ts +0 -2
  188. package/dist/tools/learn.test.d.ts.map +0 -1
  189. package/dist/tools/learn.test.js +0 -123
  190. package/dist/tools/learn.test.js.map +0 -1
  191. package/dist/tools/list-specs.test.d.ts +0 -2
  192. package/dist/tools/list-specs.test.d.ts.map +0 -1
  193. package/dist/tools/list-specs.test.js +0 -110
  194. package/dist/tools/list-specs.test.js.map +0 -1
  195. package/dist/tools/manage-context.test.d.ts +0 -2
  196. package/dist/tools/manage-context.test.d.ts.map +0 -1
  197. package/dist/tools/manage-context.test.js +0 -359
  198. package/dist/tools/manage-context.test.js.map +0 -1
  199. package/dist/tools/manage-git.test.d.ts +0 -2
  200. package/dist/tools/manage-git.test.d.ts.map +0 -1
  201. package/dist/tools/manage-git.test.js +0 -882
  202. package/dist/tools/manage-git.test.js.map +0 -1
  203. package/dist/tools/orchestrate.test.d.ts +0 -2
  204. package/dist/tools/orchestrate.test.d.ts.map +0 -1
  205. package/dist/tools/orchestrate.test.js +0 -1117
  206. package/dist/tools/orchestrate.test.js.map +0 -1
  207. package/dist/tools/reconcile-spec.test.d.ts +0 -2
  208. package/dist/tools/reconcile-spec.test.d.ts.map +0 -1
  209. package/dist/tools/reconcile-spec.test.js +0 -259
  210. package/dist/tools/reconcile-spec.test.js.map +0 -1
  211. package/dist/tools/register-platform-tools.test.d.ts +0 -2
  212. package/dist/tools/register-platform-tools.test.d.ts.map +0 -1
  213. package/dist/tools/register-platform-tools.test.js +0 -404
  214. package/dist/tools/register-platform-tools.test.js.map +0 -1
  215. package/dist/tools/register-spec-tools.test.d.ts +0 -2
  216. package/dist/tools/register-spec-tools.test.d.ts.map +0 -1
  217. package/dist/tools/register-spec-tools.test.js +0 -407
  218. package/dist/tools/register-spec-tools.test.js.map +0 -1
  219. package/dist/tools/reverse-engineer.test.d.ts +0 -2
  220. package/dist/tools/reverse-engineer.test.d.ts.map +0 -1
  221. package/dist/tools/reverse-engineer.test.js +0 -206
  222. package/dist/tools/reverse-engineer.test.js.map +0 -1
  223. package/dist/tools/schemas.d.ts +0 -20
  224. package/dist/tools/schemas.d.ts.map +0 -1
  225. package/dist/tools/schemas.js +0 -133
  226. package/dist/tools/schemas.js.map +0 -1
  227. package/dist/tools/schemas.test.d.ts +0 -2
  228. package/dist/tools/schemas.test.d.ts.map +0 -1
  229. package/dist/tools/schemas.test.js +0 -245
  230. package/dist/tools/schemas.test.js.map +0 -1
  231. package/dist/tools/set-locale.test.d.ts +0 -2
  232. package/dist/tools/set-locale.test.d.ts.map +0 -1
  233. package/dist/tools/set-locale.test.js +0 -74
  234. package/dist/tools/set-locale.test.js.map +0 -1
  235. package/dist/tools/suggest-mcps.test.d.ts +0 -2
  236. package/dist/tools/suggest-mcps.test.d.ts.map +0 -1
  237. package/dist/tools/suggest-mcps.test.js +0 -198
  238. package/dist/tools/suggest-mcps.test.js.map +0 -1
  239. package/dist/tools/suggest-stack.test.d.ts +0 -2
  240. package/dist/tools/suggest-stack.test.d.ts.map +0 -1
  241. package/dist/tools/suggest-stack.test.js +0 -181
  242. package/dist/tools/suggest-stack.test.js.map +0 -1
  243. package/dist/tools/suggest-tooling.test.d.ts +0 -2
  244. package/dist/tools/suggest-tooling.test.d.ts.map +0 -1
  245. package/dist/tools/suggest-tooling.test.js +0 -213
  246. package/dist/tools/suggest-tooling.test.js.map +0 -1
  247. package/dist/tools/summarize-spec.test.d.ts +0 -2
  248. package/dist/tools/summarize-spec.test.d.ts.map +0 -1
  249. package/dist/tools/summarize-spec.test.js +0 -180
  250. package/dist/tools/summarize-spec.test.js.map +0 -1
  251. package/dist/tools/update-status.test.d.ts +0 -2
  252. package/dist/tools/update-status.test.d.ts.map +0 -1
  253. package/dist/tools/update-status.test.js +0 -142
  254. package/dist/tools/update-status.test.js.map +0 -1
  255. package/dist/tools/validate.test.d.ts +0 -2
  256. package/dist/tools/validate.test.d.ts.map +0 -1
  257. package/dist/tools/validate.test.js +0 -137
  258. 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