@su-record/vibe 2.5.21 → 2.6.1
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.
- package/CLAUDE.md +154 -2
- package/README.md +132 -2
- package/commands/vibe.run.md +69 -44
- package/commands/vibe.spec.md +83 -0
- package/commands/vibe.trace.md +161 -0
- package/dist/cli/index.d.ts.map +1 -1
- package/dist/cli/index.js +5 -3
- package/dist/cli/index.js.map +1 -1
- package/dist/lib/IterationTracker.d.ts +3 -1
- package/dist/lib/IterationTracker.d.ts.map +1 -1
- package/dist/lib/IterationTracker.js +2 -1
- package/dist/lib/IterationTracker.js.map +1 -1
- package/dist/lib/constants.d.ts +14 -0
- package/dist/lib/constants.d.ts.map +1 -1
- package/dist/lib/constants.js +26 -0
- package/dist/lib/constants.js.map +1 -1
- package/dist/orchestrator/BackgroundManager.d.ts +109 -0
- package/dist/orchestrator/BackgroundManager.d.ts.map +1 -0
- package/dist/orchestrator/BackgroundManager.js +456 -0
- package/dist/orchestrator/BackgroundManager.js.map +1 -0
- package/dist/orchestrator/BackgroundManager.test.d.ts +6 -0
- package/dist/orchestrator/BackgroundManager.test.d.ts.map +1 -0
- package/dist/orchestrator/BackgroundManager.test.js +162 -0
- package/dist/orchestrator/BackgroundManager.test.js.map +1 -0
- package/dist/orchestrator/PhasePipeline.d.ts +106 -0
- package/dist/orchestrator/PhasePipeline.d.ts.map +1 -0
- package/dist/orchestrator/PhasePipeline.js +279 -0
- package/dist/orchestrator/PhasePipeline.js.map +1 -0
- package/dist/orchestrator/backgroundAgent.d.ts +2 -0
- package/dist/orchestrator/backgroundAgent.d.ts.map +1 -1
- package/dist/orchestrator/backgroundAgent.js +2 -0
- package/dist/orchestrator/backgroundAgent.js.map +1 -1
- package/dist/orchestrator/index.d.ts +4 -1
- package/dist/orchestrator/index.d.ts.map +1 -1
- package/dist/orchestrator/index.js +5 -1
- package/dist/orchestrator/index.js.map +1 -1
- package/dist/tools/index.d.ts +4 -0
- package/dist/tools/index.d.ts.map +1 -1
- package/dist/tools/index.js +14 -0
- package/dist/tools/index.js.map +1 -1
- package/dist/tools/interaction/askUser.d.ts +115 -0
- package/dist/tools/interaction/askUser.d.ts.map +1 -0
- package/dist/tools/interaction/askUser.js +504 -0
- package/dist/tools/interaction/askUser.js.map +1 -0
- package/dist/tools/interaction/index.d.ts +8 -0
- package/dist/tools/interaction/index.d.ts.map +1 -0
- package/dist/tools/interaction/index.js +17 -0
- package/dist/tools/interaction/index.js.map +1 -0
- package/dist/tools/spec/index.d.ts +14 -0
- package/dist/tools/spec/index.d.ts.map +1 -0
- package/dist/tools/spec/index.js +15 -0
- package/dist/tools/spec/index.js.map +1 -0
- package/dist/tools/spec/prdParser.d.ts +43 -0
- package/dist/tools/spec/prdParser.d.ts.map +1 -0
- package/dist/tools/spec/prdParser.js +291 -0
- package/dist/tools/spec/prdParser.js.map +1 -0
- package/dist/tools/spec/prdParser.test.d.ts +6 -0
- package/dist/tools/spec/prdParser.test.d.ts.map +1 -0
- package/dist/tools/spec/prdParser.test.js +332 -0
- package/dist/tools/spec/prdParser.test.js.map +1 -0
- package/dist/tools/spec/requirementId.d.ts +65 -0
- package/dist/tools/spec/requirementId.d.ts.map +1 -0
- package/dist/tools/spec/requirementId.js +161 -0
- package/dist/tools/spec/requirementId.js.map +1 -0
- package/dist/tools/spec/specGenerator.d.ts +39 -0
- package/dist/tools/spec/specGenerator.d.ts.map +1 -0
- package/dist/tools/spec/specGenerator.js +426 -0
- package/dist/tools/spec/specGenerator.js.map +1 -0
- package/dist/tools/spec/specVersioning.d.ts +77 -0
- package/dist/tools/spec/specVersioning.d.ts.map +1 -0
- package/dist/tools/spec/specVersioning.js +237 -0
- package/dist/tools/spec/specVersioning.js.map +1 -0
- package/dist/tools/spec/traceabilityMatrix.d.ts +55 -0
- package/dist/tools/spec/traceabilityMatrix.d.ts.map +1 -0
- package/dist/tools/spec/traceabilityMatrix.js +396 -0
- package/dist/tools/spec/traceabilityMatrix.js.map +1 -0
- package/dist/tools/spec/traceabilityMatrix.test.d.ts +6 -0
- package/dist/tools/spec/traceabilityMatrix.test.d.ts.map +1 -0
- package/dist/tools/spec/traceabilityMatrix.test.js +340 -0
- package/dist/tools/spec/traceabilityMatrix.test.js.map +1 -0
- package/package.json +2 -1
|
@@ -0,0 +1,332 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* PRD Parser Tests
|
|
3
|
+
* Markdown/YAML parsing, requirement extraction
|
|
4
|
+
*/
|
|
5
|
+
import { describe, it, expect, beforeEach } from 'vitest';
|
|
6
|
+
import { parsePRD, } from './prdParser.js';
|
|
7
|
+
import { resetRequirementCounter } from './requirementId.js';
|
|
8
|
+
describe('PRD Parser', () => {
|
|
9
|
+
beforeEach(() => {
|
|
10
|
+
// Reset counter between tests
|
|
11
|
+
resetRequirementCounter();
|
|
12
|
+
});
|
|
13
|
+
describe('parsePRD()', () => {
|
|
14
|
+
it('should parse basic markdown PRD', () => {
|
|
15
|
+
const content = `# Login Feature
|
|
16
|
+
|
|
17
|
+
A user authentication feature.
|
|
18
|
+
|
|
19
|
+
## Requirements
|
|
20
|
+
|
|
21
|
+
- User must be able to login with email and password
|
|
22
|
+
- User must be able to reset password
|
|
23
|
+
- User must be able to logout
|
|
24
|
+
|
|
25
|
+
## Acceptance Criteria
|
|
26
|
+
|
|
27
|
+
- Login form validates email format
|
|
28
|
+
- Password must be at least 8 characters
|
|
29
|
+
`;
|
|
30
|
+
const result = parsePRD(content, 'login');
|
|
31
|
+
expect(result.title).toBe('Login Feature');
|
|
32
|
+
expect(result.requirements.length).toBeGreaterThan(0);
|
|
33
|
+
expect(result.metadata.format).toBe('markdown');
|
|
34
|
+
expect(result.metadata.hasYamlFrontmatter).toBe(false);
|
|
35
|
+
});
|
|
36
|
+
it('should extract title from first heading', () => {
|
|
37
|
+
const content = `# My Feature Title
|
|
38
|
+
|
|
39
|
+
Some description here.
|
|
40
|
+
`;
|
|
41
|
+
const result = parsePRD(content, 'feature');
|
|
42
|
+
expect(result.title).toBe('My Feature Title');
|
|
43
|
+
});
|
|
44
|
+
it('should extract description', () => {
|
|
45
|
+
const content = `# Feature
|
|
46
|
+
|
|
47
|
+
This is the feature description.
|
|
48
|
+
It spans multiple lines.
|
|
49
|
+
|
|
50
|
+
## Requirements
|
|
51
|
+
|
|
52
|
+
- Requirement 1
|
|
53
|
+
`;
|
|
54
|
+
const result = parsePRD(content, 'feature');
|
|
55
|
+
expect(result.description).toContain('feature description');
|
|
56
|
+
});
|
|
57
|
+
it('should assign requirement IDs', () => {
|
|
58
|
+
const content = `# Feature
|
|
59
|
+
|
|
60
|
+
## Requirements
|
|
61
|
+
|
|
62
|
+
- First requirement
|
|
63
|
+
- Second requirement
|
|
64
|
+
`;
|
|
65
|
+
const result = parsePRD(content, 'test');
|
|
66
|
+
expect(result.requirements[0].id).toMatch(/^REQ-test-\d{3}$/);
|
|
67
|
+
expect(result.requirements[1].id).toMatch(/^REQ-test-\d{3}$/);
|
|
68
|
+
expect(result.requirements[0].id).not.toBe(result.requirements[1].id);
|
|
69
|
+
});
|
|
70
|
+
});
|
|
71
|
+
describe('YAML frontmatter parsing', () => {
|
|
72
|
+
it('should parse YAML frontmatter', () => {
|
|
73
|
+
const content = `---
|
|
74
|
+
title: YAML Feature
|
|
75
|
+
version: 1.0.0
|
|
76
|
+
requirements:
|
|
77
|
+
- First YAML requirement
|
|
78
|
+
- Second YAML requirement
|
|
79
|
+
---
|
|
80
|
+
|
|
81
|
+
# YAML Feature
|
|
82
|
+
|
|
83
|
+
Content here.
|
|
84
|
+
`;
|
|
85
|
+
const result = parsePRD(content, 'yaml-feature');
|
|
86
|
+
expect(result.metadata.hasYamlFrontmatter).toBe(true);
|
|
87
|
+
expect(result.metadata.format).toBe('mixed');
|
|
88
|
+
});
|
|
89
|
+
it('should extract requirements from YAML', () => {
|
|
90
|
+
const content = `---
|
|
91
|
+
requirements:
|
|
92
|
+
- YAML requirement one
|
|
93
|
+
- YAML requirement two
|
|
94
|
+
---
|
|
95
|
+
|
|
96
|
+
# Feature
|
|
97
|
+
`;
|
|
98
|
+
const result = parsePRD(content, 'yaml');
|
|
99
|
+
const yamlReqs = result.requirements.filter(r => r.source === 'YAML frontmatter');
|
|
100
|
+
expect(yamlReqs.length).toBe(2);
|
|
101
|
+
});
|
|
102
|
+
});
|
|
103
|
+
describe('Priority inference', () => {
|
|
104
|
+
it('should infer high priority from "must"', () => {
|
|
105
|
+
const content = `# Feature
|
|
106
|
+
|
|
107
|
+
## Requirements
|
|
108
|
+
|
|
109
|
+
- User must be authenticated
|
|
110
|
+
`;
|
|
111
|
+
const result = parsePRD(content, 'priority');
|
|
112
|
+
const req = result.requirements.find(r => r.description.includes('must'));
|
|
113
|
+
expect(req?.priority).toBe('high');
|
|
114
|
+
});
|
|
115
|
+
it('should infer high priority from "critical"', () => {
|
|
116
|
+
const content = `# Feature
|
|
117
|
+
|
|
118
|
+
## Requirements
|
|
119
|
+
|
|
120
|
+
- Critical security feature required
|
|
121
|
+
`;
|
|
122
|
+
const result = parsePRD(content, 'priority');
|
|
123
|
+
expect(result.requirements[0].priority).toBe('high');
|
|
124
|
+
});
|
|
125
|
+
it('should infer low priority from "nice to have"', () => {
|
|
126
|
+
const content = `# Feature
|
|
127
|
+
|
|
128
|
+
## Requirements
|
|
129
|
+
|
|
130
|
+
- Nice to have dark mode support
|
|
131
|
+
`;
|
|
132
|
+
const result = parsePRD(content, 'priority');
|
|
133
|
+
expect(result.requirements[0].priority).toBe('low');
|
|
134
|
+
});
|
|
135
|
+
it('should default to medium priority', () => {
|
|
136
|
+
const content = `# Feature
|
|
137
|
+
|
|
138
|
+
## Requirements
|
|
139
|
+
|
|
140
|
+
- Regular feature without priority keywords
|
|
141
|
+
`;
|
|
142
|
+
const result = parsePRD(content, 'priority');
|
|
143
|
+
expect(result.requirements[0].priority).toBe('medium');
|
|
144
|
+
});
|
|
145
|
+
});
|
|
146
|
+
describe('Section extraction', () => {
|
|
147
|
+
it('should extract from Requirements section', () => {
|
|
148
|
+
const content = `# Feature
|
|
149
|
+
|
|
150
|
+
## Overview
|
|
151
|
+
|
|
152
|
+
Some overview text.
|
|
153
|
+
|
|
154
|
+
## Requirements
|
|
155
|
+
|
|
156
|
+
- Requirement from requirements section
|
|
157
|
+
|
|
158
|
+
## Other Section
|
|
159
|
+
|
|
160
|
+
Other content.
|
|
161
|
+
`;
|
|
162
|
+
const result = parsePRD(content, 'section');
|
|
163
|
+
const fromReqs = result.requirements.filter(r => r.source?.includes('Requirements'));
|
|
164
|
+
expect(fromReqs.length).toBeGreaterThan(0);
|
|
165
|
+
});
|
|
166
|
+
it('should extract from User Stories section', () => {
|
|
167
|
+
const content = `# Feature
|
|
168
|
+
|
|
169
|
+
## User Stories
|
|
170
|
+
|
|
171
|
+
As a user, I want to login so that I can access my account.
|
|
172
|
+
`;
|
|
173
|
+
const result = parsePRD(content, 'story');
|
|
174
|
+
const fromStories = result.requirements.filter(r => r.source?.includes('User Stories'));
|
|
175
|
+
expect(fromStories.length).toBe(1);
|
|
176
|
+
});
|
|
177
|
+
it('should handle Korean section names', () => {
|
|
178
|
+
const content = `# 기능
|
|
179
|
+
|
|
180
|
+
## 요구사항
|
|
181
|
+
|
|
182
|
+
- 한글 요구사항 1
|
|
183
|
+
- 한글 요구사항 2
|
|
184
|
+
`;
|
|
185
|
+
const result = parsePRD(content, 'korean');
|
|
186
|
+
expect(result.requirements.length).toBe(2);
|
|
187
|
+
});
|
|
188
|
+
});
|
|
189
|
+
describe('List parsing', () => {
|
|
190
|
+
it('should parse bullet lists with -', () => {
|
|
191
|
+
const content = `# Feature
|
|
192
|
+
|
|
193
|
+
## Requirements
|
|
194
|
+
|
|
195
|
+
- Item one
|
|
196
|
+
- Item two
|
|
197
|
+
- Item three
|
|
198
|
+
`;
|
|
199
|
+
const result = parsePRD(content, 'bullet');
|
|
200
|
+
expect(result.requirements.length).toBe(3);
|
|
201
|
+
});
|
|
202
|
+
it('should parse bullet lists with *', () => {
|
|
203
|
+
const content = `# Feature
|
|
204
|
+
|
|
205
|
+
## Requirements
|
|
206
|
+
|
|
207
|
+
* Star item one
|
|
208
|
+
* Star item two
|
|
209
|
+
`;
|
|
210
|
+
const result = parsePRD(content, 'star');
|
|
211
|
+
expect(result.requirements.length).toBe(2);
|
|
212
|
+
});
|
|
213
|
+
it('should parse numbered lists', () => {
|
|
214
|
+
const content = `# Feature
|
|
215
|
+
|
|
216
|
+
## Requirements
|
|
217
|
+
|
|
218
|
+
1. First item
|
|
219
|
+
2. Second item
|
|
220
|
+
3. Third item
|
|
221
|
+
`;
|
|
222
|
+
const result = parsePRD(content, 'numbered');
|
|
223
|
+
expect(result.requirements.length).toBe(3);
|
|
224
|
+
});
|
|
225
|
+
it('should parse numbered lists with parentheses', () => {
|
|
226
|
+
const content = `# Feature
|
|
227
|
+
|
|
228
|
+
## Requirements
|
|
229
|
+
|
|
230
|
+
1) First item
|
|
231
|
+
2) Second item
|
|
232
|
+
`;
|
|
233
|
+
const result = parsePRD(content, 'paren');
|
|
234
|
+
expect(result.requirements.length).toBe(2);
|
|
235
|
+
});
|
|
236
|
+
});
|
|
237
|
+
describe('Acceptance Criteria', () => {
|
|
238
|
+
it('should extract AC and associate with requirements', () => {
|
|
239
|
+
const content = `# Feature
|
|
240
|
+
|
|
241
|
+
## Requirements
|
|
242
|
+
|
|
243
|
+
- User login functionality
|
|
244
|
+
|
|
245
|
+
## Acceptance Criteria
|
|
246
|
+
|
|
247
|
+
- Login form displays correctly
|
|
248
|
+
- Validation errors show properly
|
|
249
|
+
`;
|
|
250
|
+
const result = parsePRD(content, 'ac');
|
|
251
|
+
expect(result.requirements.length).toBeGreaterThan(0);
|
|
252
|
+
});
|
|
253
|
+
});
|
|
254
|
+
describe('Deduplication', () => {
|
|
255
|
+
it('should deduplicate similar requirements', () => {
|
|
256
|
+
const content = `# Feature
|
|
257
|
+
|
|
258
|
+
## Requirements
|
|
259
|
+
|
|
260
|
+
- User must login with email
|
|
261
|
+
- User must login with email and password
|
|
262
|
+
|
|
263
|
+
## Acceptance Criteria
|
|
264
|
+
|
|
265
|
+
- User must login with email validation
|
|
266
|
+
`;
|
|
267
|
+
const result = parsePRD(content, 'dedup');
|
|
268
|
+
// First 50 chars are used for deduplication
|
|
269
|
+
// "User must login with email" appears multiple times
|
|
270
|
+
expect(result.requirements.length).toBeLessThanOrEqual(3);
|
|
271
|
+
});
|
|
272
|
+
});
|
|
273
|
+
describe('Fallback extraction', () => {
|
|
274
|
+
it('should use fallback when no standard sections found', () => {
|
|
275
|
+
const content = `# Feature
|
|
276
|
+
|
|
277
|
+
Some text here.
|
|
278
|
+
|
|
279
|
+
- This is a long enough item to be captured
|
|
280
|
+
- Another sufficiently long item
|
|
281
|
+
- Short
|
|
282
|
+
|
|
283
|
+
Random paragraph.
|
|
284
|
+
`;
|
|
285
|
+
const result = parsePRD(content, 'fallback');
|
|
286
|
+
// Fallback only captures items > 20 chars
|
|
287
|
+
expect(result.requirements.length).toBeGreaterThan(0);
|
|
288
|
+
expect(result.metadata.parseWarnings.length).toBeGreaterThan(0);
|
|
289
|
+
});
|
|
290
|
+
});
|
|
291
|
+
describe('Metadata', () => {
|
|
292
|
+
it('should count sections correctly', () => {
|
|
293
|
+
const content = `# Feature
|
|
294
|
+
|
|
295
|
+
## Section One
|
|
296
|
+
|
|
297
|
+
Content.
|
|
298
|
+
|
|
299
|
+
## Section Two
|
|
300
|
+
|
|
301
|
+
More content.
|
|
302
|
+
|
|
303
|
+
## Section Three
|
|
304
|
+
|
|
305
|
+
Even more.
|
|
306
|
+
`;
|
|
307
|
+
const result = parsePRD(content, 'meta');
|
|
308
|
+
expect(result.metadata.sectionCount).toBe(3);
|
|
309
|
+
});
|
|
310
|
+
it('should track requirement count', () => {
|
|
311
|
+
const content = `# Feature
|
|
312
|
+
|
|
313
|
+
## Requirements
|
|
314
|
+
|
|
315
|
+
- Req 1
|
|
316
|
+
- Req 2
|
|
317
|
+
- Req 3
|
|
318
|
+
`;
|
|
319
|
+
const result = parsePRD(content, 'count');
|
|
320
|
+
expect(result.metadata.requirementCount).toBe(3);
|
|
321
|
+
});
|
|
322
|
+
it('should preserve raw content', () => {
|
|
323
|
+
const content = `# Feature
|
|
324
|
+
|
|
325
|
+
Original content preserved.
|
|
326
|
+
`;
|
|
327
|
+
const result = parsePRD(content, 'raw');
|
|
328
|
+
expect(result.raw).toBe(content);
|
|
329
|
+
});
|
|
330
|
+
});
|
|
331
|
+
});
|
|
332
|
+
//# sourceMappingURL=prdParser.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"prdParser.test.js","sourceRoot":"","sources":["../../../src/tools/spec/prdParser.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Requirement ID System - 요구사항 ID 관리
|
|
3
|
+
* v2.6.0: PRD-to-SPEC 자동화 지원
|
|
4
|
+
*
|
|
5
|
+
* ID 형식: REQ-{feature}-{number}
|
|
6
|
+
* 예: REQ-login-001, REQ-auth-002
|
|
7
|
+
*/
|
|
8
|
+
/**
|
|
9
|
+
* 새 요구사항 ID 생성
|
|
10
|
+
*/
|
|
11
|
+
export declare function generateRequirementId(feature: string): string;
|
|
12
|
+
/**
|
|
13
|
+
* 여러 요구사항 ID 일괄 생성
|
|
14
|
+
*/
|
|
15
|
+
export declare function generateRequirementIds(feature: string, count: number): string[];
|
|
16
|
+
/**
|
|
17
|
+
* ID 유효성 검증
|
|
18
|
+
*/
|
|
19
|
+
export declare function validateRequirementId(id: string): {
|
|
20
|
+
valid: boolean;
|
|
21
|
+
error?: string;
|
|
22
|
+
};
|
|
23
|
+
/**
|
|
24
|
+
* ID 중복 검사
|
|
25
|
+
*/
|
|
26
|
+
export declare function checkDuplicateId(id: string): boolean;
|
|
27
|
+
/**
|
|
28
|
+
* 기존 ID 등록 (기존 SPEC 로드 시)
|
|
29
|
+
*/
|
|
30
|
+
export declare function registerExistingId(id: string): boolean;
|
|
31
|
+
/**
|
|
32
|
+
* 여러 기존 ID 등록
|
|
33
|
+
*/
|
|
34
|
+
export declare function registerExistingIds(ids: string[]): {
|
|
35
|
+
registered: number;
|
|
36
|
+
skipped: number;
|
|
37
|
+
errors: string[];
|
|
38
|
+
};
|
|
39
|
+
/**
|
|
40
|
+
* ID에서 Feature 이름 추출
|
|
41
|
+
*/
|
|
42
|
+
export declare function extractFeatureFromId(id: string): string | null;
|
|
43
|
+
/**
|
|
44
|
+
* ID에서 번호 추출
|
|
45
|
+
*/
|
|
46
|
+
export declare function extractNumberFromId(id: string): number | null;
|
|
47
|
+
/**
|
|
48
|
+
* Feature별 사용된 ID 목록 조회
|
|
49
|
+
*/
|
|
50
|
+
export declare function getIdsByFeature(feature: string): string[];
|
|
51
|
+
/**
|
|
52
|
+
* 모든 사용된 ID 조회
|
|
53
|
+
*/
|
|
54
|
+
export declare function getAllUsedIds(): string[];
|
|
55
|
+
/**
|
|
56
|
+
* ID 카운터 리셋 (테스트용)
|
|
57
|
+
*/
|
|
58
|
+
export declare function resetCounters(): void;
|
|
59
|
+
/** Alias for resetCounters (테스트 호환성) */
|
|
60
|
+
export declare const resetRequirementCounter: typeof resetCounters;
|
|
61
|
+
/**
|
|
62
|
+
* 현재 카운터 상태 조회
|
|
63
|
+
*/
|
|
64
|
+
export declare function getCounterStatus(): Record<string, number>;
|
|
65
|
+
//# sourceMappingURL=requirementId.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"requirementId.d.ts","sourceRoot":"","sources":["../../../src/tools/spec/requirementId.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAWH;;GAEG;AACH,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAc7D;AAED;;GAEG;AACH,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,CAM/E;AAED;;GAEG;AACH,wBAAgB,qBAAqB,CAAC,EAAE,EAAE,MAAM,GAAG;IAAE,KAAK,EAAE,OAAO,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,CAapF;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAEpD;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAwBtD;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG;IAAE,UAAU,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,EAAE,CAAA;CAAE,CAkB5G;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAG9D;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAG7D;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,EAAE,CAKzD;AAED;;GAEG;AACH,wBAAgB,aAAa,IAAI,MAAM,EAAE,CAExC;AAED;;GAEG;AACH,wBAAgB,aAAa,IAAI,IAAI,CAGpC;AAED,wCAAwC;AACxC,eAAO,MAAM,uBAAuB,sBAAgB,CAAC;AAErD;;GAEG;AACH,wBAAgB,gBAAgB,IAAI,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAEzD"}
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Requirement ID System - 요구사항 ID 관리
|
|
3
|
+
* v2.6.0: PRD-to-SPEC 자동화 지원
|
|
4
|
+
*
|
|
5
|
+
* ID 형식: REQ-{feature}-{number}
|
|
6
|
+
* 예: REQ-login-001, REQ-auth-002
|
|
7
|
+
*/
|
|
8
|
+
/** 요구사항 ID 정규식 */
|
|
9
|
+
const ID_PATTERN = /^REQ-([a-z0-9-]+)-(\d{3})$/;
|
|
10
|
+
/** ID 카운터 (feature별) */
|
|
11
|
+
const counters = new Map();
|
|
12
|
+
/** 사용된 ID 추적 (중복 방지) */
|
|
13
|
+
const usedIds = new Set();
|
|
14
|
+
/**
|
|
15
|
+
* 새 요구사항 ID 생성
|
|
16
|
+
*/
|
|
17
|
+
export function generateRequirementId(feature) {
|
|
18
|
+
const normalizedFeature = normalizeFeatureName(feature);
|
|
19
|
+
const count = (counters.get(normalizedFeature) || 0) + 1;
|
|
20
|
+
counters.set(normalizedFeature, count);
|
|
21
|
+
const id = formatId(normalizedFeature, count);
|
|
22
|
+
// 중복 방지
|
|
23
|
+
if (usedIds.has(id)) {
|
|
24
|
+
return generateRequirementId(feature);
|
|
25
|
+
}
|
|
26
|
+
usedIds.add(id);
|
|
27
|
+
return id;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* 여러 요구사항 ID 일괄 생성
|
|
31
|
+
*/
|
|
32
|
+
export function generateRequirementIds(feature, count) {
|
|
33
|
+
const ids = [];
|
|
34
|
+
for (let i = 0; i < count; i++) {
|
|
35
|
+
ids.push(generateRequirementId(feature));
|
|
36
|
+
}
|
|
37
|
+
return ids;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* ID 유효성 검증
|
|
41
|
+
*/
|
|
42
|
+
export function validateRequirementId(id) {
|
|
43
|
+
if (!id) {
|
|
44
|
+
return { valid: false, error: 'ID is empty' };
|
|
45
|
+
}
|
|
46
|
+
if (!ID_PATTERN.test(id)) {
|
|
47
|
+
return {
|
|
48
|
+
valid: false,
|
|
49
|
+
error: `Invalid format. Expected: REQ-{feature}-{number}, got: ${id}`
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
return { valid: true };
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* ID 중복 검사
|
|
56
|
+
*/
|
|
57
|
+
export function checkDuplicateId(id) {
|
|
58
|
+
return usedIds.has(id);
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* 기존 ID 등록 (기존 SPEC 로드 시)
|
|
62
|
+
*/
|
|
63
|
+
export function registerExistingId(id) {
|
|
64
|
+
const validation = validateRequirementId(id);
|
|
65
|
+
if (!validation.valid) {
|
|
66
|
+
return false;
|
|
67
|
+
}
|
|
68
|
+
if (usedIds.has(id)) {
|
|
69
|
+
return false; // 이미 등록됨
|
|
70
|
+
}
|
|
71
|
+
usedIds.add(id);
|
|
72
|
+
// 카운터 업데이트
|
|
73
|
+
const match = id.match(ID_PATTERN);
|
|
74
|
+
if (match) {
|
|
75
|
+
const [, feature, numStr] = match;
|
|
76
|
+
const num = parseInt(numStr, 10);
|
|
77
|
+
const currentMax = counters.get(feature) || 0;
|
|
78
|
+
if (num > currentMax) {
|
|
79
|
+
counters.set(feature, num);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
return true;
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* 여러 기존 ID 등록
|
|
86
|
+
*/
|
|
87
|
+
export function registerExistingIds(ids) {
|
|
88
|
+
const result = { registered: 0, skipped: 0, errors: [] };
|
|
89
|
+
for (const id of ids) {
|
|
90
|
+
const validation = validateRequirementId(id);
|
|
91
|
+
if (!validation.valid) {
|
|
92
|
+
result.errors.push(`${id}: ${validation.error}`);
|
|
93
|
+
continue;
|
|
94
|
+
}
|
|
95
|
+
if (registerExistingId(id)) {
|
|
96
|
+
result.registered++;
|
|
97
|
+
}
|
|
98
|
+
else {
|
|
99
|
+
result.skipped++;
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
return result;
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* ID에서 Feature 이름 추출
|
|
106
|
+
*/
|
|
107
|
+
export function extractFeatureFromId(id) {
|
|
108
|
+
const match = id.match(ID_PATTERN);
|
|
109
|
+
return match ? match[1] : null;
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* ID에서 번호 추출
|
|
113
|
+
*/
|
|
114
|
+
export function extractNumberFromId(id) {
|
|
115
|
+
const match = id.match(ID_PATTERN);
|
|
116
|
+
return match ? parseInt(match[2], 10) : null;
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* Feature별 사용된 ID 목록 조회
|
|
120
|
+
*/
|
|
121
|
+
export function getIdsByFeature(feature) {
|
|
122
|
+
const normalizedFeature = normalizeFeatureName(feature);
|
|
123
|
+
return Array.from(usedIds)
|
|
124
|
+
.filter(id => id.startsWith(`REQ-${normalizedFeature}-`))
|
|
125
|
+
.sort();
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* 모든 사용된 ID 조회
|
|
129
|
+
*/
|
|
130
|
+
export function getAllUsedIds() {
|
|
131
|
+
return Array.from(usedIds).sort();
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* ID 카운터 리셋 (테스트용)
|
|
135
|
+
*/
|
|
136
|
+
export function resetCounters() {
|
|
137
|
+
counters.clear();
|
|
138
|
+
usedIds.clear();
|
|
139
|
+
}
|
|
140
|
+
/** Alias for resetCounters (테스트 호환성) */
|
|
141
|
+
export const resetRequirementCounter = resetCounters;
|
|
142
|
+
/**
|
|
143
|
+
* 현재 카운터 상태 조회
|
|
144
|
+
*/
|
|
145
|
+
export function getCounterStatus() {
|
|
146
|
+
return Object.fromEntries(counters);
|
|
147
|
+
}
|
|
148
|
+
// ============================================
|
|
149
|
+
// Internal Helpers
|
|
150
|
+
// ============================================
|
|
151
|
+
function normalizeFeatureName(feature) {
|
|
152
|
+
return feature
|
|
153
|
+
.toLowerCase()
|
|
154
|
+
.replace(/[^a-z0-9]+/g, '-')
|
|
155
|
+
.replace(/^-|-$/g, '')
|
|
156
|
+
.slice(0, 30); // 최대 30자
|
|
157
|
+
}
|
|
158
|
+
function formatId(feature, num) {
|
|
159
|
+
return `REQ-${feature}-${num.toString().padStart(3, '0')}`;
|
|
160
|
+
}
|
|
161
|
+
//# sourceMappingURL=requirementId.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"requirementId.js","sourceRoot":"","sources":["../../../src/tools/spec/requirementId.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SPEC Generator - PRD에서 PTCF 구조 SPEC 자동 생성
|
|
3
|
+
* v2.6.0: PRD-to-SPEC 자동화
|
|
4
|
+
*
|
|
5
|
+
* PTCF: Persona, Task, Context, Format (Gemini 프롬프트 최적화)
|
|
6
|
+
*/
|
|
7
|
+
import { ParsedPRD } from './prdParser.js';
|
|
8
|
+
/** SPEC 생성 옵션 */
|
|
9
|
+
export interface SpecGeneratorOptions {
|
|
10
|
+
/** 기술 스택 */
|
|
11
|
+
techStack?: string[];
|
|
12
|
+
/** Phase 자동 분리 임계값 (요구사항 수) */
|
|
13
|
+
phaseThreshold?: number;
|
|
14
|
+
/** 관련 코드 경로 */
|
|
15
|
+
relatedCodePaths?: string[];
|
|
16
|
+
/** 디자인 레퍼런스 */
|
|
17
|
+
designReference?: string;
|
|
18
|
+
/** 제약 조건 추가 */
|
|
19
|
+
additionalConstraints?: string[];
|
|
20
|
+
/** 출력 형식 추가 */
|
|
21
|
+
additionalOutputs?: string[];
|
|
22
|
+
}
|
|
23
|
+
/** 생성된 SPEC */
|
|
24
|
+
export interface GeneratedSpec {
|
|
25
|
+
content: string;
|
|
26
|
+
featureName: string;
|
|
27
|
+
phaseCount: number;
|
|
28
|
+
requirementCount: number;
|
|
29
|
+
isSplit: boolean;
|
|
30
|
+
splitFiles?: {
|
|
31
|
+
path: string;
|
|
32
|
+
content: string;
|
|
33
|
+
}[];
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* PRD에서 SPEC 생성 (메인 함수)
|
|
37
|
+
*/
|
|
38
|
+
export declare function generateSpec(prd: ParsedPRD, featureName: string, options?: SpecGeneratorOptions): GeneratedSpec;
|
|
39
|
+
//# sourceMappingURL=specGenerator.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"specGenerator.d.ts","sourceRoot":"","sources":["../../../src/tools/spec/specGenerator.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,SAAS,EAAe,MAAM,gBAAgB,CAAC;AAOxD,iBAAiB;AACjB,MAAM,WAAW,oBAAoB;IACnC,YAAY;IACZ,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC;IACrB,+BAA+B;IAC/B,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,eAAe;IACf,gBAAgB,CAAC,EAAE,MAAM,EAAE,CAAC;IAC5B,eAAe;IACf,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,eAAe;IACf,qBAAqB,CAAC,EAAE,MAAM,EAAE,CAAC;IACjC,eAAe;IACf,iBAAiB,CAAC,EAAE,MAAM,EAAE,CAAC;CAC9B;AAED,eAAe;AACf,MAAM,WAAW,aAAa;IAC5B,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;IACnB,gBAAgB,EAAE,MAAM,CAAC;IACzB,OAAO,EAAE,OAAO,CAAC;IACjB,UAAU,CAAC,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;CAClD;AAaD;;GAEG;AACH,wBAAgB,YAAY,CAC1B,GAAG,EAAE,SAAS,EACd,WAAW,EAAE,MAAM,EACnB,OAAO,GAAE,oBAAyB,GACjC,aAAa,CAmBf"}
|