@nahisaho/musubix-core 1.0.0 → 1.0.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.
Files changed (33) hide show
  1. package/dist/cli/commands/codegen.d.ts +125 -0
  2. package/dist/cli/commands/codegen.d.ts.map +1 -0
  3. package/dist/cli/commands/codegen.js +684 -0
  4. package/dist/cli/commands/codegen.js.map +1 -0
  5. package/dist/cli/commands/design.d.ts +158 -0
  6. package/dist/cli/commands/design.d.ts.map +1 -0
  7. package/dist/cli/commands/design.js +562 -0
  8. package/dist/cli/commands/design.js.map +1 -0
  9. package/dist/cli/commands/explain.d.ts +116 -0
  10. package/dist/cli/commands/explain.d.ts.map +1 -0
  11. package/dist/cli/commands/explain.js +419 -0
  12. package/dist/cli/commands/explain.js.map +1 -0
  13. package/dist/cli/commands/index.d.ts +13 -0
  14. package/dist/cli/commands/index.d.ts.map +1 -1
  15. package/dist/cli/commands/index.js +31 -7
  16. package/dist/cli/commands/index.js.map +1 -1
  17. package/dist/cli/commands/requirements.d.ts +103 -0
  18. package/dist/cli/commands/requirements.d.ts.map +1 -0
  19. package/dist/cli/commands/requirements.js +403 -0
  20. package/dist/cli/commands/requirements.js.map +1 -0
  21. package/dist/cli/commands/skills.d.ts +99 -0
  22. package/dist/cli/commands/skills.d.ts.map +1 -0
  23. package/dist/cli/commands/skills.js +363 -0
  24. package/dist/cli/commands/skills.js.map +1 -0
  25. package/dist/cli/commands/test.d.ts +113 -0
  26. package/dist/cli/commands/test.d.ts.map +1 -0
  27. package/dist/cli/commands/test.js +532 -0
  28. package/dist/cli/commands/test.js.map +1 -0
  29. package/dist/cli/commands/trace.d.ts +132 -0
  30. package/dist/cli/commands/trace.d.ts.map +1 -0
  31. package/dist/cli/commands/trace.js +553 -0
  32. package/dist/cli/commands/trace.js.map +1 -0
  33. package/package.json +5 -3
@@ -0,0 +1,132 @@
1
+ /**
2
+ * Trace Command
3
+ *
4
+ * CLI commands for traceability management
5
+ *
6
+ * @packageDocumentation
7
+ * @module cli/commands/trace
8
+ *
9
+ * @see REQ-CLI-005 - Trace CLI
10
+ * @see REQ-TM-001 - Traceability Matrix
11
+ * @see REQ-TM-002 - Impact Analysis
12
+ * @see DES-MUSUBIX-001 Section 16-C.5 - traceコマンド設計
13
+ * @see TSK-076〜078 - Trace CLI実装
14
+ */
15
+ import type { Command } from 'commander';
16
+ /**
17
+ * Trace command options
18
+ */
19
+ export interface TraceOptions {
20
+ output?: string;
21
+ format?: 'markdown' | 'json' | 'csv' | 'html';
22
+ verbose?: boolean;
23
+ }
24
+ /**
25
+ * Traceability link
26
+ */
27
+ export interface TraceabilityLink {
28
+ source: string;
29
+ target: string;
30
+ type: 'implements' | 'derives' | 'tests' | 'refines' | 'relates';
31
+ status: 'valid' | 'broken' | 'pending';
32
+ file?: string;
33
+ line?: number;
34
+ }
35
+ /**
36
+ * Traceability matrix entry
37
+ */
38
+ export interface MatrixEntry {
39
+ id: string;
40
+ type: 'requirement' | 'design' | 'task' | 'code' | 'test';
41
+ description: string;
42
+ links: TraceabilityLink[];
43
+ coverage: {
44
+ design: boolean;
45
+ implementation: boolean;
46
+ test: boolean;
47
+ };
48
+ }
49
+ /**
50
+ * Matrix result
51
+ */
52
+ export interface MatrixResult {
53
+ success: boolean;
54
+ entries: MatrixEntry[];
55
+ statistics: {
56
+ requirements: number;
57
+ designs: number;
58
+ tasks: number;
59
+ implementations: number;
60
+ tests: number;
61
+ coverage: number;
62
+ };
63
+ message: string;
64
+ }
65
+ /**
66
+ * Impact item
67
+ */
68
+ export interface ImpactItem {
69
+ id: string;
70
+ type: string;
71
+ impactLevel: 'direct' | 'indirect' | 'potential';
72
+ description: string;
73
+ affectedFiles?: string[];
74
+ }
75
+ /**
76
+ * Impact result
77
+ */
78
+ export interface ImpactResult {
79
+ success: boolean;
80
+ sourceId: string;
81
+ impacts: ImpactItem[];
82
+ riskLevel: 'low' | 'medium' | 'high' | 'critical';
83
+ recommendations: string[];
84
+ message: string;
85
+ }
86
+ /**
87
+ * Validation issue
88
+ */
89
+ export interface TraceValidationIssue {
90
+ type: 'missing_link' | 'broken_link' | 'orphan' | 'circular';
91
+ severity: 'error' | 'warning';
92
+ source?: string;
93
+ target?: string;
94
+ message: string;
95
+ }
96
+ /**
97
+ * Validation result
98
+ */
99
+ export interface TraceValidationResult {
100
+ success: boolean;
101
+ valid: boolean;
102
+ issues: TraceValidationIssue[];
103
+ summary: {
104
+ total: number;
105
+ valid: number;
106
+ broken: number;
107
+ orphans: number;
108
+ };
109
+ message: string;
110
+ }
111
+ /**
112
+ * Register trace command
113
+ */
114
+ export declare function registerTraceCommand(program: Command): void;
115
+ /**
116
+ * Collect artifacts from directories
117
+ */
118
+ declare function collectArtifacts(specsDir: string, srcDir: string): Promise<MatrixEntry[]>;
119
+ /**
120
+ * Build traceability links between artifacts
121
+ */
122
+ declare function buildTraceabilityLinks(entries: MatrixEntry[], _specsDir: string, _srcDir: string): Promise<void>;
123
+ /**
124
+ * Analyze impact
125
+ */
126
+ declare function analyzeImpact(source: MatrixEntry, entries: MatrixEntry[], depth: number): ImpactItem[];
127
+ /**
128
+ * Validate traceability
129
+ */
130
+ declare function validateTraceability(entries: MatrixEntry[], strict: boolean): TraceValidationIssue[];
131
+ export { collectArtifacts, buildTraceabilityLinks, analyzeImpact, validateTraceability, };
132
+ //# sourceMappingURL=trace.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"trace.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/trace.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,553 @@
1
+ /**
2
+ * Trace Command
3
+ *
4
+ * CLI commands for traceability management
5
+ *
6
+ * @packageDocumentation
7
+ * @module cli/commands/trace
8
+ *
9
+ * @see REQ-CLI-005 - Trace CLI
10
+ * @see REQ-TM-001 - Traceability Matrix
11
+ * @see REQ-TM-002 - Impact Analysis
12
+ * @see DES-MUSUBIX-001 Section 16-C.5 - traceコマンド設計
13
+ * @see TSK-076〜078 - Trace CLI実装
14
+ */
15
+ import { readFile, writeFile, readdir, mkdir } from 'fs/promises';
16
+ import { resolve, join, extname } from 'path';
17
+ import { ExitCode, getGlobalOptions, outputResult } from '../base.js';
18
+ /**
19
+ * ID patterns for different artifact types
20
+ */
21
+ const ID_PATTERNS = {
22
+ requirement: /REQ-[A-Z]+-\d+/g,
23
+ design: /DES-[A-Z]+-\d+/g,
24
+ task: /TSK-[A-Z]*-?\d+/g,
25
+ test: /TEST-[A-Z]+-\d+/g,
26
+ };
27
+ /**
28
+ * Register trace command
29
+ */
30
+ export function registerTraceCommand(program) {
31
+ const trace = program
32
+ .command('trace')
33
+ .description('Traceability management');
34
+ // trace matrix
35
+ trace
36
+ .command('matrix')
37
+ .description('Generate traceability matrix')
38
+ .option('-o, --output <file>', 'Output file')
39
+ .option('-f, --format <format>', 'Output format (markdown|json|csv|html)', 'markdown')
40
+ .option('--specs <dir>', 'Specs directory', 'storage/specs')
41
+ .option('--src <dir>', 'Source directory', 'packages')
42
+ .action(async (options) => {
43
+ const globalOpts = getGlobalOptions(program);
44
+ try {
45
+ const specsDir = resolve(process.cwd(), options.specs ?? 'storage/specs');
46
+ const srcDir = resolve(process.cwd(), options.src ?? 'packages');
47
+ // Collect all artifacts
48
+ const entries = await collectArtifacts(specsDir, srcDir);
49
+ // Build traceability links
50
+ await buildTraceabilityLinks(entries, specsDir, srcDir);
51
+ // Calculate statistics
52
+ const statistics = calculateStatistics(entries);
53
+ const result = {
54
+ success: true,
55
+ entries,
56
+ statistics,
57
+ message: `Generated traceability matrix with ${entries.length} entries (${statistics.coverage.toFixed(1)}% coverage)`,
58
+ };
59
+ // Output
60
+ if (options.output) {
61
+ const outputPath = resolve(process.cwd(), options.output);
62
+ await mkdir(resolve(outputPath, '..'), { recursive: true });
63
+ let content;
64
+ if (options.format === 'json' || globalOpts.json) {
65
+ content = JSON.stringify(result, null, 2);
66
+ }
67
+ else if (options.format === 'csv') {
68
+ content = generateCSVMatrix(entries);
69
+ }
70
+ else if (options.format === 'html') {
71
+ content = generateHTMLMatrix(entries, statistics);
72
+ }
73
+ else {
74
+ content = generateMarkdownMatrix(entries, statistics);
75
+ }
76
+ await writeFile(outputPath, content, 'utf-8');
77
+ if (!globalOpts.quiet) {
78
+ console.log(`✅ Traceability matrix saved to ${outputPath}`);
79
+ }
80
+ }
81
+ else {
82
+ outputResult(result, globalOpts);
83
+ }
84
+ process.exit(ExitCode.SUCCESS);
85
+ }
86
+ catch (error) {
87
+ if (!globalOpts.quiet) {
88
+ console.error(`❌ Matrix generation failed: ${error.message}`);
89
+ }
90
+ process.exit(ExitCode.GENERAL_ERROR);
91
+ }
92
+ });
93
+ // trace impact
94
+ trace
95
+ .command('impact <id>')
96
+ .description('Analyze change impact')
97
+ .option('--depth <number>', 'Analysis depth', '3')
98
+ .action(async (id, options) => {
99
+ const globalOpts = getGlobalOptions(program);
100
+ try {
101
+ const depth = parseInt(options.depth ?? '3', 10);
102
+ const specsDir = resolve(process.cwd(), 'storage/specs');
103
+ const srcDir = resolve(process.cwd(), 'packages');
104
+ // Find artifact by ID
105
+ const entries = await collectArtifacts(specsDir, srcDir);
106
+ await buildTraceabilityLinks(entries, specsDir, srcDir);
107
+ // Find source entry
108
+ const sourceEntry = entries.find(e => e.id === id);
109
+ if (!sourceEntry) {
110
+ throw new Error(`Artifact ${id} not found`);
111
+ }
112
+ // Analyze impact
113
+ const impacts = analyzeImpact(sourceEntry, entries, depth);
114
+ const riskLevel = calculateRiskLevel(impacts);
115
+ const recommendations = generateRecommendations(sourceEntry, impacts);
116
+ const result = {
117
+ success: true,
118
+ sourceId: id,
119
+ impacts,
120
+ riskLevel,
121
+ recommendations,
122
+ message: `Found ${impacts.length} impacted items (Risk: ${riskLevel})`,
123
+ };
124
+ outputResult(result, globalOpts);
125
+ process.exit(ExitCode.SUCCESS);
126
+ }
127
+ catch (error) {
128
+ if (!globalOpts.quiet) {
129
+ console.error(`❌ Impact analysis failed: ${error.message}`);
130
+ }
131
+ process.exit(ExitCode.GENERAL_ERROR);
132
+ }
133
+ });
134
+ // trace validate
135
+ trace
136
+ .command('validate')
137
+ .description('Validate traceability links')
138
+ .option('--strict', 'Enable strict mode', false)
139
+ .action(async (options) => {
140
+ const globalOpts = getGlobalOptions(program);
141
+ try {
142
+ const specsDir = resolve(process.cwd(), 'storage/specs');
143
+ const srcDir = resolve(process.cwd(), 'packages');
144
+ // Collect and link artifacts
145
+ const entries = await collectArtifacts(specsDir, srcDir);
146
+ await buildTraceabilityLinks(entries, specsDir, srcDir);
147
+ // Validate links
148
+ const issues = validateTraceability(entries, options.strict ?? false);
149
+ const total = entries.reduce((sum, e) => sum + e.links.length, 0);
150
+ const broken = issues.filter(i => i.type === 'broken_link').length;
151
+ const orphans = issues.filter(i => i.type === 'orphan').length;
152
+ const result = {
153
+ success: true,
154
+ valid: issues.filter(i => i.severity === 'error').length === 0,
155
+ issues,
156
+ summary: {
157
+ total,
158
+ valid: total - broken,
159
+ broken,
160
+ orphans,
161
+ },
162
+ message: issues.length === 0
163
+ ? '✅ All traceability links are valid'
164
+ : `⚠️ Found ${issues.length} issues (${broken} broken links, ${orphans} orphans)`,
165
+ };
166
+ outputResult(result, globalOpts);
167
+ process.exit(result.valid ? ExitCode.SUCCESS : ExitCode.VALIDATION_ERROR);
168
+ }
169
+ catch (error) {
170
+ if (!globalOpts.quiet) {
171
+ console.error(`❌ Validation failed: ${error.message}`);
172
+ }
173
+ process.exit(ExitCode.GENERAL_ERROR);
174
+ }
175
+ });
176
+ }
177
+ /**
178
+ * Collect artifacts from directories
179
+ */
180
+ async function collectArtifacts(specsDir, srcDir) {
181
+ const entries = [];
182
+ const seenIds = new Set();
183
+ // Collect from specs directory
184
+ try {
185
+ const specFiles = await readdir(specsDir);
186
+ for (const file of specFiles) {
187
+ if (!file.endsWith('.md'))
188
+ continue;
189
+ const content = await readFile(join(specsDir, file), 'utf-8');
190
+ // Extract requirement IDs
191
+ const reqMatches = content.match(ID_PATTERNS.requirement) || [];
192
+ for (const id of reqMatches) {
193
+ if (seenIds.has(id))
194
+ continue;
195
+ seenIds.add(id);
196
+ // Extract description
197
+ const descRegex = new RegExp(`${id}[^\\n]*\\n([^\\n]+)`, 'i');
198
+ const descMatch = content.match(descRegex);
199
+ entries.push({
200
+ id,
201
+ type: 'requirement',
202
+ description: descMatch?.[1]?.trim() || 'No description',
203
+ links: [],
204
+ coverage: { design: false, implementation: false, test: false },
205
+ });
206
+ }
207
+ // Extract design IDs
208
+ const desMatches = content.match(ID_PATTERNS.design) || [];
209
+ for (const id of desMatches) {
210
+ if (seenIds.has(id))
211
+ continue;
212
+ seenIds.add(id);
213
+ entries.push({
214
+ id,
215
+ type: 'design',
216
+ description: 'Design element',
217
+ links: [],
218
+ coverage: { design: true, implementation: false, test: false },
219
+ });
220
+ }
221
+ // Extract task IDs
222
+ const taskMatches = content.match(ID_PATTERNS.task) || [];
223
+ for (const id of taskMatches) {
224
+ if (seenIds.has(id))
225
+ continue;
226
+ seenIds.add(id);
227
+ entries.push({
228
+ id,
229
+ type: 'task',
230
+ description: 'Implementation task',
231
+ links: [],
232
+ coverage: { design: true, implementation: false, test: false },
233
+ });
234
+ }
235
+ }
236
+ }
237
+ catch {
238
+ // Specs directory doesn't exist
239
+ }
240
+ // Collect from source directory
241
+ await scanSourceDir(srcDir, entries, seenIds);
242
+ return entries;
243
+ }
244
+ /**
245
+ * Scan source directory for code references
246
+ */
247
+ async function scanSourceDir(dir, entries, seenIds) {
248
+ try {
249
+ const items = await readdir(dir, { withFileTypes: true });
250
+ for (const item of items) {
251
+ const fullPath = join(dir, item.name);
252
+ if (item.isDirectory()) {
253
+ if (!item.name.startsWith('.') && item.name !== 'node_modules' && item.name !== 'dist') {
254
+ await scanSourceDir(fullPath, entries, seenIds);
255
+ }
256
+ }
257
+ else if (item.isFile()) {
258
+ const ext = extname(item.name);
259
+ if (['.ts', '.js', '.tsx', '.jsx'].includes(ext)) {
260
+ const content = await readFile(fullPath, 'utf-8');
261
+ // Find referenced IDs in code comments
262
+ for (const pattern of Object.values(ID_PATTERNS)) {
263
+ const matches = content.match(pattern) || [];
264
+ for (const id of matches) {
265
+ // Update existing entry or add code reference
266
+ const existing = entries.find(e => e.id === id);
267
+ if (existing) {
268
+ existing.coverage.implementation = true;
269
+ existing.links.push({
270
+ source: id,
271
+ target: fullPath,
272
+ type: 'implements',
273
+ status: 'valid',
274
+ file: fullPath,
275
+ });
276
+ }
277
+ }
278
+ }
279
+ // Check for test files
280
+ if (item.name.includes('.test.') || item.name.includes('.spec.')) {
281
+ const testMatches = content.match(ID_PATTERNS.requirement) || [];
282
+ for (const id of testMatches) {
283
+ const existing = entries.find(e => e.id === id);
284
+ if (existing) {
285
+ existing.coverage.test = true;
286
+ existing.links.push({
287
+ source: id,
288
+ target: fullPath,
289
+ type: 'tests',
290
+ status: 'valid',
291
+ file: fullPath,
292
+ });
293
+ }
294
+ }
295
+ }
296
+ }
297
+ }
298
+ }
299
+ }
300
+ catch {
301
+ // Directory doesn't exist or access error
302
+ }
303
+ }
304
+ /**
305
+ * Build traceability links between artifacts
306
+ */
307
+ async function buildTraceabilityLinks(entries, _specsDir, _srcDir) {
308
+ // Build links between requirements and designs
309
+ for (const entry of entries) {
310
+ if (entry.type === 'requirement') {
311
+ // Find related designs
312
+ const designs = entries.filter(e => e.type === 'design');
313
+ for (const design of designs) {
314
+ entry.links.push({
315
+ source: entry.id,
316
+ target: design.id,
317
+ type: 'derives',
318
+ status: 'valid',
319
+ });
320
+ entry.coverage.design = true;
321
+ }
322
+ }
323
+ }
324
+ // Link requirements to tasks
325
+ const requirements = entries.filter(e => e.type === 'requirement');
326
+ const tasks = entries.filter(e => e.type === 'task');
327
+ for (const req of requirements) {
328
+ for (const task of tasks) {
329
+ // Check if task references requirement
330
+ if (task.description.includes(req.id) ||
331
+ task.links.some(l => l.target === req.id)) {
332
+ req.links.push({
333
+ source: req.id,
334
+ target: task.id,
335
+ type: 'refines',
336
+ status: 'valid',
337
+ });
338
+ }
339
+ }
340
+ }
341
+ }
342
+ /**
343
+ * Calculate statistics
344
+ */
345
+ function calculateStatistics(entries) {
346
+ const requirements = entries.filter(e => e.type === 'requirement').length;
347
+ const designs = entries.filter(e => e.type === 'design').length;
348
+ const tasks = entries.filter(e => e.type === 'task').length;
349
+ const implementations = entries.filter(e => e.coverage.implementation).length;
350
+ const tests = entries.filter(e => e.coverage.test).length;
351
+ const coveredRequirements = entries.filter(e => e.type === 'requirement' && e.coverage.design && e.coverage.implementation).length;
352
+ const coverage = requirements > 0 ? (coveredRequirements / requirements) * 100 : 0;
353
+ return { requirements, designs, tasks, implementations, tests, coverage };
354
+ }
355
+ /**
356
+ * Analyze impact
357
+ */
358
+ function analyzeImpact(source, entries, depth) {
359
+ const impacts = [];
360
+ const visited = new Set();
361
+ function traverse(entry, level) {
362
+ if (level > depth || visited.has(entry.id))
363
+ return;
364
+ visited.add(entry.id);
365
+ for (const link of entry.links) {
366
+ const target = entries.find(e => e.id === link.target);
367
+ if (target && !visited.has(target.id)) {
368
+ impacts.push({
369
+ id: target.id,
370
+ type: target.type,
371
+ impactLevel: level === 1 ? 'direct' : level === 2 ? 'indirect' : 'potential',
372
+ description: target.description,
373
+ affectedFiles: target.links
374
+ .filter(l => l.file)
375
+ .map(l => l.file),
376
+ });
377
+ traverse(target, level + 1);
378
+ }
379
+ }
380
+ }
381
+ traverse(source, 1);
382
+ return impacts;
383
+ }
384
+ /**
385
+ * Calculate risk level
386
+ */
387
+ function calculateRiskLevel(impacts) {
388
+ const direct = impacts.filter(i => i.impactLevel === 'direct').length;
389
+ const totalIndirect = impacts.filter(i => i.impactLevel === 'indirect' || i.impactLevel === 'potential').length;
390
+ if (direct > 10 || impacts.length > 20)
391
+ return 'critical';
392
+ if (direct > 5 || impacts.length > 10)
393
+ return 'high';
394
+ if (direct > 2 || impacts.length > 5 || totalIndirect > 10)
395
+ return 'medium';
396
+ return 'low';
397
+ }
398
+ /**
399
+ * Generate recommendations
400
+ */
401
+ function generateRecommendations(source, impacts) {
402
+ const recommendations = [];
403
+ if (impacts.length > 10) {
404
+ recommendations.push(`Consider breaking the change to ${source.id} into smaller increments`);
405
+ }
406
+ const codeImpacts = impacts.filter(i => i.affectedFiles && i.affectedFiles.length > 0);
407
+ if (codeImpacts.length > 0) {
408
+ recommendations.push(`Review ${codeImpacts.length} code files before making changes to ${source.id}`);
409
+ }
410
+ if (impacts.some(i => i.type === 'test')) {
411
+ recommendations.push('Update affected tests after implementation');
412
+ }
413
+ if (impacts.length === 0) {
414
+ recommendations.push('This change has minimal impact - safe to proceed');
415
+ }
416
+ return recommendations;
417
+ }
418
+ /**
419
+ * Validate traceability
420
+ */
421
+ function validateTraceability(entries, strict) {
422
+ const issues = [];
423
+ const allIds = new Set(entries.map(e => e.id));
424
+ for (const entry of entries) {
425
+ // Check for orphans (requirements without implementation)
426
+ if (entry.type === 'requirement' && !entry.coverage.implementation) {
427
+ issues.push({
428
+ type: 'orphan',
429
+ severity: strict ? 'error' : 'warning',
430
+ source: entry.id,
431
+ message: `Requirement ${entry.id} has no implementation`,
432
+ });
433
+ }
434
+ // Check for broken links
435
+ for (const link of entry.links) {
436
+ if (typeof link.target === 'string' && link.target.match(/^(REQ|DES|TSK)-/)) {
437
+ if (!allIds.has(link.target)) {
438
+ issues.push({
439
+ type: 'broken_link',
440
+ severity: 'error',
441
+ source: entry.id,
442
+ target: link.target,
443
+ message: `Link from ${entry.id} to ${link.target} is broken (target not found)`,
444
+ });
445
+ }
446
+ }
447
+ }
448
+ // Check for missing design traceability
449
+ if (entry.type === 'requirement' && !entry.coverage.design && strict) {
450
+ issues.push({
451
+ type: 'missing_link',
452
+ severity: 'warning',
453
+ source: entry.id,
454
+ message: `Requirement ${entry.id} has no design element`,
455
+ });
456
+ }
457
+ // Check for missing tests
458
+ if (entry.type === 'requirement' && !entry.coverage.test && strict) {
459
+ issues.push({
460
+ type: 'missing_link',
461
+ severity: 'warning',
462
+ source: entry.id,
463
+ message: `Requirement ${entry.id} has no test coverage`,
464
+ });
465
+ }
466
+ }
467
+ return issues;
468
+ }
469
+ /**
470
+ * Generate markdown matrix
471
+ */
472
+ function generateMarkdownMatrix(entries, stats) {
473
+ let output = '# Traceability Matrix\n\n';
474
+ output += '## Statistics\n\n';
475
+ output += `| Metric | Count |\n`;
476
+ output += `|--------|-------|\n`;
477
+ output += `| Requirements | ${stats.requirements} |\n`;
478
+ output += `| Designs | ${stats.designs} |\n`;
479
+ output += `| Tasks | ${stats.tasks} |\n`;
480
+ output += `| Implementations | ${stats.implementations} |\n`;
481
+ output += `| Tests | ${stats.tests} |\n`;
482
+ output += `| **Coverage** | **${stats.coverage.toFixed(1)}%** |\n\n`;
483
+ output += '## Matrix\n\n';
484
+ output += '| ID | Type | Design | Impl | Test |\n';
485
+ output += '|----|------|--------|------|------|\n';
486
+ for (const entry of entries) {
487
+ output += `| ${entry.id} | ${entry.type} | ${entry.coverage.design ? '✅' : '❌'} | ${entry.coverage.implementation ? '✅' : '❌'} | ${entry.coverage.test ? '✅' : '❌'} |\n`;
488
+ }
489
+ output += `\n*Generated: ${new Date().toISOString()}*\n`;
490
+ return output;
491
+ }
492
+ /**
493
+ * Generate CSV matrix
494
+ */
495
+ function generateCSVMatrix(entries) {
496
+ let output = 'ID,Type,Description,Design,Implementation,Test,Links\n';
497
+ for (const entry of entries) {
498
+ const links = entry.links.map(l => `${l.type}:${l.target}`).join(';');
499
+ output += `"${entry.id}","${entry.type}","${entry.description}",${entry.coverage.design},${entry.coverage.implementation},${entry.coverage.test},"${links}"\n`;
500
+ }
501
+ return output;
502
+ }
503
+ /**
504
+ * Generate HTML matrix
505
+ */
506
+ function generateHTMLMatrix(entries, stats) {
507
+ return `<!DOCTYPE html>
508
+ <html>
509
+ <head>
510
+ <title>Traceability Matrix</title>
511
+ <style>
512
+ body { font-family: Arial, sans-serif; margin: 20px; }
513
+ table { border-collapse: collapse; width: 100%; }
514
+ th, td { border: 1px solid #ddd; padding: 8px; text-align: left; }
515
+ th { background-color: #4CAF50; color: white; }
516
+ tr:nth-child(even) { background-color: #f2f2f2; }
517
+ .check { color: #4CAF50; }
518
+ .cross { color: #f44336; }
519
+ .summary { margin: 20px 0; padding: 15px; background: #f5f5f5; border-radius: 5px; }
520
+ </style>
521
+ </head>
522
+ <body>
523
+ <h1>Traceability Matrix</h1>
524
+
525
+ <div class="summary">
526
+ <h2>Coverage: ${stats.coverage.toFixed(1)}%</h2>
527
+ <p>Requirements: ${stats.requirements} | Designs: ${stats.designs} | Tasks: ${stats.tasks} | Tests: ${stats.tests}</p>
528
+ </div>
529
+
530
+ <table>
531
+ <tr>
532
+ <th>ID</th>
533
+ <th>Type</th>
534
+ <th>Design</th>
535
+ <th>Implementation</th>
536
+ <th>Test</th>
537
+ </tr>
538
+ ${entries.map(e => `
539
+ <tr>
540
+ <td>${e.id}</td>
541
+ <td>${e.type}</td>
542
+ <td class="${e.coverage.design ? 'check' : 'cross'}">${e.coverage.design ? '✓' : '✗'}</td>
543
+ <td class="${e.coverage.implementation ? 'check' : 'cross'}">${e.coverage.implementation ? '✓' : '✗'}</td>
544
+ <td class="${e.coverage.test ? 'check' : 'cross'}">${e.coverage.test ? '✓' : '✗'}</td>
545
+ </tr>`).join('')}
546
+ </table>
547
+
548
+ <p><em>Generated: ${new Date().toISOString()}</em></p>
549
+ </body>
550
+ </html>`;
551
+ }
552
+ export { collectArtifacts, buildTraceabilityLinks, analyzeImpact, validateTraceability, };
553
+ //# sourceMappingURL=trace.js.map