mustflow 1.18.16 → 1.30.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 (303) hide show
  1. package/README.md +16 -6
  2. package/dist/cli/commands/adapters.js +90 -0
  3. package/dist/cli/commands/classify.js +3 -4
  4. package/dist/cli/commands/contract-lint.js +26 -6
  5. package/dist/cli/commands/dashboard.js +103 -4
  6. package/dist/cli/commands/explain-verify.js +213 -0
  7. package/dist/cli/commands/explain.js +48 -4
  8. package/dist/cli/commands/handoff.js +136 -0
  9. package/dist/cli/commands/run.js +97 -136
  10. package/dist/cli/commands/update.js +91 -61
  11. package/dist/cli/commands/verify.js +230 -137
  12. package/dist/cli/i18n/en.js +65 -4
  13. package/dist/cli/i18n/es.js +65 -4
  14. package/dist/cli/i18n/fr.js +65 -4
  15. package/dist/cli/i18n/hi.js +65 -4
  16. package/dist/cli/i18n/ko.js +65 -4
  17. package/dist/cli/i18n/zh.js +65 -4
  18. package/dist/cli/index.js +11 -0
  19. package/dist/cli/lib/command-registry.js +10 -0
  20. package/dist/cli/lib/dashboard-export.js +775 -0
  21. package/dist/cli/lib/local-index.js +22 -6
  22. package/dist/cli/lib/run-plan.js +222 -0
  23. package/dist/cli/lib/templates.js +18 -3
  24. package/dist/cli/lib/update-diff-preview.js +163 -0
  25. package/dist/cli/lib/validation.js +22 -0
  26. package/dist/core/adapter-compatibility.js +235 -0
  27. package/dist/core/change-classification.js +9 -0
  28. package/dist/core/change-verification.js +10 -3
  29. package/dist/core/check-issues.js +4 -0
  30. package/dist/core/command-contract-validation.js +14 -0
  31. package/dist/core/command-cwd.js +18 -6
  32. package/dist/core/command-env.js +91 -0
  33. package/dist/core/contract-lint.js +165 -3
  34. package/dist/core/contract-models.js +172 -0
  35. package/dist/core/dashboard-verification.js +2 -0
  36. package/dist/core/doc-review-triage.js +1 -0
  37. package/dist/core/handoff-record.js +376 -0
  38. package/dist/core/public-json-contracts.js +16 -0
  39. package/dist/core/run-receipt.js +46 -7
  40. package/dist/core/run-write-drift.js +180 -0
  41. package/dist/core/secret-redaction.js +39 -0
  42. package/dist/core/source-anchors.js +3 -5
  43. package/dist/core/verification-decision-graph.js +223 -0
  44. package/package.json +3 -1
  45. package/schemas/README.md +11 -4
  46. package/schemas/adapter-compatibility-report.schema.json +184 -0
  47. package/schemas/change-verification-report.schema.json +133 -1
  48. package/schemas/commands.schema.json +8 -1
  49. package/schemas/contract-lint-report.schema.json +48 -0
  50. package/schemas/explain-report.schema.json +265 -2
  51. package/schemas/handoff-validation-report.schema.json +68 -0
  52. package/schemas/run-receipt.schema.json +74 -1
  53. package/templates/default/common/.mustflow/config/commands.toml +2 -0
  54. package/templates/default/i18n.toml +78 -234
  55. package/templates/default/locales/en/.mustflow/skills/INDEX.md +7 -3
  56. package/templates/default/locales/en/.mustflow/skills/architecture-deepening-review/SKILL.md +154 -0
  57. package/templates/default/locales/en/.mustflow/skills/behavior-preserving-refactor/SKILL.md +8 -3
  58. package/templates/default/locales/en/.mustflow/skills/code-review/SKILL.md +9 -4
  59. package/templates/default/locales/en/.mustflow/skills/date-number-audit/SKILL.md +19 -4
  60. package/templates/default/locales/en/.mustflow/skills/diff-risk-review/SKILL.md +4 -2
  61. package/templates/default/locales/en/.mustflow/skills/external-skill-intake/SKILL.md +141 -0
  62. package/templates/default/locales/en/.mustflow/skills/release-notes-authoring/SKILL.md +143 -0
  63. package/templates/default/locales/en/.mustflow/skills/repro-first-debug/SKILL.md +22 -8
  64. package/templates/default/locales/en/.mustflow/skills/skill-authoring/SKILL.md +3 -3
  65. package/templates/default/locales/en/.mustflow/skills/source-freshness-check/SKILL.md +22 -9
  66. package/templates/default/locales/en/.mustflow/skills/ui-quality-gate/SKILL.md +21 -13
  67. package/templates/default/locales/en/.mustflow/skills/vertical-slice-tdd/SKILL.md +167 -0
  68. package/templates/default/manifest.toml +16 -1
  69. package/templates/default/locales/es/.mustflow/skills/INDEX.md +0 -75
  70. package/templates/default/locales/es/.mustflow/skills/adapter-boundary/SKILL.md +0 -193
  71. package/templates/default/locales/es/.mustflow/skills/artifact-integrity-check/SKILL.md +0 -114
  72. package/templates/default/locales/es/.mustflow/skills/behavior-preserving-refactor/SKILL.md +0 -182
  73. package/templates/default/locales/es/.mustflow/skills/code-review/SKILL.md +0 -115
  74. package/templates/default/locales/es/.mustflow/skills/codebase-orientation/SKILL.md +0 -115
  75. package/templates/default/locales/es/.mustflow/skills/command-pattern/SKILL.md +0 -247
  76. package/templates/default/locales/es/.mustflow/skills/composition-over-inheritance/SKILL.md +0 -176
  77. package/templates/default/locales/es/.mustflow/skills/contract-sync-check/SKILL.md +0 -116
  78. package/templates/default/locales/es/.mustflow/skills/database-change-safety/SKILL.md +0 -155
  79. package/templates/default/locales/es/.mustflow/skills/date-number-audit/SKILL.md +0 -116
  80. package/templates/default/locales/es/.mustflow/skills/dependency-injection/SKILL.md +0 -161
  81. package/templates/default/locales/es/.mustflow/skills/dependency-reality-check/SKILL.md +0 -115
  82. package/templates/default/locales/es/.mustflow/skills/diff-risk-review/SKILL.md +0 -136
  83. package/templates/default/locales/es/.mustflow/skills/docs-prose-review/SKILL.md +0 -119
  84. package/templates/default/locales/es/.mustflow/skills/docs-update/SKILL.md +0 -97
  85. package/templates/default/locales/es/.mustflow/skills/external-prompt-injection-defense/SKILL.md +0 -116
  86. package/templates/default/locales/es/.mustflow/skills/facade-pattern/SKILL.md +0 -210
  87. package/templates/default/locales/es/.mustflow/skills/failure-triage/SKILL.md +0 -97
  88. package/templates/default/locales/es/.mustflow/skills/instruction-conflict-scope-check/SKILL.md +0 -118
  89. package/templates/default/locales/es/.mustflow/skills/line-ending-hygiene/SKILL.md +0 -111
  90. package/templates/default/locales/es/.mustflow/skills/migration-safety-check/SKILL.md +0 -117
  91. package/templates/default/locales/es/.mustflow/skills/multi-agent-work-coordination/SKILL.md +0 -260
  92. package/templates/default/locales/es/.mustflow/skills/null-object-pattern/SKILL.md +0 -196
  93. package/templates/default/locales/es/.mustflow/skills/pattern-scout/SKILL.md +0 -110
  94. package/templates/default/locales/es/.mustflow/skills/performance-budget-check/SKILL.md +0 -121
  95. package/templates/default/locales/es/.mustflow/skills/project-context-authoring/SKILL.md +0 -107
  96. package/templates/default/locales/es/.mustflow/skills/pure-core-imperative-shell/SKILL.md +0 -212
  97. package/templates/default/locales/es/.mustflow/skills/readme-authoring/SKILL.md +0 -115
  98. package/templates/default/locales/es/.mustflow/skills/repo-improvement-loop/SKILL.md +0 -150
  99. package/templates/default/locales/es/.mustflow/skills/repro-first-debug/SKILL.md +0 -112
  100. package/templates/default/locales/es/.mustflow/skills/requirement-regression-guard/SKILL.md +0 -152
  101. package/templates/default/locales/es/.mustflow/skills/result-option/SKILL.md +0 -186
  102. package/templates/default/locales/es/.mustflow/skills/security-privacy-review/SKILL.md +0 -116
  103. package/templates/default/locales/es/.mustflow/skills/security-regression-tests/SKILL.md +0 -131
  104. package/templates/default/locales/es/.mustflow/skills/skill-authoring/SKILL.md +0 -110
  105. package/templates/default/locales/es/.mustflow/skills/source-freshness-check/SKILL.md +0 -111
  106. package/templates/default/locales/es/.mustflow/skills/state-machine-pattern/SKILL.md +0 -214
  107. package/templates/default/locales/es/.mustflow/skills/strategy-pattern/SKILL.md +0 -215
  108. package/templates/default/locales/es/.mustflow/skills/structure-discovery-gate/SKILL.md +0 -159
  109. package/templates/default/locales/es/.mustflow/skills/test-design-guard/SKILL.md +0 -162
  110. package/templates/default/locales/es/.mustflow/skills/test-maintenance/SKILL.md +0 -122
  111. package/templates/default/locales/es/.mustflow/skills/ui-quality-gate/SKILL.md +0 -117
  112. package/templates/default/locales/es/.mustflow/skills/visual-review-artifact/SKILL.md +0 -127
  113. package/templates/default/locales/es/.mustflow/skills/visual-review-artifact/assets/review-template.html +0 -286
  114. package/templates/default/locales/es/.mustflow/skills/visual-review-artifact/resources.toml +0 -7
  115. package/templates/default/locales/es/.mustflow/skills/web-asset-optimization/SKILL.md +0 -108
  116. package/templates/default/locales/fr/.mustflow/skills/INDEX.md +0 -75
  117. package/templates/default/locales/fr/.mustflow/skills/adapter-boundary/SKILL.md +0 -193
  118. package/templates/default/locales/fr/.mustflow/skills/artifact-integrity-check/SKILL.md +0 -114
  119. package/templates/default/locales/fr/.mustflow/skills/behavior-preserving-refactor/SKILL.md +0 -182
  120. package/templates/default/locales/fr/.mustflow/skills/code-review/SKILL.md +0 -115
  121. package/templates/default/locales/fr/.mustflow/skills/codebase-orientation/SKILL.md +0 -115
  122. package/templates/default/locales/fr/.mustflow/skills/command-pattern/SKILL.md +0 -247
  123. package/templates/default/locales/fr/.mustflow/skills/composition-over-inheritance/SKILL.md +0 -176
  124. package/templates/default/locales/fr/.mustflow/skills/contract-sync-check/SKILL.md +0 -116
  125. package/templates/default/locales/fr/.mustflow/skills/database-change-safety/SKILL.md +0 -155
  126. package/templates/default/locales/fr/.mustflow/skills/date-number-audit/SKILL.md +0 -116
  127. package/templates/default/locales/fr/.mustflow/skills/dependency-injection/SKILL.md +0 -161
  128. package/templates/default/locales/fr/.mustflow/skills/dependency-reality-check/SKILL.md +0 -115
  129. package/templates/default/locales/fr/.mustflow/skills/diff-risk-review/SKILL.md +0 -136
  130. package/templates/default/locales/fr/.mustflow/skills/docs-prose-review/SKILL.md +0 -119
  131. package/templates/default/locales/fr/.mustflow/skills/docs-update/SKILL.md +0 -97
  132. package/templates/default/locales/fr/.mustflow/skills/external-prompt-injection-defense/SKILL.md +0 -116
  133. package/templates/default/locales/fr/.mustflow/skills/facade-pattern/SKILL.md +0 -210
  134. package/templates/default/locales/fr/.mustflow/skills/failure-triage/SKILL.md +0 -97
  135. package/templates/default/locales/fr/.mustflow/skills/instruction-conflict-scope-check/SKILL.md +0 -118
  136. package/templates/default/locales/fr/.mustflow/skills/line-ending-hygiene/SKILL.md +0 -111
  137. package/templates/default/locales/fr/.mustflow/skills/migration-safety-check/SKILL.md +0 -117
  138. package/templates/default/locales/fr/.mustflow/skills/multi-agent-work-coordination/SKILL.md +0 -260
  139. package/templates/default/locales/fr/.mustflow/skills/null-object-pattern/SKILL.md +0 -196
  140. package/templates/default/locales/fr/.mustflow/skills/pattern-scout/SKILL.md +0 -110
  141. package/templates/default/locales/fr/.mustflow/skills/performance-budget-check/SKILL.md +0 -121
  142. package/templates/default/locales/fr/.mustflow/skills/project-context-authoring/SKILL.md +0 -107
  143. package/templates/default/locales/fr/.mustflow/skills/pure-core-imperative-shell/SKILL.md +0 -212
  144. package/templates/default/locales/fr/.mustflow/skills/readme-authoring/SKILL.md +0 -115
  145. package/templates/default/locales/fr/.mustflow/skills/repo-improvement-loop/SKILL.md +0 -150
  146. package/templates/default/locales/fr/.mustflow/skills/repro-first-debug/SKILL.md +0 -112
  147. package/templates/default/locales/fr/.mustflow/skills/requirement-regression-guard/SKILL.md +0 -152
  148. package/templates/default/locales/fr/.mustflow/skills/result-option/SKILL.md +0 -186
  149. package/templates/default/locales/fr/.mustflow/skills/security-privacy-review/SKILL.md +0 -116
  150. package/templates/default/locales/fr/.mustflow/skills/security-regression-tests/SKILL.md +0 -131
  151. package/templates/default/locales/fr/.mustflow/skills/skill-authoring/SKILL.md +0 -110
  152. package/templates/default/locales/fr/.mustflow/skills/source-freshness-check/SKILL.md +0 -111
  153. package/templates/default/locales/fr/.mustflow/skills/state-machine-pattern/SKILL.md +0 -214
  154. package/templates/default/locales/fr/.mustflow/skills/strategy-pattern/SKILL.md +0 -215
  155. package/templates/default/locales/fr/.mustflow/skills/structure-discovery-gate/SKILL.md +0 -159
  156. package/templates/default/locales/fr/.mustflow/skills/test-design-guard/SKILL.md +0 -162
  157. package/templates/default/locales/fr/.mustflow/skills/test-maintenance/SKILL.md +0 -122
  158. package/templates/default/locales/fr/.mustflow/skills/ui-quality-gate/SKILL.md +0 -117
  159. package/templates/default/locales/fr/.mustflow/skills/visual-review-artifact/SKILL.md +0 -127
  160. package/templates/default/locales/fr/.mustflow/skills/visual-review-artifact/assets/review-template.html +0 -286
  161. package/templates/default/locales/fr/.mustflow/skills/visual-review-artifact/resources.toml +0 -7
  162. package/templates/default/locales/fr/.mustflow/skills/web-asset-optimization/SKILL.md +0 -108
  163. package/templates/default/locales/hi/.mustflow/skills/INDEX.md +0 -75
  164. package/templates/default/locales/hi/.mustflow/skills/adapter-boundary/SKILL.md +0 -193
  165. package/templates/default/locales/hi/.mustflow/skills/artifact-integrity-check/SKILL.md +0 -114
  166. package/templates/default/locales/hi/.mustflow/skills/behavior-preserving-refactor/SKILL.md +0 -182
  167. package/templates/default/locales/hi/.mustflow/skills/code-review/SKILL.md +0 -115
  168. package/templates/default/locales/hi/.mustflow/skills/codebase-orientation/SKILL.md +0 -115
  169. package/templates/default/locales/hi/.mustflow/skills/command-pattern/SKILL.md +0 -247
  170. package/templates/default/locales/hi/.mustflow/skills/composition-over-inheritance/SKILL.md +0 -176
  171. package/templates/default/locales/hi/.mustflow/skills/contract-sync-check/SKILL.md +0 -116
  172. package/templates/default/locales/hi/.mustflow/skills/database-change-safety/SKILL.md +0 -155
  173. package/templates/default/locales/hi/.mustflow/skills/date-number-audit/SKILL.md +0 -116
  174. package/templates/default/locales/hi/.mustflow/skills/dependency-injection/SKILL.md +0 -161
  175. package/templates/default/locales/hi/.mustflow/skills/dependency-reality-check/SKILL.md +0 -115
  176. package/templates/default/locales/hi/.mustflow/skills/diff-risk-review/SKILL.md +0 -136
  177. package/templates/default/locales/hi/.mustflow/skills/docs-prose-review/SKILL.md +0 -119
  178. package/templates/default/locales/hi/.mustflow/skills/docs-update/SKILL.md +0 -97
  179. package/templates/default/locales/hi/.mustflow/skills/external-prompt-injection-defense/SKILL.md +0 -116
  180. package/templates/default/locales/hi/.mustflow/skills/facade-pattern/SKILL.md +0 -210
  181. package/templates/default/locales/hi/.mustflow/skills/failure-triage/SKILL.md +0 -97
  182. package/templates/default/locales/hi/.mustflow/skills/instruction-conflict-scope-check/SKILL.md +0 -118
  183. package/templates/default/locales/hi/.mustflow/skills/line-ending-hygiene/SKILL.md +0 -111
  184. package/templates/default/locales/hi/.mustflow/skills/migration-safety-check/SKILL.md +0 -117
  185. package/templates/default/locales/hi/.mustflow/skills/multi-agent-work-coordination/SKILL.md +0 -260
  186. package/templates/default/locales/hi/.mustflow/skills/null-object-pattern/SKILL.md +0 -196
  187. package/templates/default/locales/hi/.mustflow/skills/pattern-scout/SKILL.md +0 -110
  188. package/templates/default/locales/hi/.mustflow/skills/performance-budget-check/SKILL.md +0 -121
  189. package/templates/default/locales/hi/.mustflow/skills/project-context-authoring/SKILL.md +0 -107
  190. package/templates/default/locales/hi/.mustflow/skills/pure-core-imperative-shell/SKILL.md +0 -212
  191. package/templates/default/locales/hi/.mustflow/skills/readme-authoring/SKILL.md +0 -115
  192. package/templates/default/locales/hi/.mustflow/skills/repo-improvement-loop/SKILL.md +0 -150
  193. package/templates/default/locales/hi/.mustflow/skills/repro-first-debug/SKILL.md +0 -112
  194. package/templates/default/locales/hi/.mustflow/skills/requirement-regression-guard/SKILL.md +0 -152
  195. package/templates/default/locales/hi/.mustflow/skills/result-option/SKILL.md +0 -186
  196. package/templates/default/locales/hi/.mustflow/skills/security-privacy-review/SKILL.md +0 -116
  197. package/templates/default/locales/hi/.mustflow/skills/security-regression-tests/SKILL.md +0 -131
  198. package/templates/default/locales/hi/.mustflow/skills/skill-authoring/SKILL.md +0 -110
  199. package/templates/default/locales/hi/.mustflow/skills/source-freshness-check/SKILL.md +0 -111
  200. package/templates/default/locales/hi/.mustflow/skills/state-machine-pattern/SKILL.md +0 -214
  201. package/templates/default/locales/hi/.mustflow/skills/strategy-pattern/SKILL.md +0 -215
  202. package/templates/default/locales/hi/.mustflow/skills/structure-discovery-gate/SKILL.md +0 -159
  203. package/templates/default/locales/hi/.mustflow/skills/test-design-guard/SKILL.md +0 -162
  204. package/templates/default/locales/hi/.mustflow/skills/test-maintenance/SKILL.md +0 -122
  205. package/templates/default/locales/hi/.mustflow/skills/ui-quality-gate/SKILL.md +0 -117
  206. package/templates/default/locales/hi/.mustflow/skills/visual-review-artifact/SKILL.md +0 -127
  207. package/templates/default/locales/hi/.mustflow/skills/visual-review-artifact/assets/review-template.html +0 -286
  208. package/templates/default/locales/hi/.mustflow/skills/visual-review-artifact/resources.toml +0 -7
  209. package/templates/default/locales/hi/.mustflow/skills/web-asset-optimization/SKILL.md +0 -108
  210. package/templates/default/locales/ko/.mustflow/skills/INDEX.md +0 -80
  211. package/templates/default/locales/ko/.mustflow/skills/adapter-boundary/SKILL.md +0 -193
  212. package/templates/default/locales/ko/.mustflow/skills/artifact-integrity-check/SKILL.md +0 -114
  213. package/templates/default/locales/ko/.mustflow/skills/behavior-preserving-refactor/SKILL.md +0 -182
  214. package/templates/default/locales/ko/.mustflow/skills/code-review/SKILL.md +0 -118
  215. package/templates/default/locales/ko/.mustflow/skills/codebase-orientation/SKILL.md +0 -115
  216. package/templates/default/locales/ko/.mustflow/skills/command-pattern/SKILL.md +0 -247
  217. package/templates/default/locales/ko/.mustflow/skills/composition-over-inheritance/SKILL.md +0 -176
  218. package/templates/default/locales/ko/.mustflow/skills/contract-sync-check/SKILL.md +0 -116
  219. package/templates/default/locales/ko/.mustflow/skills/database-change-safety/SKILL.md +0 -155
  220. package/templates/default/locales/ko/.mustflow/skills/date-number-audit/SKILL.md +0 -116
  221. package/templates/default/locales/ko/.mustflow/skills/dependency-injection/SKILL.md +0 -161
  222. package/templates/default/locales/ko/.mustflow/skills/dependency-reality-check/SKILL.md +0 -115
  223. package/templates/default/locales/ko/.mustflow/skills/diff-risk-review/SKILL.md +0 -136
  224. package/templates/default/locales/ko/.mustflow/skills/docs-prose-review/SKILL.md +0 -119
  225. package/templates/default/locales/ko/.mustflow/skills/docs-update/SKILL.md +0 -107
  226. package/templates/default/locales/ko/.mustflow/skills/external-prompt-injection-defense/SKILL.md +0 -116
  227. package/templates/default/locales/ko/.mustflow/skills/facade-pattern/SKILL.md +0 -210
  228. package/templates/default/locales/ko/.mustflow/skills/failure-triage/SKILL.md +0 -119
  229. package/templates/default/locales/ko/.mustflow/skills/instruction-conflict-scope-check/SKILL.md +0 -118
  230. package/templates/default/locales/ko/.mustflow/skills/line-ending-hygiene/SKILL.md +0 -111
  231. package/templates/default/locales/ko/.mustflow/skills/migration-safety-check/SKILL.md +0 -117
  232. package/templates/default/locales/ko/.mustflow/skills/multi-agent-work-coordination/SKILL.md +0 -259
  233. package/templates/default/locales/ko/.mustflow/skills/null-object-pattern/SKILL.md +0 -196
  234. package/templates/default/locales/ko/.mustflow/skills/pattern-scout/SKILL.md +0 -110
  235. package/templates/default/locales/ko/.mustflow/skills/performance-budget-check/SKILL.md +0 -121
  236. package/templates/default/locales/ko/.mustflow/skills/project-context-authoring/SKILL.md +0 -107
  237. package/templates/default/locales/ko/.mustflow/skills/pure-core-imperative-shell/SKILL.md +0 -212
  238. package/templates/default/locales/ko/.mustflow/skills/readme-authoring/SKILL.md +0 -115
  239. package/templates/default/locales/ko/.mustflow/skills/repo-improvement-loop/SKILL.md +0 -150
  240. package/templates/default/locales/ko/.mustflow/skills/repro-first-debug/SKILL.md +0 -112
  241. package/templates/default/locales/ko/.mustflow/skills/requirement-regression-guard/SKILL.md +0 -152
  242. package/templates/default/locales/ko/.mustflow/skills/result-option/SKILL.md +0 -186
  243. package/templates/default/locales/ko/.mustflow/skills/security-privacy-review/SKILL.md +0 -116
  244. package/templates/default/locales/ko/.mustflow/skills/security-regression-tests/SKILL.md +0 -131
  245. package/templates/default/locales/ko/.mustflow/skills/skill-authoring/SKILL.md +0 -110
  246. package/templates/default/locales/ko/.mustflow/skills/source-freshness-check/SKILL.md +0 -111
  247. package/templates/default/locales/ko/.mustflow/skills/state-machine-pattern/SKILL.md +0 -214
  248. package/templates/default/locales/ko/.mustflow/skills/strategy-pattern/SKILL.md +0 -215
  249. package/templates/default/locales/ko/.mustflow/skills/structure-discovery-gate/SKILL.md +0 -159
  250. package/templates/default/locales/ko/.mustflow/skills/test-design-guard/SKILL.md +0 -162
  251. package/templates/default/locales/ko/.mustflow/skills/test-maintenance/SKILL.md +0 -130
  252. package/templates/default/locales/ko/.mustflow/skills/ui-quality-gate/SKILL.md +0 -117
  253. package/templates/default/locales/ko/.mustflow/skills/visual-review-artifact/SKILL.md +0 -127
  254. package/templates/default/locales/ko/.mustflow/skills/visual-review-artifact/assets/review-template.html +0 -286
  255. package/templates/default/locales/ko/.mustflow/skills/visual-review-artifact/resources.toml +0 -7
  256. package/templates/default/locales/ko/.mustflow/skills/web-asset-optimization/SKILL.md +0 -108
  257. package/templates/default/locales/zh/.mustflow/skills/INDEX.md +0 -74
  258. package/templates/default/locales/zh/.mustflow/skills/adapter-boundary/SKILL.md +0 -193
  259. package/templates/default/locales/zh/.mustflow/skills/artifact-integrity-check/SKILL.md +0 -114
  260. package/templates/default/locales/zh/.mustflow/skills/behavior-preserving-refactor/SKILL.md +0 -182
  261. package/templates/default/locales/zh/.mustflow/skills/code-review/SKILL.md +0 -115
  262. package/templates/default/locales/zh/.mustflow/skills/codebase-orientation/SKILL.md +0 -115
  263. package/templates/default/locales/zh/.mustflow/skills/command-pattern/SKILL.md +0 -247
  264. package/templates/default/locales/zh/.mustflow/skills/composition-over-inheritance/SKILL.md +0 -176
  265. package/templates/default/locales/zh/.mustflow/skills/contract-sync-check/SKILL.md +0 -116
  266. package/templates/default/locales/zh/.mustflow/skills/database-change-safety/SKILL.md +0 -155
  267. package/templates/default/locales/zh/.mustflow/skills/date-number-audit/SKILL.md +0 -116
  268. package/templates/default/locales/zh/.mustflow/skills/dependency-injection/SKILL.md +0 -161
  269. package/templates/default/locales/zh/.mustflow/skills/dependency-reality-check/SKILL.md +0 -115
  270. package/templates/default/locales/zh/.mustflow/skills/diff-risk-review/SKILL.md +0 -136
  271. package/templates/default/locales/zh/.mustflow/skills/docs-prose-review/SKILL.md +0 -119
  272. package/templates/default/locales/zh/.mustflow/skills/docs-update/SKILL.md +0 -97
  273. package/templates/default/locales/zh/.mustflow/skills/external-prompt-injection-defense/SKILL.md +0 -116
  274. package/templates/default/locales/zh/.mustflow/skills/facade-pattern/SKILL.md +0 -210
  275. package/templates/default/locales/zh/.mustflow/skills/failure-triage/SKILL.md +0 -96
  276. package/templates/default/locales/zh/.mustflow/skills/instruction-conflict-scope-check/SKILL.md +0 -118
  277. package/templates/default/locales/zh/.mustflow/skills/line-ending-hygiene/SKILL.md +0 -111
  278. package/templates/default/locales/zh/.mustflow/skills/migration-safety-check/SKILL.md +0 -117
  279. package/templates/default/locales/zh/.mustflow/skills/multi-agent-work-coordination/SKILL.md +0 -260
  280. package/templates/default/locales/zh/.mustflow/skills/null-object-pattern/SKILL.md +0 -196
  281. package/templates/default/locales/zh/.mustflow/skills/pattern-scout/SKILL.md +0 -110
  282. package/templates/default/locales/zh/.mustflow/skills/performance-budget-check/SKILL.md +0 -121
  283. package/templates/default/locales/zh/.mustflow/skills/project-context-authoring/SKILL.md +0 -107
  284. package/templates/default/locales/zh/.mustflow/skills/pure-core-imperative-shell/SKILL.md +0 -212
  285. package/templates/default/locales/zh/.mustflow/skills/readme-authoring/SKILL.md +0 -115
  286. package/templates/default/locales/zh/.mustflow/skills/repo-improvement-loop/SKILL.md +0 -150
  287. package/templates/default/locales/zh/.mustflow/skills/repro-first-debug/SKILL.md +0 -112
  288. package/templates/default/locales/zh/.mustflow/skills/requirement-regression-guard/SKILL.md +0 -152
  289. package/templates/default/locales/zh/.mustflow/skills/result-option/SKILL.md +0 -186
  290. package/templates/default/locales/zh/.mustflow/skills/security-privacy-review/SKILL.md +0 -116
  291. package/templates/default/locales/zh/.mustflow/skills/security-regression-tests/SKILL.md +0 -131
  292. package/templates/default/locales/zh/.mustflow/skills/skill-authoring/SKILL.md +0 -110
  293. package/templates/default/locales/zh/.mustflow/skills/source-freshness-check/SKILL.md +0 -111
  294. package/templates/default/locales/zh/.mustflow/skills/state-machine-pattern/SKILL.md +0 -214
  295. package/templates/default/locales/zh/.mustflow/skills/strategy-pattern/SKILL.md +0 -215
  296. package/templates/default/locales/zh/.mustflow/skills/structure-discovery-gate/SKILL.md +0 -159
  297. package/templates/default/locales/zh/.mustflow/skills/test-design-guard/SKILL.md +0 -162
  298. package/templates/default/locales/zh/.mustflow/skills/test-maintenance/SKILL.md +0 -122
  299. package/templates/default/locales/zh/.mustflow/skills/ui-quality-gate/SKILL.md +0 -117
  300. package/templates/default/locales/zh/.mustflow/skills/visual-review-artifact/SKILL.md +0 -127
  301. package/templates/default/locales/zh/.mustflow/skills/visual-review-artifact/assets/review-template.html +0 -286
  302. package/templates/default/locales/zh/.mustflow/skills/visual-review-artifact/resources.toml +0 -7
  303. package/templates/default/locales/zh/.mustflow/skills/web-asset-optimization/SKILL.md +0 -108
@@ -1,5 +1,4 @@
1
1
  import { spawnSync } from 'node:child_process';
2
- import path from 'node:path';
3
2
  import { runCheck } from './check.js';
4
3
  import { runClassify } from './classify.js';
5
4
  import { runContext } from './context.js';
@@ -12,22 +11,16 @@ import { runStatus } from './status.js';
12
11
  import { runUpdate } from './update.js';
13
12
  import { runVersionSources } from './version-sources.js';
14
13
  import { canRunMustflowBuiltinInProcess, isMustflowBinName } from '../../core/command-classification.js';
15
- import { resolveSafeProjectCwd } from '../../core/command-cwd.js';
16
- import { evaluateCommandIntentEligibility } from '../../core/command-intent-eligibility.js';
14
+ import { createCommandEnv } from '../../core/command-env.js';
17
15
  import { printUsageError, renderCliError, renderHelp } from '../lib/cli-output.js';
18
- import { isRecord, readCommandContract, readMustflowConfigIfExists, readPositiveInteger, readString, readStringArray, } from '../../core/config-loading.js';
16
+ import { readCommandContract, readMustflowConfigIfExists } from '../../core/config-loading.js';
19
17
  import { resolveRunReceiptRetentionPolicy } from '../../core/retention-policy.js';
20
18
  import { t } from '../lib/i18n.js';
21
19
  import { getPackageVersion } from '../lib/package-info.js';
22
20
  import { resolveMustflowRoot } from '../lib/project-root.js';
21
+ import { createRunPlan, createRunPreview, isMustflowBuiltinIntent, renderRunPreviewText, } from '../lib/run-plan.js';
23
22
  import { createRunReceipt, writeRunReceipt } from '../../core/run-receipt.js';
24
- function getSuccessExitCodes(intent) {
25
- const value = intent.success_exit_codes;
26
- if (!Array.isArray(value) || value.length === 0 || value.some((entry) => !Number.isInteger(entry))) {
27
- return [0];
28
- }
29
- return value.map(Number);
30
- }
23
+ import { finishRunWriteTracking, startRunWriteTracking } from '../../core/run-write-drift.js';
31
24
  function emitOutput(reporter, output, stream) {
32
25
  if (!output) {
33
26
  return;
@@ -64,57 +57,6 @@ function terminateProcessTree(pid) {
64
57
  function getKillMethod() {
65
58
  return process.platform === 'win32' ? 'taskkill_process_tree' : 'process_group_sigterm';
66
59
  }
67
- function getPathEnvKey(env) {
68
- return Object.keys(env).find((key) => key.toLowerCase() === 'path') ?? 'PATH';
69
- }
70
- function sameResolvedPath(left, right) {
71
- const resolvedLeft = path.resolve(left);
72
- const resolvedRight = path.resolve(right);
73
- return process.platform === 'win32'
74
- ? resolvedLeft.toLowerCase() === resolvedRight.toLowerCase()
75
- : resolvedLeft === resolvedRight;
76
- }
77
- function createCommandEnv(projectRoot) {
78
- const env = { ...process.env };
79
- const pathKey = getPathEnvKey(env);
80
- const localBinPath = path.join(projectRoot, 'node_modules', '.bin');
81
- const currentPath = env[pathKey];
82
- if (currentPath) {
83
- env[pathKey] = currentPath
84
- .split(path.delimiter)
85
- .filter((entry) => entry.length > 0 && !sameResolvedPath(entry, localBinPath))
86
- .join(path.delimiter);
87
- }
88
- return env;
89
- }
90
- function shouldUseShellForArgvExecutable(executablePath) {
91
- return process.platform === 'win32' && executablePath.toLowerCase().endsWith('.cmd');
92
- }
93
- function isMustflowBuiltinIntent(intent) {
94
- return readString(intent, 'kind') === 'mustflow_builtin';
95
- }
96
- function resolveCurrentCliEntrypoint() {
97
- const entrypoint = process.argv[1];
98
- return entrypoint ? path.resolve(entrypoint) : undefined;
99
- }
100
- function resolveArgvCommand(intent, commandArgv) {
101
- const [command = '', ...args] = commandArgv;
102
- if (isMustflowBuiltinIntent(intent) && isMustflowBinName(command)) {
103
- const entrypoint = resolveCurrentCliEntrypoint();
104
- if (entrypoint) {
105
- return {
106
- executable: process.execPath,
107
- args: [entrypoint, ...args],
108
- shell: false,
109
- };
110
- }
111
- }
112
- return {
113
- executable: command,
114
- args,
115
- shell: shouldUseShellForArgvExecutable(command),
116
- };
117
- }
118
60
  function createBufferedReporter() {
119
61
  const stdout = [];
120
62
  const stderr = [];
@@ -260,15 +202,66 @@ function getRunStatus(error, exitCode, successExitCodes) {
260
202
  }
261
203
  return exitCode !== null && successExitCodes.includes(exitCode) ? 'passed' : 'failed';
262
204
  }
205
+ function getRunPlanDetail(plan, lang, fallbackKey) {
206
+ return plan.detail ?? t(lang, fallbackKey);
207
+ }
208
+ function reportRunPlanFailure(plan, reporter, lang) {
209
+ let message;
210
+ switch (plan.reasonCode) {
211
+ case 'status_not_configured':
212
+ message = t(lang, 'run.error.statusNotConfigured', { intent: plan.intentName, status: plan.intentStatus ?? 'unknown' });
213
+ break;
214
+ case 'lifecycle_not_oneshot':
215
+ message = t(lang, 'run.error.lifecycleNotOneshot', { intent: plan.intentName, lifecycle: plan.lifecycle ?? 'unknown' });
216
+ break;
217
+ case 'run_policy_not_agent_allowed':
218
+ message = t(lang, 'run.error.runPolicy', { intent: plan.intentName });
219
+ break;
220
+ case 'stdin_not_closed':
221
+ message = t(lang, 'run.error.stdin', { intent: plan.intentName });
222
+ break;
223
+ case 'missing_timeout':
224
+ message = t(lang, 'run.error.timeout', { intent: plan.intentName });
225
+ break;
226
+ case 'missing_command_source':
227
+ message = t(lang, 'run.error.commandSource', { intent: plan.intentName });
228
+ break;
229
+ case 'unsafe_intent_name':
230
+ message = t(lang, 'run.error.unsafeIntent', {
231
+ intent: plan.intentName,
232
+ detail: getRunPlanDetail(plan, lang, 'run.error.unsafeIntentDetail'),
233
+ });
234
+ break;
235
+ case 'blocked_shell_background_pattern':
236
+ message = t(lang, 'run.error.blockedShellBackground', {
237
+ intent: plan.intentName,
238
+ detail: getRunPlanDetail(plan, lang, 'run.error.blockedShellBackgroundDetail'),
239
+ });
240
+ break;
241
+ case 'cwd_outside_project':
242
+ message = t(lang, 'run.error.cwdOutsideProject', {
243
+ intent: plan.intentName,
244
+ detail: getRunPlanDetail(plan, lang, 'run.error.cwdOutsideProjectDetail'),
245
+ });
246
+ break;
247
+ case 'intent_not_table':
248
+ default:
249
+ message = t(lang, 'run.error.unknownIntent', { intent: plan.intentName });
250
+ break;
251
+ }
252
+ reporter.stderr(renderCliError(message, 'mf help commands', lang));
253
+ }
263
254
  export function getRunHelp(lang = 'en') {
264
255
  return renderHelp({
265
256
  usage: 'mf run <intent> [options]',
266
257
  summary: t(lang, 'run.help.summary'),
267
258
  options: [
259
+ { label: '--dry-run', description: t(lang, 'run.help.option.dryRun') },
260
+ { label: '--plan-only', description: t(lang, 'run.help.option.planOnly') },
268
261
  { label: '--json', description: t(lang, 'run.help.option.json') },
269
262
  { label: '-h, --help', description: t(lang, 'cli.option.help') },
270
263
  ],
271
- examples: ['mf run test', 'mf run lint --json', 'mf run mustflow_check'],
264
+ examples: ['mf run test', 'mf run lint --json', 'mf run mustflow_check --dry-run --json'],
272
265
  exitCodes: [
273
266
  {
274
267
  label: '0',
@@ -293,13 +286,20 @@ export async function runRun(args, reporter, lang = 'en') {
293
286
  reporter.stdout(getRunHelp(lang));
294
287
  return 0;
295
288
  }
296
- const supportedOptions = new Set(['--json']);
289
+ const supportedOptions = new Set(['--json', '--dry-run', '--plan-only']);
297
290
  const unsupported = args.filter((arg) => arg.startsWith('-') && !supportedOptions.has(arg));
298
291
  if (unsupported.length > 0) {
299
292
  printUsageError(reporter, t(lang, 'cli.error.unknownOption', { option: unsupported[0] }), 'mf run --help', getRunHelp(lang), lang);
300
293
  return 1;
301
294
  }
302
295
  const json = args.includes('--json');
296
+ const dryRun = args.includes('--dry-run');
297
+ const planOnly = args.includes('--plan-only');
298
+ const previewMode = dryRun ? 'dry-run' : planOnly ? 'plan-only' : null;
299
+ if (dryRun && planOnly) {
300
+ printUsageError(reporter, t(lang, 'run.error.conflictingPreviewModes'), 'mf run --help', getRunHelp(lang), lang);
301
+ return 1;
302
+ }
303
303
  const positional = args.filter((arg) => !supportedOptions.has(arg));
304
304
  const [intentName, ...extra] = positional;
305
305
  if (!intentName) {
@@ -312,78 +312,36 @@ export async function runRun(args, reporter, lang = 'en') {
312
312
  }
313
313
  const projectRoot = resolveMustflowRoot();
314
314
  const contract = readCommandContract(projectRoot);
315
- const runReceiptPolicy = resolveRunReceiptRetentionPolicy(readMustflowConfigIfExists(projectRoot));
316
- const intent = contract.intents[intentName];
317
- if (!isRecord(intent)) {
318
- reporter.stderr(renderCliError(t(lang, 'run.error.unknownIntent', { intent: intentName }), 'mf help commands', lang));
319
- return 1;
320
- }
321
- const eligibility = evaluateCommandIntentEligibility(intentName, intent);
322
- const intentStatus = readString(intent, 'status') ?? 'unknown';
323
- const lifecycle = readString(intent, 'lifecycle');
324
- const runPolicy = readString(intent, 'run_policy');
325
- const timeoutSeconds = readPositiveInteger(intent, 'timeout_seconds');
326
- if (!eligibility.ok) {
327
- if (eligibility.code === 'status_not_configured') {
328
- reporter.stderr(renderCliError(t(lang, 'run.error.statusNotConfigured', { intent: intentName, status: intentStatus }), 'mf help commands', lang));
329
- return 1;
330
- }
331
- if (eligibility.code === 'lifecycle_not_oneshot') {
332
- reporter.stderr(renderCliError(t(lang, 'run.error.lifecycleNotOneshot', { intent: intentName, lifecycle: lifecycle ?? 'unknown' }), 'mf help commands', lang));
333
- return 1;
334
- }
335
- if (eligibility.code === 'run_policy_not_agent_allowed') {
336
- reporter.stderr(renderCliError(t(lang, 'run.error.runPolicy', { intent: intentName }), 'mf help commands', lang));
337
- return 1;
338
- }
339
- if (eligibility.code === 'stdin_not_closed') {
340
- reporter.stderr(renderCliError(t(lang, 'run.error.stdin', { intent: intentName }), 'mf help commands', lang));
341
- return 1;
342
- }
343
- if (eligibility.code === 'missing_timeout') {
344
- reporter.stderr(renderCliError(t(lang, 'run.error.timeout', { intent: intentName }), 'mf help commands', lang));
345
- return 1;
315
+ const plan = createRunPlan(projectRoot, contract, intentName);
316
+ if (previewMode) {
317
+ if (json) {
318
+ reporter.stdout(JSON.stringify(createRunPreview(plan, previewMode), null, 2));
346
319
  }
347
- if (eligibility.code === 'missing_command_source') {
348
- reporter.stderr(renderCliError(t(lang, 'run.error.commandSource', { intent: intentName }), 'mf help commands', lang));
349
- return 1;
320
+ else {
321
+ reporter.stdout(renderRunPreviewText(plan, previewMode));
350
322
  }
351
- if (eligibility.code === 'unsafe_intent_name') {
352
- reporter.stderr(renderCliError(`Intent ${intentName} has an unsafe name. ${eligibility.detail ?? 'Use a shell-safe intent name.'}`, 'mf help commands', lang));
353
- return 1;
354
- }
355
- if (eligibility.code === 'blocked_shell_background_pattern') {
356
- reporter.stderr(renderCliError(`Intent ${intentName} is blocked. ${eligibility.detail ?? 'Shell commands must not spawn background work.'}`, 'mf help commands', lang));
357
- return 1;
358
- }
359
- reporter.stderr(renderCliError(t(lang, 'run.error.unknownIntent', { intent: intentName }), 'mf help commands', lang));
360
- return 1;
323
+ return plan.ok ? 0 : 1;
361
324
  }
362
- const maxOutputBytes = readPositiveInteger(intent, 'max_output_bytes') ?? readPositiveInteger(contract.defaults, 'max_output_bytes') ?? 1_048_576;
363
- if (!timeoutSeconds) {
364
- reporter.stderr(renderCliError(t(lang, 'run.error.timeout', { intent: intentName }), 'mf help commands', lang));
325
+ if (!plan.ok) {
326
+ reportRunPlanFailure(plan, reporter, lang);
365
327
  return 1;
366
328
  }
367
- const cwd = resolveSafeProjectCwd(projectRoot, readString(intent, 'cwd') ?? readString(contract.defaults, 'default_cwd'));
368
- const successExitCodes = getSuccessExitCodes(intent);
369
- const argv = readStringArray(intent, 'argv');
370
- const commandArgv = argv && argv.length > 0 ? argv : undefined;
371
- const shellCommand = intent.mode === 'shell' ? readString(intent, 'cmd') : undefined;
372
- const env = createCommandEnv(projectRoot);
373
- const lifecycleValue = lifecycle ?? 'oneshot';
374
- const runPolicyValue = runPolicy ?? 'agent_allowed';
375
- const mode = commandArgv ? 'argv' : 'shell';
329
+ const runReceiptPolicy = resolveRunReceiptRetentionPolicy(readMustflowConfigIfExists(projectRoot));
330
+ const env = createCommandEnv(projectRoot, { policy: plan.envPolicy, allowlist: plan.envAllowlist });
331
+ const lifecycleValue = plan.lifecycle ?? 'oneshot';
332
+ const runPolicyValue = plan.runPolicy ?? 'agent_allowed';
333
+ const writeTracker = startRunWriteTracking(projectRoot, contract, intentName);
376
334
  const startedAt = new Date();
377
- const argvCommand = commandArgv ? resolveArgvCommand(intent, commandArgv) : undefined;
378
- const result = commandArgv && isMustflowBuiltinIntent(intent)
379
- ? ((await runBuiltinArgvInProcess(commandArgv, cwd, lang)) ??
380
- runArgvCommand(argvCommand, cwd, maxOutputBytes, env, timeoutSeconds))
381
- : commandArgv
382
- ? runArgvCommand(argvCommand, cwd, maxOutputBytes, env, timeoutSeconds)
383
- : runShellCommand(shellCommand, cwd, maxOutputBytes, env, timeoutSeconds);
335
+ const result = plan.commandArgv && isMustflowBuiltinIntent(plan.intent)
336
+ ? ((await runBuiltinArgvInProcess(plan.commandArgv, plan.cwd, lang)) ??
337
+ runArgvCommand(plan.argvCommand, plan.cwd, plan.maxOutputBytes, env, plan.timeoutSeconds))
338
+ : plan.commandArgv
339
+ ? runArgvCommand(plan.argvCommand, plan.cwd, plan.maxOutputBytes, env, plan.timeoutSeconds)
340
+ : runShellCommand(plan.shellCommand, plan.cwd, plan.maxOutputBytes, env, plan.timeoutSeconds);
384
341
  const finishedAt = new Date();
342
+ const writeDrift = finishRunWriteTracking(writeTracker);
385
343
  const exitCode = typeof result.status === 'number' ? result.status : null;
386
- const runStatus = getRunStatus(result.error, exitCode, successExitCodes);
344
+ const runStatus = getRunStatus(result.error, exitCode, plan.successExitCodes);
387
345
  let killMethod = null;
388
346
  if (runStatus === 'timed_out') {
389
347
  killMethod = getKillMethod();
@@ -396,21 +354,24 @@ export async function runRun(args, reporter, lang = 'en') {
396
354
  startedAt,
397
355
  finishedAt,
398
356
  projectRoot,
399
- cwd,
357
+ cwd: plan.cwd,
400
358
  lifecycle: lifecycleValue,
401
359
  runPolicy: runPolicyValue,
402
- mode,
403
- argv: commandArgv,
404
- cmd: shellCommand,
405
- timeoutSeconds,
406
- maxOutputBytes,
407
- successExitCodes,
360
+ mode: plan.mode,
361
+ argv: plan.commandArgv,
362
+ cmd: plan.shellCommand,
363
+ envPolicy: plan.envPolicy,
364
+ envAllowlist: plan.envAllowlist,
365
+ timeoutSeconds: plan.timeoutSeconds,
366
+ maxOutputBytes: plan.maxOutputBytes,
367
+ successExitCodes: plan.successExitCodes,
408
368
  exitCode,
409
369
  signal: result.signal,
410
370
  error: result.error?.message ?? null,
411
371
  killMethod,
412
372
  stdout: result.stdout,
413
373
  stderr: result.stderr,
374
+ writeDrift,
414
375
  stdoutTailBytes: runReceiptPolicy.stdoutTailBytes,
415
376
  stderrTailBytes: runReceiptPolicy.stderrTailBytes,
416
377
  });
@@ -424,7 +385,7 @@ export async function runRun(args, reporter, lang = 'en') {
424
385
  if (result.error) {
425
386
  const errorWithCode = result.error;
426
387
  if (errorWithCode.code === 'ETIMEDOUT') {
427
- reporter.stderr(t(lang, 'run.error.timedOut', { intent: intentName, seconds: timeoutSeconds }));
388
+ reporter.stderr(t(lang, 'run.error.timedOut', { intent: intentName, seconds: plan.timeoutSeconds }));
428
389
  return 1;
429
390
  }
430
391
  reporter.stderr(t(lang, 'run.error.startFailed', { intent: intentName, message: result.error.message }));
@@ -8,6 +8,7 @@ import { t } from '../lib/i18n.js';
8
8
  import { resolveMustflowRoot } from '../lib/project-root.js';
9
9
  import { getDefaultTemplate, getTemplateFiles, skillNameForTemplatePath } from '../lib/templates.js';
10
10
  import { readTomlFile, stringifyToml } from '../lib/toml.js';
11
+ import { createUpdateDiffPreview, shouldPreviewUpdateDiff } from '../lib/update-diff-preview.js';
11
12
  const UPDATE_SCHEMA_VERSION = '1';
12
13
  const CUSTOMIZED_LOCK_ACTION = 'customized';
13
14
  const UPDATE_POLICY = {
@@ -25,6 +26,7 @@ export function getUpdateHelp(lang = 'en') {
25
26
  summary: t(lang, 'update.help.summary'),
26
27
  options: [
27
28
  { label: '--dry-run', description: t(lang, 'update.help.option.dryRun') },
29
+ { label: '--diff', description: t(lang, 'update.help.option.diff') },
28
30
  {
29
31
  label: '--apply',
30
32
  description: t(lang, 'update.help.option.apply'),
@@ -32,7 +34,7 @@ export function getUpdateHelp(lang = 'en') {
32
34
  { label: '--json', description: t(lang, 'cli.option.json') },
33
35
  { label: '-h, --help', description: t(lang, 'cli.option.help') },
34
36
  ],
35
- examples: ['mf update --dry-run', 'mf update --dry-run --json', 'mf update --apply'],
37
+ examples: ['mf update --dry-run', 'mf update --dry-run --diff', 'mf update --dry-run --diff --json', 'mf update --apply'],
36
38
  exitCodes: [
37
39
  {
38
40
  label: '0',
@@ -86,7 +88,27 @@ function templateTargetSafetyIssue(projectRoot, targetPath, allowMissingLeaf) {
86
88
  return error instanceof Error ? error.message : String(error);
87
89
  }
88
90
  }
89
- export function planUpdate(projectRoot) {
91
+ function createPlanItem(source, action, reason) {
92
+ return {
93
+ relativePath: source.relativePath,
94
+ sourceKind: source.sourceKind,
95
+ source,
96
+ action,
97
+ reason,
98
+ };
99
+ }
100
+ function publicPlanItem(item) {
101
+ return {
102
+ relativePath: item.relativePath,
103
+ sourceKind: item.sourceKind,
104
+ action: item.action,
105
+ reason: item.reason,
106
+ };
107
+ }
108
+ function publicPlanItems(items) {
109
+ return items.map((item) => publicPlanItem(item));
110
+ }
111
+ function createUpdatePlan(projectRoot) {
90
112
  const lockResult = readManifestLock(projectRoot);
91
113
  if (lockResult.kind === 'missing') {
92
114
  return { items: [], error: `Missing ${MANIFEST_LOCK_RELATIVE_PATH}` };
@@ -111,94 +133,68 @@ export function planUpdate(projectRoot) {
111
133
  ensureInside(projectRoot, targetPath);
112
134
  const unsafeTargetReason = templateTargetSafetyIssue(projectRoot, targetPath, true);
113
135
  if (unsafeTargetReason) {
114
- items.push({
115
- relativePath: source.relativePath,
116
- sourceKind: source.sourceKind,
117
- action: 'blocked-local-change',
118
- reason: unsafeTargetReason,
119
- });
136
+ items.push(createPlanItem(source, 'blocked-local-change', unsafeTargetReason));
120
137
  continue;
121
138
  }
122
139
  if (!existsSync(targetPath)) {
123
140
  if (lockedFile) {
124
- items.push({
125
- relativePath: source.relativePath,
126
- sourceKind: source.sourceKind,
127
- action: 'blocked-local-change',
128
- reason: 'target file is missing but tracked by the manifest lock',
129
- });
141
+ items.push(createPlanItem(source, 'blocked-local-change', 'target file is missing but tracked by the manifest lock'));
130
142
  continue;
131
143
  }
132
- items.push({
133
- relativePath: source.relativePath,
134
- sourceKind: source.sourceKind,
135
- action: 'create',
136
- reason: 'target file is missing',
137
- });
144
+ items.push(createPlanItem(source, 'create', 'target file is missing'));
138
145
  continue;
139
146
  }
140
147
  const currentHash = sha256File(targetPath);
141
148
  const templateHash = templateFileHash(source);
142
149
  if (!lockedFile && currentHash !== templateHash) {
143
- items.push({
144
- relativePath: source.relativePath,
145
- sourceKind: source.sourceKind,
146
- action: 'blocked-local-change',
147
- reason: 'target file exists but is not tracked by the manifest lock',
148
- });
150
+ items.push(createPlanItem(source, 'blocked-local-change', 'target file exists but is not tracked by the manifest lock'));
149
151
  continue;
150
152
  }
151
153
  if (lockedFile && currentHash !== lockedFile.contentHash) {
152
- items.push({
153
- relativePath: source.relativePath,
154
- sourceKind: source.sourceKind,
155
- action: 'blocked-local-change',
156
- reason: 'current file differs from the manifest lock baseline',
157
- });
154
+ items.push(createPlanItem(source, 'blocked-local-change', 'current file differs from the manifest lock baseline'));
158
155
  continue;
159
156
  }
160
157
  if (lockedFile?.lastAction === CUSTOMIZED_LOCK_ACTION && currentHash !== templateHash) {
161
- items.push({
162
- relativePath: source.relativePath,
163
- sourceKind: source.sourceKind,
164
- action: 'unchanged',
165
- reason: 'manifest lock marks this file as customized and current file matches that baseline',
166
- });
158
+ items.push(createPlanItem(source, 'unchanged', 'manifest lock marks this file as customized and current file matches that baseline'));
167
159
  continue;
168
160
  }
169
161
  if (lockedFile?.source === 'managed_block' && currentHash !== templateHash) {
170
- items.push({
171
- relativePath: source.relativePath,
172
- sourceKind: source.sourceKind,
173
- action: 'manual-review',
174
- reason: 'managed block requires a block-level manifest baseline',
175
- });
162
+ items.push(createPlanItem(source, 'manual-review', 'managed block requires a block-level manifest baseline'));
176
163
  continue;
177
164
  }
178
165
  if (currentHash !== templateHash) {
179
- items.push({
180
- relativePath: source.relativePath,
181
- sourceKind: source.sourceKind,
182
- action: 'update',
183
- reason: 'template content differs from current file',
184
- });
166
+ items.push(createPlanItem(source, 'update', 'template content differs from current file'));
185
167
  continue;
186
168
  }
187
- items.push({
188
- relativePath: source.relativePath,
189
- sourceKind: source.sourceKind,
190
- action: 'unchanged',
191
- reason: 'current file matches the bundled template',
192
- });
169
+ items.push(createPlanItem(source, 'unchanged', 'current file matches the bundled template'));
193
170
  }
194
171
  return { items };
195
172
  }
173
+ export function planUpdate(projectRoot) {
174
+ const plan = createUpdatePlan(projectRoot);
175
+ return {
176
+ items: publicPlanItems(plan.items),
177
+ ...(plan.error ? { error: plan.error } : {}),
178
+ };
179
+ }
196
180
  function printItems(title, items, reporter) {
197
181
  reporter.stdout(`${title}: ${items.length}`);
198
182
  for (const item of items) {
199
183
  reporter.stdout(`- ${item.relativePath} (${item.reason})`);
200
184
  }
201
185
  }
186
+ function withDiffPreviews(projectRoot, items) {
187
+ return items.map((item) => {
188
+ const publicItem = publicPlanItem(item);
189
+ if (!shouldPreviewUpdateDiff(item.action)) {
190
+ return publicItem;
191
+ }
192
+ return {
193
+ ...publicItem,
194
+ diff_preview: createUpdateDiffPreview(projectRoot, item),
195
+ };
196
+ });
197
+ }
202
198
  export function summarizePlan(items) {
203
199
  return {
204
200
  blockedLocalChanges: items.filter((item) => item.action === 'blocked-local-change').length,
@@ -369,16 +365,37 @@ function printPlan(output, reporter, lang) {
369
365
  reporter.stdout(t(lang, 'update.plan.noUpdates'));
370
366
  }
371
367
  }
368
+ function printDiffPreviews(items, reporter, lang) {
369
+ const itemsWithDiff = items.filter((item) => item.diff_preview);
370
+ if (itemsWithDiff.length === 0) {
371
+ return;
372
+ }
373
+ reporter.stdout(t(lang, 'update.diff.title'));
374
+ for (const item of itemsWithDiff) {
375
+ const preview = item.diff_preview;
376
+ if (!preview) {
377
+ continue;
378
+ }
379
+ if (!preview.available) {
380
+ reporter.stdout(`# ${item.relativePath}: ${t(lang, 'update.diff.unavailable', { reason: preview.reason ?? 'unknown' })}`);
381
+ continue;
382
+ }
383
+ for (const line of preview.lines) {
384
+ reporter.stdout(line);
385
+ }
386
+ }
387
+ }
372
388
  export function runUpdate(args, reporter, lang = 'en') {
373
389
  if (args.includes('--help') || args.includes('-h')) {
374
390
  reporter.stdout(getUpdateHelp(lang));
375
391
  return 0;
376
392
  }
377
- const supported = new Set(['--dry-run', '--apply', '--json']);
393
+ const supported = new Set(['--dry-run', '--apply', '--json', '--diff']);
378
394
  const unsupported = args.filter((arg) => !supported.has(arg));
379
395
  const wantsJson = args.includes('--json');
380
396
  const wantsDryRun = args.includes('--dry-run');
381
397
  const wantsApply = args.includes('--apply');
398
+ const wantsDiff = args.includes('--diff');
382
399
  const requestedMode = getRequestedMode(wantsDryRun, wantsApply);
383
400
  if (unsupported.length > 0) {
384
401
  printUsageError(reporter, t(lang, 'cli.error.unknownOption', { option: unsupported[0] }), 'mf update --help', getUpdateHelp(lang), lang);
@@ -393,6 +410,15 @@ export function runUpdate(args, reporter, lang = 'en') {
393
410
  printUsageError(reporter, error, 'mf update --help', getUpdateHelp(lang), lang);
394
411
  return 1;
395
412
  }
413
+ if (wantsDiff && !wantsDryRun) {
414
+ const error = t(lang, 'update.error.diffRequiresDryRun');
415
+ if (wantsJson) {
416
+ reporter.stdout(JSON.stringify(withMode(planOutput([], error, false), requestedMode), null, 2));
417
+ return 1;
418
+ }
419
+ printUsageError(reporter, error, 'mf update --help', getUpdateHelp(lang), lang);
420
+ return 1;
421
+ }
396
422
  if (!wantsDryRun && !wantsApply) {
397
423
  const error = t(lang, 'update.error.missingMode');
398
424
  if (wantsJson) {
@@ -403,22 +429,26 @@ export function runUpdate(args, reporter, lang = 'en') {
403
429
  return 1;
404
430
  }
405
431
  const projectRoot = resolveMustflowRoot();
406
- const plan = planUpdate(projectRoot);
432
+ const plan = createUpdatePlan(projectRoot);
407
433
  if (plan.error) {
408
434
  if (wantsJson) {
409
- reporter.stdout(JSON.stringify(withMode(planOutput(plan.items, plan.error, false), requestedMode), null, 2));
435
+ reporter.stdout(JSON.stringify(withMode(planOutput(publicPlanItems(plan.items), plan.error, false), requestedMode), null, 2));
410
436
  return 1;
411
437
  }
412
438
  reporter.stderr(plan.error);
413
439
  return 1;
414
440
  }
415
- const dryRunOutput = withMode(planOutput(plan.items, undefined, false), requestedMode);
441
+ const outputItems = wantsDiff ? withDiffPreviews(projectRoot, plan.items) : publicPlanItems(plan.items);
442
+ const dryRunOutput = withMode(planOutput(outputItems, undefined, false), requestedMode);
416
443
  if (wantsDryRun) {
417
444
  if (wantsJson) {
418
445
  reporter.stdout(JSON.stringify(dryRunOutput, null, 2));
419
446
  return dryRunOutput.ok ? 0 : 1;
420
447
  }
421
448
  printPlan(dryRunOutput, reporter, lang);
449
+ if (wantsDiff) {
450
+ printDiffPreviews(dryRunOutput.items, reporter, lang);
451
+ }
422
452
  reporter.stdout(t(lang, 'update.plan.noFilesWritten'));
423
453
  return dryRunOutput.ok ? 0 : 1;
424
454
  }
@@ -437,7 +467,7 @@ export function runUpdate(args, reporter, lang = 'en') {
437
467
  stdout: () => undefined,
438
468
  stderr: (message) => reporter.stderr(message),
439
469
  }, lang);
440
- reporter.stdout(JSON.stringify(withMode(planOutput(plan.items, undefined, applyResult.wroteFiles), 'apply'), null, 2));
470
+ reporter.stdout(JSON.stringify(withMode(planOutput(publicPlanItems(plan.items), undefined, applyResult.wroteFiles), 'apply'), null, 2));
441
471
  return 0;
442
472
  }
443
473
  const applyResult = applyUpdate(projectRoot, plan.items, reporter, lang);