musubi-sdd 6.2.1 → 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 +23 -14
- 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 +400 -0
- package/bin/musubi.js +16 -1
- package/package.json +4 -3
- 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 +58 -49
- package/src/constitutional/index.js +2 -2
- package/src/constitutional/phase-minus-one.js +24 -27
- package/src/constitutional/steering-sync.js +29 -40
- package/src/dashboard/index.js +2 -2
- package/src/dashboard/sprint-planner.js +17 -19
- package/src/dashboard/sprint-reporter.js +47 -38
- package/src/dashboard/transition-recorder.js +12 -18
- package/src/dashboard/workflow-dashboard.js +28 -39
- package/src/enterprise/error-recovery.js +109 -49
- package/src/enterprise/experiment-report.js +63 -37
- 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 +22 -21
- 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,10 +1,10 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Rollback Manager
|
|
3
|
-
*
|
|
3
|
+
*
|
|
4
4
|
* Supports rollback to previous state with cleanup.
|
|
5
|
-
*
|
|
5
|
+
*
|
|
6
6
|
* Requirement: IMP-6.2-008-02
|
|
7
|
-
*
|
|
7
|
+
*
|
|
8
8
|
* @module enterprise/rollback-manager
|
|
9
9
|
*/
|
|
10
10
|
|
|
@@ -19,7 +19,7 @@ const ROLLBACK_LEVEL = {
|
|
|
19
19
|
FILE: 'file',
|
|
20
20
|
COMMIT: 'commit',
|
|
21
21
|
STAGE: 'stage',
|
|
22
|
-
SPRINT: 'sprint'
|
|
22
|
+
SPRINT: 'sprint',
|
|
23
23
|
};
|
|
24
24
|
|
|
25
25
|
/**
|
|
@@ -30,7 +30,7 @@ const ROLLBACK_STATUS = {
|
|
|
30
30
|
IN_PROGRESS: 'in-progress',
|
|
31
31
|
COMPLETED: 'completed',
|
|
32
32
|
FAILED: 'failed',
|
|
33
|
-
CANCELLED: 'cancelled'
|
|
33
|
+
CANCELLED: 'cancelled',
|
|
34
34
|
};
|
|
35
35
|
|
|
36
36
|
/**
|
|
@@ -41,7 +41,7 @@ const WORKFLOW_STAGE = {
|
|
|
41
41
|
DESIGN: 'design',
|
|
42
42
|
TASKS: 'tasks',
|
|
43
43
|
IMPLEMENT: 'implement',
|
|
44
|
-
VALIDATE: 'validate'
|
|
44
|
+
VALIDATE: 'validate',
|
|
45
45
|
};
|
|
46
46
|
|
|
47
47
|
/**
|
|
@@ -59,7 +59,7 @@ class RollbackManager {
|
|
|
59
59
|
maxHistory: config.maxHistory || 50,
|
|
60
60
|
requireConfirmation: config.requireConfirmation !== false,
|
|
61
61
|
gitEnabled: config.gitEnabled !== false,
|
|
62
|
-
...config
|
|
62
|
+
...config,
|
|
63
63
|
};
|
|
64
64
|
|
|
65
65
|
this.rollbackHistory = [];
|
|
@@ -82,7 +82,7 @@ class RollbackManager {
|
|
|
82
82
|
description: options.description || '',
|
|
83
83
|
files: [],
|
|
84
84
|
gitRef: null,
|
|
85
|
-
metadata: options.metadata || {}
|
|
85
|
+
metadata: options.metadata || {},
|
|
86
86
|
};
|
|
87
87
|
|
|
88
88
|
// Capture current state
|
|
@@ -114,20 +114,20 @@ class RollbackManager {
|
|
|
114
114
|
try {
|
|
115
115
|
const content = await fs.readFile(filePath, 'utf-8');
|
|
116
116
|
const stats = await fs.stat(filePath);
|
|
117
|
-
|
|
117
|
+
|
|
118
118
|
backups.push({
|
|
119
119
|
path: filePath,
|
|
120
120
|
content,
|
|
121
121
|
mode: stats.mode,
|
|
122
122
|
mtime: stats.mtime.toISOString(),
|
|
123
|
-
size: stats.size
|
|
123
|
+
size: stats.size,
|
|
124
124
|
});
|
|
125
125
|
} catch (error) {
|
|
126
126
|
// File doesn't exist or can't be read
|
|
127
127
|
backups.push({
|
|
128
128
|
path: filePath,
|
|
129
129
|
exists: false,
|
|
130
|
-
error: error.message
|
|
130
|
+
error: error.message,
|
|
131
131
|
});
|
|
132
132
|
}
|
|
133
133
|
}
|
|
@@ -154,8 +154,9 @@ class RollbackManager {
|
|
|
154
154
|
* @returns {Promise<Object>} Rollback result
|
|
155
155
|
*/
|
|
156
156
|
async rollback(checkpointId, options = {}) {
|
|
157
|
-
const checkpoint =
|
|
158
|
-
|
|
157
|
+
const checkpoint =
|
|
158
|
+
this.checkpoints.get(checkpointId) || (await this.loadCheckpoint(checkpointId));
|
|
159
|
+
|
|
159
160
|
if (!checkpoint) {
|
|
160
161
|
throw new Error(`Checkpoint not found: ${checkpointId}`);
|
|
161
162
|
}
|
|
@@ -169,7 +170,7 @@ class RollbackManager {
|
|
|
169
170
|
level: checkpoint.level,
|
|
170
171
|
beforeState: null,
|
|
171
172
|
changes: [],
|
|
172
|
-
options
|
|
173
|
+
options,
|
|
173
174
|
};
|
|
174
175
|
|
|
175
176
|
// Require confirmation if enabled
|
|
@@ -178,7 +179,7 @@ class RollbackManager {
|
|
|
178
179
|
...rollback,
|
|
179
180
|
status: ROLLBACK_STATUS.PENDING,
|
|
180
181
|
requiresConfirmation: true,
|
|
181
|
-
checkpoint: this.summarizeCheckpoint(checkpoint)
|
|
182
|
+
checkpoint: this.summarizeCheckpoint(checkpoint),
|
|
182
183
|
};
|
|
183
184
|
}
|
|
184
185
|
|
|
@@ -187,9 +188,7 @@ class RollbackManager {
|
|
|
187
188
|
|
|
188
189
|
// Capture current state before rollback
|
|
189
190
|
if (checkpoint.files.length > 0) {
|
|
190
|
-
rollback.beforeState = await this.captureFiles(
|
|
191
|
-
checkpoint.files.map(f => f.path)
|
|
192
|
-
);
|
|
191
|
+
rollback.beforeState = await this.captureFiles(checkpoint.files.map(f => f.path));
|
|
193
192
|
}
|
|
194
193
|
|
|
195
194
|
// Perform rollback based on level
|
|
@@ -334,7 +333,7 @@ class RollbackManager {
|
|
|
334
333
|
*/
|
|
335
334
|
cancelRollback(rollbackId) {
|
|
336
335
|
const rollback = this.rollbackHistory.find(r => r.id === rollbackId);
|
|
337
|
-
|
|
336
|
+
|
|
338
337
|
if (!rollback) {
|
|
339
338
|
throw new Error(`Rollback not found: ${rollbackId}`);
|
|
340
339
|
}
|
|
@@ -402,7 +401,7 @@ class RollbackManager {
|
|
|
402
401
|
stage: checkpoint.stage,
|
|
403
402
|
description: checkpoint.description,
|
|
404
403
|
fileCount: checkpoint.files.length,
|
|
405
|
-
hasGitRef: !!checkpoint.gitRef
|
|
404
|
+
hasGitRef: !!checkpoint.gitRef,
|
|
406
405
|
};
|
|
407
406
|
}
|
|
408
407
|
|
|
@@ -413,10 +412,10 @@ class RollbackManager {
|
|
|
413
412
|
*/
|
|
414
413
|
async saveCheckpoint(checkpoint) {
|
|
415
414
|
await this.ensureStorageDir();
|
|
416
|
-
|
|
415
|
+
|
|
417
416
|
const fileName = `checkpoint-${checkpoint.id}.json`;
|
|
418
417
|
const filePath = path.join(this.config.storageDir, fileName);
|
|
419
|
-
|
|
418
|
+
|
|
420
419
|
await fs.writeFile(filePath, JSON.stringify(checkpoint, null, 2), 'utf-8');
|
|
421
420
|
return filePath;
|
|
422
421
|
}
|
|
@@ -429,7 +428,7 @@ class RollbackManager {
|
|
|
429
428
|
async loadCheckpoint(id) {
|
|
430
429
|
const fileName = `checkpoint-${id}.json`;
|
|
431
430
|
const filePath = path.join(this.config.storageDir, fileName);
|
|
432
|
-
|
|
431
|
+
|
|
433
432
|
try {
|
|
434
433
|
const content = await fs.readFile(filePath, 'utf-8');
|
|
435
434
|
const checkpoint = JSON.parse(content);
|
|
@@ -447,10 +446,10 @@ class RollbackManager {
|
|
|
447
446
|
*/
|
|
448
447
|
async saveRollback(rollback) {
|
|
449
448
|
await this.ensureStorageDir();
|
|
450
|
-
|
|
449
|
+
|
|
451
450
|
const fileName = `rollback-${rollback.id}.json`;
|
|
452
451
|
const filePath = path.join(this.config.storageDir, fileName);
|
|
453
|
-
|
|
452
|
+
|
|
454
453
|
await fs.writeFile(filePath, JSON.stringify(rollback, null, 2), 'utf-8');
|
|
455
454
|
return filePath;
|
|
456
455
|
}
|
|
@@ -479,7 +478,7 @@ class RollbackManager {
|
|
|
479
478
|
*/
|
|
480
479
|
generateReport(rollbackId) {
|
|
481
480
|
const rollback = this.rollbackHistory.find(r => r.id === rollbackId);
|
|
482
|
-
|
|
481
|
+
|
|
483
482
|
if (!rollback) {
|
|
484
483
|
throw new Error(`Rollback not found: ${rollbackId}`);
|
|
485
484
|
}
|
|
@@ -526,10 +525,10 @@ class RollbackManager {
|
|
|
526
525
|
*/
|
|
527
526
|
async deleteCheckpoint(checkpointId) {
|
|
528
527
|
this.checkpoints.delete(checkpointId);
|
|
529
|
-
|
|
528
|
+
|
|
530
529
|
const fileName = `checkpoint-${checkpointId}.json`;
|
|
531
530
|
const filePath = path.join(this.config.storageDir, fileName);
|
|
532
|
-
|
|
531
|
+
|
|
533
532
|
try {
|
|
534
533
|
await fs.unlink(filePath);
|
|
535
534
|
return true;
|
|
@@ -580,5 +579,5 @@ module.exports = {
|
|
|
580
579
|
createRollbackManager,
|
|
581
580
|
ROLLBACK_LEVEL,
|
|
582
581
|
ROLLBACK_STATUS,
|
|
583
|
-
WORKFLOW_STAGE
|
|
582
|
+
WORKFLOW_STAGE,
|
|
584
583
|
};
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Tech Article Generator
|
|
3
|
-
*
|
|
3
|
+
*
|
|
4
4
|
* Generates publication-ready technical articles for various platforms.
|
|
5
|
-
*
|
|
5
|
+
*
|
|
6
6
|
* Requirement: IMP-6.2-006-02
|
|
7
|
-
*
|
|
7
|
+
*
|
|
8
8
|
* @module enterprise/tech-article
|
|
9
9
|
*/
|
|
10
10
|
|
|
@@ -19,7 +19,7 @@ const PLATFORM = {
|
|
|
19
19
|
ZENN: 'zenn',
|
|
20
20
|
MEDIUM: 'medium',
|
|
21
21
|
DEVTO: 'devto',
|
|
22
|
-
GENERIC: 'generic'
|
|
22
|
+
GENERIC: 'generic',
|
|
23
23
|
};
|
|
24
24
|
|
|
25
25
|
/**
|
|
@@ -31,7 +31,7 @@ const ARTICLE_TYPE = {
|
|
|
31
31
|
ANNOUNCEMENT: 'announcement',
|
|
32
32
|
COMPARISON: 'comparison',
|
|
33
33
|
HOW_TO: 'how-to',
|
|
34
|
-
CASE_STUDY: 'case-study'
|
|
34
|
+
CASE_STUDY: 'case-study',
|
|
35
35
|
};
|
|
36
36
|
|
|
37
37
|
/**
|
|
@@ -49,7 +49,7 @@ class TechArticleGenerator {
|
|
|
49
49
|
defaultLanguage: config.defaultLanguage || 'ja',
|
|
50
50
|
includeTableOfContents: config.includeTableOfContents !== false,
|
|
51
51
|
includeFrontMatter: config.includeFrontMatter !== false,
|
|
52
|
-
...config
|
|
52
|
+
...config,
|
|
53
53
|
};
|
|
54
54
|
|
|
55
55
|
this.templates = this.loadTemplates();
|
|
@@ -62,37 +62,38 @@ class TechArticleGenerator {
|
|
|
62
62
|
loadTemplates() {
|
|
63
63
|
return {
|
|
64
64
|
[PLATFORM.QIITA]: {
|
|
65
|
-
frontMatter:
|
|
65
|
+
frontMatter: meta => `---
|
|
66
66
|
title: "${meta.title}"
|
|
67
67
|
tags: [${meta.tags.map(t => `"${t}"`).join(', ')}]
|
|
68
68
|
private: false
|
|
69
69
|
---`,
|
|
70
70
|
codeBlock: (lang, code) => `\`\`\`${lang}\n${code}\n\`\`\``,
|
|
71
71
|
note: (text, type = 'info') => `:::note ${type}\n${text}\n:::`,
|
|
72
|
-
link: (text, url) => `[${text}](${url})
|
|
72
|
+
link: (text, url) => `[${text}](${url})`,
|
|
73
73
|
},
|
|
74
74
|
[PLATFORM.ZENN]: {
|
|
75
|
-
frontMatter:
|
|
75
|
+
frontMatter: meta => `---
|
|
76
76
|
title: "${meta.title}"
|
|
77
77
|
emoji: "${meta.emoji || '📝'}"
|
|
78
78
|
type: "${meta.articleType || 'tech'}"
|
|
79
79
|
topics: [${meta.tags.map(t => `"${t}"`).join(', ')}]
|
|
80
80
|
published: true
|
|
81
81
|
---`,
|
|
82
|
-
codeBlock: (lang, code, filename) =>
|
|
83
|
-
|
|
84
|
-
|
|
82
|
+
codeBlock: (lang, code, filename) =>
|
|
83
|
+
filename
|
|
84
|
+
? `\`\`\`${lang}:${filename}\n${code}\n\`\`\``
|
|
85
|
+
: `\`\`\`${lang}\n${code}\n\`\`\``,
|
|
85
86
|
note: (text, type = 'info') => `:::message ${type === 'warn' ? 'alert' : ''}\n${text}\n:::`,
|
|
86
|
-
link: (text, url) => `[${text}](${url})
|
|
87
|
+
link: (text, url) => `[${text}](${url})`,
|
|
87
88
|
},
|
|
88
89
|
[PLATFORM.MEDIUM]: {
|
|
89
90
|
frontMatter: () => '', // Medium doesn't use front matter
|
|
90
91
|
codeBlock: (lang, code) => `\`\`\`${lang}\n${code}\n\`\`\``,
|
|
91
|
-
note:
|
|
92
|
-
link: (text, url) => `[${text}](${url})
|
|
92
|
+
note: text => `> **Note:** ${text}`,
|
|
93
|
+
link: (text, url) => `[${text}](${url})`,
|
|
93
94
|
},
|
|
94
95
|
[PLATFORM.DEVTO]: {
|
|
95
|
-
frontMatter:
|
|
96
|
+
frontMatter: meta => `---
|
|
96
97
|
title: "${meta.title}"
|
|
97
98
|
published: true
|
|
98
99
|
description: "${meta.description || ''}"
|
|
@@ -100,20 +101,21 @@ tags: ${meta.tags.slice(0, 4).join(', ')}
|
|
|
100
101
|
cover_image: ${meta.coverImage || ''}
|
|
101
102
|
---`,
|
|
102
103
|
codeBlock: (lang, code) => `\`\`\`${lang}\n${code}\n\`\`\``,
|
|
103
|
-
note: (text, type = 'info') =>
|
|
104
|
-
|
|
104
|
+
note: (text, type = 'info') =>
|
|
105
|
+
`{% ${type === 'warn' ? 'warning' : type} %}\n${text}\n{% end${type === 'warn' ? 'warning' : type} %}`,
|
|
106
|
+
link: (text, url) => `[${text}](${url})`,
|
|
105
107
|
},
|
|
106
108
|
[PLATFORM.GENERIC]: {
|
|
107
|
-
frontMatter:
|
|
109
|
+
frontMatter: meta => `---
|
|
108
110
|
title: "${meta.title}"
|
|
109
111
|
date: "${meta.date || new Date().toISOString()}"
|
|
110
112
|
author: "${meta.author || 'MUSUBI SDD'}"
|
|
111
113
|
tags: [${meta.tags.map(t => `"${t}"`).join(', ')}]
|
|
112
114
|
---`,
|
|
113
115
|
codeBlock: (lang, code) => `\`\`\`${lang}\n${code}\n\`\`\``,
|
|
114
|
-
note:
|
|
115
|
-
link: (text, url) => `[${text}](${url})
|
|
116
|
-
}
|
|
116
|
+
note: text => `> **Note:** ${text}`,
|
|
117
|
+
link: (text, url) => `[${text}](${url})`,
|
|
118
|
+
},
|
|
117
119
|
};
|
|
118
120
|
}
|
|
119
121
|
|
|
@@ -135,7 +137,7 @@ tags: [${meta.tags.map(t => `"${t}"`).join(', ')}]
|
|
|
135
137
|
date: new Date().toISOString(),
|
|
136
138
|
emoji: content.emoji || '📝',
|
|
137
139
|
articleType: content.articleType || ARTICLE_TYPE.TUTORIAL,
|
|
138
|
-
coverImage: content.coverImage || ''
|
|
140
|
+
coverImage: content.coverImage || '',
|
|
139
141
|
};
|
|
140
142
|
|
|
141
143
|
const sections = [];
|
|
@@ -186,7 +188,9 @@ tags: [${meta.tags.map(t => `"${t}"`).join(', ')}]
|
|
|
186
188
|
sections.push(example.description);
|
|
187
189
|
sections.push('');
|
|
188
190
|
}
|
|
189
|
-
sections.push(
|
|
191
|
+
sections.push(
|
|
192
|
+
template.codeBlock(example.language || 'javascript', example.code, example.filename)
|
|
193
|
+
);
|
|
190
194
|
sections.push('');
|
|
191
195
|
}
|
|
192
196
|
}
|
|
@@ -259,7 +263,7 @@ tags: [${meta.tags.map(t => `"${t}"`).join(', ')}]
|
|
|
259
263
|
filePath,
|
|
260
264
|
platform,
|
|
261
265
|
wordCount: this.countWords(article),
|
|
262
|
-
readingTime: this.estimateReadingTime(article)
|
|
266
|
+
readingTime: this.estimateReadingTime(article),
|
|
263
267
|
};
|
|
264
268
|
}
|
|
265
269
|
|
|
@@ -278,7 +282,7 @@ tags: [${meta.tags.map(t => `"${t}"`).join(', ')}]
|
|
|
278
282
|
sections: this.generateExperimentSections(experimentReport),
|
|
279
283
|
benchmarks: this.extractBenchmarks(experimentReport),
|
|
280
284
|
conclusion: options.conclusion || this.generateExperimentConclusion(experimentReport),
|
|
281
|
-
references: options.references || []
|
|
285
|
+
references: options.references || [],
|
|
282
286
|
};
|
|
283
287
|
|
|
284
288
|
return this.generate(content, options);
|
|
@@ -291,9 +295,11 @@ tags: [${meta.tags.map(t => `"${t}"`).join(', ')}]
|
|
|
291
295
|
*/
|
|
292
296
|
generateExperimentIntroduction(report) {
|
|
293
297
|
const summary = report.summary || {};
|
|
294
|
-
return
|
|
295
|
-
|
|
296
|
-
|
|
298
|
+
return (
|
|
299
|
+
`本記事では、${report.metadata?.title || 'テスト'}の実験結果を報告します。` +
|
|
300
|
+
`合計${summary.total || 0}件のテストを実行し、` +
|
|
301
|
+
`${summary.passRate || '0%'}のパス率を達成しました。`
|
|
302
|
+
);
|
|
297
303
|
}
|
|
298
304
|
|
|
299
305
|
/**
|
|
@@ -315,14 +321,14 @@ tags: [${meta.tags.map(t => `"${t}"`).join(', ')}]
|
|
|
315
321
|
| 失敗 | ${report.summary?.failed || 0} |
|
|
316
322
|
| スキップ | ${report.summary?.skipped || 0} |
|
|
317
323
|
| パス率 | ${report.summary?.passRate || '0%'} |
|
|
318
|
-
`.trim()
|
|
324
|
+
`.trim(),
|
|
319
325
|
});
|
|
320
326
|
|
|
321
327
|
// Metrics section (if available)
|
|
322
328
|
if (report.metrics && Object.keys(report.metrics).length > 0) {
|
|
323
329
|
sections.push({
|
|
324
330
|
title: 'メトリクス',
|
|
325
|
-
content: this.formatMetricsSection(report.metrics)
|
|
331
|
+
content: this.formatMetricsSection(report.metrics),
|
|
326
332
|
});
|
|
327
333
|
}
|
|
328
334
|
|
|
@@ -330,7 +336,7 @@ tags: [${meta.tags.map(t => `"${t}"`).join(', ')}]
|
|
|
330
336
|
if (report.observations && report.observations.length > 0) {
|
|
331
337
|
sections.push({
|
|
332
338
|
title: '観察結果',
|
|
333
|
-
content: report.observations.map(o => `- ${o}`).join('\n')
|
|
339
|
+
content: report.observations.map(o => `- ${o}`).join('\n'),
|
|
334
340
|
});
|
|
335
341
|
}
|
|
336
342
|
|
|
@@ -376,11 +382,11 @@ tags: [${meta.tags.map(t => `"${t}"`).join(', ')}]
|
|
|
376
382
|
*/
|
|
377
383
|
extractBenchmarks(report) {
|
|
378
384
|
const benchmarks = {};
|
|
379
|
-
|
|
385
|
+
|
|
380
386
|
if (report.metrics?.performance) {
|
|
381
387
|
Object.assign(benchmarks, report.metrics.performance);
|
|
382
388
|
}
|
|
383
|
-
|
|
389
|
+
|
|
384
390
|
if (report.summary?.duration) {
|
|
385
391
|
benchmarks['Total Duration'] = `${report.summary.duration}ms`;
|
|
386
392
|
}
|
|
@@ -505,5 +511,5 @@ module.exports = {
|
|
|
505
511
|
TechArticleGenerator,
|
|
506
512
|
createTechArticleGenerator,
|
|
507
513
|
PLATFORM,
|
|
508
|
-
ARTICLE_TYPE
|
|
514
|
+
ARTICLE_TYPE,
|
|
509
515
|
};
|
package/src/generators/design.js
CHANGED
|
@@ -36,7 +36,7 @@ class DesignGenerator {
|
|
|
36
36
|
* @returns {Promise<object>} Result with path
|
|
37
37
|
*/
|
|
38
38
|
async init(feature, options = {}) {
|
|
39
|
-
const outputDir = path.join(this.rootDir, options.output || '
|
|
39
|
+
const outputDir = path.join(this.rootDir, options.output || 'storage/design');
|
|
40
40
|
await fs.ensureDir(outputDir);
|
|
41
41
|
|
|
42
42
|
const fileName = `${this.slugify(feature)}.md`;
|
|
@@ -90,7 +90,7 @@ class DesignGenerator {
|
|
|
90
90
|
* @returns {Promise<string[]>} List of design file paths
|
|
91
91
|
*/
|
|
92
92
|
async findDesignFiles() {
|
|
93
|
-
const patterns = ['
|
|
93
|
+
const patterns = ['storage/design/**/*.md', 'storage/design/*.md', 'design/**/*.md', 'design/*.md'];
|
|
94
94
|
|
|
95
95
|
const files = [];
|
|
96
96
|
for (const pattern of patterns) {
|
|
@@ -605,7 +605,7 @@ Service --> Repository
|
|
|
605
605
|
const matrix = [];
|
|
606
606
|
|
|
607
607
|
// Find requirement files
|
|
608
|
-
const reqFiles = await glob('
|
|
608
|
+
const reqFiles = await glob('storage/specs/**/*.md', {
|
|
609
609
|
cwd: this.rootDir,
|
|
610
610
|
absolute: true,
|
|
611
611
|
});
|
|
@@ -32,7 +32,7 @@ class RequirementsGenerator {
|
|
|
32
32
|
* @returns {Promise<object>} Result with path
|
|
33
33
|
*/
|
|
34
34
|
async init(feature, options = {}) {
|
|
35
|
-
const outputDir = path.join(this.rootDir, options.output || '
|
|
35
|
+
const outputDir = path.join(this.rootDir, options.output || 'storage/specs');
|
|
36
36
|
await fs.ensureDir(outputDir);
|
|
37
37
|
|
|
38
38
|
const fileName = `${this.slugify(feature)}.md`;
|
|
@@ -87,8 +87,10 @@ class RequirementsGenerator {
|
|
|
87
87
|
*/
|
|
88
88
|
async findRequirementsFiles() {
|
|
89
89
|
const patterns = [
|
|
90
|
-
'
|
|
91
|
-
'
|
|
90
|
+
'storage/specs/**/*-requirements.md',
|
|
91
|
+
'storage/specs/*-requirements.md',
|
|
92
|
+
'storage/specs/**/*.md',
|
|
93
|
+
'storage/specs/*.md',
|
|
92
94
|
'requirements/**/*.md',
|
|
93
95
|
'requirements/*.md',
|
|
94
96
|
];
|
package/src/generators/tasks.js
CHANGED
|
@@ -19,7 +19,7 @@ class TasksGenerator {
|
|
|
19
19
|
* Initialize task breakdown document
|
|
20
20
|
*/
|
|
21
21
|
async init(feature, options = {}) {
|
|
22
|
-
const outputDir = path.join(this.workspaceRoot, options.output || '
|
|
22
|
+
const outputDir = path.join(this.workspaceRoot, options.output || 'storage/tasks');
|
|
23
23
|
await fs.ensureDir(outputDir);
|
|
24
24
|
|
|
25
25
|
const fileName = this.slugify(feature) + '.md';
|
|
@@ -45,7 +45,7 @@ class TasksGenerator {
|
|
|
45
45
|
* Find all task breakdown files
|
|
46
46
|
*/
|
|
47
47
|
async findTaskFiles() {
|
|
48
|
-
const patterns = ['
|
|
48
|
+
const patterns = ['storage/tasks/**/*.md', 'tasks/**/*.md'];
|
|
49
49
|
|
|
50
50
|
const files = [];
|
|
51
51
|
for (const pattern of patterns) {
|
|
@@ -289,7 +289,7 @@ npx musubi-sdd <command>
|
|
|
289
289
|
|
|
290
290
|
## Learn More
|
|
291
291
|
|
|
292
|
-
- [MUSUBI Documentation](https://github.com/
|
|
292
|
+
- [MUSUBI Documentation](https://github.com/nahisaho/MUSUBI)
|
|
293
293
|
- [Constitutional Governance](steering/rules/constitution.md)
|
|
294
294
|
- [8-Stage SDD Workflow](steering/rules/workflow.md)
|
|
295
295
|
- [EARS Format Guide](steering/rules/ears-format.md)
|