musubi-sdd 0.6.1 → 0.8.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 CHANGED
@@ -13,9 +13,14 @@ MUSUBIは、6つの主要フレームワークのベスト機能を統合した
13
13
  - GitHub Copilot & Cursor: AGENTS.md(公式サポート)
14
14
  - その他4エージェント: AGENTS.md(互換形式)
15
15
  - 📋 **憲法ガバナンス** - 9つの不変条項 + フェーズ-1ゲートによる品質保証
16
- - 📝 **EARS要件形式** - 完全なトレーサビリティを持つ明確な要件
16
+ - 📝 **EARS要件ジェネレーター** - 5つのEARSパターンで明確な要件を作成(v0.8.0)
17
17
  - 🔄 **差分仕様** - ブラウンフィールドおよびグリーンフィールドプロジェクト対応
18
18
  - 🧭 **自動更新プロジェクトメモリ** - ステアリングシステムがアーキテクチャ、技術スタック、製品コンテキストを維持
19
+ - 🚀 **自動オンボーディング** - `musubi-onboard` が既存プロジェクトを分析し、ステアリングドキュメントを生成(2-5分)
20
+ - 🔄 **自動同期** - `musubi-sync` がコードベースの変更を検出し、ステアリングドキュメントを最新に保つ
21
+ - 🔍 **インテリジェントコード分析** - `musubi-analyze` が品質メトリクス、複雑度分析、技術的負債検出を提供
22
+ - 🤝 **チーム連携** - `musubi-share` がメモリ共有、インポート/エクスポート、マルチプラットフォーム同期を実現(v0.6.0)
23
+ - ✅ **憲法バリデーション** - `musubi-validate` が9つの不変ガバナンス条項とフェーズ-1ゲートを強制(v0.7.0)
19
24
  - ✅ **完全なトレーサビリティ** - 要件 → 設計 → コード → テストのマッピング
20
25
  - 🌐 **バイリンガルドキュメント** - すべてのエージェント生成ドキュメントは英語と日本語の両方で作成
21
26
 
@@ -72,6 +77,40 @@ npx musubi-sdd init --windsurf
72
77
  # またはグローバルインストール
73
78
  npm install -g musubi-sdd
74
79
  musubi init --claude # または --copilot、--cursorなど
80
+
81
+ # 既存プロジェクトのオンボーディング(自動分析)
82
+ musubi-onboard
83
+
84
+ # コードベースとステアリングドキュメントの同期
85
+ musubi-sync
86
+ musubi-sync --dry-run # 変更のプレビュー
87
+ musubi-sync --auto-approve # 自動適用(CI/CD)
88
+
89
+ # コード品質分析(v0.5.0)
90
+ musubi-analyze # 完全分析
91
+ musubi-analyze --type=quality # 品質メトリクスのみ
92
+ musubi-analyze --type=dependencies # 依存関係のみ
93
+ musubi-analyze --type=security # セキュリティ監査
94
+ musubi-analyze --output=report.md # レポート保存
95
+
96
+ # チームとプロジェクトメモリを共有(v0.6.0)
97
+ musubi-share export # メモリをJSONにエクスポート
98
+ musubi-share import memories.json # チームメイトからインポート
99
+ musubi-share sync --platform=copilot # 特定プラットフォームに同期
100
+
101
+ # 憲法準拠の検証(v0.7.0)
102
+ musubi-validate constitution # 全9条項を検証
103
+ musubi-validate article 3 # テストファースト原則を検証
104
+ musubi-validate gates # フェーズ-1ゲートを検証
105
+ musubi-validate complexity # 複雑度制限をチェック
106
+ musubi-validate all -v # 詳細付き完全検証
107
+
108
+ # EARS要件の作成(v0.8.0)
109
+ musubi-requirements init "ユーザー認証" # 要件ドキュメント初期化
110
+ musubi-requirements add # インタラクティブに要件追加
111
+ musubi-requirements list # 全要件リスト表示
112
+ musubi-requirements validate # EARS形式検証
113
+ musubi-requirements trace # トレーサビリティマトリクス表示
75
114
  ```
76
115
 
77
116
  ### プロジェクトタイプ
package/README.md CHANGED
@@ -17,13 +17,14 @@ MUSUBI is a comprehensive SDD (Specification Driven Development) framework that
17
17
  - GitHub Copilot & Cursor: AGENTS.md (official support)
18
18
  - Other 4 agents: AGENTS.md (compatible format)
19
19
  - 📋 **Constitutional Governance** - 9 immutable articles + Phase -1 Gates for quality enforcement
20
- - 📝 **EARS Requirements Format** - Unambiguous requirements with complete traceability
20
+ - 📝 **EARS Requirements Generator** - Create unambiguous requirements with 5 EARS patterns (v0.8.0)
21
21
  - 🔄 **Delta Specifications** - Brownfield and greenfield project support
22
22
  - 🧭 **Auto-Updating Project Memory** - Steering system maintains architecture, tech stack, and product context
23
23
  - 🚀 **Automatic Onboarding** - `musubi-onboard` analyzes existing projects and generates steering docs (2-5 minutes)
24
24
  - 🔄 **Auto-Sync** - `musubi-sync` detects codebase changes and keeps steering docs current
25
25
  - 🔍 **Intelligent Code Analysis** - `musubi-analyze` provides quality metrics, complexity analysis, and technical debt detection
26
26
  - 🤝 **Team Collaboration** - `musubi-share` enables memory sharing, import/export, and multi-platform sync (v0.6.0)
27
+ - ✅ **Constitutional Validation** - `musubi-validate` enforces 9 immutable governance articles with Phase -1 Gates (v0.7.0)
27
28
  - ✅ **Complete Traceability** - Requirements → Design → Code → Tests mapping
28
29
  - 🌐 **Bilingual Documentation** - All agent-generated documents created in both English and Japanese
29
30
 
@@ -99,8 +100,21 @@ musubi-analyze --output=report.md # Save report
99
100
  # Share project memories with team (v0.6.0)
100
101
  musubi-share export # Export memories to JSON
101
102
  musubi-share import memories.json # Import from teammate
102
- musubi-share sync # Sync across AI platforms
103
- musubi-share status # Show sharing status
103
+ musubi-share sync --platform=copilot # Sync to specific platform
104
+
105
+ # Validate constitutional compliance (v0.7.0)
106
+ musubi-validate constitution # Validate all 9 articles
107
+ musubi-validate article 3 # Validate Test-First Imperative
108
+ musubi-validate gates # Validate Phase -1 Gates
109
+ musubi-validate complexity # Check complexity limits
110
+ musubi-validate all -v # Full validation with details
111
+
112
+ # Create EARS requirements (v0.8.0)
113
+ musubi-requirements init "User Authentication" # Initialize requirements doc
114
+ musubi-requirements add # Add requirement interactively
115
+ musubi-requirements list # List all requirements
116
+ musubi-requirements validate # Validate EARS format
117
+ musubi-requirements trace # Show traceability matrix
104
118
  ```
105
119
 
106
120
  ### Project Types
@@ -0,0 +1,330 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * MUSUBI Requirements Generator CLI
5
+ *
6
+ * Generates EARS (Easy Approach to Requirements Syntax) formatted requirements
7
+ * Supports 5 EARS patterns for unambiguous specification
8
+ *
9
+ * Usage:
10
+ * musubi-requirements init <feature> # Initialize requirements document
11
+ * musubi-requirements add <pattern> <title> # Add requirement with EARS pattern
12
+ * musubi-requirements list # List all requirements
13
+ * musubi-requirements validate # Validate EARS format compliance
14
+ * musubi-requirements trace # Show traceability matrix
15
+ */
16
+
17
+ const { Command } = require('commander');
18
+ const chalk = require('chalk');
19
+ const inquirer = require('inquirer');
20
+ const RequirementsGenerator = require('../src/generators/requirements');
21
+
22
+ const program = new Command();
23
+
24
+ program
25
+ .name('musubi-requirements')
26
+ .description('EARS Requirements Generator - Create unambiguous specifications')
27
+ .version('0.8.0');
28
+
29
+ // Initialize requirements document
30
+ program
31
+ .command('init <feature>')
32
+ .description('Initialize requirements document for a feature')
33
+ .option('-o, --output <path>', 'Output directory', 'docs/requirements')
34
+ .option('-a, --author <name>', 'Author name')
35
+ .option('--project <name>', 'Project name')
36
+ .action(async (feature, options) => {
37
+ try {
38
+ console.log(chalk.bold(`\n📋 Initializing requirements for: ${feature}\n`));
39
+
40
+ const generator = new RequirementsGenerator(process.cwd());
41
+ const result = await generator.init(feature, options);
42
+
43
+ console.log(chalk.green('✓ Requirements document created'));
44
+ console.log(chalk.dim(` ${result.path}`));
45
+ console.log();
46
+ console.log(chalk.bold('Next steps:'));
47
+ console.log(chalk.dim(` 1. Edit ${result.path}`));
48
+ console.log(chalk.dim(' 2. Add requirements: musubi-requirements add <pattern> <title>'));
49
+ console.log(chalk.dim(' 3. Validate: musubi-requirements validate'));
50
+ console.log();
51
+
52
+ process.exit(0);
53
+ } catch (error) {
54
+ console.error(chalk.red('✗ Error:'), error.message);
55
+ process.exit(1);
56
+ }
57
+ });
58
+
59
+ // Add requirement with EARS pattern
60
+ program
61
+ .command('add')
62
+ .description('Add requirement with EARS pattern (interactive)')
63
+ .option('-f, --file <path>', 'Requirements file path')
64
+ .option('-p, --pattern <type>', 'EARS pattern (ubiquitous|event|state|unwanted|optional)')
65
+ .option('-t, --title <text>', 'Requirement title')
66
+ .action(async (options) => {
67
+ try {
68
+ console.log(chalk.bold('\n📝 Add EARS Requirement\n'));
69
+
70
+ const generator = new RequirementsGenerator(process.cwd());
71
+
72
+ // Find requirements file
73
+ let reqFile = options.file;
74
+ if (!reqFile) {
75
+ const files = await generator.findRequirementsFiles();
76
+ if (files.length === 0) {
77
+ console.error(chalk.red('✗ No requirements files found'));
78
+ console.log(chalk.dim(' Run: musubi-requirements init <feature>'));
79
+ process.exit(1);
80
+ }
81
+
82
+ if (files.length === 1) {
83
+ reqFile = files[0];
84
+ } else {
85
+ const answer = await inquirer.prompt([{
86
+ type: 'list',
87
+ name: 'file',
88
+ message: 'Select requirements file:',
89
+ choices: files
90
+ }]);
91
+ reqFile = answer.file;
92
+ }
93
+ }
94
+
95
+ // Interactive prompts if not provided
96
+ let pattern = options.pattern;
97
+ let title = options.title;
98
+
99
+ if (!pattern || !title) {
100
+ const answers = await inquirer.prompt([
101
+ {
102
+ type: 'list',
103
+ name: 'pattern',
104
+ message: 'Select EARS pattern:',
105
+ choices: [
106
+ { name: 'Ubiquitous - The [system] SHALL [requirement]', value: 'ubiquitous' },
107
+ { name: 'Event-Driven - WHEN [event], THEN [system] SHALL [response]', value: 'event' },
108
+ { name: 'State-Driven - WHILE [state], [system] SHALL [response]', value: 'state' },
109
+ { name: 'Unwanted Behavior - IF [error], THEN [system] SHALL [response]', value: 'unwanted' },
110
+ { name: 'Optional Feature - WHERE [feature], [system] SHALL [response]', value: 'optional' }
111
+ ],
112
+ when: () => !pattern
113
+ },
114
+ {
115
+ type: 'input',
116
+ name: 'title',
117
+ message: 'Requirement title:',
118
+ when: () => !title,
119
+ validate: (input) => input.length > 0 || 'Title is required'
120
+ },
121
+ {
122
+ type: 'input',
123
+ name: 'system',
124
+ message: 'System/component name:',
125
+ default: 'system'
126
+ },
127
+ {
128
+ type: 'input',
129
+ name: 'statement',
130
+ message: (answers) => {
131
+ const prompts = {
132
+ ubiquitous: 'What SHALL the system do?',
133
+ event: 'What event triggers this? (WHEN...)',
134
+ state: 'What state/condition? (WHILE...)',
135
+ unwanted: 'What error/unwanted condition? (IF...)',
136
+ optional: 'What optional feature? (WHERE...)'
137
+ };
138
+ return prompts[answers.pattern || pattern];
139
+ },
140
+ validate: (input) => input.length > 0 || 'Statement is required'
141
+ },
142
+ {
143
+ type: 'input',
144
+ name: 'response',
145
+ message: 'What SHALL the system do? (response)',
146
+ validate: (input) => input.length > 0 || 'Response is required'
147
+ },
148
+ {
149
+ type: 'input',
150
+ name: 'criteria',
151
+ message: 'Acceptance criteria (comma-separated):',
152
+ filter: (input) => input.split(',').map(s => s.trim()).filter(s => s.length > 0)
153
+ }
154
+ ]);
155
+
156
+ pattern = pattern || answers.pattern;
157
+ title = title || answers.title;
158
+
159
+ const requirement = {
160
+ pattern,
161
+ title,
162
+ system: answers.system,
163
+ statement: answers.statement,
164
+ response: answers.response,
165
+ criteria: answers.criteria
166
+ };
167
+
168
+ const result = await generator.addRequirement(reqFile, requirement);
169
+
170
+ console.log(chalk.green('\n✓ Requirement added:'));
171
+ console.log(chalk.dim(` ${result.id}: ${title}`));
172
+ console.log(chalk.bold('\n📄 EARS Statement:'));
173
+ console.log(chalk.cyan(result.statement));
174
+ console.log();
175
+
176
+ process.exit(0);
177
+ }
178
+ } catch (error) {
179
+ console.error(chalk.red('✗ Error:'), error.message);
180
+ process.exit(1);
181
+ }
182
+ });
183
+
184
+ // List all requirements
185
+ program
186
+ .command('list')
187
+ .description('List all requirements in the project')
188
+ .option('-f, --file <path>', 'Specific requirements file')
189
+ .option('--format <type>', 'Output format (table|json|markdown)', 'table')
190
+ .action(async (options) => {
191
+ try {
192
+ const generator = new RequirementsGenerator(process.cwd());
193
+ const requirements = await generator.listRequirements(options.file);
194
+
195
+ if (requirements.length === 0) {
196
+ console.log(chalk.yellow('No requirements found'));
197
+ process.exit(0);
198
+ }
199
+
200
+ console.log(chalk.bold(`\n📋 Requirements (${requirements.length} total)\n`));
201
+
202
+ if (options.format === 'json') {
203
+ console.log(JSON.stringify(requirements, null, 2));
204
+ } else if (options.format === 'markdown') {
205
+ requirements.forEach(req => {
206
+ console.log(`## ${req.id}: ${req.title}`);
207
+ console.log();
208
+ console.log(`**Pattern**: ${req.pattern}`);
209
+ console.log();
210
+ console.log(req.statement);
211
+ console.log();
212
+ });
213
+ } else {
214
+ // Table format
215
+ requirements.forEach(req => {
216
+ console.log(chalk.bold(`${req.id}: ${req.title}`));
217
+ console.log(chalk.dim(` Pattern: ${req.pattern}`));
218
+ console.log(chalk.cyan(` ${req.statement.substring(0, 100)}...`));
219
+ console.log();
220
+ });
221
+ }
222
+
223
+ process.exit(0);
224
+ } catch (error) {
225
+ console.error(chalk.red('✗ Error:'), error.message);
226
+ process.exit(1);
227
+ }
228
+ });
229
+
230
+ // Validate EARS format compliance
231
+ program
232
+ .command('validate')
233
+ .description('Validate requirements against EARS format')
234
+ .option('-f, --file <path>', 'Specific requirements file')
235
+ .option('-v, --verbose', 'Show detailed validation results')
236
+ .action(async (options) => {
237
+ try {
238
+ console.log(chalk.bold('\n🔍 Validating EARS Requirements\n'));
239
+
240
+ const generator = new RequirementsGenerator(process.cwd());
241
+ const results = await generator.validate(options.file);
242
+
243
+ if (results.passed) {
244
+ console.log(chalk.green('✓ All requirements valid\n'));
245
+ } else {
246
+ console.log(chalk.red('✗ Validation failed\n'));
247
+ }
248
+
249
+ console.log(chalk.bold('Summary:'));
250
+ console.log(chalk.dim(` Total: ${results.total}`));
251
+ console.log(chalk.green(` Valid: ${results.valid}`));
252
+ console.log(chalk.red(` Invalid: ${results.invalid}`));
253
+ console.log();
254
+
255
+ if (results.violations.length > 0) {
256
+ console.log(chalk.bold.red('Violations:'));
257
+ results.violations.forEach(v => {
258
+ console.log(chalk.red(` • ${v}`));
259
+ });
260
+ console.log();
261
+ }
262
+
263
+ if (options.verbose && results.details) {
264
+ console.log(chalk.bold('Details:'));
265
+ results.details.forEach(d => {
266
+ const icon = d.valid ? chalk.green('✓') : chalk.red('✗');
267
+ console.log(` ${icon} ${d.id}: ${d.message}`);
268
+ });
269
+ console.log();
270
+ }
271
+
272
+ process.exit(results.passed ? 0 : 1);
273
+ } catch (error) {
274
+ console.error(chalk.red('✗ Error:'), error.message);
275
+ process.exit(1);
276
+ }
277
+ });
278
+
279
+ // Show traceability matrix
280
+ program
281
+ .command('trace')
282
+ .description('Show requirements traceability matrix')
283
+ .option('-f, --file <path>', 'Specific requirements file')
284
+ .option('--format <type>', 'Output format (table|json|markdown)', 'table')
285
+ .action(async (options) => {
286
+ try {
287
+ console.log(chalk.bold('\n📊 Requirements Traceability Matrix\n'));
288
+
289
+ const generator = new RequirementsGenerator(process.cwd());
290
+ const matrix = await generator.generateTraceabilityMatrix(options.file);
291
+
292
+ if (options.format === 'json') {
293
+ console.log(JSON.stringify(matrix, null, 2));
294
+ } else {
295
+ console.log(chalk.bold('| Requirement | Design | Code | Tests | Status |'));
296
+ console.log('|-------------|--------|------|-------|--------|');
297
+
298
+ matrix.forEach(row => {
299
+ const design = row.design ? '✓' : '-';
300
+ const code = row.code ? '✓' : '-';
301
+ const tests = row.tests ? '✓' : '-';
302
+ const status = row.complete ? chalk.green('Complete') : chalk.yellow('Incomplete');
303
+
304
+ console.log(`| ${row.id} | ${design} | ${code} | ${tests} | ${status} |`);
305
+ });
306
+ console.log();
307
+
308
+ const complete = matrix.filter(r => r.complete).length;
309
+ const total = matrix.length;
310
+ const percentage = total > 0 ? Math.round((complete / total) * 100) : 0;
311
+
312
+ console.log(chalk.bold('Coverage:'));
313
+ console.log(chalk.dim(` ${complete}/${total} requirements traced (${percentage}%)`));
314
+ console.log();
315
+ }
316
+
317
+ process.exit(0);
318
+ } catch (error) {
319
+ console.error(chalk.red('✗ Error:'), error.message);
320
+ process.exit(1);
321
+ }
322
+ });
323
+
324
+ // Parse arguments
325
+ program.parse(process.argv);
326
+
327
+ // Show help if no command provided
328
+ if (!process.argv.slice(2).length) {
329
+ program.outputHelp();
330
+ }