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.
Files changed (55) hide show
  1. package/README.ja.md +3 -3
  2. package/README.md +3 -3
  3. package/bin/musubi-dashboard.js +23 -14
  4. package/bin/musubi-design.js +3 -3
  5. package/bin/musubi-gaps.js +9 -9
  6. package/bin/musubi-init.js +14 -1310
  7. package/bin/musubi-requirements.js +1 -1
  8. package/bin/musubi-tasks.js +5 -5
  9. package/bin/musubi-trace.js +23 -23
  10. package/bin/musubi-upgrade.js +400 -0
  11. package/bin/musubi.js +16 -1
  12. package/package.json +4 -3
  13. package/src/analyzers/gap-detector.js +3 -3
  14. package/src/analyzers/traceability.js +17 -17
  15. package/src/cli/dashboard-cli.js +54 -60
  16. package/src/cli/init-generators.js +464 -0
  17. package/src/cli/init-helpers.js +884 -0
  18. package/src/constitutional/checker.js +67 -65
  19. package/src/constitutional/ci-reporter.js +58 -49
  20. package/src/constitutional/index.js +2 -2
  21. package/src/constitutional/phase-minus-one.js +24 -27
  22. package/src/constitutional/steering-sync.js +29 -40
  23. package/src/dashboard/index.js +2 -2
  24. package/src/dashboard/sprint-planner.js +17 -19
  25. package/src/dashboard/sprint-reporter.js +47 -38
  26. package/src/dashboard/transition-recorder.js +12 -18
  27. package/src/dashboard/workflow-dashboard.js +28 -39
  28. package/src/enterprise/error-recovery.js +109 -49
  29. package/src/enterprise/experiment-report.js +63 -37
  30. package/src/enterprise/index.js +5 -5
  31. package/src/enterprise/rollback-manager.js +28 -29
  32. package/src/enterprise/tech-article.js +41 -35
  33. package/src/generators/design.js +3 -3
  34. package/src/generators/requirements.js +5 -3
  35. package/src/generators/tasks.js +2 -2
  36. package/src/integrations/platforms.js +1 -1
  37. package/src/templates/agents/claude-code/CLAUDE.md +1 -1
  38. package/src/templates/agents/claude-code/skills/design-reviewer/SKILL.md +132 -113
  39. package/src/templates/agents/claude-code/skills/requirements-reviewer/SKILL.md +85 -56
  40. package/src/templates/agents/codex/AGENTS.md +2 -2
  41. package/src/templates/agents/cursor/AGENTS.md +2 -2
  42. package/src/templates/agents/gemini-cli/GEMINI.md +2 -2
  43. package/src/templates/agents/github-copilot/AGENTS.md +2 -2
  44. package/src/templates/agents/github-copilot/commands/sdd-requirements.prompt.md +23 -4
  45. package/src/templates/agents/qwen-code/QWEN.md +2 -2
  46. package/src/templates/agents/shared/AGENTS.md +1 -1
  47. package/src/templates/agents/windsurf/AGENTS.md +2 -2
  48. package/src/templates/skills/browser-agent.md +1 -1
  49. package/src/traceability/extractor.js +22 -21
  50. package/src/traceability/gap-detector.js +19 -17
  51. package/src/traceability/index.js +2 -2
  52. package/src/traceability/matrix-storage.js +20 -22
  53. package/src/validators/constitution.js +5 -2
  54. package/src/validators/critic-system.js +6 -6
  55. package/src/validators/traceability-validator.js +3 -3
@@ -22,871 +22,22 @@ const fs = require('fs-extra');
22
22
  const path = require('path');
23
23
  const chalk = require('chalk');
24
24
 
25
+ // Import helpers from separate modules to reduce file size
26
+ const {
27
+ fetchExternalSpec,
28
+ fetchGitHubRepos,
29
+ analyzeReposForImprovements,
30
+ saveReferenceRepos,
31
+ saveSpecReference,
32
+ recommendLanguages,
33
+ } = require('../src/cli/init-helpers');
34
+
35
+ const { generateDependencyFiles, generateTechMd } = require('../src/cli/init-generators');
36
+
25
37
  const TEMPLATE_DIR = path.join(__dirname, '..', 'src', 'templates');
26
38
  const SHARED_TEMPLATE_DIR = path.join(TEMPLATE_DIR, 'shared');
27
39
  const AGENTS_TEMPLATE_DIR = path.join(TEMPLATE_DIR, 'agents');
28
40
 
29
- /**
30
- * External specification reference handler
31
- * Supports: URL (http/https), local file path, Git repository
32
- * @param {string} specSource - Specification source (URL, file path, or git URL)
33
- * @returns {object} Parsed specification with metadata
34
- */
35
- async function fetchExternalSpec(specSource) {
36
- const result = {
37
- source: specSource,
38
- type: 'unknown',
39
- content: null,
40
- metadata: {},
41
- error: null,
42
- };
43
-
44
- try {
45
- // Determine source type
46
- if (specSource.startsWith('http://') || specSource.startsWith('https://')) {
47
- result.type = 'url';
48
- const https = require('https');
49
- const http = require('http');
50
- const protocol = specSource.startsWith('https://') ? https : http;
51
-
52
- result.content = await new Promise((resolve, reject) => {
53
- protocol
54
- .get(specSource, res => {
55
- if (res.statusCode >= 300 && res.statusCode < 400 && res.headers.location) {
56
- // Handle redirect
57
- fetchExternalSpec(res.headers.location).then(r => resolve(r.content));
58
- return;
59
- }
60
- if (res.statusCode !== 200) {
61
- reject(new Error(`HTTP ${res.statusCode}`));
62
- return;
63
- }
64
- let data = '';
65
- res.on('data', chunk => (data += chunk));
66
- res.on('end', () => resolve(data));
67
- })
68
- .on('error', reject);
69
- });
70
-
71
- // Extract metadata from URL
72
- result.metadata.url = specSource;
73
- result.metadata.fetchedAt = new Date().toISOString();
74
- } else if (specSource.startsWith('git://') || specSource.includes('.git')) {
75
- result.type = 'git';
76
- result.metadata.repository = specSource;
77
- // For Git repos, we'll store the reference for later cloning
78
- result.content = `# External Specification Reference\n\nRepository: ${specSource}\n\n> Clone this repository to access the full specification.\n`;
79
- } else if (fs.existsSync(specSource)) {
80
- result.type = 'file';
81
- result.content = await fs.readFile(specSource, 'utf8');
82
- result.metadata.path = path.resolve(specSource);
83
- result.metadata.readAt = new Date().toISOString();
84
- } else {
85
- result.error = `Specification source not found: ${specSource}`;
86
- }
87
-
88
- // Try to parse specification format
89
- if (result.content) {
90
- result.metadata.format = detectSpecFormat(result.content, specSource);
91
- result.metadata.summary = extractSpecSummary(result.content);
92
- }
93
- } catch (err) {
94
- result.error = err.message;
95
- }
96
-
97
- return result;
98
- }
99
-
100
- /**
101
- * Parse GitHub repository reference
102
- * Supports formats:
103
- * - owner/repo
104
- * - https://github.com/owner/repo
105
- * - git@github.com:owner/repo.git
106
- * @param {string} repoRef - Repository reference string
107
- * @returns {object} Parsed repository info
108
- */
109
- function parseGitHubRepo(repoRef) {
110
- let owner = '';
111
- let repo = '';
112
- let branch = 'main';
113
- let path = '';
114
-
115
- // Handle owner/repo format
116
- const simpleMatch = repoRef.match(/^([^/]+)\/([^/@#]+)(?:@([^#]+))?(?:#(.+))?$/);
117
- if (simpleMatch) {
118
- owner = simpleMatch[1];
119
- repo = simpleMatch[2];
120
- branch = simpleMatch[3] || 'main';
121
- path = simpleMatch[4] || '';
122
- return { owner, repo, branch, path, url: `https://github.com/${owner}/${repo}` };
123
- }
124
-
125
- // Handle https://github.com/owner/repo format
126
- const httpsMatch = repoRef.match(
127
- /github\.com\/([^/]+)\/([^/@#\s]+?)(?:\.git)?(?:@([^#]+))?(?:#(.+))?$/
128
- );
129
- if (httpsMatch) {
130
- owner = httpsMatch[1];
131
- repo = httpsMatch[2];
132
- branch = httpsMatch[3] || 'main';
133
- path = httpsMatch[4] || '';
134
- return { owner, repo, branch, path, url: `https://github.com/${owner}/${repo}` };
135
- }
136
-
137
- // Handle git@github.com:owner/repo.git format
138
- const sshMatch = repoRef.match(
139
- /git@github\.com:([^/]+)\/([^/.]+)(?:\.git)?(?:@([^#]+))?(?:#(.+))?$/
140
- );
141
- if (sshMatch) {
142
- owner = sshMatch[1];
143
- repo = sshMatch[2];
144
- branch = sshMatch[3] || 'main';
145
- path = sshMatch[4] || '';
146
- return { owner, repo, branch, path, url: `https://github.com/${owner}/${repo}` };
147
- }
148
-
149
- return { error: `Invalid GitHub repository format: ${repoRef}` };
150
- }
151
-
152
- /**
153
- * Fetch GitHub repository metadata and key files
154
- * @param {string} repoRef - Repository reference (owner/repo, URL, etc.)
155
- * @returns {object} Repository data with structure and key files
156
- */
157
- async function fetchGitHubRepo(repoRef) {
158
- const parsed = parseGitHubRepo(repoRef);
159
- if (parsed.error) {
160
- return { source: repoRef, error: parsed.error };
161
- }
162
-
163
- const { owner, repo, branch, path: subPath } = parsed;
164
- const https = require('https');
165
-
166
- const result = {
167
- source: repoRef,
168
- owner,
169
- repo,
170
- branch,
171
- url: parsed.url,
172
- metadata: {},
173
- files: {},
174
- structure: [],
175
- improvements: [],
176
- error: null,
177
- };
178
-
179
- // Helper to fetch from GitHub API
180
- const fetchGitHubAPI = endpoint =>
181
- new Promise((resolve, reject) => {
182
- const options = {
183
- hostname: 'api.github.com',
184
- path: endpoint,
185
- headers: {
186
- 'User-Agent': 'MUSUBI-SDD',
187
- Accept: 'application/vnd.github.v3+json',
188
- },
189
- };
190
-
191
- // Add GitHub token if available
192
- if (process.env.GITHUB_TOKEN) {
193
- options.headers['Authorization'] = `token ${process.env.GITHUB_TOKEN}`;
194
- }
195
-
196
- https
197
- .get(options, res => {
198
- let data = '';
199
- res.on('data', chunk => (data += chunk));
200
- res.on('end', () => {
201
- if (res.statusCode === 200) {
202
- try {
203
- resolve(JSON.parse(data));
204
- } catch {
205
- reject(new Error('Invalid JSON response'));
206
- }
207
- } else if (res.statusCode === 404) {
208
- reject(new Error(`Repository not found: ${owner}/${repo}`));
209
- } else if (res.statusCode === 403) {
210
- reject(
211
- new Error('GitHub API rate limit exceeded. Set GITHUB_TOKEN environment variable.')
212
- );
213
- } else {
214
- reject(new Error(`GitHub API error: ${res.statusCode}`));
215
- }
216
- });
217
- })
218
- .on('error', reject);
219
- });
220
-
221
- // Fetch raw file content
222
- const fetchRawFile = filePath =>
223
- new Promise((resolve, reject) => {
224
- const rawUrl = `https://raw.githubusercontent.com/${owner}/${repo}/${branch}/${filePath}`;
225
- https
226
- .get(rawUrl, res => {
227
- if (res.statusCode === 302 || res.statusCode === 301) {
228
- https
229
- .get(res.headers.location, res2 => {
230
- let data = '';
231
- res2.on('data', chunk => (data += chunk));
232
- res2.on('end', () => resolve(data));
233
- })
234
- .on('error', reject);
235
- return;
236
- }
237
- if (res.statusCode !== 200) {
238
- resolve(null); // File not found is OK
239
- return;
240
- }
241
- let data = '';
242
- res.on('data', chunk => (data += chunk));
243
- res.on('end', () => resolve(data));
244
- })
245
- .on('error', reject);
246
- });
247
-
248
- try {
249
- // Fetch repository metadata
250
- const repoData = await fetchGitHubAPI(`/repos/${owner}/${repo}`);
251
- result.metadata = {
252
- name: repoData.name,
253
- description: repoData.description,
254
- language: repoData.language,
255
- stars: repoData.stargazers_count,
256
- topics: repoData.topics || [],
257
- license: repoData.license?.spdx_id,
258
- defaultBranch: repoData.default_branch,
259
- updatedAt: repoData.updated_at,
260
- };
261
-
262
- // Fetch directory structure (root level)
263
- const treePath = subPath
264
- ? `/repos/${owner}/${repo}/contents/${subPath}`
265
- : `/repos/${owner}/${repo}/contents`;
266
- try {
267
- const contents = await fetchGitHubAPI(treePath);
268
- if (Array.isArray(contents)) {
269
- result.structure = contents.map(item => ({
270
- name: item.name,
271
- type: item.type,
272
- path: item.path,
273
- }));
274
- }
275
- } catch {
276
- // Ignore structure fetch errors
277
- }
278
-
279
- // Fetch key files for analysis
280
- const keyFiles = [
281
- 'README.md',
282
- 'package.json',
283
- 'Cargo.toml',
284
- 'pyproject.toml',
285
- 'go.mod',
286
- 'pom.xml',
287
- '.github/CODEOWNERS',
288
- 'ARCHITECTURE.md',
289
- 'CONTRIBUTING.md',
290
- 'docs/architecture.md',
291
- 'src/lib.rs',
292
- 'src/index.ts',
293
- 'src/main.ts',
294
- ];
295
-
296
- for (const file of keyFiles) {
297
- const filePath = subPath ? `${subPath}/${file}` : file;
298
- try {
299
- const content = await fetchRawFile(filePath);
300
- if (content) {
301
- result.files[file] = content.slice(0, 10000); // Limit content size
302
- }
303
- } catch {
304
- // Ignore individual file fetch errors
305
- }
306
- }
307
- } catch (err) {
308
- result.error = err.message;
309
- }
310
-
311
- return result;
312
- }
313
-
314
- /**
315
- * Fetch multiple GitHub repositories
316
- * @param {string[]} repos - Array of repository references
317
- * @returns {object[]} Array of repository data
318
- */
319
- async function fetchGitHubRepos(repos) {
320
- const results = [];
321
-
322
- for (const repoRef of repos) {
323
- console.log(chalk.cyan(` 📦 Fetching ${repoRef}...`));
324
- const repoData = await fetchGitHubRepo(repoRef);
325
-
326
- if (repoData.error) {
327
- console.log(chalk.yellow(` ⚠️ ${repoData.error}`));
328
- } else {
329
- console.log(
330
- chalk.green(
331
- ` ✓ ${repoData.metadata.name || repoData.repo} (${repoData.metadata.language || 'unknown'})`
332
- )
333
- );
334
- if (repoData.metadata.description) {
335
- console.log(chalk.gray(` ${repoData.metadata.description.slice(0, 80)}`));
336
- }
337
- }
338
-
339
- results.push(repoData);
340
- }
341
-
342
- return results;
343
- }
344
-
345
- /**
346
- * Analyze repositories for improvement suggestions
347
- * @param {object[]} repos - Array of fetched repository data
348
- * @returns {object} Analysis results with patterns and suggestions
349
- */
350
- function analyzeReposForImprovements(repos) {
351
- const analysis = {
352
- patterns: [],
353
- architectures: [],
354
- technologies: [],
355
- configurations: [],
356
- suggestions: [],
357
- };
358
-
359
- for (const repo of repos) {
360
- if (repo.error) continue;
361
-
362
- // Detect architecture patterns from structure
363
- const dirs = repo.structure.filter(s => s.type === 'dir').map(s => s.name);
364
- const files = repo.structure.filter(s => s.type === 'file').map(s => s.name);
365
-
366
- // Check for Clean Architecture
367
- if (dirs.some(d => ['domain', 'application', 'infrastructure', 'interface'].includes(d))) {
368
- analysis.architectures.push({
369
- repo: repo.repo,
370
- pattern: 'clean-architecture',
371
- evidence: dirs.filter(d =>
372
- ['domain', 'application', 'infrastructure', 'interface'].includes(d)
373
- ),
374
- });
375
- }
376
-
377
- // Check for Hexagonal Architecture
378
- if (dirs.some(d => ['adapters', 'ports', 'core', 'hexagon'].includes(d))) {
379
- analysis.architectures.push({
380
- repo: repo.repo,
381
- pattern: 'hexagonal',
382
- evidence: dirs.filter(d => ['adapters', 'ports', 'core', 'hexagon'].includes(d)),
383
- });
384
- }
385
-
386
- // Check for DDD patterns
387
- if (
388
- dirs.some(d =>
389
- ['aggregates', 'entities', 'valueobjects', 'repositories', 'services'].includes(
390
- d.toLowerCase()
391
- )
392
- )
393
- ) {
394
- analysis.patterns.push({
395
- repo: repo.repo,
396
- pattern: 'domain-driven-design',
397
- evidence: dirs,
398
- });
399
- }
400
-
401
- // Check for monorepo patterns
402
- if (
403
- dirs.includes('packages') ||
404
- dirs.includes('apps') ||
405
- files.includes('pnpm-workspace.yaml')
406
- ) {
407
- analysis.patterns.push({
408
- repo: repo.repo,
409
- pattern: 'monorepo',
410
- evidence: dirs.filter(d => ['packages', 'apps', 'libs'].includes(d)),
411
- });
412
- }
413
-
414
- // Analyze package.json for technologies
415
- if (repo.files['package.json']) {
416
- try {
417
- const pkg = JSON.parse(repo.files['package.json']);
418
- const deps = { ...pkg.dependencies, ...pkg.devDependencies };
419
-
420
- // Detect frameworks
421
- if (deps['react']) analysis.technologies.push({ repo: repo.repo, tech: 'react' });
422
- if (deps['vue']) analysis.technologies.push({ repo: repo.repo, tech: 'vue' });
423
- if (deps['@angular/core']) analysis.technologies.push({ repo: repo.repo, tech: 'angular' });
424
- if (deps['express']) analysis.technologies.push({ repo: repo.repo, tech: 'express' });
425
- if (deps['fastify']) analysis.technologies.push({ repo: repo.repo, tech: 'fastify' });
426
- if (deps['next']) analysis.technologies.push({ repo: repo.repo, tech: 'nextjs' });
427
- if (deps['typescript']) analysis.technologies.push({ repo: repo.repo, tech: 'typescript' });
428
-
429
- // Detect testing frameworks
430
- if (deps['jest']) analysis.configurations.push({ repo: repo.repo, config: 'jest' });
431
- if (deps['vitest']) analysis.configurations.push({ repo: repo.repo, config: 'vitest' });
432
- if (deps['mocha']) analysis.configurations.push({ repo: repo.repo, config: 'mocha' });
433
-
434
- // Detect linting/formatting
435
- if (deps['eslint']) analysis.configurations.push({ repo: repo.repo, config: 'eslint' });
436
- if (deps['prettier']) analysis.configurations.push({ repo: repo.repo, config: 'prettier' });
437
- if (deps['biome']) analysis.configurations.push({ repo: repo.repo, config: 'biome' });
438
- } catch {
439
- // Ignore JSON parse errors
440
- }
441
- }
442
-
443
- // Analyze Cargo.toml for Rust patterns
444
- if (repo.files['Cargo.toml']) {
445
- const cargo = repo.files['Cargo.toml'];
446
- if (cargo.includes('[workspace]')) {
447
- analysis.patterns.push({ repo: repo.repo, pattern: 'rust-workspace' });
448
- }
449
- if (cargo.includes('tokio')) analysis.technologies.push({ repo: repo.repo, tech: 'tokio' });
450
- if (cargo.includes('actix')) analysis.technologies.push({ repo: repo.repo, tech: 'actix' });
451
- if (cargo.includes('axum')) analysis.technologies.push({ repo: repo.repo, tech: 'axum' });
452
- }
453
-
454
- // Analyze pyproject.toml for Python patterns
455
- if (repo.files['pyproject.toml']) {
456
- const pyproj = repo.files['pyproject.toml'];
457
- if (pyproj.includes('fastapi'))
458
- analysis.technologies.push({ repo: repo.repo, tech: 'fastapi' });
459
- if (pyproj.includes('django'))
460
- analysis.technologies.push({ repo: repo.repo, tech: 'django' });
461
- if (pyproj.includes('flask')) analysis.technologies.push({ repo: repo.repo, tech: 'flask' });
462
- if (pyproj.includes('pytest'))
463
- analysis.configurations.push({ repo: repo.repo, config: 'pytest' });
464
- }
465
-
466
- // Extract README insights
467
- if (repo.files['README.md']) {
468
- const readme = repo.files['README.md'];
469
-
470
- // Check for badges that indicate good practices
471
- if (readme.includes('coverage')) {
472
- analysis.suggestions.push({
473
- repo: repo.repo,
474
- suggestion: 'code-coverage',
475
- description: 'Implements code coverage tracking',
476
- });
477
- }
478
- if (readme.includes('CI/CD') || readme.includes('Actions')) {
479
- analysis.suggestions.push({
480
- repo: repo.repo,
481
- suggestion: 'ci-cd',
482
- description: 'Has CI/CD pipeline configured',
483
- });
484
- }
485
- }
486
- }
487
-
488
- // Generate improvement suggestions based on analysis
489
- if (analysis.architectures.length > 0) {
490
- const archCounts = {};
491
- for (const arch of analysis.architectures) {
492
- archCounts[arch.pattern] = (archCounts[arch.pattern] || 0) + 1;
493
- }
494
- const mostCommon = Object.entries(archCounts).sort((a, b) => b[1] - a[1])[0];
495
- if (mostCommon) {
496
- analysis.suggestions.push({
497
- type: 'architecture',
498
- suggestion: `Consider using ${mostCommon[0]} pattern`,
499
- count: mostCommon[1],
500
- repos: analysis.architectures.filter(a => a.pattern === mostCommon[0]).map(a => a.repo),
501
- });
502
- }
503
- }
504
-
505
- if (analysis.technologies.length > 0) {
506
- const techCounts = {};
507
- for (const tech of analysis.technologies) {
508
- techCounts[tech.tech] = (techCounts[tech.tech] || 0) + 1;
509
- }
510
- const popular = Object.entries(techCounts)
511
- .sort((a, b) => b[1] - a[1])
512
- .slice(0, 3);
513
- for (const [tech, count] of popular) {
514
- analysis.suggestions.push({
515
- type: 'technology',
516
- suggestion: `Consider using ${tech}`,
517
- count,
518
- repos: analysis.technologies.filter(t => t.tech === tech).map(t => t.repo),
519
- });
520
- }
521
- }
522
-
523
- return analysis;
524
- }
525
-
526
- /**
527
- * Save reference repositories analysis to steering/references/
528
- * @param {object[]} repos - Fetched repository data
529
- * @param {object} analysis - Analysis results
530
- * @param {string} projectPath - Target project path
531
- * @returns {string} Created file path
532
- */
533
- async function saveReferenceRepos(repos, analysis, projectPath) {
534
- const refsDir = path.join(projectPath, 'steering', 'references');
535
- await fs.ensureDir(refsDir);
536
-
537
- const timestamp = new Date().toISOString().split('T')[0];
538
- const filename = `github-references-${timestamp}.md`;
539
-
540
- // Build markdown content
541
- let content = `# GitHub Reference Repositories
542
-
543
- > Analyzed on ${new Date().toISOString()}
544
-
545
- ## Referenced Repositories
546
-
547
- `;
548
-
549
- for (const repo of repos) {
550
- if (repo.error) {
551
- content += `### ❌ ${repo.source}\n\n`;
552
- content += `Error: ${repo.error}\n\n`;
553
- continue;
554
- }
555
-
556
- content += `### ${repo.metadata.name || repo.repo}\n\n`;
557
- content += `- **URL**: ${repo.url}\n`;
558
- content += `- **Language**: ${repo.metadata.language || 'Unknown'}\n`;
559
- content += `- **Stars**: ${repo.metadata.stars || 0}\n`;
560
- if (repo.metadata.description) {
561
- content += `- **Description**: ${repo.metadata.description}\n`;
562
- }
563
- if (repo.metadata.topics && repo.metadata.topics.length > 0) {
564
- content += `- **Topics**: ${repo.metadata.topics.join(', ')}\n`;
565
- }
566
- if (repo.metadata.license) {
567
- content += `- **License**: ${repo.metadata.license}\n`;
568
- }
569
- content += '\n';
570
-
571
- // Structure
572
- if (repo.structure.length > 0) {
573
- content += '**Directory Structure:**\n\n';
574
- content += '```\n';
575
- for (const item of repo.structure.slice(0, 20)) {
576
- content += `${item.type === 'dir' ? '📁' : '📄'} ${item.name}\n`;
577
- }
578
- if (repo.structure.length > 20) {
579
- content += `... and ${repo.structure.length - 20} more items\n`;
580
- }
581
- content += '```\n\n';
582
- }
583
- }
584
-
585
- // Analysis section
586
- content += `## Analysis Results
587
-
588
- ### Architecture Patterns Detected
589
-
590
- `;
591
-
592
- if (analysis.architectures.length > 0) {
593
- for (const arch of analysis.architectures) {
594
- content += `- **${arch.pattern}** in \`${arch.repo}\`\n`;
595
- content += ` - Evidence: ${arch.evidence.join(', ')}\n`;
596
- }
597
- } else {
598
- content += '_No specific architecture patterns detected_\n';
599
- }
600
-
601
- content += `\n### Design Patterns
602
-
603
- `;
604
-
605
- if (analysis.patterns.length > 0) {
606
- for (const pattern of analysis.patterns) {
607
- content += `- **${pattern.pattern}** in \`${pattern.repo}\`\n`;
608
- }
609
- } else {
610
- content += '_No specific design patterns detected_\n';
611
- }
612
-
613
- content += `\n### Technologies Used
614
-
615
- `;
616
-
617
- if (analysis.technologies.length > 0) {
618
- const techByRepo = {};
619
- for (const tech of analysis.technologies) {
620
- if (!techByRepo[tech.repo]) techByRepo[tech.repo] = [];
621
- techByRepo[tech.repo].push(tech.tech);
622
- }
623
- for (const [repo, techs] of Object.entries(techByRepo)) {
624
- content += `- **${repo}**: ${techs.join(', ')}\n`;
625
- }
626
- } else {
627
- content += '_No specific technologies detected_\n';
628
- }
629
-
630
- content += `\n### Configurations
631
-
632
- `;
633
-
634
- if (analysis.configurations.length > 0) {
635
- const configByRepo = {};
636
- for (const config of analysis.configurations) {
637
- if (!configByRepo[config.repo]) configByRepo[config.repo] = [];
638
- configByRepo[config.repo].push(config.config);
639
- }
640
- for (const [repo, configs] of Object.entries(configByRepo)) {
641
- content += `- **${repo}**: ${configs.join(', ')}\n`;
642
- }
643
- } else {
644
- content += '_No specific configurations detected_\n';
645
- }
646
-
647
- content += `\n## Improvement Suggestions
648
-
649
- Based on the referenced repositories, consider the following improvements:
650
-
651
- `;
652
-
653
- if (analysis.suggestions.length > 0) {
654
- let i = 1;
655
- for (const suggestion of analysis.suggestions) {
656
- if (suggestion.type === 'architecture') {
657
- content += `${i}. **Architecture**: ${suggestion.suggestion}\n`;
658
- content += ` - Found in ${suggestion.count} repository(ies): ${suggestion.repos.join(', ')}\n\n`;
659
- } else if (suggestion.type === 'technology') {
660
- content += `${i}. **Technology**: ${suggestion.suggestion}\n`;
661
- content += ` - Used by ${suggestion.count} repository(ies): ${suggestion.repos.join(', ')}\n\n`;
662
- } else {
663
- content += `${i}. **${suggestion.suggestion}**: ${suggestion.description}\n`;
664
- content += ` - Found in: ${suggestion.repo}\n\n`;
665
- }
666
- i++;
667
- }
668
- } else {
669
- content += '_No specific suggestions generated_\n';
670
- }
671
-
672
- content += `
673
- ---
674
- *Generated by MUSUBI SDD - GitHub Reference Analysis*
675
- `;
676
-
677
- await fs.writeFile(path.join(refsDir, filename), content);
678
- return filename;
679
- }
680
-
681
- /**
682
- * Detect specification format from content and filename
683
- */
684
- function detectSpecFormat(content, source) {
685
- const ext = path.extname(source).toLowerCase();
686
- if (ext === '.json') return 'json';
687
- if (ext === '.yaml' || ext === '.yml') return 'yaml';
688
- if (ext === '.md') return 'markdown';
689
- if (ext === '.rst') return 'rst';
690
- if (ext === '.html') return 'html';
691
-
692
- // Try to detect from content
693
- if (content.trim().startsWith('{')) return 'json';
694
- if (content.includes('openapi:') || content.includes('swagger:')) return 'openapi';
695
- if (content.includes('asyncapi:')) return 'asyncapi';
696
- if (content.includes('# ')) return 'markdown';
697
-
698
- return 'text';
699
- }
700
-
701
- /**
702
- * Extract summary from specification content
703
- */
704
- function extractSpecSummary(content) {
705
- // Extract first heading and description
706
- const lines = content.split('\n').slice(0, 50);
707
- let title = '';
708
- let description = '';
709
-
710
- for (const line of lines) {
711
- if (!title && line.startsWith('# ')) {
712
- title = line.replace('# ', '').trim();
713
- } else if (title && !description && line.trim() && !line.startsWith('#')) {
714
- description = line.trim().slice(0, 200);
715
- break;
716
- }
717
- }
718
-
719
- return { title, description };
720
- }
721
-
722
- /**
723
- * Save external specification reference to steering/specs/
724
- */
725
- async function saveSpecReference(specResult, projectPath) {
726
- const specsDir = path.join(projectPath, 'steering', 'specs');
727
- await fs.ensureDir(specsDir);
728
-
729
- // Create spec reference file
730
- const timestamp = new Date().toISOString().split('T')[0];
731
- const safeName = specResult.metadata.summary?.title
732
- ? specResult.metadata.summary.title
733
- .toLowerCase()
734
- .replace(/[^a-z0-9]+/g, '-')
735
- .slice(0, 50)
736
- : 'external-spec';
737
- const filename = `${safeName}-${timestamp}.md`;
738
-
739
- const refContent = `# External Specification Reference
740
-
741
- ## Source Information
742
-
743
- - **Type**: ${specResult.type}
744
- - **Source**: ${specResult.source}
745
- - **Format**: ${specResult.metadata.format || 'unknown'}
746
- - **Fetched**: ${specResult.metadata.fetchedAt || specResult.metadata.readAt || 'N/A'}
747
-
748
- ## Summary
749
-
750
- ${specResult.metadata.summary?.title ? `**Title**: ${specResult.metadata.summary.title}` : ''}
751
- ${specResult.metadata.summary?.description ? `\n**Description**: ${specResult.metadata.summary.description}` : ''}
752
-
753
- ## Integration Notes
754
-
755
- This specification is used as a reference for:
756
- - Requirements analysis
757
- - Architecture design
758
- - API design
759
- - Compliance validation
760
-
761
- ## Original Content
762
-
763
- \`\`\`${specResult.metadata.format || 'text'}
764
- ${specResult.content?.slice(0, 5000) || 'Content not available'}${specResult.content?.length > 5000 ? '\n\n... (truncated, see original source)' : ''}
765
- \`\`\`
766
-
767
- ---
768
- *Generated by MUSUBI SDD - External Specification Reference*
769
- `;
770
-
771
- await fs.writeFile(path.join(specsDir, filename), refContent);
772
- return filename;
773
- }
774
-
775
- /**
776
- * Language recommendation engine
777
- * @param {object} requirements - User's answers about app types, performance, expertise
778
- * @returns {Array} Recommended languages with reasons
779
- */
780
- function recommendLanguages(requirements) {
781
- const { appTypes, performanceNeeds, teamExpertise } = requirements;
782
- const scores = {};
783
- const reasons = {};
784
-
785
- // Initialize scores
786
- const allLangs = [
787
- 'javascript',
788
- 'python',
789
- 'rust',
790
- 'go',
791
- 'java',
792
- 'csharp',
793
- 'cpp',
794
- 'swift',
795
- 'ruby',
796
- 'php',
797
- ];
798
- for (const lang of allLangs) {
799
- scores[lang] = 0;
800
- reasons[lang] = [];
801
- }
802
-
803
- // Score by application type
804
- const appTypeScores = {
805
- 'web-frontend': { javascript: 10, reason: 'Best ecosystem for web frontend' },
806
- 'web-backend': {
807
- javascript: 6,
808
- python: 7,
809
- go: 8,
810
- rust: 7,
811
- java: 7,
812
- csharp: 6,
813
- ruby: 5,
814
- php: 5,
815
- reason: 'Strong backend frameworks',
816
- },
817
- cli: { rust: 9, go: 9, python: 6, reason: 'Fast startup, single binary' },
818
- desktop: { rust: 7, csharp: 8, cpp: 7, swift: 6, java: 6, reason: 'Native GUI support' },
819
- mobile: { swift: 9, java: 8, javascript: 6, reason: 'Mobile platform support' },
820
- data: { python: 10, rust: 6, reason: 'Rich data science ecosystem' },
821
- ml: { python: 10, rust: 5, cpp: 5, reason: 'ML/AI libraries and frameworks' },
822
- embedded: { rust: 10, cpp: 9, reason: 'Memory safety, no runtime' },
823
- game: { cpp: 9, csharp: 8, rust: 6, reason: 'Game engine support' },
824
- systems: { rust: 10, go: 8, cpp: 9, reason: 'Systems programming' },
825
- };
826
-
827
- for (const appType of appTypes || []) {
828
- const typeScores = appTypeScores[appType];
829
- if (typeScores) {
830
- for (const [lang, score] of Object.entries(typeScores)) {
831
- if (typeof score === 'number') {
832
- scores[lang] += score;
833
- if (!reasons[lang].includes(typeScores.reason)) {
834
- reasons[lang].push(typeScores.reason);
835
- }
836
- }
837
- }
838
- }
839
- }
840
-
841
- // Score by performance needs
842
- if (performanceNeeds === 'high') {
843
- scores.rust += 8;
844
- scores.go += 6;
845
- scores.cpp += 7;
846
- reasons.rust.push('High performance, zero-cost abstractions');
847
- reasons.go.push('Fast compilation, efficient runtime');
848
- } else if (performanceNeeds === 'rapid') {
849
- scores.python += 5;
850
- scores.javascript += 5;
851
- scores.ruby += 4;
852
- reasons.python.push('Rapid development, extensive libraries');
853
- reasons.javascript.push('Fast iteration, universal runtime');
854
- }
855
-
856
- // Boost by team expertise
857
- for (const lang of teamExpertise || []) {
858
- scores[lang] += 5;
859
- reasons[lang].push('Team has expertise');
860
- }
861
-
862
- // Sort and return top recommendations
863
- const sorted = Object.entries(scores)
864
- .filter(([, score]) => score > 0)
865
- .sort((a, b) => b[1] - a[1])
866
- .slice(0, 3);
867
-
868
- const langInfo = {
869
- javascript: { name: 'JavaScript/TypeScript', emoji: '🟨' },
870
- python: { name: 'Python', emoji: '🐍' },
871
- rust: { name: 'Rust', emoji: '🦀' },
872
- go: { name: 'Go', emoji: '🐹' },
873
- java: { name: 'Java/Kotlin', emoji: '☕' },
874
- csharp: { name: 'C#/.NET', emoji: '💜' },
875
- cpp: { name: 'C/C++', emoji: '⚙️' },
876
- swift: { name: 'Swift', emoji: '🍎' },
877
- ruby: { name: 'Ruby', emoji: '💎' },
878
- php: { name: 'PHP', emoji: '🐘' },
879
- };
880
-
881
- return sorted.map(([lang]) => ({
882
- value: lang,
883
- name: langInfo[lang].name,
884
- emoji: langInfo[lang].emoji,
885
- reason: reasons[lang].slice(0, 2).join('; ') || 'General purpose',
886
- score: scores[lang],
887
- }));
888
- }
889
-
890
41
  /**
891
42
  * Main initialization function
892
43
  * @param {object} agent - Agent definition from registry
@@ -1389,7 +540,7 @@ async function main(agent, agentKey, options = {}) {
1389
540
 
1390
541
  const cmdExample = agent.commands.requirements.replace(' <feature>', ' authentication');
1391
542
  console.log(chalk.gray(` 4. Try commands: ${cmdExample}\n`));
1392
- console.log(chalk.cyan('Learn more: https://github.com/your-org/musubi\n'));
543
+ console.log(chalk.cyan('Learn more: https://github.com/nahisaho/MUSUBI\n'));
1393
544
  }
1394
545
 
1395
546
  async function copySkill(skillName, agent) {
@@ -1878,453 +1029,6 @@ if __name__ == "__main__":
1878
1029
  }
1879
1030
  }
1880
1031
 
1881
- /**
1882
- * Generate language-specific dependency files for single-package projects
1883
- */
1884
- async function generateDependencyFiles(primaryLang, answers) {
1885
- const projectName = answers.projectName || 'my-project';
1886
- const safeName = projectName.toLowerCase().replace(/[^a-z0-9-]/g, '-');
1887
-
1888
- if (primaryLang === 'javascript') {
1889
- // Check if package.json already exists
1890
- if (!(await fs.pathExists('package.json'))) {
1891
- const packageJson = {
1892
- name: safeName,
1893
- version: '0.1.0',
1894
- description: answers.description || '',
1895
- type: 'module',
1896
- main: 'dist/index.js',
1897
- types: 'dist/index.d.ts',
1898
- scripts: {
1899
- build: 'tsc',
1900
- test: 'jest',
1901
- lint: 'eslint src/',
1902
- format: 'prettier --write .',
1903
- },
1904
- devDependencies: {
1905
- typescript: '^5.0.0',
1906
- '@types/node': '^20.0.0',
1907
- jest: '^29.0.0',
1908
- '@types/jest': '^29.0.0',
1909
- eslint: '^9.0.0',
1910
- prettier: '^3.0.0',
1911
- },
1912
- };
1913
- await fs.writeFile('package.json', JSON.stringify(packageJson, null, 2) + '\n');
1914
- }
1915
-
1916
- // Generate tsconfig.json
1917
- if (!(await fs.pathExists('tsconfig.json'))) {
1918
- const tsconfig = {
1919
- compilerOptions: {
1920
- target: 'ES2022',
1921
- module: 'NodeNext',
1922
- moduleResolution: 'NodeNext',
1923
- declaration: true,
1924
- outDir: './dist',
1925
- rootDir: './src',
1926
- strict: true,
1927
- esModuleInterop: true,
1928
- skipLibCheck: true,
1929
- forceConsistentCasingInFileNames: true,
1930
- },
1931
- include: ['src/**/*'],
1932
- exclude: ['node_modules', 'dist'],
1933
- };
1934
- await fs.writeFile('tsconfig.json', JSON.stringify(tsconfig, null, 2) + '\n');
1935
- }
1936
- } else if (primaryLang === 'rust') {
1937
- // Check if Cargo.toml already exists
1938
- if (!(await fs.pathExists('Cargo.toml'))) {
1939
- const cargoToml = `[package]
1940
- name = "${safeName}"
1941
- version = "0.1.0"
1942
- edition = "2021"
1943
- description = "${answers.description || ''}"
1944
- license = "MIT"
1945
-
1946
- [dependencies]
1947
- tokio = { version = "1", features = ["full"] }
1948
- serde = { version = "1", features = ["derive"] }
1949
- serde_json = "1"
1950
- thiserror = "1"
1951
- tracing = "0.1"
1952
-
1953
- [dev-dependencies]
1954
- tokio-test = "0.4"
1955
- `;
1956
- await fs.writeFile('Cargo.toml', cargoToml);
1957
-
1958
- // Create src/main.rs or src/lib.rs
1959
- await fs.ensureDir('src');
1960
- if (!(await fs.pathExists('src/main.rs')) && !(await fs.pathExists('src/lib.rs'))) {
1961
- const mainRs = `//! ${answers.description || projectName}
1962
-
1963
- fn main() {
1964
- println!("Hello from ${projectName}!");
1965
- }
1966
- `;
1967
- await fs.writeFile('src/main.rs', mainRs);
1968
- }
1969
- }
1970
- } else if (primaryLang === 'python') {
1971
- // Check if pyproject.toml already exists
1972
- if (!(await fs.pathExists('pyproject.toml'))) {
1973
- const pyprojectToml = `[project]
1974
- name = "${safeName}"
1975
- version = "0.1.0"
1976
- description = "${answers.description || ''}"
1977
- requires-python = ">=3.11"
1978
- dependencies = []
1979
-
1980
- [project.optional-dependencies]
1981
- dev = [
1982
- "pytest>=7.0",
1983
- "ruff>=0.1",
1984
- "mypy>=1.0",
1985
- ]
1986
-
1987
- [tool.ruff]
1988
- line-length = 100
1989
- target-version = "py311"
1990
-
1991
- [tool.ruff.lint]
1992
- select = ["E", "F", "I", "N", "W"]
1993
-
1994
- [tool.mypy]
1995
- python_version = "3.11"
1996
- strict = true
1997
-
1998
- [tool.pytest.ini_options]
1999
- testpaths = ["tests"]
2000
- `;
2001
- await fs.writeFile('pyproject.toml', pyprojectToml);
2002
-
2003
- // Create src directory and __init__.py
2004
- const srcDir = `src/${safeName.replace(/-/g, '_')}`;
2005
- await fs.ensureDir(srcDir);
2006
- if (!(await fs.pathExists(`${srcDir}/__init__.py`))) {
2007
- await fs.writeFile(
2008
- `${srcDir}/__init__.py`,
2009
- `"""${answers.description || projectName}"""\n\n__version__ = "0.1.0"\n`
2010
- );
2011
- }
2012
- }
2013
- } else if (primaryLang === 'go') {
2014
- // Check if go.mod already exists
2015
- if (!(await fs.pathExists('go.mod'))) {
2016
- const goMod = `module github.com/${safeName}
2017
-
2018
- go 1.21
2019
-
2020
- require (
2021
- // Add dependencies here
2022
- )
2023
- `;
2024
- await fs.writeFile('go.mod', goMod);
2025
-
2026
- // Create main.go
2027
- await fs.ensureDir('cmd');
2028
- if (!(await fs.pathExists('cmd/main.go'))) {
2029
- const mainGo = `package main
2030
-
2031
- import "fmt"
2032
-
2033
- func main() {
2034
- fmt.Println("Hello from ${projectName}!")
2035
- }
2036
- `;
2037
- await fs.writeFile('cmd/main.go', mainGo);
2038
- }
2039
- }
2040
- } else if (primaryLang === 'java') {
2041
- // Generate pom.xml for Maven
2042
- if (!(await fs.pathExists('pom.xml'))) {
2043
- const pomXml = `<?xml version="1.0" encoding="UTF-8"?>
2044
- <project xmlns="http://maven.apache.org/POM/4.0.0"
2045
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
2046
- xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
2047
- <modelVersion>4.0.0</modelVersion>
2048
-
2049
- <groupId>com.example</groupId>
2050
- <artifactId>${safeName}</artifactId>
2051
- <version>0.1.0</version>
2052
- <packaging>jar</packaging>
2053
-
2054
- <name>${projectName}</name>
2055
- <description>${answers.description || ''}</description>
2056
-
2057
- <properties>
2058
- <maven.compiler.source>21</maven.compiler.source>
2059
- <maven.compiler.target>21</maven.compiler.target>
2060
- <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
2061
- </properties>
2062
-
2063
- <dependencies>
2064
- <dependency>
2065
- <groupId>org.junit.jupiter</groupId>
2066
- <artifactId>junit-jupiter</artifactId>
2067
- <version>5.10.0</version>
2068
- <scope>test</scope>
2069
- </dependency>
2070
- </dependencies>
2071
- </project>
2072
- `;
2073
- await fs.writeFile('pom.xml', pomXml);
2074
- }
2075
- } else if (primaryLang === 'csharp') {
2076
- // Generate .csproj file
2077
- const csprojPath = `${projectName}.csproj`;
2078
- if (!(await fs.pathExists(csprojPath))) {
2079
- const csproj = `<Project Sdk="Microsoft.NET.Sdk">
2080
-
2081
- <PropertyGroup>
2082
- <OutputType>Exe</OutputType>
2083
- <TargetFramework>net8.0</TargetFramework>
2084
- <ImplicitUsings>enable</ImplicitUsings>
2085
- <Nullable>enable</Nullable>
2086
- </PropertyGroup>
2087
-
2088
- <ItemGroup>
2089
- <PackageReference Include="Microsoft.Extensions.Logging" Version="8.0.0" />
2090
- </ItemGroup>
2091
-
2092
- </Project>
2093
- `;
2094
- await fs.writeFile(csprojPath, csproj);
2095
- }
2096
- }
2097
- }
2098
-
2099
- /**
2100
- * Generate language-specific tech.md content
2101
- */
2102
- function generateTechMd(languages, answers, _locale) {
2103
- const langInfo = {
2104
- javascript: {
2105
- name: 'JavaScript/TypeScript',
2106
- version: 'ES2022+ / TypeScript 5.0+',
2107
- runtime: 'Node.js 20+ LTS, Bun, Deno',
2108
- packageManager: 'npm, pnpm, yarn',
2109
- frameworks: 'React, Vue, Next.js, Express, Fastify',
2110
- testing: 'Jest, Vitest, Playwright',
2111
- },
2112
- python: {
2113
- name: 'Python',
2114
- version: '3.11+',
2115
- runtime: 'CPython, PyPy',
2116
- packageManager: 'pip, poetry, uv',
2117
- frameworks: 'FastAPI, Django, Flask',
2118
- testing: 'pytest, unittest',
2119
- },
2120
- rust: {
2121
- name: 'Rust',
2122
- version: '1.75+ stable',
2123
- runtime: 'Native binary',
2124
- packageManager: 'Cargo',
2125
- frameworks: 'Axum, Actix-web, Tokio',
2126
- testing: 'cargo test, criterion',
2127
- },
2128
- go: {
2129
- name: 'Go',
2130
- version: '1.21+',
2131
- runtime: 'Native binary',
2132
- packageManager: 'Go modules',
2133
- frameworks: 'Gin, Echo, Chi',
2134
- testing: 'go test, testify',
2135
- },
2136
- java: {
2137
- name: 'Java/Kotlin',
2138
- version: 'Java 21 LTS / Kotlin 1.9+',
2139
- runtime: 'JVM, GraalVM',
2140
- packageManager: 'Maven, Gradle',
2141
- frameworks: 'Spring Boot, Quarkus, Ktor',
2142
- testing: 'JUnit 5, Kotest',
2143
- },
2144
- csharp: {
2145
- name: 'C#/.NET',
2146
- version: '.NET 8+',
2147
- runtime: '.NET Runtime',
2148
- packageManager: 'NuGet',
2149
- frameworks: 'ASP.NET Core, MAUI',
2150
- testing: 'xUnit, NUnit',
2151
- },
2152
- cpp: {
2153
- name: 'C/C++',
2154
- version: 'C++20',
2155
- runtime: 'Native binary',
2156
- packageManager: 'vcpkg, Conan',
2157
- frameworks: 'Qt, Boost',
2158
- testing: 'GoogleTest, Catch2',
2159
- },
2160
- swift: {
2161
- name: 'Swift',
2162
- version: '5.9+',
2163
- runtime: 'Native binary',
2164
- packageManager: 'Swift Package Manager',
2165
- frameworks: 'SwiftUI, Vapor',
2166
- testing: 'XCTest',
2167
- },
2168
- ruby: {
2169
- name: 'Ruby',
2170
- version: '3.2+',
2171
- runtime: 'CRuby, JRuby',
2172
- packageManager: 'Bundler, RubyGems',
2173
- frameworks: 'Rails, Sinatra',
2174
- testing: 'RSpec, Minitest',
2175
- },
2176
- php: {
2177
- name: 'PHP',
2178
- version: '8.2+',
2179
- runtime: 'PHP-FPM, Swoole',
2180
- packageManager: 'Composer',
2181
- frameworks: 'Laravel, Symfony',
2182
- testing: 'PHPUnit, Pest',
2183
- },
2184
- };
2185
-
2186
- const isUndecided = languages[0] === 'undecided';
2187
- const date = new Date().toISOString().split('T')[0];
2188
-
2189
- if (isUndecided) {
2190
- return `# Technology Stack
2191
-
2192
- **Project**: ${answers.projectName}
2193
- **Last Updated**: ${date}
2194
- **Status**: Technology stack to be determined
2195
-
2196
- ---
2197
-
2198
- ## Overview
2199
-
2200
- The technology stack for this project has not yet been decided. This document will be updated once the technical decisions are made.
2201
-
2202
- ## Decision Criteria
2203
-
2204
- When selecting technologies, consider:
2205
-
2206
- 1. **Application Type**: What type of application is being built?
2207
- 2. **Performance Requirements**: What are the performance constraints?
2208
- 3. **Team Expertise**: What technologies is the team familiar with?
2209
- 4. **Ecosystem**: What libraries and tools are available?
2210
- 5. **Long-term Maintainability**: How well-supported is the technology?
2211
-
2212
- ## Candidates Under Consideration
2213
-
2214
- | Aspect | Options | Decision |
2215
- |--------|---------|----------|
2216
- | Primary Language | TBD | ⏳ Pending |
2217
- | Web Framework | TBD | ⏳ Pending |
2218
- | Database | TBD | ⏳ Pending |
2219
- | Hosting | TBD | ⏳ Pending |
2220
-
2221
- ## Next Steps
2222
-
2223
- 1. [ ] Define functional requirements
2224
- 2. [ ] Identify performance constraints
2225
- 3. [ ] Evaluate team skills
2226
- 4. [ ] Create proof-of-concept
2227
- 5. [ ] Make final decision and update this document
2228
-
2229
- ---
2230
-
2231
- *Run \`musubi steering\` to update this document after decisions are made.*
2232
- `;
2233
- }
2234
-
2235
- // Generate tech.md for selected languages
2236
- const primaryLang = languages[0];
2237
- const primary = langInfo[primaryLang] || { name: primaryLang, version: 'Latest' };
2238
-
2239
- let languageTable = `### Programming Languages
2240
-
2241
- | Language | Version | Role | Notes |
2242
- |----------|---------|------|-------|
2243
- `;
2244
-
2245
- for (let i = 0; i < languages.length; i++) {
2246
- const lang = languages[i];
2247
- const info = langInfo[lang] || { name: lang, version: 'Latest' };
2248
- const role = i === 0 ? 'Primary' : 'Secondary';
2249
- languageTable += `| ${info.name} | ${info.version} | ${role} | ${info.runtime || ''} |\n`;
2250
- }
2251
-
2252
- let frameworksSection = '';
2253
- for (const lang of languages) {
2254
- const info = langInfo[lang];
2255
- if (info && info.frameworks) {
2256
- frameworksSection += `
2257
- ### ${info.name} Ecosystem
2258
-
2259
- - **Package Manager**: ${info.packageManager}
2260
- - **Frameworks**: ${info.frameworks}
2261
- - **Testing**: ${info.testing}
2262
- `;
2263
- }
2264
- }
2265
-
2266
- return `# Technology Stack
2267
-
2268
- **Project**: ${answers.projectName}
2269
- **Last Updated**: ${date}
2270
- **Version**: 0.1.0
2271
-
2272
- ---
2273
-
2274
- ## Overview
2275
-
2276
- ${answers.description}
2277
-
2278
- ---
2279
-
2280
- ## Primary Technologies
2281
-
2282
- ${languageTable}
2283
- ${frameworksSection}
2284
-
2285
- ---
2286
-
2287
- ## Development Environment
2288
-
2289
- ### Required Tools
2290
-
2291
- - Primary language runtime (see above)
2292
- - Git 2.40+
2293
- - IDE: VS Code / JetBrains / Neovim
2294
-
2295
- ### Recommended Extensions
2296
-
2297
- - Language-specific LSP
2298
- - Linter/Formatter integration
2299
- - Test runner integration
2300
-
2301
- ---
2302
-
2303
- ## Architecture Decisions
2304
-
2305
- | Decision | Choice | Rationale |
2306
- |----------|--------|-----------|
2307
- | Primary Language | ${primary.name} | Selected during project initialization |
2308
- | Package Manager | ${primary.packageManager || 'TBD'} | Standard for ${primary.name} |
2309
-
2310
- ---
2311
-
2312
- ## Dependencies
2313
-
2314
- ### Production Dependencies
2315
-
2316
- *To be documented as dependencies are added.*
2317
-
2318
- ### Development Dependencies
2319
-
2320
- *To be documented as dependencies are added.*
2321
-
2322
- ---
2323
-
2324
- *Generated by MUSUBI SDD - Update with \`musubi steering\`*
2325
- `;
2326
- }
2327
-
2328
1032
  async function createConstitution() {
2329
1033
  const constitutionTemplate = path.join(SHARED_TEMPLATE_DIR, 'constitution', 'constitution.md');
2330
1034
  await fs.copy(constitutionTemplate, 'steering/rules/constitution.md');
@@ -2376,7 +1080,7 @@ ${skillsSection}
2376
1080
 
2377
1081
  ### Learn More
2378
1082
 
2379
- - [MUSUBI Documentation](https://github.com/your-org/musubi)
1083
+ - [MUSUBI Documentation](https://github.com/nahisaho/MUSUBI)
2380
1084
  - [Constitutional Governance](steering/rules/constitution.md)
2381
1085
  - [8-Stage SDD Workflow](steering/rules/workflow.md)
2382
1086