musubi-sdd 5.1.0 → 5.6.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (232) hide show
  1. package/README.ja.md +106 -48
  2. package/README.md +110 -32
  3. package/bin/musubi-analyze.js +74 -67
  4. package/bin/musubi-browser.js +27 -26
  5. package/bin/musubi-change.js +48 -47
  6. package/bin/musubi-checkpoint.js +10 -7
  7. package/bin/musubi-convert.js +25 -25
  8. package/bin/musubi-costs.js +27 -10
  9. package/bin/musubi-gui.js +52 -46
  10. package/bin/musubi-init.js +1952 -10
  11. package/bin/musubi-orchestrate.js +327 -239
  12. package/bin/musubi-remember.js +69 -56
  13. package/bin/musubi-resolve.js +53 -45
  14. package/bin/musubi-trace.js +51 -22
  15. package/bin/musubi-validate.js +39 -30
  16. package/bin/musubi-workflow.js +33 -34
  17. package/bin/musubi.js +39 -2
  18. package/package.json +1 -1
  19. package/src/agents/agent-loop.js +94 -95
  20. package/src/agents/agentic/code-generator.js +119 -109
  21. package/src/agents/agentic/code-reviewer.js +105 -108
  22. package/src/agents/agentic/index.js +4 -4
  23. package/src/agents/browser/action-executor.js +13 -13
  24. package/src/agents/browser/ai-comparator.js +11 -10
  25. package/src/agents/browser/context-manager.js +6 -6
  26. package/src/agents/browser/index.js +5 -5
  27. package/src/agents/browser/nl-parser.js +31 -46
  28. package/src/agents/browser/screenshot.js +2 -2
  29. package/src/agents/browser/test-generator.js +6 -4
  30. package/src/agents/function-tool.js +71 -65
  31. package/src/agents/index.js +7 -7
  32. package/src/agents/schema-generator.js +98 -94
  33. package/src/analyzers/ast-extractor.js +158 -146
  34. package/src/analyzers/codegraph-auto-update.js +858 -0
  35. package/src/analyzers/complexity-analyzer.js +536 -0
  36. package/src/analyzers/context-optimizer.js +241 -126
  37. package/src/analyzers/impact-analyzer.js +1 -1
  38. package/src/analyzers/large-project-analyzer.js +766 -0
  39. package/src/analyzers/repository-map.js +77 -81
  40. package/src/analyzers/security-analyzer.js +19 -11
  41. package/src/analyzers/stuck-detector.js +19 -17
  42. package/src/converters/index.js +78 -57
  43. package/src/converters/ir/types.js +12 -12
  44. package/src/converters/parsers/musubi-parser.js +134 -126
  45. package/src/converters/parsers/openapi-parser.js +70 -53
  46. package/src/converters/parsers/speckit-parser.js +239 -175
  47. package/src/converters/writers/musubi-writer.js +123 -118
  48. package/src/converters/writers/speckit-writer.js +124 -113
  49. package/src/generators/rust-migration-generator.js +512 -0
  50. package/src/gui/public/index.html +1365 -1211
  51. package/src/gui/server.js +41 -40
  52. package/src/gui/services/file-watcher.js +23 -8
  53. package/src/gui/services/project-scanner.js +26 -20
  54. package/src/gui/services/replanning-service.js +27 -23
  55. package/src/gui/services/traceability-service.js +8 -8
  56. package/src/gui/services/workflow-service.js +14 -7
  57. package/src/index.js +151 -0
  58. package/src/integrations/cicd.js +90 -104
  59. package/src/integrations/codegraph-mcp.js +643 -0
  60. package/src/integrations/documentation.js +142 -103
  61. package/src/integrations/examples.js +95 -80
  62. package/src/integrations/github-client.js +17 -17
  63. package/src/integrations/index.js +5 -5
  64. package/src/integrations/mcp/index.js +21 -21
  65. package/src/integrations/mcp/mcp-context-provider.js +76 -78
  66. package/src/integrations/mcp/mcp-discovery.js +74 -72
  67. package/src/integrations/mcp/mcp-tool-registry.js +99 -94
  68. package/src/integrations/mcp-connector.js +70 -66
  69. package/src/integrations/platforms.js +50 -49
  70. package/src/integrations/tool-discovery.js +37 -31
  71. package/src/llm-providers/anthropic-provider.js +11 -11
  72. package/src/llm-providers/base-provider.js +16 -18
  73. package/src/llm-providers/copilot-provider.js +22 -19
  74. package/src/llm-providers/index.js +26 -25
  75. package/src/llm-providers/ollama-provider.js +11 -11
  76. package/src/llm-providers/openai-provider.js +12 -12
  77. package/src/managers/agent-memory.js +36 -24
  78. package/src/managers/checkpoint-manager.js +4 -8
  79. package/src/managers/delta-spec.js +19 -19
  80. package/src/managers/index.js +13 -4
  81. package/src/managers/memory-condenser.js +35 -45
  82. package/src/managers/repo-skill-manager.js +57 -31
  83. package/src/managers/skill-loader.js +25 -22
  84. package/src/managers/skill-tools.js +36 -72
  85. package/src/managers/workflow.js +30 -22
  86. package/src/monitoring/cost-tracker.js +48 -46
  87. package/src/monitoring/incident-manager.js +116 -106
  88. package/src/monitoring/index.js +144 -134
  89. package/src/monitoring/observability.js +75 -62
  90. package/src/monitoring/quality-dashboard.js +45 -41
  91. package/src/monitoring/release-manager.js +63 -53
  92. package/src/orchestration/agent-skill-binding.js +39 -47
  93. package/src/orchestration/error-handler.js +65 -107
  94. package/src/orchestration/guardrails/base-guardrail.js +26 -24
  95. package/src/orchestration/guardrails/guardrail-rules.js +50 -64
  96. package/src/orchestration/guardrails/index.js +5 -5
  97. package/src/orchestration/guardrails/input-guardrail.js +58 -45
  98. package/src/orchestration/guardrails/output-guardrail.js +104 -81
  99. package/src/orchestration/guardrails/safety-check.js +79 -79
  100. package/src/orchestration/index.js +38 -55
  101. package/src/orchestration/mcp-tool-adapters.js +96 -99
  102. package/src/orchestration/orchestration-engine.js +21 -21
  103. package/src/orchestration/pattern-registry.js +60 -45
  104. package/src/orchestration/patterns/auto.js +34 -47
  105. package/src/orchestration/patterns/group-chat.js +59 -65
  106. package/src/orchestration/patterns/handoff.js +67 -65
  107. package/src/orchestration/patterns/human-in-loop.js +51 -72
  108. package/src/orchestration/patterns/nested.js +25 -40
  109. package/src/orchestration/patterns/sequential.js +35 -34
  110. package/src/orchestration/patterns/swarm.js +63 -56
  111. package/src/orchestration/patterns/triage.js +150 -109
  112. package/src/orchestration/reasoning/index.js +9 -9
  113. package/src/orchestration/reasoning/planning-engine.js +143 -140
  114. package/src/orchestration/reasoning/reasoning-engine.js +206 -144
  115. package/src/orchestration/reasoning/self-correction.js +121 -128
  116. package/src/orchestration/replanning/adaptive-goal-modifier.js +107 -112
  117. package/src/orchestration/replanning/alternative-generator.js +37 -42
  118. package/src/orchestration/replanning/config.js +63 -59
  119. package/src/orchestration/replanning/goal-progress-tracker.js +98 -100
  120. package/src/orchestration/replanning/index.js +24 -20
  121. package/src/orchestration/replanning/plan-evaluator.js +49 -50
  122. package/src/orchestration/replanning/plan-monitor.js +32 -28
  123. package/src/orchestration/replanning/proactive-path-optimizer.js +175 -178
  124. package/src/orchestration/replanning/replan-history.js +33 -26
  125. package/src/orchestration/replanning/replanning-engine.js +106 -108
  126. package/src/orchestration/skill-executor.js +107 -109
  127. package/src/orchestration/skill-registry.js +85 -89
  128. package/src/orchestration/workflow-examples.js +228 -231
  129. package/src/orchestration/workflow-executor.js +65 -68
  130. package/src/orchestration/workflow-orchestrator.js +72 -73
  131. package/src/phase4-integration.js +47 -40
  132. package/src/phase5-integration.js +89 -30
  133. package/src/reporters/coverage-report.js +82 -30
  134. package/src/reporters/hierarchical-reporter.js +498 -0
  135. package/src/reporters/traceability-matrix-report.js +29 -20
  136. package/src/resolvers/issue-resolver.js +43 -31
  137. package/src/steering/advanced-validation.js +133 -124
  138. package/src/steering/auto-updater.js +60 -73
  139. package/src/steering/index.js +6 -6
  140. package/src/steering/quality-metrics.js +41 -35
  141. package/src/steering/steering-auto-update.js +83 -86
  142. package/src/steering/steering-validator.js +98 -106
  143. package/src/steering/template-constraints.js +53 -54
  144. package/src/templates/agents/claude-code/CLAUDE.md +32 -32
  145. package/src/templates/agents/claude-code/skills/agent-assistant/SKILL.md +13 -5
  146. package/src/templates/agents/claude-code/skills/ai-ml-engineer/mlops-guide.md +23 -23
  147. package/src/templates/agents/claude-code/skills/ai-ml-engineer/model-card-template.md +60 -41
  148. package/src/templates/agents/claude-code/skills/api-designer/api-patterns.md +27 -19
  149. package/src/templates/agents/claude-code/skills/api-designer/openapi-template.md +11 -7
  150. package/src/templates/agents/claude-code/skills/bug-hunter/SKILL.md +4 -3
  151. package/src/templates/agents/claude-code/skills/bug-hunter/root-cause-analysis.md +37 -15
  152. package/src/templates/agents/claude-code/skills/change-impact-analyzer/dependency-graph-patterns.md +36 -42
  153. package/src/templates/agents/claude-code/skills/change-impact-analyzer/impact-analysis-template.md +69 -60
  154. package/src/templates/agents/claude-code/skills/cloud-architect/aws-patterns.md +31 -38
  155. package/src/templates/agents/claude-code/skills/cloud-architect/azure-patterns.md +28 -23
  156. package/src/templates/agents/claude-code/skills/code-reviewer/SKILL.md +61 -0
  157. package/src/templates/agents/claude-code/skills/code-reviewer/best-practices.md +27 -0
  158. package/src/templates/agents/claude-code/skills/code-reviewer/review-checklist.md +29 -10
  159. package/src/templates/agents/claude-code/skills/code-reviewer/review-standards.md +29 -24
  160. package/src/templates/agents/claude-code/skills/constitution-enforcer/SKILL.md +8 -6
  161. package/src/templates/agents/claude-code/skills/constitution-enforcer/constitutional-articles.md +62 -26
  162. package/src/templates/agents/claude-code/skills/constitution-enforcer/phase-minus-one-gates.md +35 -16
  163. package/src/templates/agents/claude-code/skills/database-administrator/backup-recovery.md +27 -17
  164. package/src/templates/agents/claude-code/skills/database-administrator/tuning-guide.md +25 -20
  165. package/src/templates/agents/claude-code/skills/database-schema-designer/schema-patterns.md +39 -22
  166. package/src/templates/agents/claude-code/skills/devops-engineer/ci-cd-templates.md +25 -22
  167. package/src/templates/agents/claude-code/skills/issue-resolver/SKILL.md +24 -21
  168. package/src/templates/agents/claude-code/skills/orchestrator/SKILL.md +148 -63
  169. package/src/templates/agents/claude-code/skills/orchestrator/patterns.md +35 -16
  170. package/src/templates/agents/claude-code/skills/orchestrator/selection-matrix.md +69 -64
  171. package/src/templates/agents/claude-code/skills/performance-engineer/optimization-playbook.md +47 -47
  172. package/src/templates/agents/claude-code/skills/performance-optimizer/SKILL.md +69 -0
  173. package/src/templates/agents/claude-code/skills/performance-optimizer/benchmark-template.md +63 -45
  174. package/src/templates/agents/claude-code/skills/performance-optimizer/optimization-patterns.md +33 -35
  175. package/src/templates/agents/claude-code/skills/project-manager/SKILL.md +7 -6
  176. package/src/templates/agents/claude-code/skills/project-manager/agile-ceremonies.md +47 -28
  177. package/src/templates/agents/claude-code/skills/project-manager/project-templates.md +94 -78
  178. package/src/templates/agents/claude-code/skills/quality-assurance/SKILL.md +20 -17
  179. package/src/templates/agents/claude-code/skills/quality-assurance/qa-plan-template.md +63 -49
  180. package/src/templates/agents/claude-code/skills/release-coordinator/SKILL.md +5 -5
  181. package/src/templates/agents/claude-code/skills/release-coordinator/feature-flag-guide.md +30 -26
  182. package/src/templates/agents/claude-code/skills/release-coordinator/release-plan-template.md +67 -35
  183. package/src/templates/agents/claude-code/skills/requirements-analyst/ears-format.md +54 -42
  184. package/src/templates/agents/claude-code/skills/requirements-analyst/validation-rules.md +36 -33
  185. package/src/templates/agents/claude-code/skills/security-auditor/SKILL.md +77 -19
  186. package/src/templates/agents/claude-code/skills/security-auditor/audit-checklists.md +24 -24
  187. package/src/templates/agents/claude-code/skills/security-auditor/owasp-top-10.md +61 -20
  188. package/src/templates/agents/claude-code/skills/security-auditor/vulnerability-patterns.md +43 -11
  189. package/src/templates/agents/claude-code/skills/site-reliability-engineer/SKILL.md +1 -0
  190. package/src/templates/agents/claude-code/skills/site-reliability-engineer/incident-response-template.md +55 -25
  191. package/src/templates/agents/claude-code/skills/site-reliability-engineer/observability-patterns.md +78 -68
  192. package/src/templates/agents/claude-code/skills/site-reliability-engineer/slo-sli-guide.md +73 -53
  193. package/src/templates/agents/claude-code/skills/software-developer/solid-principles.md +83 -37
  194. package/src/templates/agents/claude-code/skills/software-developer/test-first-workflow.md +38 -31
  195. package/src/templates/agents/claude-code/skills/steering/SKILL.md +1 -0
  196. package/src/templates/agents/claude-code/skills/steering/auto-update-rules.md +31 -0
  197. package/src/templates/agents/claude-code/skills/system-architect/adr-template.md +25 -7
  198. package/src/templates/agents/claude-code/skills/system-architect/c4-model-guide.md +74 -61
  199. package/src/templates/agents/claude-code/skills/technical-writer/doc-templates/documentation-templates.md +70 -52
  200. package/src/templates/agents/claude-code/skills/test-engineer/SKILL.md +2 -0
  201. package/src/templates/agents/claude-code/skills/test-engineer/ears-test-mapping.md +75 -71
  202. package/src/templates/agents/claude-code/skills/test-engineer/test-types.md +85 -63
  203. package/src/templates/agents/claude-code/skills/traceability-auditor/coverage-matrix-template.md +39 -36
  204. package/src/templates/agents/claude-code/skills/traceability-auditor/gap-detection-rules.md +22 -17
  205. package/src/templates/agents/claude-code/skills/ui-ux-designer/SKILL.md +1 -0
  206. package/src/templates/agents/claude-code/skills/ui-ux-designer/accessibility-guidelines.md +49 -75
  207. package/src/templates/agents/claude-code/skills/ui-ux-designer/design-system-components.md +71 -59
  208. package/src/templates/agents/codex/AGENTS.md +74 -42
  209. package/src/templates/agents/cursor/AGENTS.md +74 -42
  210. package/src/templates/agents/gemini-cli/GEMINI.md +74 -42
  211. package/src/templates/agents/github-copilot/AGENTS.md +83 -51
  212. package/src/templates/agents/qwen-code/QWEN.md +74 -42
  213. package/src/templates/agents/windsurf/AGENTS.md +74 -42
  214. package/src/templates/architectures/README.md +41 -0
  215. package/src/templates/architectures/clean-architecture/README.md +113 -0
  216. package/src/templates/architectures/event-driven/README.md +162 -0
  217. package/src/templates/architectures/hexagonal/README.md +130 -0
  218. package/src/templates/index.js +6 -1
  219. package/src/templates/locale-manager.js +16 -16
  220. package/src/templates/shared/delta-spec-template.md +20 -13
  221. package/src/templates/shared/github-actions/musubi-issue-resolver.yml +5 -5
  222. package/src/templates/shared/github-actions/musubi-security-check.yml +3 -3
  223. package/src/templates/shared/github-actions/musubi-validate.yml +4 -4
  224. package/src/templates/shared/steering/structure.md +95 -0
  225. package/src/templates/skills/browser-agent.md +21 -16
  226. package/src/templates/skills/web-gui.md +8 -0
  227. package/src/templates/template-constraints.js +50 -53
  228. package/src/validators/advanced-validation.js +30 -36
  229. package/src/validators/constitutional-validator.js +77 -73
  230. package/src/validators/critic-system.js +49 -59
  231. package/src/validators/delta-format.js +59 -55
  232. package/src/validators/traceability-validator.js +7 -11
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * MUSUBI Writer
3
- *
3
+ *
4
4
  * Writes Intermediate Representation (IR) to MUSUBI project structure
5
5
  */
6
6
 
@@ -21,7 +21,7 @@ async function writeMusubiProject(ir, outputPath, options = {}) {
21
21
  const { dryRun = false, force = false, preserveRaw = false, verbose = false } = options;
22
22
  const warnings = [];
23
23
  let filesWritten = 0;
24
-
24
+
25
25
  // Create base directories
26
26
  const dirs = [
27
27
  path.join(outputPath, 'steering'),
@@ -30,13 +30,13 @@ async function writeMusubiProject(ir, outputPath, options = {}) {
30
30
  path.join(outputPath, 'steering', 'memories'),
31
31
  path.join(outputPath, 'storage', 'specs'),
32
32
  ];
33
-
33
+
34
34
  if (!dryRun) {
35
35
  for (const dir of dirs) {
36
36
  await fs.ensureDir(dir);
37
37
  }
38
38
  }
39
-
39
+
40
40
  // Write project.yml
41
41
  const projectYmlPath = path.join(outputPath, 'steering', 'project.yml');
42
42
  const projectYml = generateProjectYml(ir);
@@ -45,7 +45,7 @@ async function writeMusubiProject(ir, outputPath, options = {}) {
45
45
  filesWritten++;
46
46
  }
47
47
  if (verbose) console.log(` Writing: ${projectYmlPath}`);
48
-
48
+
49
49
  // Write constitution
50
50
  const constitutionPath = path.join(outputPath, 'steering', 'rules', 'constitution.md');
51
51
  const constitution = generateConstitution(ir.constitution, preserveRaw);
@@ -54,7 +54,7 @@ async function writeMusubiProject(ir, outputPath, options = {}) {
54
54
  filesWritten++;
55
55
  }
56
56
  if (verbose) console.log(` Writing: ${constitutionPath}`);
57
-
57
+
58
58
  // Write product.md
59
59
  const productPath = path.join(outputPath, 'steering', 'product.md');
60
60
  const product = generateProduct(ir);
@@ -63,7 +63,7 @@ async function writeMusubiProject(ir, outputPath, options = {}) {
63
63
  filesWritten++;
64
64
  }
65
65
  if (verbose) console.log(` Writing: ${productPath}`);
66
-
66
+
67
67
  // Write structure.md
68
68
  const structurePath = path.join(outputPath, 'steering', 'structure.md');
69
69
  const structure = generateStructure(ir);
@@ -72,7 +72,7 @@ async function writeMusubiProject(ir, outputPath, options = {}) {
72
72
  filesWritten++;
73
73
  }
74
74
  if (verbose) console.log(` Writing: ${structurePath}`);
75
-
75
+
76
76
  // Write tech.md
77
77
  const techPath = path.join(outputPath, 'steering', 'tech.md');
78
78
  const tech = generateTech(ir);
@@ -81,15 +81,20 @@ async function writeMusubiProject(ir, outputPath, options = {}) {
81
81
  filesWritten++;
82
82
  }
83
83
  if (verbose) console.log(` Writing: ${techPath}`);
84
-
84
+
85
85
  // Write features
86
86
  for (const feature of ir.features) {
87
87
  const featurePath = path.join(outputPath, 'storage', 'specs', feature.id);
88
- const result = await writeFeature(feature, featurePath, { dryRun, force, preserveRaw, verbose });
88
+ const result = await writeFeature(feature, featurePath, {
89
+ dryRun,
90
+ force,
91
+ preserveRaw,
92
+ verbose,
93
+ });
89
94
  filesWritten += result.filesWritten;
90
95
  warnings.push(...result.warnings);
91
96
  }
92
-
97
+
93
98
  // Write templates
94
99
  for (const template of ir.templates) {
95
100
  const templatePath = path.join(outputPath, 'steering', 'templates', `${template.name}.md`);
@@ -99,7 +104,7 @@ async function writeMusubiProject(ir, outputPath, options = {}) {
99
104
  }
100
105
  if (verbose) console.log(` Writing: ${templatePath}`);
101
106
  }
102
-
107
+
103
108
  // Write memories
104
109
  for (const memory of ir.memories) {
105
110
  const memoryPath = path.join(outputPath, 'steering', 'memories', `${memory.category}.md`);
@@ -110,18 +115,18 @@ async function writeMusubiProject(ir, outputPath, options = {}) {
110
115
  }
111
116
  if (verbose) console.log(` Writing: ${memoryPath}`);
112
117
  }
113
-
118
+
114
119
  return { filesWritten, warnings };
115
120
  }
116
121
 
117
122
  /**
118
123
  * Write file with optional force overwrite
119
- * @param {string} filePath
120
- * @param {string} content
121
- * @param {boolean} force
124
+ * @param {string} filePath
125
+ * @param {string} content
126
+ * @param {boolean} force
122
127
  */
123
128
  async function writeFile(filePath, content, force = false) {
124
- if (await fs.pathExists(filePath) && !force) {
129
+ if ((await fs.pathExists(filePath)) && !force) {
125
130
  throw new Error(`File exists: ${filePath} (use --force to overwrite)`);
126
131
  }
127
132
  await fs.writeFile(filePath, content, 'utf-8');
@@ -129,7 +134,7 @@ async function writeFile(filePath, content, force = false) {
129
134
 
130
135
  /**
131
136
  * Generate project.yml content
132
- * @param {import('../ir/types').ProjectIR} ir
137
+ * @param {import('../ir/types').ProjectIR} ir
133
138
  * @returns {string}
134
139
  */
135
140
  function generateProjectYml(ir) {
@@ -150,34 +155,34 @@ function generateProjectYml(ir) {
150
155
  status: f.status,
151
156
  })),
152
157
  };
153
-
158
+
154
159
  return yaml.dump(projectData, { lineWidth: 100 });
155
160
  }
156
161
 
157
162
  /**
158
163
  * Generate constitution.md content
159
- * @param {import('../ir/types').ConstitutionIR} constitution
160
- * @param {boolean} preserveRaw
164
+ * @param {import('../ir/types').ConstitutionIR} constitution
165
+ * @param {boolean} preserveRaw
161
166
  * @returns {string}
162
167
  */
163
168
  function generateConstitution(constitution, preserveRaw = false) {
164
169
  const lines = [];
165
-
170
+
166
171
  lines.push('# MUSUBI Constitution');
167
172
  lines.push('');
168
173
  lines.push('The fundamental principles governing this project.');
169
174
  lines.push('');
170
-
175
+
171
176
  // Write articles
172
177
  for (const article of constitution.articles) {
173
178
  lines.push(`## Article ${article.number}: ${article.name}`);
174
179
  lines.push('');
175
-
180
+
176
181
  if (article.description) {
177
182
  lines.push(article.description);
178
183
  lines.push('');
179
184
  }
180
-
185
+
181
186
  if (article.rules && article.rules.length > 0) {
182
187
  lines.push('### Rules');
183
188
  lines.push('');
@@ -186,20 +191,20 @@ function generateConstitution(constitution, preserveRaw = false) {
186
191
  }
187
192
  lines.push('');
188
193
  }
189
-
194
+
190
195
  if (article.mappedFrom) {
191
196
  lines.push(`> Mapped from: ${article.mappedFrom}`);
192
197
  lines.push('');
193
198
  }
194
199
  }
195
-
200
+
196
201
  // Write governance
197
202
  if (constitution.governance) {
198
203
  lines.push('## Governance');
199
204
  lines.push('');
200
205
  lines.push(`Version: ${constitution.governance.version}`);
201
206
  lines.push('');
202
-
207
+
203
208
  if (constitution.governance.rules && constitution.governance.rules.length > 0) {
204
209
  for (const rule of constitution.governance.rules) {
205
210
  lines.push(`- ${rule}`);
@@ -207,7 +212,7 @@ function generateConstitution(constitution, preserveRaw = false) {
207
212
  lines.push('');
208
213
  }
209
214
  }
210
-
215
+
211
216
  // Preserve raw content if requested
212
217
  if (preserveRaw && constitution.rawContent) {
213
218
  lines.push('---');
@@ -218,18 +223,18 @@ function generateConstitution(constitution, preserveRaw = false) {
218
223
  lines.push(constitution.rawContent);
219
224
  lines.push('```');
220
225
  }
221
-
226
+
222
227
  return lines.join('\n');
223
228
  }
224
229
 
225
230
  /**
226
231
  * Generate product.md content
227
- * @param {import('../ir/types').ProjectIR} ir
232
+ * @param {import('../ir/types').ProjectIR} ir
228
233
  * @returns {string}
229
234
  */
230
235
  function generateProduct(ir) {
231
236
  const lines = [];
232
-
237
+
233
238
  lines.push(`# ${ir.metadata.name}`);
234
239
  lines.push('');
235
240
  lines.push('## Overview');
@@ -238,27 +243,27 @@ function generateProduct(ir) {
238
243
  lines.push('');
239
244
  lines.push('## Features');
240
245
  lines.push('');
241
-
246
+
242
247
  for (const feature of ir.features) {
243
248
  lines.push(`- **${feature.name}** (${feature.id}) - ${feature.status}`);
244
249
  }
245
250
  lines.push('');
246
-
251
+
247
252
  lines.push('## Version History');
248
253
  lines.push('');
249
254
  lines.push(`- ${ir.metadata.version} - Initial conversion from ${ir.metadata.sourceFormat}`);
250
-
255
+
251
256
  return lines.join('\n');
252
257
  }
253
258
 
254
259
  /**
255
260
  * Generate structure.md content
256
- * @param {import('../ir/types').ProjectIR} ir
261
+ * @param {import('../ir/types').ProjectIR} ir
257
262
  * @returns {string}
258
263
  */
259
264
  function generateStructure(ir) {
260
265
  const lines = [];
261
-
266
+
262
267
  lines.push('# Project Structure');
263
268
  lines.push('');
264
269
  lines.push('## Directory Layout');
@@ -276,39 +281,39 @@ function generateStructure(ir) {
276
281
  lines.push('');
277
282
  lines.push('storage/');
278
283
  lines.push('└── specs/');
279
-
284
+
280
285
  for (const feature of ir.features) {
281
286
  lines.push(` └── ${feature.id}/`);
282
287
  lines.push(' ├── spec.md');
283
288
  lines.push(' ├── plan.md');
284
289
  lines.push(' └── tasks.md');
285
290
  }
286
-
291
+
287
292
  lines.push('```');
288
-
293
+
289
294
  return lines.join('\n');
290
295
  }
291
296
 
292
297
  /**
293
298
  * Generate tech.md content
294
- * @param {import('../ir/types').ProjectIR} ir
299
+ * @param {import('../ir/types').ProjectIR} ir
295
300
  * @returns {string}
296
301
  */
297
302
  function generateTech(ir) {
298
303
  const lines = [];
299
-
304
+
300
305
  lines.push('# Technology Stack');
301
306
  lines.push('');
302
-
307
+
303
308
  // Extract technical context from first feature with a plan
304
309
  const featureWithPlan = ir.features.find(f => f.plan);
305
-
310
+
306
311
  if (featureWithPlan && featureWithPlan.plan) {
307
312
  const tech = featureWithPlan.plan.technicalContext;
308
-
313
+
309
314
  lines.push('## Core Technologies');
310
315
  lines.push('');
311
-
316
+
312
317
  if (tech.language) {
313
318
  lines.push(`- **Language**: ${tech.language}${tech.version ? ` ${tech.version}` : ''}`);
314
319
  }
@@ -321,7 +326,7 @@ function generateTech(ir) {
321
326
  if (tech.targetPlatform) {
322
327
  lines.push(`- **Platform**: ${tech.targetPlatform}`);
323
328
  }
324
-
329
+
325
330
  if (tech.dependencies && tech.dependencies.length > 0) {
326
331
  lines.push('');
327
332
  lines.push('## Dependencies');
@@ -335,26 +340,26 @@ function generateTech(ir) {
335
340
  lines.push('');
336
341
  lines.push('> Technology stack to be defined based on project requirements.');
337
342
  }
338
-
343
+
339
344
  return lines.join('\n');
340
345
  }
341
346
 
342
347
  /**
343
348
  * Write a feature to MUSUBI format
344
- * @param {import('../ir/types').FeatureIR} feature
345
- * @param {string} featurePath
346
- * @param {Object} options
349
+ * @param {import('../ir/types').FeatureIR} feature
350
+ * @param {string} featurePath
351
+ * @param {Object} options
347
352
  * @returns {Promise<{filesWritten: number, warnings: string[]}>}
348
353
  */
349
354
  async function writeFeature(feature, featurePath, options = {}) {
350
355
  const { dryRun = false, force = false, preserveRaw = false, verbose = false } = options;
351
356
  const warnings = [];
352
357
  let filesWritten = 0;
353
-
358
+
354
359
  if (!dryRun) {
355
360
  await fs.ensureDir(featurePath);
356
361
  }
357
-
362
+
358
363
  // Write spec.md
359
364
  const specPath = path.join(featurePath, 'spec.md');
360
365
  const specContent = generateSpec(feature, preserveRaw);
@@ -363,7 +368,7 @@ async function writeFeature(feature, featurePath, options = {}) {
363
368
  filesWritten++;
364
369
  }
365
370
  if (verbose) console.log(` Writing: ${specPath}`);
366
-
371
+
367
372
  // Write plan.md
368
373
  if (feature.plan) {
369
374
  const planPath = path.join(featurePath, 'plan.md');
@@ -374,7 +379,7 @@ async function writeFeature(feature, featurePath, options = {}) {
374
379
  }
375
380
  if (verbose) console.log(` Writing: ${planPath}`);
376
381
  }
377
-
382
+
378
383
  // Write tasks.md
379
384
  if (feature.tasks && feature.tasks.length > 0) {
380
385
  const tasksPath = path.join(featurePath, 'tasks.md');
@@ -385,7 +390,7 @@ async function writeFeature(feature, featurePath, options = {}) {
385
390
  }
386
391
  if (verbose) console.log(` Writing: ${tasksPath}`);
387
392
  }
388
-
393
+
389
394
  // Write research.md
390
395
  if (feature.research) {
391
396
  const researchPath = path.join(featurePath, 'research.md');
@@ -396,7 +401,7 @@ async function writeFeature(feature, featurePath, options = {}) {
396
401
  }
397
402
  if (verbose) console.log(` Writing: ${researchPath}`);
398
403
  }
399
-
404
+
400
405
  // Write data-model.md
401
406
  if (feature.dataModel) {
402
407
  const dataModelPath = path.join(featurePath, 'data-model.md');
@@ -407,14 +412,14 @@ async function writeFeature(feature, featurePath, options = {}) {
407
412
  }
408
413
  if (verbose) console.log(` Writing: ${dataModelPath}`);
409
414
  }
410
-
415
+
411
416
  // Write contracts
412
417
  if (feature.contracts && feature.contracts.length > 0) {
413
418
  const contractsPath = path.join(featurePath, 'contracts');
414
419
  if (!dryRun) {
415
420
  await fs.ensureDir(contractsPath);
416
421
  }
417
-
422
+
418
423
  for (const contract of feature.contracts) {
419
424
  const contractFile = path.join(contractsPath, `${contract.name}.md`);
420
425
  const contractContent = contract.rawContent || generateContract(contract);
@@ -425,33 +430,33 @@ async function writeFeature(feature, featurePath, options = {}) {
425
430
  if (verbose) console.log(` Writing: ${contractFile}`);
426
431
  }
427
432
  }
428
-
433
+
429
434
  return { filesWritten, warnings };
430
435
  }
431
436
 
432
437
  /**
433
438
  * Generate spec.md content (MUSUBI format with EARS)
434
- * @param {import('../ir/types').FeatureIR} feature
435
- * @param {boolean} preserveRaw
439
+ * @param {import('../ir/types').FeatureIR} feature
440
+ * @param {boolean} preserveRaw
436
441
  * @returns {string}
437
442
  */
438
443
  function generateSpec(feature, preserveRaw = false) {
439
444
  const lines = [];
440
445
  const spec = feature.specification;
441
-
446
+
442
447
  lines.push(`# ${spec.title || feature.name}`);
443
448
  lines.push('');
444
-
449
+
445
450
  if (spec.description) {
446
451
  lines.push(spec.description);
447
452
  lines.push('');
448
453
  }
449
-
454
+
450
455
  // Write requirements (EARS format)
451
456
  if (spec.requirements && spec.requirements.length > 0) {
452
457
  lines.push('## Requirements');
453
458
  lines.push('');
454
-
459
+
455
460
  for (const req of spec.requirements) {
456
461
  lines.push(`### ${req.id}: ${req.title || 'Requirement'}`);
457
462
  lines.push('');
@@ -460,7 +465,7 @@ function generateSpec(feature, preserveRaw = false) {
460
465
  lines.push('');
461
466
  lines.push(`**Statement**: ${req.statement}`);
462
467
  lines.push('');
463
-
468
+
464
469
  if (req.acceptanceCriteria && req.acceptanceCriteria.length > 0) {
465
470
  lines.push('**Acceptance Criteria**:');
466
471
  for (const ac of req.acceptanceCriteria) {
@@ -468,14 +473,14 @@ function generateSpec(feature, preserveRaw = false) {
468
473
  }
469
474
  lines.push('');
470
475
  }
471
-
476
+
472
477
  if (req.mappedFromUserStory) {
473
478
  lines.push(`> Converted from User Story: ${req.mappedFromUserStory}`);
474
479
  lines.push('');
475
480
  }
476
481
  }
477
482
  }
478
-
483
+
479
484
  // Write success criteria
480
485
  if (spec.successCriteria && spec.successCriteria.length > 0) {
481
486
  lines.push('## Success Criteria');
@@ -485,7 +490,7 @@ function generateSpec(feature, preserveRaw = false) {
485
490
  }
486
491
  lines.push('');
487
492
  }
488
-
493
+
489
494
  // Preserve raw content if requested
490
495
  if (preserveRaw && spec.rawContent) {
491
496
  lines.push('---');
@@ -496,33 +501,33 @@ function generateSpec(feature, preserveRaw = false) {
496
501
  lines.push(spec.rawContent);
497
502
  lines.push('```');
498
503
  }
499
-
504
+
500
505
  return lines.join('\n');
501
506
  }
502
507
 
503
508
  /**
504
509
  * Generate plan.md content
505
- * @param {import('../ir/types').PlanIR} plan
506
- * @param {boolean} preserveRaw
510
+ * @param {import('../ir/types').PlanIR} plan
511
+ * @param {boolean} preserveRaw
507
512
  * @returns {string}
508
513
  */
509
514
  function generatePlan(plan, preserveRaw = false) {
510
515
  const lines = [];
511
-
516
+
512
517
  lines.push('# Implementation Plan');
513
518
  lines.push('');
514
-
519
+
515
520
  if (plan.summary) {
516
521
  lines.push(plan.summary);
517
522
  lines.push('');
518
523
  }
519
-
524
+
520
525
  // Technical Context
521
526
  const tech = plan.technicalContext;
522
527
  if (tech && (tech.language || tech.framework)) {
523
528
  lines.push('## Technical Context');
524
529
  lines.push('');
525
-
530
+
526
531
  if (tech.language) {
527
532
  lines.push(`- **Language**: ${tech.language}${tech.version ? ` ${tech.version}` : ''}`);
528
533
  }
@@ -537,21 +542,21 @@ function generatePlan(plan, preserveRaw = false) {
537
542
  }
538
543
  lines.push('');
539
544
  }
540
-
545
+
541
546
  // Phases
542
547
  if (plan.phases && plan.phases.length > 0) {
543
548
  lines.push('## Phases');
544
549
  lines.push('');
545
-
550
+
546
551
  for (const phase of plan.phases) {
547
552
  lines.push(`### Phase ${phase.number}: ${phase.name}`);
548
553
  lines.push('');
549
-
554
+
550
555
  if (phase.purpose) {
551
556
  lines.push(phase.purpose);
552
557
  lines.push('');
553
558
  }
554
-
559
+
555
560
  if (phase.outputs && phase.outputs.length > 0) {
556
561
  lines.push('**Outputs**:');
557
562
  for (const output of phase.outputs) {
@@ -561,7 +566,7 @@ function generatePlan(plan, preserveRaw = false) {
561
566
  }
562
567
  }
563
568
  }
564
-
569
+
565
570
  // Preserve raw content if requested
566
571
  if (preserveRaw && plan.rawContent) {
567
572
  lines.push('---');
@@ -572,21 +577,21 @@ function generatePlan(plan, preserveRaw = false) {
572
577
  lines.push(plan.rawContent);
573
578
  lines.push('```');
574
579
  }
575
-
580
+
576
581
  return lines.join('\n');
577
582
  }
578
583
 
579
584
  /**
580
585
  * Generate tasks.md content (MUSUBI format)
581
- * @param {import('../ir/types').TaskIR[]} tasks
586
+ * @param {import('../ir/types').TaskIR[]} tasks
582
587
  * @returns {string}
583
588
  */
584
589
  function generateTasks(tasks) {
585
590
  const lines = [];
586
-
591
+
587
592
  lines.push('# Tasks');
588
593
  lines.push('');
589
-
594
+
590
595
  // Group by phase
591
596
  const phases = {};
592
597
  for (const task of tasks) {
@@ -596,17 +601,17 @@ function generateTasks(tasks) {
596
601
  }
597
602
  phases[phase].push(task);
598
603
  }
599
-
604
+
600
605
  for (const [phaseNum, phaseTasks] of Object.entries(phases)) {
601
606
  lines.push(`## Phase ${phaseNum}`);
602
607
  lines.push('');
603
-
608
+
604
609
  for (const task of phaseTasks) {
605
610
  const checkbox = task.completed ? '[x]' : '[ ]';
606
611
  let taskLine = `- ${checkbox} ${task.id}: ${task.description}`;
607
-
612
+
608
613
  lines.push(taskLine);
609
-
614
+
610
615
  // Add metadata as sub-items
611
616
  if (task.filePath) {
612
617
  lines.push(` - Path: ${task.filePath}`);
@@ -620,27 +625,27 @@ function generateTasks(tasks) {
620
625
  }
621
626
  lines.push('');
622
627
  }
623
-
628
+
624
629
  return lines.join('\n');
625
630
  }
626
631
 
627
632
  /**
628
633
  * Generate research.md content
629
- * @param {import('../ir/types').ResearchIR} research
630
- * @param {boolean} preserveRaw
634
+ * @param {import('../ir/types').ResearchIR} research
635
+ * @param {boolean} preserveRaw
631
636
  * @returns {string}
632
637
  */
633
638
  function generateResearch(research, preserveRaw = false) {
634
639
  const lines = [];
635
-
640
+
636
641
  lines.push('# Research');
637
642
  lines.push('');
638
-
643
+
639
644
  // Decisions
640
645
  if (research.decisions && research.decisions.length > 0) {
641
646
  lines.push('## Decisions');
642
647
  lines.push('');
643
-
648
+
644
649
  for (const decision of research.decisions) {
645
650
  lines.push(`### ${decision.topic}`);
646
651
  lines.push('');
@@ -651,16 +656,16 @@ function generateResearch(research, preserveRaw = false) {
651
656
  lines.push('');
652
657
  }
653
658
  }
654
-
659
+
655
660
  // Alternatives
656
661
  if (research.alternatives && research.alternatives.length > 0) {
657
662
  lines.push('## Alternatives Considered');
658
663
  lines.push('');
659
-
664
+
660
665
  for (const alt of research.alternatives) {
661
666
  lines.push(`### ${alt.name}`);
662
667
  lines.push('');
663
-
668
+
664
669
  if (alt.pros && alt.pros.length > 0) {
665
670
  lines.push('**Pros**:');
666
671
  for (const pro of alt.pros) {
@@ -668,7 +673,7 @@ function generateResearch(research, preserveRaw = false) {
668
673
  }
669
674
  lines.push('');
670
675
  }
671
-
676
+
672
677
  if (alt.cons && alt.cons.length > 0) {
673
678
  lines.push('**Cons**:');
674
679
  for (const con of alt.cons) {
@@ -676,7 +681,7 @@ function generateResearch(research, preserveRaw = false) {
676
681
  }
677
682
  lines.push('');
678
683
  }
679
-
684
+
680
685
  if (alt.rejected) {
681
686
  lines.push(`**Status**: Rejected`);
682
687
  if (alt.reason) {
@@ -686,7 +691,7 @@ function generateResearch(research, preserveRaw = false) {
686
691
  }
687
692
  }
688
693
  }
689
-
694
+
690
695
  // Preserve raw content if requested
691
696
  if (preserveRaw && research.rawContent) {
692
697
  lines.push('---');
@@ -697,36 +702,36 @@ function generateResearch(research, preserveRaw = false) {
697
702
  lines.push(research.rawContent);
698
703
  lines.push('```');
699
704
  }
700
-
705
+
701
706
  return lines.join('\n');
702
707
  }
703
708
 
704
709
  /**
705
710
  * Generate data-model.md content
706
- * @param {import('../ir/types').DataModelIR} dataModel
707
- * @param {boolean} preserveRaw
711
+ * @param {import('../ir/types').DataModelIR} dataModel
712
+ * @param {boolean} preserveRaw
708
713
  * @returns {string}
709
714
  */
710
715
  function generateDataModel(dataModel, preserveRaw = false) {
711
716
  const lines = [];
712
-
717
+
713
718
  lines.push('# Data Model');
714
719
  lines.push('');
715
-
720
+
716
721
  // Entities
717
722
  if (dataModel.entities && dataModel.entities.length > 0) {
718
723
  lines.push('## Entities');
719
724
  lines.push('');
720
-
725
+
721
726
  for (const entity of dataModel.entities) {
722
727
  lines.push(`### ${entity.name}`);
723
728
  lines.push('');
724
-
729
+
725
730
  if (entity.description) {
726
731
  lines.push(entity.description);
727
732
  lines.push('');
728
733
  }
729
-
734
+
730
735
  if (entity.fields && entity.fields.length > 0) {
731
736
  lines.push('**Fields**:');
732
737
  for (const field of entity.fields) {
@@ -743,18 +748,18 @@ function generateDataModel(dataModel, preserveRaw = false) {
743
748
  }
744
749
  }
745
750
  }
746
-
751
+
747
752
  // Relationships
748
753
  if (dataModel.relationships && dataModel.relationships.length > 0) {
749
754
  lines.push('## Relationships');
750
755
  lines.push('');
751
-
756
+
752
757
  for (const rel of dataModel.relationships) {
753
758
  lines.push(`- ${rel.from} → ${rel.to} (${rel.type})`);
754
759
  }
755
760
  lines.push('');
756
761
  }
757
-
762
+
758
763
  // Preserve raw content if requested
759
764
  if (preserveRaw && dataModel.rawContent) {
760
765
  lines.push('---');
@@ -765,29 +770,29 @@ function generateDataModel(dataModel, preserveRaw = false) {
765
770
  lines.push(dataModel.rawContent);
766
771
  lines.push('```');
767
772
  }
768
-
773
+
769
774
  return lines.join('\n');
770
775
  }
771
776
 
772
777
  /**
773
778
  * Generate contract content
774
- * @param {import('../ir/types').ContractIR} contract
779
+ * @param {import('../ir/types').ContractIR} contract
775
780
  * @returns {string}
776
781
  */
777
782
  function generateContract(contract) {
778
783
  const lines = [];
779
-
784
+
780
785
  lines.push(`# ${contract.name}`);
781
786
  lines.push('');
782
787
  lines.push(`**Type**: ${contract.type}`);
783
788
  lines.push('');
784
-
789
+
785
790
  if (contract.rawContent) {
786
791
  lines.push(contract.rawContent);
787
792
  } else {
788
793
  lines.push('> Contract details to be defined.');
789
794
  }
790
-
795
+
791
796
  return lines.join('\n');
792
797
  }
793
798