musubi-sdd 6.2.2 → 6.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.ja.md +3 -3
- package/README.md +3 -3
- package/bin/musubi-dashboard.js +22 -13
- package/bin/musubi-design.js +3 -3
- package/bin/musubi-gaps.js +9 -9
- package/bin/musubi-init.js +14 -1310
- package/bin/musubi-requirements.js +1 -1
- package/bin/musubi-tasks.js +5 -5
- package/bin/musubi-trace.js +23 -23
- package/bin/musubi-upgrade.js +7 -2
- package/bin/musubi.js +1 -1
- package/package.json +2 -2
- package/src/analyzers/gap-detector.js +3 -3
- package/src/analyzers/traceability.js +17 -17
- package/src/cli/dashboard-cli.js +54 -60
- package/src/cli/init-generators.js +464 -0
- package/src/cli/init-helpers.js +884 -0
- package/src/constitutional/checker.js +67 -65
- package/src/constitutional/ci-reporter.js +50 -43
- package/src/constitutional/index.js +2 -2
- package/src/constitutional/phase-minus-one.js +22 -25
- package/src/constitutional/steering-sync.js +28 -39
- package/src/dashboard/index.js +2 -2
- package/src/dashboard/sprint-planner.js +17 -19
- package/src/dashboard/sprint-reporter.js +46 -37
- package/src/dashboard/transition-recorder.js +12 -18
- package/src/dashboard/workflow-dashboard.js +27 -38
- package/src/enterprise/error-recovery.js +109 -49
- package/src/enterprise/experiment-report.js +62 -36
- package/src/enterprise/index.js +5 -5
- package/src/enterprise/rollback-manager.js +28 -29
- package/src/enterprise/tech-article.js +41 -35
- package/src/generators/design.js +3 -3
- package/src/generators/requirements.js +5 -3
- package/src/generators/tasks.js +2 -2
- package/src/integrations/platforms.js +1 -1
- package/src/templates/agents/claude-code/CLAUDE.md +1 -1
- package/src/templates/agents/claude-code/skills/design-reviewer/SKILL.md +132 -113
- package/src/templates/agents/claude-code/skills/requirements-reviewer/SKILL.md +85 -56
- package/src/templates/agents/codex/AGENTS.md +2 -2
- package/src/templates/agents/cursor/AGENTS.md +2 -2
- package/src/templates/agents/gemini-cli/GEMINI.md +2 -2
- package/src/templates/agents/github-copilot/AGENTS.md +2 -2
- package/src/templates/agents/github-copilot/commands/sdd-requirements.prompt.md +23 -4
- package/src/templates/agents/qwen-code/QWEN.md +2 -2
- package/src/templates/agents/shared/AGENTS.md +1 -1
- package/src/templates/agents/windsurf/AGENTS.md +2 -2
- package/src/templates/skills/browser-agent.md +1 -1
- package/src/traceability/extractor.js +21 -20
- package/src/traceability/gap-detector.js +19 -17
- package/src/traceability/index.js +2 -2
- package/src/traceability/matrix-storage.js +20 -22
- package/src/validators/constitution.js +5 -2
- package/src/validators/critic-system.js +6 -6
- package/src/validators/traceability-validator.js +3 -3
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* GapDetector Implementation
|
|
3
|
-
*
|
|
3
|
+
*
|
|
4
4
|
* Detects requirements without implementation or tests.
|
|
5
|
-
*
|
|
5
|
+
*
|
|
6
6
|
* Requirement: IMP-6.2-004-02
|
|
7
7
|
* Design: Section 5.2
|
|
8
8
|
*/
|
|
@@ -14,32 +14,35 @@ const SEVERITY_MAP = {
|
|
|
14
14
|
'no-test': 'critical',
|
|
15
15
|
'no-code': 'high',
|
|
16
16
|
'no-design': 'medium',
|
|
17
|
-
'no-commit': 'low'
|
|
17
|
+
'no-commit': 'low',
|
|
18
18
|
};
|
|
19
19
|
|
|
20
20
|
/**
|
|
21
21
|
* Severity ordering for sorting
|
|
22
22
|
*/
|
|
23
23
|
const SEVERITY_ORDER = {
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
24
|
+
critical: 0,
|
|
25
|
+
high: 1,
|
|
26
|
+
medium: 2,
|
|
27
|
+
low: 3,
|
|
28
28
|
};
|
|
29
29
|
|
|
30
30
|
/**
|
|
31
31
|
* Suggestions for each gap type
|
|
32
32
|
*/
|
|
33
33
|
const SUGGESTIONS = {
|
|
34
|
-
'no-test':
|
|
34
|
+
'no-test':
|
|
35
|
+
'この要件に対するテストを作成してください。Article III (Test-First) に従い、実装前にテストを書くことを推奨します。',
|
|
35
36
|
'no-code': '要件の実装が必要です。設計ドキュメントを参照して実装を開始してください。',
|
|
36
|
-
'no-design':
|
|
37
|
-
|
|
37
|
+
'no-design':
|
|
38
|
+
'設計ドキュメントを作成してください。C4モデルに従い、コンポーネント図とADRを追加することを推奨します。',
|
|
39
|
+
'no-commit':
|
|
40
|
+
'この要件に関連するコミットがありません。コミットメッセージに要件IDを含めてください。',
|
|
38
41
|
};
|
|
39
42
|
|
|
40
43
|
/**
|
|
41
44
|
* GapDetector
|
|
42
|
-
*
|
|
45
|
+
*
|
|
43
46
|
* Detects gaps in traceability between requirements and artifacts.
|
|
44
47
|
*/
|
|
45
48
|
class GapDetector {
|
|
@@ -82,7 +85,7 @@ class GapDetector {
|
|
|
82
85
|
requirementId,
|
|
83
86
|
gapType,
|
|
84
87
|
severity: SEVERITY_MAP[gapType],
|
|
85
|
-
suggestion: SUGGESTIONS[gapType]
|
|
88
|
+
suggestion: SUGGESTIONS[gapType],
|
|
86
89
|
};
|
|
87
90
|
}
|
|
88
91
|
|
|
@@ -117,8 +120,7 @@ class GapDetector {
|
|
|
117
120
|
gapsByType[gap.gapType] = (gapsByType[gap.gapType] || 0) + 1;
|
|
118
121
|
|
|
119
122
|
// Count by requirement
|
|
120
|
-
gapsByRequirement[gap.requirementId] =
|
|
121
|
-
(gapsByRequirement[gap.requirementId] || 0) + 1;
|
|
123
|
+
gapsByRequirement[gap.requirementId] = (gapsByRequirement[gap.requirementId] || 0) + 1;
|
|
122
124
|
|
|
123
125
|
// Count by severity
|
|
124
126
|
switch (gap.severity) {
|
|
@@ -144,7 +146,7 @@ class GapDetector {
|
|
|
144
146
|
mediumGaps,
|
|
145
147
|
lowGaps,
|
|
146
148
|
gapsByType,
|
|
147
|
-
gapsByRequirement
|
|
149
|
+
gapsByRequirement,
|
|
148
150
|
};
|
|
149
151
|
}
|
|
150
152
|
|
|
@@ -161,7 +163,7 @@ class GapDetector {
|
|
|
161
163
|
return {
|
|
162
164
|
generatedAt: new Date().toISOString(),
|
|
163
165
|
gaps: sortedGaps,
|
|
164
|
-
summary
|
|
166
|
+
summary,
|
|
165
167
|
};
|
|
166
168
|
}
|
|
167
169
|
|
|
@@ -222,7 +224,7 @@ class GapDetector {
|
|
|
222
224
|
|
|
223
225
|
const reqsWithGaps = this.getRequirementsWithGaps(links);
|
|
224
226
|
const covered = links.length - reqsWithGaps.length;
|
|
225
|
-
|
|
227
|
+
|
|
226
228
|
return Math.round((covered / links.length) * 100);
|
|
227
229
|
}
|
|
228
230
|
}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* MatrixStorage Implementation
|
|
3
|
-
*
|
|
3
|
+
*
|
|
4
4
|
* YAML-based persistence for traceability matrices.
|
|
5
|
-
*
|
|
5
|
+
*
|
|
6
6
|
* Requirement: IMP-6.2-004-03
|
|
7
7
|
* Design: ADR-6.2-002
|
|
8
8
|
*/
|
|
@@ -15,12 +15,12 @@ const yaml = require('yaml');
|
|
|
15
15
|
* Default configuration
|
|
16
16
|
*/
|
|
17
17
|
const DEFAULT_CONFIG = {
|
|
18
|
-
storageDir: 'storage/traceability'
|
|
18
|
+
storageDir: 'storage/traceability',
|
|
19
19
|
};
|
|
20
20
|
|
|
21
21
|
/**
|
|
22
22
|
* MatrixStorage
|
|
23
|
-
*
|
|
23
|
+
*
|
|
24
24
|
* Persists traceability matrices as YAML files.
|
|
25
25
|
*/
|
|
26
26
|
class MatrixStorage {
|
|
@@ -46,11 +46,11 @@ class MatrixStorage {
|
|
|
46
46
|
|
|
47
47
|
const yamlContent = yaml.stringify(matrix, {
|
|
48
48
|
indent: 2,
|
|
49
|
-
lineWidth: 0
|
|
49
|
+
lineWidth: 0,
|
|
50
50
|
});
|
|
51
51
|
|
|
52
52
|
await fs.writeFile(filePath, yamlContent, 'utf-8');
|
|
53
|
-
|
|
53
|
+
|
|
54
54
|
return filePath;
|
|
55
55
|
}
|
|
56
56
|
|
|
@@ -62,7 +62,7 @@ class MatrixStorage {
|
|
|
62
62
|
async load(filename) {
|
|
63
63
|
try {
|
|
64
64
|
let filePath;
|
|
65
|
-
|
|
65
|
+
|
|
66
66
|
if (filename.endsWith('.yaml') || filename.endsWith('.yml')) {
|
|
67
67
|
filePath = path.join(this.config.storageDir, filename);
|
|
68
68
|
} else {
|
|
@@ -74,7 +74,7 @@ class MatrixStorage {
|
|
|
74
74
|
|
|
75
75
|
await fs.access(filePath);
|
|
76
76
|
const content = await fs.readFile(filePath, 'utf-8');
|
|
77
|
-
|
|
77
|
+
|
|
78
78
|
return yaml.parse(content);
|
|
79
79
|
} catch {
|
|
80
80
|
return null;
|
|
@@ -88,15 +88,15 @@ class MatrixStorage {
|
|
|
88
88
|
*/
|
|
89
89
|
async loadLatest(featureId) {
|
|
90
90
|
const files = await this.list(featureId);
|
|
91
|
-
|
|
91
|
+
|
|
92
92
|
if (files.length === 0) return null;
|
|
93
93
|
|
|
94
94
|
// Sort by date (newest first)
|
|
95
95
|
files.sort().reverse();
|
|
96
|
-
|
|
96
|
+
|
|
97
97
|
const latestFile = files[0];
|
|
98
98
|
const filePath = path.join(this.config.storageDir, latestFile);
|
|
99
|
-
|
|
99
|
+
|
|
100
100
|
const content = await fs.readFile(filePath, 'utf-8');
|
|
101
101
|
return yaml.parse(content);
|
|
102
102
|
}
|
|
@@ -109,9 +109,7 @@ class MatrixStorage {
|
|
|
109
109
|
async list(prefix) {
|
|
110
110
|
try {
|
|
111
111
|
const files = await fs.readdir(this.config.storageDir);
|
|
112
|
-
const yamlFiles = files.filter(f =>
|
|
113
|
-
f.endsWith('.yaml') || f.endsWith('.yml')
|
|
114
|
-
);
|
|
112
|
+
const yamlFiles = files.filter(f => f.endsWith('.yaml') || f.endsWith('.yml'));
|
|
115
113
|
|
|
116
114
|
if (prefix) {
|
|
117
115
|
return yamlFiles.filter(f => f.startsWith(prefix));
|
|
@@ -145,7 +143,7 @@ class MatrixStorage {
|
|
|
145
143
|
// Get all requirement IDs
|
|
146
144
|
const allReqIds = new Set([
|
|
147
145
|
...Object.keys(matrix1.requirements),
|
|
148
|
-
...Object.keys(matrix2.requirements)
|
|
146
|
+
...Object.keys(matrix2.requirements),
|
|
149
147
|
]);
|
|
150
148
|
|
|
151
149
|
for (const reqId of allReqIds) {
|
|
@@ -159,7 +157,7 @@ class MatrixStorage {
|
|
|
159
157
|
design: this.mergeLinks(link1.design, link2.design),
|
|
160
158
|
code: this.mergeLinks(link1.code, link2.code),
|
|
161
159
|
tests: this.mergeLinks(link1.tests, link2.tests),
|
|
162
|
-
commits: this.mergeLinks(link1.commits, link2.commits)
|
|
160
|
+
commits: this.mergeLinks(link1.commits, link2.commits),
|
|
163
161
|
};
|
|
164
162
|
} else {
|
|
165
163
|
requirements[reqId] = link1 || link2;
|
|
@@ -170,7 +168,7 @@ class MatrixStorage {
|
|
|
170
168
|
version: matrix2.version,
|
|
171
169
|
generatedAt: new Date().toISOString(),
|
|
172
170
|
requirements,
|
|
173
|
-
summary: this.calculateSummary(requirements)
|
|
171
|
+
summary: this.calculateSummary(requirements),
|
|
174
172
|
};
|
|
175
173
|
}
|
|
176
174
|
|
|
@@ -182,7 +180,7 @@ class MatrixStorage {
|
|
|
182
180
|
*/
|
|
183
181
|
mergeLinks(links1, links2) {
|
|
184
182
|
const merged = [...links1];
|
|
185
|
-
|
|
183
|
+
|
|
186
184
|
for (const link of links2) {
|
|
187
185
|
const exists = merged.some(l => {
|
|
188
186
|
if (l.path && link.path) {
|
|
@@ -219,7 +217,7 @@ class MatrixStorage {
|
|
|
219
217
|
withCode: 0,
|
|
220
218
|
withTests: 0,
|
|
221
219
|
gaps: 0,
|
|
222
|
-
coveragePercentage: 0
|
|
220
|
+
coveragePercentage: 0,
|
|
223
221
|
};
|
|
224
222
|
}
|
|
225
223
|
|
|
@@ -249,8 +247,8 @@ class MatrixStorage {
|
|
|
249
247
|
}
|
|
250
248
|
|
|
251
249
|
// Calculate coverage as percentage of requirements with full coverage
|
|
252
|
-
const fullyLinked = links.filter(
|
|
253
|
-
l.design.length > 0 && l.code.length > 0 && l.tests.length > 0
|
|
250
|
+
const fullyLinked = links.filter(
|
|
251
|
+
l => l.design.length > 0 && l.code.length > 0 && l.tests.length > 0
|
|
254
252
|
).length;
|
|
255
253
|
|
|
256
254
|
return {
|
|
@@ -260,7 +258,7 @@ class MatrixStorage {
|
|
|
260
258
|
withCode,
|
|
261
259
|
withTests,
|
|
262
260
|
gaps: gapCount,
|
|
263
|
-
coveragePercentage: Math.round((fullyLinked / total) * 100)
|
|
261
|
+
coveragePercentage: Math.round((fullyLinked / total) * 100),
|
|
264
262
|
};
|
|
265
263
|
}
|
|
266
264
|
|
|
@@ -567,12 +567,15 @@ class ConstitutionValidator {
|
|
|
567
567
|
files: [],
|
|
568
568
|
};
|
|
569
569
|
|
|
570
|
-
// Find all source files
|
|
570
|
+
// Find all source files (excluding node_modules)
|
|
571
571
|
const sourcePatterns = ['src/**/*.js', 'lib/**/*.js', 'bin/**/*.js'];
|
|
572
572
|
|
|
573
573
|
const files = [];
|
|
574
574
|
for (const pattern of sourcePatterns) {
|
|
575
|
-
const matches = await glob(pattern, {
|
|
575
|
+
const matches = await glob(pattern, {
|
|
576
|
+
cwd: this.projectRoot,
|
|
577
|
+
ignore: ['**/node_modules/**'],
|
|
578
|
+
});
|
|
576
579
|
files.push(...matches.map(f => path.join(this.projectRoot, f)));
|
|
577
580
|
}
|
|
578
581
|
|
|
@@ -211,7 +211,7 @@ class RequirementsCritic extends BaseCritic {
|
|
|
211
211
|
*/
|
|
212
212
|
checkEarsFormat(context) {
|
|
213
213
|
const content =
|
|
214
|
-
context.content || this.readFile('
|
|
214
|
+
context.content || this.readFile('storage/specs/srs/srs-musubi-v3.0.0.ja.md') || '';
|
|
215
215
|
|
|
216
216
|
// EARS キーワードパターン
|
|
217
217
|
const earsPatterns = [
|
|
@@ -241,7 +241,7 @@ class RequirementsCritic extends BaseCritic {
|
|
|
241
241
|
*/
|
|
242
242
|
checkCompleteness(context) {
|
|
243
243
|
const content =
|
|
244
|
-
context.content || this.readFile('
|
|
244
|
+
context.content || this.readFile('storage/specs/srs/srs-musubi-v3.0.0.ja.md') || '';
|
|
245
245
|
|
|
246
246
|
const requiredSections = [
|
|
247
247
|
/## 機能要件|## Functional Requirements/i,
|
|
@@ -258,7 +258,7 @@ class RequirementsCritic extends BaseCritic {
|
|
|
258
258
|
*/
|
|
259
259
|
checkTestability(context) {
|
|
260
260
|
const content =
|
|
261
|
-
context.content || this.readFile('
|
|
261
|
+
context.content || this.readFile('storage/specs/srs/srs-musubi-v3.0.0.ja.md') || '';
|
|
262
262
|
|
|
263
263
|
// 数値目標や測定可能な基準があるかチェック
|
|
264
264
|
const measurablePatterns = [
|
|
@@ -340,7 +340,7 @@ class DesignCritic extends BaseCritic {
|
|
|
340
340
|
* C4モデル準拠チェック
|
|
341
341
|
*/
|
|
342
342
|
checkC4Format(_context) {
|
|
343
|
-
const designDir = path.join(this.projectRoot, '
|
|
343
|
+
const designDir = path.join(this.projectRoot, 'storage/design');
|
|
344
344
|
if (!fs.existsSync(designDir)) return 0;
|
|
345
345
|
|
|
346
346
|
// C4レベルのキーワードをチェック
|
|
@@ -362,7 +362,7 @@ class DesignCritic extends BaseCritic {
|
|
|
362
362
|
* ADR存在チェック
|
|
363
363
|
*/
|
|
364
364
|
checkAdrPresence(_context) {
|
|
365
|
-
const adrDir = path.join(this.projectRoot, '
|
|
365
|
+
const adrDir = path.join(this.projectRoot, 'storage/design/adr');
|
|
366
366
|
if (!fs.existsSync(adrDir)) return 0;
|
|
367
367
|
|
|
368
368
|
const adrFiles = fs.readdirSync(adrDir).filter(f => f.startsWith('ADR-') && f.endsWith('.md'));
|
|
@@ -375,7 +375,7 @@ class DesignCritic extends BaseCritic {
|
|
|
375
375
|
* 要件カバレッジチェック
|
|
376
376
|
*/
|
|
377
377
|
checkRequirementCoverage(_context) {
|
|
378
|
-
const designDir = path.join(this.projectRoot, '
|
|
378
|
+
const designDir = path.join(this.projectRoot, 'storage/design');
|
|
379
379
|
if (!fs.existsSync(designDir)) return 0;
|
|
380
380
|
|
|
381
381
|
const files = fs.readdirSync(designDir).filter(f => f.endsWith('.md'));
|
|
@@ -67,9 +67,9 @@ const defaultConfig = {
|
|
|
67
67
|
|
|
68
68
|
// Paths configuration
|
|
69
69
|
paths: {
|
|
70
|
-
requirements: '
|
|
71
|
-
design: '
|
|
72
|
-
tasks: '
|
|
70
|
+
requirements: 'storage/specs',
|
|
71
|
+
design: 'storage/design',
|
|
72
|
+
tasks: 'storage/tasks',
|
|
73
73
|
code: 'src',
|
|
74
74
|
tests: 'tests',
|
|
75
75
|
},
|