mustflow 1.15.97

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 (415) hide show
  1. package/LICENSE +16 -0
  2. package/README.md +422 -0
  3. package/dist/cli/commands/check.js +73 -0
  4. package/dist/cli/commands/classify.js +104 -0
  5. package/dist/cli/commands/context.js +95 -0
  6. package/dist/cli/commands/contract-lint.js +74 -0
  7. package/dist/cli/commands/dashboard.js +654 -0
  8. package/dist/cli/commands/docs.js +382 -0
  9. package/dist/cli/commands/doctor.js +232 -0
  10. package/dist/cli/commands/explain.js +293 -0
  11. package/dist/cli/commands/help.js +148 -0
  12. package/dist/cli/commands/impact.js +120 -0
  13. package/dist/cli/commands/index.js +70 -0
  14. package/dist/cli/commands/init.js +986 -0
  15. package/dist/cli/commands/line-endings.js +102 -0
  16. package/dist/cli/commands/map.js +95 -0
  17. package/dist/cli/commands/run.js +442 -0
  18. package/dist/cli/commands/search.js +166 -0
  19. package/dist/cli/commands/status.js +65 -0
  20. package/dist/cli/commands/update.js +443 -0
  21. package/dist/cli/commands/verify.js +448 -0
  22. package/dist/cli/commands/version-sources.js +79 -0
  23. package/dist/cli/commands/version.js +57 -0
  24. package/dist/cli/i18n/en.js +702 -0
  25. package/dist/cli/i18n/es.js +702 -0
  26. package/dist/cli/i18n/fr.js +702 -0
  27. package/dist/cli/i18n/hi.js +702 -0
  28. package/dist/cli/i18n/ko.js +702 -0
  29. package/dist/cli/i18n/zh.js +702 -0
  30. package/dist/cli/index.js +218 -0
  31. package/dist/cli/lib/agent-context.js +342 -0
  32. package/dist/cli/lib/browser-open.js +58 -0
  33. package/dist/cli/lib/cli-output.js +36 -0
  34. package/dist/cli/lib/command-contract.js +1 -0
  35. package/dist/cli/lib/command-registry.js +107 -0
  36. package/dist/cli/lib/dashboard-html.js +1866 -0
  37. package/dist/cli/lib/dashboard-locale.js +309 -0
  38. package/dist/cli/lib/dashboard-preferences.js +405 -0
  39. package/dist/cli/lib/doc-review-ledger.js +226 -0
  40. package/dist/cli/lib/filesystem.js +125 -0
  41. package/dist/cli/lib/git-changes.js +13 -0
  42. package/dist/cli/lib/i18n.js +55 -0
  43. package/dist/cli/lib/local-index.js +1014 -0
  44. package/dist/cli/lib/locale-tags.js +4 -0
  45. package/dist/cli/lib/manifest-lock.js +131 -0
  46. package/dist/cli/lib/npm-version-check.js +97 -0
  47. package/dist/cli/lib/package-info.js +13 -0
  48. package/dist/cli/lib/preferences-options.js +8 -0
  49. package/dist/cli/lib/project-root.js +23 -0
  50. package/dist/cli/lib/repo-map.js +635 -0
  51. package/dist/cli/lib/reporter.js +8 -0
  52. package/dist/cli/lib/run-receipt.js +1 -0
  53. package/dist/cli/lib/template-i18n.js +265 -0
  54. package/dist/cli/lib/templates.js +188 -0
  55. package/dist/cli/lib/toml.js +1 -0
  56. package/dist/cli/lib/validation.js +1639 -0
  57. package/dist/cli/lib/version-sources.js +1 -0
  58. package/dist/core/authority-resolution.js +155 -0
  59. package/dist/core/change-classification.js +122 -0
  60. package/dist/core/change-verification.js +80 -0
  61. package/dist/core/check-issues.js +67 -0
  62. package/dist/core/command-classification.js +22 -0
  63. package/dist/core/command-contract-rules.js +27 -0
  64. package/dist/core/command-contract-validation.js +197 -0
  65. package/dist/core/command-cwd.js +12 -0
  66. package/dist/core/command-effects.js +182 -0
  67. package/dist/core/command-explanation.js +135 -0
  68. package/dist/core/command-intent-eligibility.js +76 -0
  69. package/dist/core/config-loading.js +54 -0
  70. package/dist/core/contract-lint.js +110 -0
  71. package/dist/core/contract-models.js +53 -0
  72. package/dist/core/dashboard-verification.js +132 -0
  73. package/dist/core/doc-review-triage.js +92 -0
  74. package/dist/core/line-endings.js +144 -0
  75. package/dist/core/public-json-contracts.js +112 -0
  76. package/dist/core/public-surface-explanation.js +49 -0
  77. package/dist/core/release-version-validation.js +53 -0
  78. package/dist/core/retention-explanation.js +74 -0
  79. package/dist/core/retention-policy.js +57 -0
  80. package/dist/core/run-receipt.js +77 -0
  81. package/dist/core/skill-route-alignment.js +100 -0
  82. package/dist/core/skill-route-explanation.js +117 -0
  83. package/dist/core/source-anchor-explanation.js +33 -0
  84. package/dist/core/source-anchor-status.js +269 -0
  85. package/dist/core/source-anchor-symbols.js +181 -0
  86. package/dist/core/source-anchor-validation.js +158 -0
  87. package/dist/core/source-anchors.js +194 -0
  88. package/dist/core/surface-decision-model.js +18 -0
  89. package/dist/core/toml.js +11 -0
  90. package/dist/core/verification-plan.js +41 -0
  91. package/dist/core/verification-scheduler.js +92 -0
  92. package/dist/core/version-impact.js +54 -0
  93. package/dist/core/version-sources.js +235 -0
  94. package/dist/core/version-sync-policy.js +85 -0
  95. package/examples/README.md +13 -0
  96. package/examples/docs-only/README.md +72 -0
  97. package/examples/host-instruction-conflicts/README.md +47 -0
  98. package/examples/minimal-js/README.md +98 -0
  99. package/examples/missing-command-contracts/README.md +70 -0
  100. package/examples/nested-repos/README.md +62 -0
  101. package/package.json +80 -0
  102. package/schemas/README.md +32 -0
  103. package/schemas/change-verification-report.schema.json +319 -0
  104. package/schemas/classify-report.schema.json +113 -0
  105. package/schemas/commands.schema.json +116 -0
  106. package/schemas/context-report.schema.json +341 -0
  107. package/schemas/contract-lint-report.schema.json +61 -0
  108. package/schemas/docs-review-list.schema.json +72 -0
  109. package/schemas/doctor-report.schema.json +175 -0
  110. package/schemas/explain-report.schema.json +471 -0
  111. package/schemas/impact-report.schema.json +121 -0
  112. package/schemas/line-endings-report.schema.json +63 -0
  113. package/schemas/run-receipt.schema.json +75 -0
  114. package/schemas/verify-report.schema.json +67 -0
  115. package/schemas/version-sources-report.schema.json +42 -0
  116. package/templates/default/common/.mustflow/config/commands.toml +251 -0
  117. package/templates/default/common/.mustflow/config/mustflow.toml +424 -0
  118. package/templates/default/common/.mustflow/config/preferences.toml +125 -0
  119. package/templates/default/common/gitignore.mustflow +9 -0
  120. package/templates/default/i18n.toml +483 -0
  121. package/templates/default/locales/en/.mustflow/context/INDEX.md +39 -0
  122. package/templates/default/locales/en/.mustflow/context/PROJECT.md +66 -0
  123. package/templates/default/locales/en/.mustflow/docs/agent-workflow.md +345 -0
  124. package/templates/default/locales/en/.mustflow/skills/INDEX.md +78 -0
  125. package/templates/default/locales/en/.mustflow/skills/adapter-boundary/SKILL.md +193 -0
  126. package/templates/default/locales/en/.mustflow/skills/artifact-integrity-check/SKILL.md +121 -0
  127. package/templates/default/locales/en/.mustflow/skills/behavior-preserving-refactor/SKILL.md +182 -0
  128. package/templates/default/locales/en/.mustflow/skills/code-review/SKILL.md +115 -0
  129. package/templates/default/locales/en/.mustflow/skills/codebase-orientation/SKILL.md +115 -0
  130. package/templates/default/locales/en/.mustflow/skills/command-pattern/SKILL.md +247 -0
  131. package/templates/default/locales/en/.mustflow/skills/composition-over-inheritance/SKILL.md +176 -0
  132. package/templates/default/locales/en/.mustflow/skills/contract-sync-check/SKILL.md +116 -0
  133. package/templates/default/locales/en/.mustflow/skills/date-number-audit/SKILL.md +116 -0
  134. package/templates/default/locales/en/.mustflow/skills/dependency-injection/SKILL.md +161 -0
  135. package/templates/default/locales/en/.mustflow/skills/dependency-reality-check/SKILL.md +115 -0
  136. package/templates/default/locales/en/.mustflow/skills/diff-risk-review/SKILL.md +143 -0
  137. package/templates/default/locales/en/.mustflow/skills/docs-prose-review/SKILL.md +119 -0
  138. package/templates/default/locales/en/.mustflow/skills/docs-update/SKILL.md +100 -0
  139. package/templates/default/locales/en/.mustflow/skills/external-prompt-injection-defense/SKILL.md +124 -0
  140. package/templates/default/locales/en/.mustflow/skills/facade-pattern/SKILL.md +210 -0
  141. package/templates/default/locales/en/.mustflow/skills/failure-triage/SKILL.md +97 -0
  142. package/templates/default/locales/en/.mustflow/skills/instruction-conflict-scope-check/SKILL.md +118 -0
  143. package/templates/default/locales/en/.mustflow/skills/line-ending-hygiene/SKILL.md +111 -0
  144. package/templates/default/locales/en/.mustflow/skills/migration-safety-check/SKILL.md +117 -0
  145. package/templates/default/locales/en/.mustflow/skills/multi-agent-work-coordination/SKILL.md +260 -0
  146. package/templates/default/locales/en/.mustflow/skills/null-object-pattern/SKILL.md +196 -0
  147. package/templates/default/locales/en/.mustflow/skills/pattern-scout/SKILL.md +110 -0
  148. package/templates/default/locales/en/.mustflow/skills/performance-budget-check/SKILL.md +121 -0
  149. package/templates/default/locales/en/.mustflow/skills/project-context-authoring/SKILL.md +107 -0
  150. package/templates/default/locales/en/.mustflow/skills/pure-core-imperative-shell/SKILL.md +212 -0
  151. package/templates/default/locales/en/.mustflow/skills/readme-authoring/SKILL.md +115 -0
  152. package/templates/default/locales/en/.mustflow/skills/repo-improvement-loop/SKILL.md +150 -0
  153. package/templates/default/locales/en/.mustflow/skills/repro-first-debug/SKILL.md +112 -0
  154. package/templates/default/locales/en/.mustflow/skills/requirement-regression-guard/SKILL.md +152 -0
  155. package/templates/default/locales/en/.mustflow/skills/result-option/SKILL.md +186 -0
  156. package/templates/default/locales/en/.mustflow/skills/security-privacy-review/SKILL.md +130 -0
  157. package/templates/default/locales/en/.mustflow/skills/security-regression-tests/SKILL.md +157 -0
  158. package/templates/default/locales/en/.mustflow/skills/skill-authoring/SKILL.md +110 -0
  159. package/templates/default/locales/en/.mustflow/skills/source-freshness-check/SKILL.md +111 -0
  160. package/templates/default/locales/en/.mustflow/skills/state-machine-pattern/SKILL.md +214 -0
  161. package/templates/default/locales/en/.mustflow/skills/strategy-pattern/SKILL.md +215 -0
  162. package/templates/default/locales/en/.mustflow/skills/structure-discovery-gate/SKILL.md +159 -0
  163. package/templates/default/locales/en/.mustflow/skills/test-maintenance/SKILL.md +122 -0
  164. package/templates/default/locales/en/.mustflow/skills/ui-quality-gate/SKILL.md +119 -0
  165. package/templates/default/locales/en/.mustflow/skills/visual-review-artifact/SKILL.md +127 -0
  166. package/templates/default/locales/en/.mustflow/skills/visual-review-artifact/assets/review-template.html +286 -0
  167. package/templates/default/locales/en/.mustflow/skills/visual-review-artifact/resources.toml +7 -0
  168. package/templates/default/locales/en/.mustflow/skills/web-asset-optimization/SKILL.md +108 -0
  169. package/templates/default/locales/en/AGENTS.md +114 -0
  170. package/templates/default/locales/es/.mustflow/context/INDEX.md +39 -0
  171. package/templates/default/locales/es/.mustflow/context/PROJECT.md +63 -0
  172. package/templates/default/locales/es/.mustflow/docs/agent-workflow.md +365 -0
  173. package/templates/default/locales/es/.mustflow/skills/INDEX.md +78 -0
  174. package/templates/default/locales/es/.mustflow/skills/adapter-boundary/SKILL.md +193 -0
  175. package/templates/default/locales/es/.mustflow/skills/artifact-integrity-check/SKILL.md +114 -0
  176. package/templates/default/locales/es/.mustflow/skills/behavior-preserving-refactor/SKILL.md +182 -0
  177. package/templates/default/locales/es/.mustflow/skills/code-review/SKILL.md +115 -0
  178. package/templates/default/locales/es/.mustflow/skills/codebase-orientation/SKILL.md +115 -0
  179. package/templates/default/locales/es/.mustflow/skills/command-pattern/SKILL.md +247 -0
  180. package/templates/default/locales/es/.mustflow/skills/composition-over-inheritance/SKILL.md +176 -0
  181. package/templates/default/locales/es/.mustflow/skills/contract-sync-check/SKILL.md +116 -0
  182. package/templates/default/locales/es/.mustflow/skills/date-number-audit/SKILL.md +116 -0
  183. package/templates/default/locales/es/.mustflow/skills/dependency-injection/SKILL.md +161 -0
  184. package/templates/default/locales/es/.mustflow/skills/dependency-reality-check/SKILL.md +115 -0
  185. package/templates/default/locales/es/.mustflow/skills/diff-risk-review/SKILL.md +136 -0
  186. package/templates/default/locales/es/.mustflow/skills/docs-prose-review/SKILL.md +119 -0
  187. package/templates/default/locales/es/.mustflow/skills/docs-update/SKILL.md +97 -0
  188. package/templates/default/locales/es/.mustflow/skills/external-prompt-injection-defense/SKILL.md +116 -0
  189. package/templates/default/locales/es/.mustflow/skills/facade-pattern/SKILL.md +210 -0
  190. package/templates/default/locales/es/.mustflow/skills/failure-triage/SKILL.md +97 -0
  191. package/templates/default/locales/es/.mustflow/skills/instruction-conflict-scope-check/SKILL.md +118 -0
  192. package/templates/default/locales/es/.mustflow/skills/line-ending-hygiene/SKILL.md +111 -0
  193. package/templates/default/locales/es/.mustflow/skills/migration-safety-check/SKILL.md +117 -0
  194. package/templates/default/locales/es/.mustflow/skills/multi-agent-work-coordination/SKILL.md +260 -0
  195. package/templates/default/locales/es/.mustflow/skills/null-object-pattern/SKILL.md +196 -0
  196. package/templates/default/locales/es/.mustflow/skills/pattern-scout/SKILL.md +110 -0
  197. package/templates/default/locales/es/.mustflow/skills/performance-budget-check/SKILL.md +121 -0
  198. package/templates/default/locales/es/.mustflow/skills/project-context-authoring/SKILL.md +107 -0
  199. package/templates/default/locales/es/.mustflow/skills/pure-core-imperative-shell/SKILL.md +212 -0
  200. package/templates/default/locales/es/.mustflow/skills/readme-authoring/SKILL.md +115 -0
  201. package/templates/default/locales/es/.mustflow/skills/repo-improvement-loop/SKILL.md +150 -0
  202. package/templates/default/locales/es/.mustflow/skills/repro-first-debug/SKILL.md +112 -0
  203. package/templates/default/locales/es/.mustflow/skills/requirement-regression-guard/SKILL.md +152 -0
  204. package/templates/default/locales/es/.mustflow/skills/result-option/SKILL.md +186 -0
  205. package/templates/default/locales/es/.mustflow/skills/security-privacy-review/SKILL.md +116 -0
  206. package/templates/default/locales/es/.mustflow/skills/security-regression-tests/SKILL.md +131 -0
  207. package/templates/default/locales/es/.mustflow/skills/skill-authoring/SKILL.md +110 -0
  208. package/templates/default/locales/es/.mustflow/skills/source-freshness-check/SKILL.md +111 -0
  209. package/templates/default/locales/es/.mustflow/skills/state-machine-pattern/SKILL.md +214 -0
  210. package/templates/default/locales/es/.mustflow/skills/strategy-pattern/SKILL.md +215 -0
  211. package/templates/default/locales/es/.mustflow/skills/structure-discovery-gate/SKILL.md +159 -0
  212. package/templates/default/locales/es/.mustflow/skills/test-maintenance/SKILL.md +122 -0
  213. package/templates/default/locales/es/.mustflow/skills/ui-quality-gate/SKILL.md +117 -0
  214. package/templates/default/locales/es/.mustflow/skills/visual-review-artifact/SKILL.md +127 -0
  215. package/templates/default/locales/es/.mustflow/skills/visual-review-artifact/assets/review-template.html +286 -0
  216. package/templates/default/locales/es/.mustflow/skills/visual-review-artifact/resources.toml +7 -0
  217. package/templates/default/locales/es/.mustflow/skills/web-asset-optimization/SKILL.md +108 -0
  218. package/templates/default/locales/es/AGENTS.md +83 -0
  219. package/templates/default/locales/fr/.mustflow/context/INDEX.md +39 -0
  220. package/templates/default/locales/fr/.mustflow/context/PROJECT.md +63 -0
  221. package/templates/default/locales/fr/.mustflow/docs/agent-workflow.md +368 -0
  222. package/templates/default/locales/fr/.mustflow/skills/INDEX.md +78 -0
  223. package/templates/default/locales/fr/.mustflow/skills/adapter-boundary/SKILL.md +193 -0
  224. package/templates/default/locales/fr/.mustflow/skills/artifact-integrity-check/SKILL.md +114 -0
  225. package/templates/default/locales/fr/.mustflow/skills/behavior-preserving-refactor/SKILL.md +182 -0
  226. package/templates/default/locales/fr/.mustflow/skills/code-review/SKILL.md +115 -0
  227. package/templates/default/locales/fr/.mustflow/skills/codebase-orientation/SKILL.md +115 -0
  228. package/templates/default/locales/fr/.mustflow/skills/command-pattern/SKILL.md +247 -0
  229. package/templates/default/locales/fr/.mustflow/skills/composition-over-inheritance/SKILL.md +176 -0
  230. package/templates/default/locales/fr/.mustflow/skills/contract-sync-check/SKILL.md +116 -0
  231. package/templates/default/locales/fr/.mustflow/skills/date-number-audit/SKILL.md +116 -0
  232. package/templates/default/locales/fr/.mustflow/skills/dependency-injection/SKILL.md +161 -0
  233. package/templates/default/locales/fr/.mustflow/skills/dependency-reality-check/SKILL.md +115 -0
  234. package/templates/default/locales/fr/.mustflow/skills/diff-risk-review/SKILL.md +136 -0
  235. package/templates/default/locales/fr/.mustflow/skills/docs-prose-review/SKILL.md +119 -0
  236. package/templates/default/locales/fr/.mustflow/skills/docs-update/SKILL.md +97 -0
  237. package/templates/default/locales/fr/.mustflow/skills/external-prompt-injection-defense/SKILL.md +116 -0
  238. package/templates/default/locales/fr/.mustflow/skills/facade-pattern/SKILL.md +210 -0
  239. package/templates/default/locales/fr/.mustflow/skills/failure-triage/SKILL.md +97 -0
  240. package/templates/default/locales/fr/.mustflow/skills/instruction-conflict-scope-check/SKILL.md +118 -0
  241. package/templates/default/locales/fr/.mustflow/skills/line-ending-hygiene/SKILL.md +111 -0
  242. package/templates/default/locales/fr/.mustflow/skills/migration-safety-check/SKILL.md +117 -0
  243. package/templates/default/locales/fr/.mustflow/skills/multi-agent-work-coordination/SKILL.md +260 -0
  244. package/templates/default/locales/fr/.mustflow/skills/null-object-pattern/SKILL.md +196 -0
  245. package/templates/default/locales/fr/.mustflow/skills/pattern-scout/SKILL.md +110 -0
  246. package/templates/default/locales/fr/.mustflow/skills/performance-budget-check/SKILL.md +121 -0
  247. package/templates/default/locales/fr/.mustflow/skills/project-context-authoring/SKILL.md +107 -0
  248. package/templates/default/locales/fr/.mustflow/skills/pure-core-imperative-shell/SKILL.md +212 -0
  249. package/templates/default/locales/fr/.mustflow/skills/readme-authoring/SKILL.md +115 -0
  250. package/templates/default/locales/fr/.mustflow/skills/repo-improvement-loop/SKILL.md +150 -0
  251. package/templates/default/locales/fr/.mustflow/skills/repro-first-debug/SKILL.md +112 -0
  252. package/templates/default/locales/fr/.mustflow/skills/requirement-regression-guard/SKILL.md +152 -0
  253. package/templates/default/locales/fr/.mustflow/skills/result-option/SKILL.md +186 -0
  254. package/templates/default/locales/fr/.mustflow/skills/security-privacy-review/SKILL.md +116 -0
  255. package/templates/default/locales/fr/.mustflow/skills/security-regression-tests/SKILL.md +131 -0
  256. package/templates/default/locales/fr/.mustflow/skills/skill-authoring/SKILL.md +110 -0
  257. package/templates/default/locales/fr/.mustflow/skills/source-freshness-check/SKILL.md +111 -0
  258. package/templates/default/locales/fr/.mustflow/skills/state-machine-pattern/SKILL.md +214 -0
  259. package/templates/default/locales/fr/.mustflow/skills/strategy-pattern/SKILL.md +215 -0
  260. package/templates/default/locales/fr/.mustflow/skills/structure-discovery-gate/SKILL.md +159 -0
  261. package/templates/default/locales/fr/.mustflow/skills/test-maintenance/SKILL.md +122 -0
  262. package/templates/default/locales/fr/.mustflow/skills/ui-quality-gate/SKILL.md +117 -0
  263. package/templates/default/locales/fr/.mustflow/skills/visual-review-artifact/SKILL.md +127 -0
  264. package/templates/default/locales/fr/.mustflow/skills/visual-review-artifact/assets/review-template.html +286 -0
  265. package/templates/default/locales/fr/.mustflow/skills/visual-review-artifact/resources.toml +7 -0
  266. package/templates/default/locales/fr/.mustflow/skills/web-asset-optimization/SKILL.md +108 -0
  267. package/templates/default/locales/fr/AGENTS.md +84 -0
  268. package/templates/default/locales/hi/.mustflow/context/INDEX.md +39 -0
  269. package/templates/default/locales/hi/.mustflow/context/PROJECT.md +65 -0
  270. package/templates/default/locales/hi/.mustflow/docs/agent-workflow.md +359 -0
  271. package/templates/default/locales/hi/.mustflow/skills/INDEX.md +78 -0
  272. package/templates/default/locales/hi/.mustflow/skills/adapter-boundary/SKILL.md +193 -0
  273. package/templates/default/locales/hi/.mustflow/skills/artifact-integrity-check/SKILL.md +114 -0
  274. package/templates/default/locales/hi/.mustflow/skills/behavior-preserving-refactor/SKILL.md +182 -0
  275. package/templates/default/locales/hi/.mustflow/skills/code-review/SKILL.md +115 -0
  276. package/templates/default/locales/hi/.mustflow/skills/codebase-orientation/SKILL.md +115 -0
  277. package/templates/default/locales/hi/.mustflow/skills/command-pattern/SKILL.md +247 -0
  278. package/templates/default/locales/hi/.mustflow/skills/composition-over-inheritance/SKILL.md +176 -0
  279. package/templates/default/locales/hi/.mustflow/skills/contract-sync-check/SKILL.md +116 -0
  280. package/templates/default/locales/hi/.mustflow/skills/date-number-audit/SKILL.md +116 -0
  281. package/templates/default/locales/hi/.mustflow/skills/dependency-injection/SKILL.md +161 -0
  282. package/templates/default/locales/hi/.mustflow/skills/dependency-reality-check/SKILL.md +115 -0
  283. package/templates/default/locales/hi/.mustflow/skills/diff-risk-review/SKILL.md +136 -0
  284. package/templates/default/locales/hi/.mustflow/skills/docs-prose-review/SKILL.md +119 -0
  285. package/templates/default/locales/hi/.mustflow/skills/docs-update/SKILL.md +97 -0
  286. package/templates/default/locales/hi/.mustflow/skills/external-prompt-injection-defense/SKILL.md +116 -0
  287. package/templates/default/locales/hi/.mustflow/skills/facade-pattern/SKILL.md +210 -0
  288. package/templates/default/locales/hi/.mustflow/skills/failure-triage/SKILL.md +97 -0
  289. package/templates/default/locales/hi/.mustflow/skills/instruction-conflict-scope-check/SKILL.md +118 -0
  290. package/templates/default/locales/hi/.mustflow/skills/line-ending-hygiene/SKILL.md +111 -0
  291. package/templates/default/locales/hi/.mustflow/skills/migration-safety-check/SKILL.md +117 -0
  292. package/templates/default/locales/hi/.mustflow/skills/multi-agent-work-coordination/SKILL.md +260 -0
  293. package/templates/default/locales/hi/.mustflow/skills/null-object-pattern/SKILL.md +196 -0
  294. package/templates/default/locales/hi/.mustflow/skills/pattern-scout/SKILL.md +110 -0
  295. package/templates/default/locales/hi/.mustflow/skills/performance-budget-check/SKILL.md +121 -0
  296. package/templates/default/locales/hi/.mustflow/skills/project-context-authoring/SKILL.md +107 -0
  297. package/templates/default/locales/hi/.mustflow/skills/pure-core-imperative-shell/SKILL.md +212 -0
  298. package/templates/default/locales/hi/.mustflow/skills/readme-authoring/SKILL.md +115 -0
  299. package/templates/default/locales/hi/.mustflow/skills/repo-improvement-loop/SKILL.md +150 -0
  300. package/templates/default/locales/hi/.mustflow/skills/repro-first-debug/SKILL.md +112 -0
  301. package/templates/default/locales/hi/.mustflow/skills/requirement-regression-guard/SKILL.md +152 -0
  302. package/templates/default/locales/hi/.mustflow/skills/result-option/SKILL.md +186 -0
  303. package/templates/default/locales/hi/.mustflow/skills/security-privacy-review/SKILL.md +116 -0
  304. package/templates/default/locales/hi/.mustflow/skills/security-regression-tests/SKILL.md +131 -0
  305. package/templates/default/locales/hi/.mustflow/skills/skill-authoring/SKILL.md +110 -0
  306. package/templates/default/locales/hi/.mustflow/skills/source-freshness-check/SKILL.md +111 -0
  307. package/templates/default/locales/hi/.mustflow/skills/state-machine-pattern/SKILL.md +214 -0
  308. package/templates/default/locales/hi/.mustflow/skills/strategy-pattern/SKILL.md +215 -0
  309. package/templates/default/locales/hi/.mustflow/skills/structure-discovery-gate/SKILL.md +159 -0
  310. package/templates/default/locales/hi/.mustflow/skills/test-maintenance/SKILL.md +122 -0
  311. package/templates/default/locales/hi/.mustflow/skills/ui-quality-gate/SKILL.md +117 -0
  312. package/templates/default/locales/hi/.mustflow/skills/visual-review-artifact/SKILL.md +127 -0
  313. package/templates/default/locales/hi/.mustflow/skills/visual-review-artifact/assets/review-template.html +286 -0
  314. package/templates/default/locales/hi/.mustflow/skills/visual-review-artifact/resources.toml +7 -0
  315. package/templates/default/locales/hi/.mustflow/skills/web-asset-optimization/SKILL.md +108 -0
  316. package/templates/default/locales/hi/AGENTS.md +83 -0
  317. package/templates/default/locales/ko/.mustflow/context/INDEX.md +39 -0
  318. package/templates/default/locales/ko/.mustflow/context/PROJECT.md +66 -0
  319. package/templates/default/locales/ko/.mustflow/docs/agent-workflow.md +506 -0
  320. package/templates/default/locales/ko/.mustflow/skills/INDEX.md +78 -0
  321. package/templates/default/locales/ko/.mustflow/skills/adapter-boundary/SKILL.md +193 -0
  322. package/templates/default/locales/ko/.mustflow/skills/artifact-integrity-check/SKILL.md +114 -0
  323. package/templates/default/locales/ko/.mustflow/skills/behavior-preserving-refactor/SKILL.md +182 -0
  324. package/templates/default/locales/ko/.mustflow/skills/code-review/SKILL.md +118 -0
  325. package/templates/default/locales/ko/.mustflow/skills/codebase-orientation/SKILL.md +115 -0
  326. package/templates/default/locales/ko/.mustflow/skills/command-pattern/SKILL.md +247 -0
  327. package/templates/default/locales/ko/.mustflow/skills/composition-over-inheritance/SKILL.md +176 -0
  328. package/templates/default/locales/ko/.mustflow/skills/contract-sync-check/SKILL.md +116 -0
  329. package/templates/default/locales/ko/.mustflow/skills/date-number-audit/SKILL.md +116 -0
  330. package/templates/default/locales/ko/.mustflow/skills/dependency-injection/SKILL.md +161 -0
  331. package/templates/default/locales/ko/.mustflow/skills/dependency-reality-check/SKILL.md +115 -0
  332. package/templates/default/locales/ko/.mustflow/skills/diff-risk-review/SKILL.md +136 -0
  333. package/templates/default/locales/ko/.mustflow/skills/docs-prose-review/SKILL.md +119 -0
  334. package/templates/default/locales/ko/.mustflow/skills/docs-update/SKILL.md +107 -0
  335. package/templates/default/locales/ko/.mustflow/skills/external-prompt-injection-defense/SKILL.md +116 -0
  336. package/templates/default/locales/ko/.mustflow/skills/facade-pattern/SKILL.md +210 -0
  337. package/templates/default/locales/ko/.mustflow/skills/failure-triage/SKILL.md +119 -0
  338. package/templates/default/locales/ko/.mustflow/skills/instruction-conflict-scope-check/SKILL.md +118 -0
  339. package/templates/default/locales/ko/.mustflow/skills/line-ending-hygiene/SKILL.md +111 -0
  340. package/templates/default/locales/ko/.mustflow/skills/migration-safety-check/SKILL.md +117 -0
  341. package/templates/default/locales/ko/.mustflow/skills/multi-agent-work-coordination/SKILL.md +259 -0
  342. package/templates/default/locales/ko/.mustflow/skills/null-object-pattern/SKILL.md +196 -0
  343. package/templates/default/locales/ko/.mustflow/skills/pattern-scout/SKILL.md +110 -0
  344. package/templates/default/locales/ko/.mustflow/skills/performance-budget-check/SKILL.md +121 -0
  345. package/templates/default/locales/ko/.mustflow/skills/project-context-authoring/SKILL.md +107 -0
  346. package/templates/default/locales/ko/.mustflow/skills/pure-core-imperative-shell/SKILL.md +212 -0
  347. package/templates/default/locales/ko/.mustflow/skills/readme-authoring/SKILL.md +115 -0
  348. package/templates/default/locales/ko/.mustflow/skills/repo-improvement-loop/SKILL.md +150 -0
  349. package/templates/default/locales/ko/.mustflow/skills/repro-first-debug/SKILL.md +112 -0
  350. package/templates/default/locales/ko/.mustflow/skills/requirement-regression-guard/SKILL.md +152 -0
  351. package/templates/default/locales/ko/.mustflow/skills/result-option/SKILL.md +186 -0
  352. package/templates/default/locales/ko/.mustflow/skills/security-privacy-review/SKILL.md +116 -0
  353. package/templates/default/locales/ko/.mustflow/skills/security-regression-tests/SKILL.md +131 -0
  354. package/templates/default/locales/ko/.mustflow/skills/skill-authoring/SKILL.md +110 -0
  355. package/templates/default/locales/ko/.mustflow/skills/source-freshness-check/SKILL.md +111 -0
  356. package/templates/default/locales/ko/.mustflow/skills/state-machine-pattern/SKILL.md +214 -0
  357. package/templates/default/locales/ko/.mustflow/skills/strategy-pattern/SKILL.md +215 -0
  358. package/templates/default/locales/ko/.mustflow/skills/structure-discovery-gate/SKILL.md +159 -0
  359. package/templates/default/locales/ko/.mustflow/skills/test-maintenance/SKILL.md +130 -0
  360. package/templates/default/locales/ko/.mustflow/skills/ui-quality-gate/SKILL.md +117 -0
  361. package/templates/default/locales/ko/.mustflow/skills/visual-review-artifact/SKILL.md +127 -0
  362. package/templates/default/locales/ko/.mustflow/skills/visual-review-artifact/assets/review-template.html +286 -0
  363. package/templates/default/locales/ko/.mustflow/skills/visual-review-artifact/resources.toml +7 -0
  364. package/templates/default/locales/ko/.mustflow/skills/web-asset-optimization/SKILL.md +108 -0
  365. package/templates/default/locales/ko/AGENTS.md +85 -0
  366. package/templates/default/locales/zh/.mustflow/context/INDEX.md +39 -0
  367. package/templates/default/locales/zh/.mustflow/context/PROJECT.md +64 -0
  368. package/templates/default/locales/zh/.mustflow/docs/agent-workflow.md +310 -0
  369. package/templates/default/locales/zh/.mustflow/skills/INDEX.md +78 -0
  370. package/templates/default/locales/zh/.mustflow/skills/adapter-boundary/SKILL.md +193 -0
  371. package/templates/default/locales/zh/.mustflow/skills/artifact-integrity-check/SKILL.md +114 -0
  372. package/templates/default/locales/zh/.mustflow/skills/behavior-preserving-refactor/SKILL.md +182 -0
  373. package/templates/default/locales/zh/.mustflow/skills/code-review/SKILL.md +115 -0
  374. package/templates/default/locales/zh/.mustflow/skills/codebase-orientation/SKILL.md +115 -0
  375. package/templates/default/locales/zh/.mustflow/skills/command-pattern/SKILL.md +247 -0
  376. package/templates/default/locales/zh/.mustflow/skills/composition-over-inheritance/SKILL.md +176 -0
  377. package/templates/default/locales/zh/.mustflow/skills/contract-sync-check/SKILL.md +116 -0
  378. package/templates/default/locales/zh/.mustflow/skills/date-number-audit/SKILL.md +116 -0
  379. package/templates/default/locales/zh/.mustflow/skills/dependency-injection/SKILL.md +161 -0
  380. package/templates/default/locales/zh/.mustflow/skills/dependency-reality-check/SKILL.md +115 -0
  381. package/templates/default/locales/zh/.mustflow/skills/diff-risk-review/SKILL.md +136 -0
  382. package/templates/default/locales/zh/.mustflow/skills/docs-prose-review/SKILL.md +119 -0
  383. package/templates/default/locales/zh/.mustflow/skills/docs-update/SKILL.md +97 -0
  384. package/templates/default/locales/zh/.mustflow/skills/external-prompt-injection-defense/SKILL.md +116 -0
  385. package/templates/default/locales/zh/.mustflow/skills/facade-pattern/SKILL.md +210 -0
  386. package/templates/default/locales/zh/.mustflow/skills/failure-triage/SKILL.md +96 -0
  387. package/templates/default/locales/zh/.mustflow/skills/instruction-conflict-scope-check/SKILL.md +118 -0
  388. package/templates/default/locales/zh/.mustflow/skills/line-ending-hygiene/SKILL.md +111 -0
  389. package/templates/default/locales/zh/.mustflow/skills/migration-safety-check/SKILL.md +117 -0
  390. package/templates/default/locales/zh/.mustflow/skills/multi-agent-work-coordination/SKILL.md +260 -0
  391. package/templates/default/locales/zh/.mustflow/skills/null-object-pattern/SKILL.md +196 -0
  392. package/templates/default/locales/zh/.mustflow/skills/pattern-scout/SKILL.md +110 -0
  393. package/templates/default/locales/zh/.mustflow/skills/performance-budget-check/SKILL.md +121 -0
  394. package/templates/default/locales/zh/.mustflow/skills/project-context-authoring/SKILL.md +107 -0
  395. package/templates/default/locales/zh/.mustflow/skills/pure-core-imperative-shell/SKILL.md +212 -0
  396. package/templates/default/locales/zh/.mustflow/skills/readme-authoring/SKILL.md +115 -0
  397. package/templates/default/locales/zh/.mustflow/skills/repo-improvement-loop/SKILL.md +150 -0
  398. package/templates/default/locales/zh/.mustflow/skills/repro-first-debug/SKILL.md +112 -0
  399. package/templates/default/locales/zh/.mustflow/skills/requirement-regression-guard/SKILL.md +152 -0
  400. package/templates/default/locales/zh/.mustflow/skills/result-option/SKILL.md +186 -0
  401. package/templates/default/locales/zh/.mustflow/skills/security-privacy-review/SKILL.md +116 -0
  402. package/templates/default/locales/zh/.mustflow/skills/security-regression-tests/SKILL.md +131 -0
  403. package/templates/default/locales/zh/.mustflow/skills/skill-authoring/SKILL.md +110 -0
  404. package/templates/default/locales/zh/.mustflow/skills/source-freshness-check/SKILL.md +111 -0
  405. package/templates/default/locales/zh/.mustflow/skills/state-machine-pattern/SKILL.md +214 -0
  406. package/templates/default/locales/zh/.mustflow/skills/strategy-pattern/SKILL.md +215 -0
  407. package/templates/default/locales/zh/.mustflow/skills/structure-discovery-gate/SKILL.md +159 -0
  408. package/templates/default/locales/zh/.mustflow/skills/test-maintenance/SKILL.md +122 -0
  409. package/templates/default/locales/zh/.mustflow/skills/ui-quality-gate/SKILL.md +117 -0
  410. package/templates/default/locales/zh/.mustflow/skills/visual-review-artifact/SKILL.md +127 -0
  411. package/templates/default/locales/zh/.mustflow/skills/visual-review-artifact/assets/review-template.html +286 -0
  412. package/templates/default/locales/zh/.mustflow/skills/visual-review-artifact/resources.toml +7 -0
  413. package/templates/default/locales/zh/.mustflow/skills/web-asset-optimization/SKILL.md +108 -0
  414. package/templates/default/locales/zh/AGENTS.md +86 -0
  415. package/templates/default/manifest.toml +339 -0
@@ -0,0 +1,1866 @@
1
+ import { getDashboardLocaleBundle } from './dashboard-locale.js';
2
+ function escapeHtml(value) {
3
+ return value
4
+ .replace(/&/g, '&')
5
+ .replace(/</g, '&lt;')
6
+ .replace(/>/g, '&gt;')
7
+ .replace(/"/g, '&quot;')
8
+ .replace(/'/g, '&#39;');
9
+ }
10
+ export function renderDashboardHtml(snapshot, token, statusSnapshot, docReviewSnapshot) {
11
+ const root = escapeHtml(snapshot.projectRoot);
12
+ const preferencesPath = escapeHtml(snapshot.preferencesPath);
13
+ const serializedSnapshot = JSON.stringify(snapshot);
14
+ const serializedStatusSnapshot = JSON.stringify(statusSnapshot);
15
+ const serializedDocReviewSnapshot = JSON.stringify(docReviewSnapshot);
16
+ const serializedToken = JSON.stringify(token);
17
+ const localeBundle = getDashboardLocaleBundle();
18
+ const serializedLocaleBundle = JSON.stringify(localeBundle);
19
+ const serializedAvailableLocales = JSON.stringify(localeBundle.locales);
20
+ return `<!doctype html>
21
+ <html lang="en">
22
+ <head>
23
+ <meta charset="utf-8">
24
+ <meta name="viewport" content="width=device-width, initial-scale=1">
25
+ <title>mustflow dashboard</title>
26
+ <style>
27
+ :root {
28
+ color-scheme: light dark;
29
+ --bg: #101216;
30
+ --panel: #181b21;
31
+ --line: #2a2f3a;
32
+ --text: #eef1f7;
33
+ --muted: #aeb6c5;
34
+ --accent: #8fb4ff;
35
+ --danger: #ff9a9a;
36
+ --ok: #9be7ba;
37
+ font-family: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
38
+ }
39
+ * { box-sizing: border-box; }
40
+ body {
41
+ margin: 0;
42
+ background: var(--bg);
43
+ color: var(--text);
44
+ font-size: 17px;
45
+ }
46
+ header {
47
+ border-bottom: 1px solid var(--line);
48
+ padding: 16px 20px;
49
+ }
50
+ .title-row {
51
+ align-items: center;
52
+ display: flex;
53
+ gap: 8px;
54
+ margin-bottom: 8px;
55
+ }
56
+ h1 {
57
+ font-size: 22px;
58
+ line-height: 1.2;
59
+ margin: 0;
60
+ font-weight: 650;
61
+ }
62
+ .icon-button {
63
+ align-items: center;
64
+ display: inline-flex;
65
+ height: 34px;
66
+ justify-content: center;
67
+ padding: 0;
68
+ width: 34px;
69
+ }
70
+ .icon-button svg {
71
+ height: 18px;
72
+ width: 18px;
73
+ }
74
+ .path {
75
+ color: var(--muted);
76
+ font-size: 14px;
77
+ overflow-wrap: anywhere;
78
+ }
79
+ main {
80
+ max-width: 980px;
81
+ margin: 0 auto;
82
+ padding: 20px;
83
+ }
84
+ .toolbar {
85
+ align-items: center;
86
+ display: flex;
87
+ flex-wrap: wrap;
88
+ gap: 12px;
89
+ justify-content: flex-end;
90
+ margin-bottom: 14px;
91
+ min-height: 36px;
92
+ }
93
+ .tabs {
94
+ display: flex;
95
+ gap: 8px;
96
+ margin-bottom: 14px;
97
+ overflow-x: auto;
98
+ }
99
+ .tab {
100
+ border-color: transparent;
101
+ min-width: 110px;
102
+ }
103
+ .tab[aria-selected="true"] {
104
+ background: var(--panel);
105
+ border-color: var(--line);
106
+ }
107
+ .tab-panel[hidden] {
108
+ display: none;
109
+ }
110
+ .language-picker {
111
+ align-items: center;
112
+ display: inline-flex;
113
+ flex-shrink: 0;
114
+ gap: 8px;
115
+ }
116
+ .language-picker span {
117
+ color: var(--muted);
118
+ font-size: 14px;
119
+ white-space: nowrap;
120
+ }
121
+ .language-picker select {
122
+ min-width: 130px;
123
+ }
124
+ .status {
125
+ color: var(--muted);
126
+ font-size: 15px;
127
+ margin-right: auto;
128
+ }
129
+ .status.ok { color: var(--ok); }
130
+ .status.error { color: var(--danger); }
131
+ button, select, input {
132
+ background: #11141a;
133
+ border: 1px solid var(--line);
134
+ border-radius: 6px;
135
+ color: var(--text);
136
+ font: inherit;
137
+ min-height: 38px;
138
+ }
139
+ button {
140
+ cursor: pointer;
141
+ padding: 0 14px;
142
+ }
143
+ button:disabled {
144
+ cursor: not-allowed;
145
+ opacity: 0.6;
146
+ }
147
+ section {
148
+ border-top: 1px solid var(--line);
149
+ padding: 14px 0;
150
+ }
151
+ h2 {
152
+ font-size: 15px;
153
+ line-height: 1.25;
154
+ margin: 0 0 8px;
155
+ color: var(--muted);
156
+ font-weight: 650;
157
+ }
158
+ .setting {
159
+ align-items: center;
160
+ display: grid;
161
+ gap: 12px;
162
+ grid-template-columns: minmax(220px, 1fr) minmax(120px, 240px);
163
+ min-height: 48px;
164
+ padding: 6px 0;
165
+ }
166
+ .label {
167
+ font-size: 16px;
168
+ }
169
+ .value-description {
170
+ color: var(--muted);
171
+ font-size: 13px;
172
+ line-height: 1.35;
173
+ margin-left: 10px;
174
+ }
175
+ .meta {
176
+ color: var(--muted);
177
+ font-size: 13px;
178
+ margin-top: 2px;
179
+ }
180
+ .status-grid {
181
+ display: grid;
182
+ gap: 8px;
183
+ grid-template-columns: repeat(2, minmax(0, 1fr));
184
+ }
185
+ .status-item {
186
+ border-bottom: 1px solid var(--line);
187
+ display: grid;
188
+ gap: 4px;
189
+ padding: 8px 0;
190
+ }
191
+ .status-label {
192
+ color: var(--muted);
193
+ font-size: 13px;
194
+ }
195
+ .status-value {
196
+ font-size: 15px;
197
+ overflow-wrap: anywhere;
198
+ }
199
+ .status-value.ok { color: var(--ok); }
200
+ .status-value.warn { color: var(--danger); }
201
+ .issue-list {
202
+ margin: 0;
203
+ padding-left: 18px;
204
+ }
205
+ .issue-list li {
206
+ margin: 4px 0;
207
+ overflow-wrap: anywhere;
208
+ }
209
+ .command-row {
210
+ border-bottom: 1px solid var(--line);
211
+ display: grid;
212
+ gap: 10px;
213
+ grid-template-columns: minmax(160px, 220px) 1fr;
214
+ padding: 10px 0;
215
+ }
216
+ .command-name {
217
+ font-weight: 650;
218
+ overflow-wrap: anywhere;
219
+ }
220
+ .command-state {
221
+ color: var(--muted);
222
+ font-size: 13px;
223
+ margin-top: 4px;
224
+ }
225
+ .command-state.ok { color: var(--ok); }
226
+ .command-state.warn { color: var(--danger); }
227
+ .command-description {
228
+ font-size: 15px;
229
+ overflow-wrap: anywhere;
230
+ }
231
+ .command-meta {
232
+ color: var(--muted);
233
+ display: flex;
234
+ flex-wrap: wrap;
235
+ font-size: 13px;
236
+ gap: 8px 14px;
237
+ margin-top: 6px;
238
+ }
239
+ .command-note {
240
+ color: var(--muted);
241
+ font-size: 13px;
242
+ margin-top: 6px;
243
+ overflow-wrap: anywhere;
244
+ }
245
+ .verification-row {
246
+ border-bottom: 1px solid var(--line);
247
+ display: grid;
248
+ gap: 10px;
249
+ grid-template-columns: minmax(160px, 220px) 1fr auto;
250
+ padding: 10px 0;
251
+ }
252
+ .verification-command {
253
+ font-family: ui-monospace, SFMono-Regular, Consolas, "Liberation Mono", monospace;
254
+ font-size: 14px;
255
+ overflow-wrap: anywhere;
256
+ }
257
+ .verification-files {
258
+ color: var(--muted);
259
+ font-size: 13px;
260
+ margin-top: 6px;
261
+ overflow-wrap: anywhere;
262
+ }
263
+ .verification-copy {
264
+ min-height: 34px;
265
+ padding: 0 10px;
266
+ }
267
+ .doc-controls {
268
+ display: grid;
269
+ gap: 10px;
270
+ margin-bottom: 14px;
271
+ }
272
+ .doc-filter-controls,
273
+ .doc-review-controls {
274
+ align-items: end;
275
+ display: grid;
276
+ gap: 10px;
277
+ }
278
+ .doc-filter-controls {
279
+ grid-template-columns: minmax(130px, 160px) minmax(180px, 1fr);
280
+ }
281
+ .doc-review-controls {
282
+ grid-template-columns: minmax(130px, 170px) minmax(160px, 1fr) minmax(180px, 1fr);
283
+ }
284
+ .doc-controls label,
285
+ .doc-control-group-label {
286
+ display: grid;
287
+ gap: 5px;
288
+ }
289
+ .doc-controls span,
290
+ .doc-control-group-label {
291
+ color: var(--muted);
292
+ font-size: 13px;
293
+ }
294
+ .doc-list {
295
+ border-top: 1px solid var(--line);
296
+ }
297
+ .doc-row {
298
+ align-items: center;
299
+ border-bottom: 1px solid var(--line);
300
+ display: grid;
301
+ gap: 12px;
302
+ grid-template-columns: minmax(0, 1fr) minmax(90px, auto) auto;
303
+ padding: 10px 0;
304
+ }
305
+ .doc-path {
306
+ font-size: 15px;
307
+ overflow-wrap: anywhere;
308
+ }
309
+ .doc-meta {
310
+ color: var(--muted);
311
+ font-size: 13px;
312
+ margin-top: 3px;
313
+ overflow-wrap: anywhere;
314
+ }
315
+ .doc-comment {
316
+ background: rgba(255, 255, 255, 0.04);
317
+ border: 1px solid var(--line);
318
+ border-radius: 6px;
319
+ color: var(--text);
320
+ font: inherit;
321
+ font-size: 13px;
322
+ line-height: 1.45;
323
+ margin: 8px 0 0;
324
+ max-height: 180px;
325
+ overflow: auto;
326
+ padding: 8px;
327
+ white-space: pre-wrap;
328
+ }
329
+ .doc-status {
330
+ color: var(--muted);
331
+ font-size: 13px;
332
+ white-space: nowrap;
333
+ }
334
+ .doc-actions {
335
+ display: flex;
336
+ flex-wrap: wrap;
337
+ gap: 8px;
338
+ justify-content: flex-end;
339
+ }
340
+ .doc-actions button {
341
+ min-height: 34px;
342
+ padding: 0 10px;
343
+ }
344
+ .empty {
345
+ color: var(--muted);
346
+ padding: 14px 0;
347
+ }
348
+ select, input[type="number"], input[type="text"] {
349
+ padding: 0 12px;
350
+ width: 100%;
351
+ }
352
+ select {
353
+ appearance: none;
354
+ background-image:
355
+ linear-gradient(45deg, transparent 50%, currentColor 50%),
356
+ linear-gradient(135deg, currentColor 50%, transparent 50%);
357
+ background-position:
358
+ calc(100% - 22px) 50%,
359
+ calc(100% - 16px) 50%;
360
+ background-repeat: no-repeat;
361
+ background-size: 6px 6px, 6px 6px;
362
+ padding-right: 44px;
363
+ }
364
+ select::-ms-expand {
365
+ display: none;
366
+ }
367
+ .setting-control {
368
+ width: 100%;
369
+ }
370
+ .locale-tag-control {
371
+ display: grid;
372
+ gap: 8px;
373
+ width: 100%;
374
+ }
375
+ .locale-tag-control input[hidden] {
376
+ display: none;
377
+ }
378
+ input[type="checkbox"] {
379
+ height: 22px;
380
+ justify-self: end;
381
+ min-height: 22px;
382
+ width: 22px;
383
+ }
384
+ @media (max-width: 640px) {
385
+ main { padding: 14px; }
386
+ .setting {
387
+ grid-template-columns: 1fr;
388
+ gap: 6px;
389
+ }
390
+ input[type="checkbox"] {
391
+ justify-self: start;
392
+ }
393
+ .doc-controls,
394
+ .doc-filter-controls,
395
+ .doc-review-controls,
396
+ .doc-row,
397
+ .verification-row,
398
+ .status-grid {
399
+ grid-template-columns: 1fr;
400
+ }
401
+ .doc-actions {
402
+ justify-content: flex-start;
403
+ }
404
+ }
405
+ </style>
406
+ </head>
407
+ <body>
408
+ <header>
409
+ <div class="title-row">
410
+ <h1 id="dashboard-title">mustflow dashboard</h1>
411
+ <button id="open-mustflow" class="icon-button" type="button" aria-label="Open .mustflow folder" title="Open .mustflow folder">
412
+ <svg aria-hidden="true" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
413
+ <path d="M4 20h16a2 2 0 0 0 2-2V8a2 2 0 0 0-2-2h-7.2a2 2 0 0 1-1.6-.8L10 4H4a2 2 0 0 0-2 2v12a2 2 0 0 0 2 2Z"></path>
414
+ </svg>
415
+ </button>
416
+ </div>
417
+ <div class="path">${root}</div>
418
+ <div class="path">${preferencesPath}</div>
419
+ </header>
420
+ <main>
421
+ <nav class="tabs" aria-label="Dashboard sections">
422
+ <button id="tab-status" class="tab" type="button" data-tab="status" aria-controls="panel-status" aria-selected="true">Status</button>
423
+ <button id="tab-verification" class="tab" type="button" data-tab="verification" aria-controls="panel-verification" aria-selected="false">Verification</button>
424
+ <button id="tab-commands" class="tab" type="button" data-tab="commands" aria-controls="panel-commands" aria-selected="false">Commands</button>
425
+ <button id="tab-release" class="tab" type="button" data-tab="release" aria-controls="panel-release" aria-selected="false">Release</button>
426
+ <button id="tab-update" class="tab" type="button" data-tab="update" aria-controls="panel-update" aria-selected="false">Update</button>
427
+ <button id="tab-runs" class="tab" type="button" data-tab="runs" aria-controls="panel-runs" aria-selected="false">Runs</button>
428
+ <button id="tab-skills" class="tab" type="button" data-tab="skills" aria-controls="panel-skills" aria-selected="false">Skills</button>
429
+ <button id="tab-settings" class="tab" type="button" data-tab="settings" aria-controls="panel-settings" aria-selected="false">Settings</button>
430
+ <button id="tab-documents" class="tab" type="button" data-tab="documents" aria-controls="panel-documents" aria-selected="false">Documents</button>
431
+ </nav>
432
+ <div class="toolbar">
433
+ <div id="status" class="status">No changes</div>
434
+ <label class="language-picker" for="dashboard-language">
435
+ <span id="dashboard-language-label">Language</span>
436
+ <select id="dashboard-language" name="dashboard-language"></select>
437
+ </label>
438
+ <button id="reload" type="button">Reload</button>
439
+ <button id="save" type="button" disabled>Save</button>
440
+ </div>
441
+ <div id="panel-status" class="tab-panel">
442
+ <div id="dashboard-status"></div>
443
+ </div>
444
+ <div id="panel-verification" class="tab-panel" hidden>
445
+ <div id="dashboard-verification"></div>
446
+ </div>
447
+ <div id="panel-commands" class="tab-panel" hidden>
448
+ <div id="dashboard-commands"></div>
449
+ </div>
450
+ <div id="panel-release" class="tab-panel" hidden>
451
+ <div id="dashboard-release"></div>
452
+ </div>
453
+ <div id="panel-update" class="tab-panel" hidden>
454
+ <div id="dashboard-update"></div>
455
+ </div>
456
+ <div id="panel-runs" class="tab-panel" hidden>
457
+ <div id="dashboard-runs"></div>
458
+ </div>
459
+ <div id="panel-skills" class="tab-panel" hidden>
460
+ <div id="dashboard-skills"></div>
461
+ </div>
462
+ <div id="panel-settings" class="tab-panel" hidden>
463
+ <div id="settings"></div>
464
+ </div>
465
+ <div id="panel-documents" class="tab-panel" hidden>
466
+ <div class="doc-controls">
467
+ <div class="doc-filter-controls">
468
+ <label for="doc-status-filter">
469
+ <span id="doc-status-filter-label">Status</span>
470
+ <select id="doc-status-filter"></select>
471
+ </label>
472
+ <label for="doc-path-filter">
473
+ <span id="doc-path-filter-label">File name</span>
474
+ <input id="doc-path-filter" type="text" autocomplete="off" spellcheck="false">
475
+ </label>
476
+ </div>
477
+ <div class="doc-control-group-label" id="doc-review-fields-label">Review record</div>
478
+ <div class="doc-review-controls">
479
+ <label for="doc-reviewer-kind">
480
+ <span id="doc-reviewer-kind-label">Reviewer kind</span>
481
+ <select id="doc-reviewer-kind"></select>
482
+ </label>
483
+ <label for="doc-reviewer-id">
484
+ <span id="doc-reviewer-id-label">Reviewer ID</span>
485
+ <input id="doc-reviewer-id" type="text" autocomplete="off" spellcheck="false">
486
+ </label>
487
+ <label for="doc-review-summary">
488
+ <span id="doc-review-summary-label">Summary</span>
489
+ <input id="doc-review-summary" type="text" autocomplete="off">
490
+ </label>
491
+ </div>
492
+ </div>
493
+ <div id="docs-review-list" class="doc-list"></div>
494
+ </div>
495
+ </main>
496
+ <script>
497
+ const initialSnapshot = ${serializedSnapshot};
498
+ const dashboardToken = ${serializedToken};
499
+ const dashboardLocales = ${serializedLocaleBundle};
500
+ const availableLocales = ${serializedAvailableLocales};
501
+ const initialStatusSnapshot = ${serializedStatusSnapshot};
502
+ const initialDocReview = ${serializedDocReviewSnapshot};
503
+ let snapshot = initialSnapshot;
504
+ let pending = new Map();
505
+ let currentLocale = resolveInitialLocale();
506
+ let statusState = { key: "dashboard.ui.noChanges", text: "", type: "" };
507
+ let currentTab = "status";
508
+ let dashboardStatus = initialStatusSnapshot;
509
+ let docReview = initialDocReview;
510
+
511
+ const groups = [
512
+ ["dashboard.group.git", ["git.auto_stage", "git.auto_commit", "git.auto_push"]],
513
+ ["dashboard.group.commitMessage", "git.commit_message."],
514
+ ["dashboard.group.reporting", "reporting."],
515
+ ["dashboard.group.verification", "verification.selection."],
516
+ ["dashboard.group.testAuthoring", "testing.authoring."],
517
+ ["dashboard.group.codeStyle", "code_style."],
518
+ ["dashboard.group.refactoring", "refactoring.hotspots."],
519
+ ["dashboard.group.versioning", "release.versioning."]
520
+ ];
521
+ const docStatusFilters = ["active", "pending", "in_review", "changes_made", "needs_human", "approved", "ignored", "all"];
522
+ const reviewerKinds = ["human", "llm", "tool", "external"];
523
+
524
+ function resolveInitialLocale() {
525
+ const stored = window.localStorage.getItem("mustflow.dashboard.language");
526
+ if (availableLocales.includes(stored)) return stored;
527
+ const browserLocale = (window.navigator.language || "").slice(0, 2).toLowerCase();
528
+ return availableLocales.includes(browserLocale) ? browserLocale : "en";
529
+ }
530
+
531
+ function message(key) {
532
+ return dashboardLocales.messages[currentLocale]?.[key] ?? dashboardLocales.messages.en[key] ?? key;
533
+ }
534
+
535
+ function messageExists(key) {
536
+ return Boolean(dashboardLocales.messages[currentLocale]?.[key] ?? dashboardLocales.messages.en[key]);
537
+ }
538
+
539
+ function statusText(text, type = "") {
540
+ statusState = { key: "", text, type };
541
+ renderStatus();
542
+ }
543
+
544
+ function statusKey(key, type = "") {
545
+ statusState = { key, text: "", type };
546
+ renderStatus();
547
+ }
548
+
549
+ function renderStatus() {
550
+ const element = document.getElementById("status");
551
+ const text = statusState.key ? message(statusState.key) : statusState.text;
552
+ element.textContent = text;
553
+ element.className = statusState.type ? "status " + statusState.type : "status";
554
+ }
555
+
556
+ function settingValue(id) {
557
+ return pending.has(id) ? pending.get(id) : snapshot.settings.find((setting) => setting.id === id)?.value;
558
+ }
559
+
560
+ function settingDescriptionKey(setting) {
561
+ const valueSpecificKey = "dashboard.setting." + setting.id + ".description." + String(settingValue(setting.id));
562
+ if (messageExists(valueSpecificKey)) return valueSpecificKey;
563
+ const key = "dashboard.setting." + setting.id + ".description";
564
+ return messageExists(key) ? key : "";
565
+ }
566
+
567
+ function settingDescription(setting) {
568
+ const key = settingDescriptionKey(setting);
569
+ return key ? message(key) : "";
570
+ }
571
+
572
+ function updateSettingDescription(id) {
573
+ const setting = snapshot.settings.find((item) => item.id === id);
574
+ if (!setting) return;
575
+ const element = document.getElementById(controlId(setting) + "-description");
576
+ if (element) element.textContent = settingDescription(setting);
577
+ }
578
+
579
+ function setPending(id, value) {
580
+ const original = snapshot.settings.find((setting) => setting.id === id)?.value;
581
+ if (Object.is(original, value)) {
582
+ pending.delete(id);
583
+ } else {
584
+ pending.set(id, value);
585
+ }
586
+ document.getElementById("save").disabled = pending.size === 0;
587
+ statusKey(pending.size === 0 ? "dashboard.ui.noChanges" : "dashboard.ui.unsavedChanges");
588
+ updateSettingDescription(id);
589
+ }
590
+
591
+ function controlId(setting) {
592
+ return "setting-" + setting.id.replace(/[^a-zA-Z0-9_-]/g, "-");
593
+ }
594
+
595
+ function renderInput(setting) {
596
+ if (setting.kind === "boolean") {
597
+ const input = document.createElement("input");
598
+ const inputId = controlId(setting);
599
+ input.id = inputId;
600
+ input.name = setting.id;
601
+ input.type = "checkbox";
602
+ input.checked = Boolean(settingValue(setting.id));
603
+ input.disabled = !setting.editable;
604
+ input.addEventListener("change", () => setPending(setting.id, input.checked));
605
+ return input;
606
+ }
607
+
608
+ if (setting.kind === "number") {
609
+ const input = document.createElement("input");
610
+ const inputId = controlId(setting);
611
+ input.id = inputId;
612
+ input.name = setting.id;
613
+ input.type = "number";
614
+ input.value = String(settingValue(setting.id));
615
+ if (setting.min !== undefined) input.min = String(setting.min);
616
+ if (setting.max !== undefined) input.max = String(setting.max);
617
+ input.disabled = !setting.editable;
618
+ input.addEventListener("input", () => setPending(setting.id, Number(input.value)));
619
+ return input;
620
+ }
621
+
622
+ if (setting.acceptsLocaleTag) {
623
+ const wrapper = document.createElement("div");
624
+ const select = document.createElement("select");
625
+ const customInput = document.createElement("input");
626
+ const inputId = controlId(setting);
627
+ const customInputId = inputId + "-custom";
628
+ const optionValues = setting.options || [];
629
+ const currentValue = String(settingValue(setting.id));
630
+ const customLocaleOptionValue = "__mustflow_custom_locale__";
631
+ const isCustomValue = !optionValues.includes(currentValue);
632
+ wrapper.className = "locale-tag-control";
633
+ select.id = inputId;
634
+ select.name = setting.id;
635
+ for (const option of optionValues) {
636
+ const child = document.createElement("option");
637
+ child.value = option;
638
+ child.textContent = option;
639
+ child.selected = option === currentValue;
640
+ select.appendChild(child);
641
+ }
642
+ const customChild = document.createElement("option");
643
+ customChild.value = customLocaleOptionValue;
644
+ customChild.textContent = message("dashboard.ui.customLocale");
645
+ customChild.selected = isCustomValue;
646
+ select.appendChild(customChild);
647
+ select.disabled = !setting.editable;
648
+
649
+ customInput.id = customInputId;
650
+ customInput.name = setting.id + ".custom";
651
+ customInput.type = "text";
652
+ customInput.autocomplete = "off";
653
+ customInput.spellcheck = false;
654
+ customInput.placeholder = "pt-BR";
655
+ customInput.value = isCustomValue ? currentValue : "";
656
+ customInput.hidden = !isCustomValue;
657
+ customInput.disabled = !setting.editable || !isCustomValue;
658
+ customInput.setAttribute("aria-label", message("dashboard.ui.customLocale"));
659
+
660
+ function updateCustomPending() {
661
+ const value = customInput.value.trim();
662
+ if (value.length > 0) {
663
+ setPending(setting.id, value);
664
+ } else {
665
+ const original = snapshot.settings.find((item) => item.id === setting.id)?.value;
666
+ if (original !== undefined) {
667
+ setPending(setting.id, original);
668
+ }
669
+ }
670
+ }
671
+
672
+ select.addEventListener("change", () => {
673
+ const customSelected = select.value === customLocaleOptionValue;
674
+ customInput.hidden = !customSelected;
675
+ customInput.disabled = !setting.editable || !customSelected;
676
+ if (customSelected) {
677
+ customInput.focus();
678
+ updateCustomPending();
679
+ } else {
680
+ setPending(setting.id, select.value);
681
+ }
682
+ });
683
+ customInput.addEventListener("input", updateCustomPending);
684
+ wrapper.appendChild(select);
685
+ wrapper.appendChild(customInput);
686
+ return wrapper;
687
+ }
688
+
689
+ const select = document.createElement("select");
690
+ const inputId = controlId(setting);
691
+ select.id = inputId;
692
+ select.name = setting.id;
693
+ for (const option of setting.options || []) {
694
+ const child = document.createElement("option");
695
+ child.value = option;
696
+ child.textContent = option;
697
+ child.selected = option === settingValue(setting.id);
698
+ select.appendChild(child);
699
+ }
700
+ select.disabled = !setting.editable;
701
+ select.addEventListener("change", () => setPending(setting.id, select.value));
702
+ return select;
703
+ }
704
+
705
+ function render() {
706
+ const root = document.getElementById("settings");
707
+ root.textContent = "";
708
+ for (const [titleKey, matcher] of groups) {
709
+ const settings = Array.isArray(matcher)
710
+ ? snapshot.settings.filter((setting) => matcher.includes(setting.id))
711
+ : snapshot.settings.filter((setting) => setting.id.startsWith(matcher));
712
+ if (settings.length === 0) continue;
713
+ const section = document.createElement("section");
714
+ const heading = document.createElement("h2");
715
+ heading.textContent = message(titleKey);
716
+ section.appendChild(heading);
717
+ for (const setting of settings) {
718
+ const row = document.createElement("div");
719
+ row.className = "setting";
720
+ const label = document.createElement("label");
721
+ label.htmlFor = controlId(setting);
722
+ const labelText = document.createElement("div");
723
+ labelText.className = "label";
724
+ const labelName = document.createElement("span");
725
+ labelName.textContent = message("dashboard.setting." + setting.id) || setting.label;
726
+ labelText.appendChild(labelName);
727
+ const descriptionText = settingDescription(setting);
728
+ if (descriptionText) {
729
+ const description = document.createElement("span");
730
+ description.id = controlId(setting) + "-description";
731
+ description.className = "value-description";
732
+ description.textContent = descriptionText;
733
+ labelText.appendChild(description);
734
+ }
735
+ label.appendChild(labelText);
736
+ if (!setting.editable) {
737
+ const meta = document.createElement("div");
738
+ meta.className = "meta";
739
+ meta.textContent = setting.lockedReason
740
+ ? message("dashboard.ui.locked") + ": " + message(setting.lockedReason)
741
+ : message("dashboard.ui.locked");
742
+ label.appendChild(meta);
743
+ }
744
+ row.appendChild(label);
745
+ row.appendChild(renderInput(setting));
746
+ section.appendChild(row);
747
+ }
748
+ root.appendChild(section);
749
+ }
750
+ }
751
+
752
+ function renderLocaleSelector() {
753
+ const select = document.getElementById("dashboard-language");
754
+ select.textContent = "";
755
+ for (const locale of availableLocales) {
756
+ const option = document.createElement("option");
757
+ option.value = locale;
758
+ option.textContent = dashboardLocales.names[locale] ?? locale;
759
+ option.selected = locale === currentLocale;
760
+ select.appendChild(option);
761
+ }
762
+ }
763
+
764
+ function renderChrome() {
765
+ document.documentElement.lang = currentLocale;
766
+ document.getElementById("dashboard-title").textContent = message("dashboard.ui.title");
767
+ document.getElementById("tab-status").textContent = message("dashboard.tab.status");
768
+ document.getElementById("tab-verification").textContent = message("dashboard.tab.verification") + " (" + dashboardStatus.verification.recommendations.length + ")";
769
+ document.getElementById("tab-commands").textContent = message("dashboard.tab.commands");
770
+ document.getElementById("tab-release").textContent = message("dashboard.tab.release");
771
+ document.getElementById("tab-update").textContent = message("dashboard.tab.update") + " (" + (dashboardStatus.update.blockers.length + dashboardStatus.update.changes.length) + ")";
772
+ document.getElementById("tab-runs").textContent = message("dashboard.tab.runs");
773
+ document.getElementById("tab-skills").textContent = message("dashboard.tab.skills") + " (" + dashboardStatus.skills.count + ")";
774
+ document.getElementById("tab-settings").textContent = message("dashboard.tab.settings");
775
+ document.getElementById("tab-documents").textContent = message("dashboard.tab.documents") + " (" + docReview.count + ")";
776
+ const openMustflow = document.getElementById("open-mustflow");
777
+ openMustflow.title = message("dashboard.ui.openMustflow");
778
+ openMustflow.setAttribute("aria-label", message("dashboard.ui.openMustflow"));
779
+ document.getElementById("dashboard-language-label").textContent = message("dashboard.ui.language");
780
+ document.getElementById("reload").textContent = message("dashboard.ui.reload");
781
+ document.getElementById("save").textContent = message("dashboard.ui.save");
782
+ document.getElementById("save").hidden = currentTab !== "settings";
783
+ document.getElementById("doc-status-filter-label").textContent = message("dashboard.docs.statusFilter");
784
+ document.getElementById("doc-path-filter-label").textContent = message("dashboard.docs.pathFilter");
785
+ document.getElementById("doc-review-fields-label").textContent = message("dashboard.docs.reviewFields");
786
+ document.getElementById("doc-reviewer-kind-label").textContent = message("dashboard.docs.reviewerKind");
787
+ document.getElementById("doc-reviewer-id-label").textContent = message("dashboard.docs.reviewerId");
788
+ document.getElementById("doc-review-summary-label").textContent = message("dashboard.docs.summary");
789
+ document.getElementById("doc-path-filter").placeholder = message("dashboard.docs.pathFilterPlaceholder");
790
+ document.getElementById("doc-reviewer-id").placeholder = message("dashboard.docs.reviewerIdPlaceholder");
791
+ document.getElementById("doc-review-summary").placeholder = message("dashboard.docs.summaryPlaceholder");
792
+ renderStatus();
793
+ }
794
+
795
+ function renderTabState() {
796
+ for (const tab of document.querySelectorAll(".tab")) {
797
+ const selected = tab.dataset.tab === currentTab;
798
+ tab.setAttribute("aria-selected", selected ? "true" : "false");
799
+ }
800
+ document.getElementById("panel-status").hidden = currentTab !== "status";
801
+ document.getElementById("panel-verification").hidden = currentTab !== "verification";
802
+ document.getElementById("panel-commands").hidden = currentTab !== "commands";
803
+ document.getElementById("panel-release").hidden = currentTab !== "release";
804
+ document.getElementById("panel-update").hidden = currentTab !== "update";
805
+ document.getElementById("panel-runs").hidden = currentTab !== "runs";
806
+ document.getElementById("panel-skills").hidden = currentTab !== "skills";
807
+ document.getElementById("panel-settings").hidden = currentTab !== "settings";
808
+ document.getElementById("panel-documents").hidden = currentTab !== "documents";
809
+ renderChrome();
810
+ }
811
+
812
+ async function openMustflowFolder() {
813
+ const response = await fetch("/api/open-mustflow", {
814
+ method: "POST",
815
+ headers: { "x-mustflow-dashboard-token": dashboardToken }
816
+ });
817
+ if (!response.ok) throw new Error(await response.text());
818
+ statusKey("dashboard.ui.openedMustflow", "ok");
819
+ }
820
+
821
+ async function loadSnapshot() {
822
+ const response = await fetch("/api/preferences", {
823
+ headers: { "x-mustflow-dashboard-token": dashboardToken }
824
+ });
825
+ if (!response.ok) throw new Error(await response.text());
826
+ snapshot = await response.json();
827
+ pending = new Map();
828
+ document.getElementById("save").disabled = true;
829
+ statusKey("dashboard.ui.reloaded", "ok");
830
+ render();
831
+ }
832
+
833
+ async function loadStatus() {
834
+ const response = await fetch("/api/status", {
835
+ headers: { "x-mustflow-dashboard-token": dashboardToken }
836
+ });
837
+ if (!response.ok) throw new Error(await response.text());
838
+ dashboardStatus = await response.json();
839
+ statusKey(
840
+ currentTab === "commands"
841
+ ? "dashboard.commands.reloaded"
842
+ : currentTab === "verification"
843
+ ? "dashboard.verification.reloaded"
844
+ : currentTab === "release"
845
+ ? "dashboard.release.reloaded"
846
+ : currentTab === "update"
847
+ ? "dashboard.update.reloaded"
848
+ : currentTab === "runs"
849
+ ? "dashboard.runs.reloaded"
850
+ : currentTab === "skills"
851
+ ? "dashboard.skills.reloaded"
852
+ : "dashboard.status.reloaded",
853
+ "ok"
854
+ );
855
+ renderStatusPanel();
856
+ renderVerificationPanel();
857
+ renderCommandPanel();
858
+ renderReleasePanel();
859
+ renderUpdatePanel();
860
+ renderRunsPanel();
861
+ renderSkillsPanel();
862
+ }
863
+
864
+ function docStatusQuery() {
865
+ const value = document.getElementById("doc-status-filter").value;
866
+ if (value === "active") return "";
867
+ if (value === "all") return "?all=1";
868
+ return "?status=" + encodeURIComponent(value);
869
+ }
870
+
871
+ function formatBoolean(value) {
872
+ return message(value ? "dashboard.status.yes" : "dashboard.status.no");
873
+ }
874
+
875
+ function formatLatestRun(latestRun) {
876
+ if (!latestRun.exists) return message("dashboard.status.latestRunMissing");
877
+ if (!latestRun.valid) return message("dashboard.status.latestRunInvalid") + ": " + latestRun.error;
878
+ const parts = [latestRun.intent, latestRun.status];
879
+ if (latestRun.exit_code !== null) parts.push("exit " + latestRun.exit_code);
880
+ if (latestRun.finished_at) parts.push(latestRun.finished_at);
881
+ return parts.join(" / ");
882
+ }
883
+
884
+ function appendStatusItem(root, labelKey, value, tone = "") {
885
+ const item = document.createElement("div");
886
+ item.className = "status-item";
887
+ const label = document.createElement("div");
888
+ label.className = "status-label";
889
+ label.textContent = message(labelKey);
890
+ const content = document.createElement("div");
891
+ content.className = tone ? "status-value " + tone : "status-value";
892
+ content.textContent = value;
893
+ item.appendChild(label);
894
+ item.appendChild(content);
895
+ root.appendChild(item);
896
+ }
897
+
898
+ function renderStatusPanel() {
899
+ const root = document.getElementById("dashboard-status");
900
+ root.textContent = "";
901
+ const section = document.createElement("section");
902
+ const heading = document.createElement("h2");
903
+ heading.textContent = message("dashboard.status.overview");
904
+ const grid = document.createElement("div");
905
+ grid.className = "status-grid";
906
+ const hasIssues = dashboardStatus.issues.length > 0 || dashboardStatus.changed_files.length > 0 || dashboardStatus.missing_files.length > 0;
907
+ appendStatusItem(grid, "dashboard.status.installed", formatBoolean(dashboardStatus.installed), dashboardStatus.installed ? "ok" : "warn");
908
+ appendStatusItem(grid, "dashboard.status.manifestLock", dashboardStatus.manifest_lock, dashboardStatus.manifest_lock === "present" ? "ok" : "warn");
909
+ appendStatusItem(grid, "dashboard.status.template", dashboardStatus.template ? dashboardStatus.template.id + " " + dashboardStatus.template.version : message("value.none"));
910
+ appendStatusItem(grid, "dashboard.status.trackedFiles", String(dashboardStatus.tracked_files));
911
+ appendStatusItem(grid, "dashboard.status.changedFiles", String(dashboardStatus.changed_files.length), dashboardStatus.changed_files.length === 0 ? "ok" : "warn");
912
+ appendStatusItem(grid, "dashboard.status.missingFiles", String(dashboardStatus.missing_files.length), dashboardStatus.missing_files.length === 0 ? "ok" : "warn");
913
+ appendStatusItem(grid, "dashboard.status.runnableIntents", String(dashboardStatus.runnable_intents.length));
914
+ appendStatusItem(grid, "dashboard.status.activeReviewDocuments", String(dashboardStatus.active_review_documents));
915
+ appendStatusItem(grid, "dashboard.status.latestRun", formatLatestRun(dashboardStatus.latest_run), dashboardStatus.latest_run.exists && dashboardStatus.latest_run.valid ? "ok" : "");
916
+ section.appendChild(heading);
917
+ section.appendChild(grid);
918
+ root.appendChild(section);
919
+
920
+ const issuesSection = document.createElement("section");
921
+ const issuesHeading = document.createElement("h2");
922
+ issuesHeading.textContent = message("dashboard.status.issues");
923
+ issuesSection.appendChild(issuesHeading);
924
+ if (!hasIssues) {
925
+ const empty = document.createElement("div");
926
+ empty.className = "empty";
927
+ empty.textContent = message("dashboard.status.noIssues");
928
+ issuesSection.appendChild(empty);
929
+ } else {
930
+ const list = document.createElement("ul");
931
+ list.className = "issue-list";
932
+ for (const issue of dashboardStatus.issues) {
933
+ const item = document.createElement("li");
934
+ item.textContent = issue;
935
+ list.appendChild(item);
936
+ }
937
+ for (const changed of dashboardStatus.changed_files) {
938
+ const item = document.createElement("li");
939
+ item.textContent = message("dashboard.status.changedFile") + ": " + changed;
940
+ list.appendChild(item);
941
+ }
942
+ for (const missing of dashboardStatus.missing_files) {
943
+ const item = document.createElement("li");
944
+ item.textContent = message("dashboard.status.missingFile") + ": " + missing;
945
+ list.appendChild(item);
946
+ }
947
+ issuesSection.appendChild(list);
948
+ }
949
+ root.appendChild(issuesSection);
950
+ }
951
+
952
+ async function copyVerificationCommand(command) {
953
+ await navigator.clipboard.writeText(command);
954
+ statusKey("dashboard.verification.copied", "ok");
955
+ }
956
+
957
+ async function copyVerificationPlan(commands) {
958
+ await navigator.clipboard.writeText(commands.join("\\n"));
959
+ statusKey("dashboard.verification.planCopied", "ok");
960
+ }
961
+
962
+ async function copyReleaseCommand(command) {
963
+ await navigator.clipboard.writeText(command);
964
+ statusKey("dashboard.release.copied", "ok");
965
+ }
966
+
967
+ async function copyUpdateCommand(command) {
968
+ await navigator.clipboard.writeText(command);
969
+ statusKey("dashboard.update.copied", "ok");
970
+ }
971
+
972
+ function appendVerificationFiles(root, files) {
973
+ if (files.length === 0) return;
974
+ const details = document.createElement("div");
975
+ details.className = "verification-files";
976
+ details.textContent = message("dashboard.verification.files") + ": " + files.join(", ");
977
+ root.appendChild(details);
978
+ }
979
+
980
+ function renderVerificationPanel() {
981
+ const root = document.getElementById("dashboard-verification");
982
+ root.textContent = "";
983
+ const verification = dashboardStatus.verification;
984
+
985
+ const section = document.createElement("section");
986
+ const heading = document.createElement("h2");
987
+ heading.textContent = message("dashboard.verification.recommendations");
988
+ section.appendChild(heading);
989
+
990
+ if (verification.changed_files.length === 0) {
991
+ const empty = document.createElement("div");
992
+ empty.className = "empty";
993
+ empty.textContent = message("dashboard.verification.empty");
994
+ section.appendChild(empty);
995
+ root.appendChild(section);
996
+ return;
997
+ }
998
+
999
+ if (verification.recommendations.length === 0) {
1000
+ const empty = document.createElement("div");
1001
+ empty.className = "empty";
1002
+ empty.textContent = message("dashboard.verification.none");
1003
+ section.appendChild(empty);
1004
+ root.appendChild(section);
1005
+ return;
1006
+ }
1007
+
1008
+ for (const recommendation of verification.recommendations) {
1009
+ const row = document.createElement("div");
1010
+ row.className = "verification-row";
1011
+ const summary = document.createElement("div");
1012
+ const name = document.createElement("div");
1013
+ name.className = "command-name";
1014
+ name.textContent = recommendation.intent;
1015
+ const state = document.createElement("div");
1016
+ state.className = recommendation.runnable ? "command-state ok" : "command-state warn";
1017
+ state.textContent = recommendation.runnable ? message("dashboard.commands.runnable") : message("dashboard.verification.unavailable");
1018
+ summary.appendChild(name);
1019
+ summary.appendChild(state);
1020
+
1021
+ const details = document.createElement("div");
1022
+ const command = document.createElement("div");
1023
+ command.className = "verification-command";
1024
+ command.textContent = recommendation.command;
1025
+ const reason = document.createElement("div");
1026
+ reason.className = "command-note";
1027
+ reason.textContent = message(recommendation.reason_key);
1028
+ details.appendChild(command);
1029
+ details.appendChild(reason);
1030
+ appendVerificationFiles(details, recommendation.files);
1031
+
1032
+ const copy = document.createElement("button");
1033
+ copy.type = "button";
1034
+ copy.className = "verification-copy";
1035
+ copy.textContent = message("dashboard.verification.copy");
1036
+ copy.title = message("dashboard.verification.copy");
1037
+ copy.setAttribute("aria-label", message("dashboard.verification.copy"));
1038
+ copy.disabled = !recommendation.runnable;
1039
+ copy.addEventListener("click", () => {
1040
+ copyVerificationCommand(recommendation.command).catch((error) => statusText(error.message, "error"));
1041
+ });
1042
+
1043
+ row.appendChild(summary);
1044
+ row.appendChild(details);
1045
+ row.appendChild(copy);
1046
+ section.appendChild(row);
1047
+ }
1048
+
1049
+ root.appendChild(section);
1050
+
1051
+ if (verification.schedule.batches.length > 0) {
1052
+ const scheduleSection = document.createElement("section");
1053
+ const scheduleHeading = document.createElement("h2");
1054
+ scheduleHeading.textContent = message("dashboard.verification.schedule");
1055
+ scheduleSection.appendChild(scheduleHeading);
1056
+ const entriesByIntent = new Map(verification.schedule.entries.map((entry) => [entry.intent, entry]));
1057
+ const planCommands = verification.schedule.batches.flatMap((batch) => batch.commands);
1058
+ for (const batch of verification.schedule.batches) {
1059
+ const row = document.createElement("div");
1060
+ row.className = "verification-row";
1061
+ const summary = document.createElement("div");
1062
+ const name = document.createElement("div");
1063
+ name.className = "command-name";
1064
+ name.textContent = message("dashboard.verification.batch") + " " + batch.index;
1065
+ const state = document.createElement("div");
1066
+ state.className = "command-state ok";
1067
+ state.textContent = batch.locks.length > 0 ? message("dashboard.verification.locks") + ": " + batch.locks.join(", ") : message("dashboard.verification.noLocks");
1068
+ summary.appendChild(name);
1069
+ summary.appendChild(state);
1070
+
1071
+ const details = document.createElement("div");
1072
+ const commands = document.createElement("div");
1073
+ commands.className = "verification-command";
1074
+ commands.textContent = batch.commands.join(" -> ");
1075
+ details.appendChild(commands);
1076
+ for (const intent of batch.intents) {
1077
+ const entry = entriesByIntent.get(intent);
1078
+ if (!entry) continue;
1079
+ const effects = document.createElement("div");
1080
+ effects.className = "verification-files";
1081
+ effects.textContent = message("dashboard.verification.effects") + ": " + entry.effects.map((effect) => effect.mode + " " + effect.path + " [" + effect.lock + "]").join(", ");
1082
+ details.appendChild(effects);
1083
+ if (entry.conflicts.length > 0) {
1084
+ const conflicts = document.createElement("div");
1085
+ conflicts.className = "command-note";
1086
+ conflicts.textContent = message("dashboard.verification.conflicts") + ": " + entry.conflicts.map((conflict) => conflict.intent + " (" + conflict.lock + ")").join(", ");
1087
+ details.appendChild(conflicts);
1088
+ }
1089
+ }
1090
+
1091
+ const copy = document.createElement("button");
1092
+ copy.type = "button";
1093
+ copy.className = "verification-copy";
1094
+ copy.textContent = message("dashboard.verification.copyPlan");
1095
+ copy.title = message("dashboard.verification.copyPlan");
1096
+ copy.setAttribute("aria-label", message("dashboard.verification.copyPlan"));
1097
+ copy.disabled = planCommands.length === 0;
1098
+ copy.addEventListener("click", () => {
1099
+ copyVerificationPlan(planCommands).catch((error) => statusText(error.message, "error"));
1100
+ });
1101
+
1102
+ row.appendChild(summary);
1103
+ row.appendChild(details);
1104
+ row.appendChild(copy);
1105
+ scheduleSection.appendChild(row);
1106
+ }
1107
+ root.appendChild(scheduleSection);
1108
+ }
1109
+
1110
+ if (verification.skipped.length > 0) {
1111
+ const skippedSection = document.createElement("section");
1112
+ const skippedHeading = document.createElement("h2");
1113
+ skippedHeading.textContent = message("dashboard.verification.skipped");
1114
+ skippedSection.appendChild(skippedHeading);
1115
+ for (const skipped of verification.skipped) {
1116
+ const row = document.createElement("div");
1117
+ row.className = "command-note";
1118
+ row.textContent = skipped.intent + ": " + message(skipped.reason_key);
1119
+ skippedSection.appendChild(row);
1120
+ }
1121
+ root.appendChild(skippedSection);
1122
+ }
1123
+ }
1124
+
1125
+ function appendCommandMeta(root, labelKey, value) {
1126
+ if (value === null || value === undefined || value === "") return;
1127
+ const item = document.createElement("span");
1128
+ item.textContent = message(labelKey) + ": " + value;
1129
+ root.appendChild(item);
1130
+ }
1131
+
1132
+ function commandStateKey(intent) {
1133
+ if (intent.runnable) return "dashboard.commands.runnable";
1134
+ if (intent.status === "manual_only") return "dashboard.commands.manualOnly";
1135
+ if (intent.status === "unknown") return "dashboard.commands.unavailable";
1136
+ return "dashboard.commands.blocked";
1137
+ }
1138
+
1139
+ function formatList(values) {
1140
+ return values.length === 0 ? message("value.none") : values.join(", ");
1141
+ }
1142
+
1143
+ function renderCommandPanel() {
1144
+ const root = document.getElementById("dashboard-commands");
1145
+ root.textContent = "";
1146
+ const section = document.createElement("section");
1147
+ const heading = document.createElement("h2");
1148
+ heading.textContent = message("dashboard.commands.heading");
1149
+ section.appendChild(heading);
1150
+
1151
+ if (!dashboardStatus.command_contract.exists || dashboardStatus.command_contract.intents.length === 0) {
1152
+ const empty = document.createElement("div");
1153
+ empty.className = "empty";
1154
+ empty.textContent = message("dashboard.commands.empty");
1155
+ section.appendChild(empty);
1156
+ root.appendChild(section);
1157
+ return;
1158
+ }
1159
+
1160
+ for (const intent of dashboardStatus.command_contract.intents) {
1161
+ const row = document.createElement("div");
1162
+ row.className = "command-row";
1163
+ const summary = document.createElement("div");
1164
+ const name = document.createElement("div");
1165
+ name.className = "command-name";
1166
+ name.textContent = intent.name;
1167
+ const state = document.createElement("div");
1168
+ state.className = intent.runnable ? "command-state ok" : "command-state warn";
1169
+ state.textContent = message(commandStateKey(intent));
1170
+ summary.appendChild(name);
1171
+ summary.appendChild(state);
1172
+
1173
+ const details = document.createElement("div");
1174
+ const description = document.createElement("div");
1175
+ description.className = "command-description";
1176
+ description.textContent = intent.description || message("value.none");
1177
+ const meta = document.createElement("div");
1178
+ meta.className = "command-meta";
1179
+ appendCommandMeta(meta, "dashboard.commands.status", intent.status);
1180
+ appendCommandMeta(meta, "dashboard.commands.lifecycle", intent.lifecycle);
1181
+ appendCommandMeta(meta, "dashboard.commands.runPolicy", intent.run_policy);
1182
+ appendCommandMeta(meta, "dashboard.commands.stdin", intent.stdin);
1183
+ appendCommandMeta(meta, "dashboard.commands.timeout", intent.timeout_seconds);
1184
+ appendCommandMeta(meta, "dashboard.commands.cwd", intent.cwd);
1185
+ appendCommandMeta(meta, "dashboard.commands.writes", formatList(intent.writes));
1186
+ details.appendChild(description);
1187
+ details.appendChild(meta);
1188
+ if (intent.reason) {
1189
+ const reason = document.createElement("div");
1190
+ reason.className = "command-note";
1191
+ reason.textContent = message("dashboard.commands.reason") + ": " + intent.reason;
1192
+ details.appendChild(reason);
1193
+ }
1194
+ if (intent.agent_action) {
1195
+ const action = document.createElement("div");
1196
+ action.className = "command-note";
1197
+ action.textContent = message("dashboard.commands.agentAction") + ": " + intent.agent_action;
1198
+ details.appendChild(action);
1199
+ }
1200
+
1201
+ row.appendChild(summary);
1202
+ row.appendChild(details);
1203
+ section.appendChild(row);
1204
+ }
1205
+
1206
+ root.appendChild(section);
1207
+ }
1208
+
1209
+ function findIntent(name) {
1210
+ return dashboardStatus.command_contract.intents.find((intent) => intent.name === name);
1211
+ }
1212
+
1213
+ function renderReleaseCommand(root, intentName, fallbackCommand, reasonKey) {
1214
+ const intent = findIntent(intentName);
1215
+ const row = document.createElement("div");
1216
+ row.className = "verification-row";
1217
+ const summary = document.createElement("div");
1218
+ const name = document.createElement("div");
1219
+ name.className = "command-name";
1220
+ name.textContent = intentName;
1221
+ const state = document.createElement("div");
1222
+ const runnable = intentName === "version_check" ? true : intent ? intent.runnable : false;
1223
+ state.className = runnable ? "command-state ok" : "command-state warn";
1224
+ state.textContent = runnable ? message("dashboard.commands.runnable") : message("dashboard.verification.unavailable");
1225
+ summary.appendChild(name);
1226
+ summary.appendChild(state);
1227
+
1228
+ const details = document.createElement("div");
1229
+ const command = document.createElement("div");
1230
+ command.className = "verification-command";
1231
+ command.textContent = fallbackCommand;
1232
+ const reason = document.createElement("div");
1233
+ reason.className = "command-note";
1234
+ reason.textContent = message(reasonKey);
1235
+ details.appendChild(command);
1236
+ details.appendChild(reason);
1237
+
1238
+ const copy = document.createElement("button");
1239
+ copy.type = "button";
1240
+ copy.className = "verification-copy";
1241
+ copy.textContent = message("dashboard.verification.copy");
1242
+ copy.title = message("dashboard.verification.copy");
1243
+ copy.setAttribute("aria-label", message("dashboard.verification.copy"));
1244
+ copy.disabled = !runnable;
1245
+ copy.addEventListener("click", () => {
1246
+ copyReleaseCommand(fallbackCommand).catch((error) => statusText(error.message, "error"));
1247
+ });
1248
+
1249
+ row.appendChild(summary);
1250
+ row.appendChild(details);
1251
+ row.appendChild(copy);
1252
+ root.appendChild(row);
1253
+ }
1254
+
1255
+ function renderReleasePanel() {
1256
+ const root = document.getElementById("dashboard-release");
1257
+ root.textContent = "";
1258
+ const overview = document.createElement("section");
1259
+ const overviewHeading = document.createElement("h2");
1260
+ overviewHeading.textContent = message("dashboard.release.overview");
1261
+ const grid = document.createElement("div");
1262
+ grid.className = "status-grid";
1263
+ appendStatusItem(grid, "dashboard.release.packageVersion", dashboardStatus.release.package_name + " " + dashboardStatus.release.package_version);
1264
+ appendStatusItem(grid, "dashboard.release.templateVersion", dashboardStatus.template ? dashboardStatus.template.id + " " + dashboardStatus.template.version : message("value.none"));
1265
+ appendStatusItem(grid, "dashboard.release.autoBump", formatBoolean(Boolean(settingValue("release.versioning.auto_bump"))), settingValue("release.versioning.auto_bump") ? "ok" : "");
1266
+ appendStatusItem(grid, "dashboard.release.requireConfirmation", formatBoolean(Boolean(settingValue("release.versioning.require_user_confirmation"))));
1267
+ appendStatusItem(grid, "dashboard.release.changedFiles", String(dashboardStatus.release.release_sensitive_changed_files.length), dashboardStatus.release.release_sensitive_changed_files.length === 0 ? "ok" : "warn");
1268
+ overview.appendChild(overviewHeading);
1269
+ overview.appendChild(grid);
1270
+ root.appendChild(overview);
1271
+
1272
+ const sources = document.createElement("section");
1273
+ const sourcesHeading = document.createElement("h2");
1274
+ sourcesHeading.textContent = message("dashboard.release.versionSources");
1275
+ sources.appendChild(sourcesHeading);
1276
+ if (dashboardStatus.release.version_sources.length === 0) {
1277
+ const empty = document.createElement("div");
1278
+ empty.className = "empty";
1279
+ empty.textContent = message("dashboard.release.noVersionSources");
1280
+ sources.appendChild(empty);
1281
+ } else {
1282
+ for (const source of dashboardStatus.release.version_sources) {
1283
+ const row = document.createElement("div");
1284
+ row.className = "command-row";
1285
+ const summary = document.createElement("div");
1286
+ const name = document.createElement("div");
1287
+ name.className = "command-name";
1288
+ name.textContent = source.path;
1289
+ const state = document.createElement("div");
1290
+ state.className = "command-state";
1291
+ state.textContent = source.kind;
1292
+ summary.appendChild(name);
1293
+ summary.appendChild(state);
1294
+ const details = document.createElement("div");
1295
+ const meta = document.createElement("div");
1296
+ meta.className = "command-meta";
1297
+ appendCommandMeta(meta, "dashboard.release.declared", source.declared ? message("dashboard.status.yes") : message("dashboard.status.no"));
1298
+ appendCommandMeta(meta, "dashboard.release.authority", source.authority || message("value.none"));
1299
+ details.appendChild(meta);
1300
+ row.appendChild(summary);
1301
+ row.appendChild(details);
1302
+ sources.appendChild(row);
1303
+ }
1304
+ }
1305
+ root.appendChild(sources);
1306
+
1307
+ const changed = document.createElement("section");
1308
+ const changedHeading = document.createElement("h2");
1309
+ changedHeading.textContent = message("dashboard.release.changedFiles");
1310
+ changed.appendChild(changedHeading);
1311
+ if (dashboardStatus.release.release_sensitive_changed_files.length === 0) {
1312
+ const empty = document.createElement("div");
1313
+ empty.className = "empty";
1314
+ empty.textContent = message("dashboard.release.noChangedFiles");
1315
+ changed.appendChild(empty);
1316
+ } else {
1317
+ const list = document.createElement("ul");
1318
+ list.className = "issue-list";
1319
+ for (const file of dashboardStatus.release.release_sensitive_changed_files) {
1320
+ const item = document.createElement("li");
1321
+ item.textContent = file;
1322
+ list.appendChild(item);
1323
+ }
1324
+ changed.appendChild(list);
1325
+ }
1326
+ root.appendChild(changed);
1327
+
1328
+ const commands = document.createElement("section");
1329
+ const commandsHeading = document.createElement("h2");
1330
+ commandsHeading.textContent = message("dashboard.release.commands");
1331
+ commands.appendChild(commandsHeading);
1332
+ renderReleaseCommand(commands, "version_check", "mf version --check", "dashboard.release.reason.versionCheck");
1333
+ renderReleaseCommand(commands, "test_release", "mf run test_release", "dashboard.release.reason.testRelease");
1334
+ renderReleaseCommand(commands, "docs_validate", "mf run docs_validate", "dashboard.release.reason.docsValidate");
1335
+ root.appendChild(commands);
1336
+ }
1337
+
1338
+ function renderUpdateCommand(root, command, labelKey, reasonKey, enabled = true) {
1339
+ const row = document.createElement("div");
1340
+ row.className = "verification-row";
1341
+ const summary = document.createElement("div");
1342
+ const name = document.createElement("div");
1343
+ name.className = "command-name";
1344
+ name.textContent = message(labelKey);
1345
+ const state = document.createElement("div");
1346
+ state.className = enabled ? "command-state ok" : "command-state warn";
1347
+ state.textContent = enabled ? message("dashboard.commands.runnable") : message("dashboard.update.blocked");
1348
+ summary.appendChild(name);
1349
+ summary.appendChild(state);
1350
+
1351
+ const details = document.createElement("div");
1352
+ const commandText = document.createElement("div");
1353
+ commandText.className = "verification-command";
1354
+ commandText.textContent = command;
1355
+ const reason = document.createElement("div");
1356
+ reason.className = "command-note";
1357
+ reason.textContent = message(reasonKey);
1358
+ details.appendChild(commandText);
1359
+ details.appendChild(reason);
1360
+
1361
+ const copy = document.createElement("button");
1362
+ copy.type = "button";
1363
+ copy.className = "verification-copy";
1364
+ copy.textContent = message("dashboard.verification.copy");
1365
+ copy.title = message("dashboard.verification.copy");
1366
+ copy.setAttribute("aria-label", message("dashboard.verification.copy"));
1367
+ copy.disabled = !enabled;
1368
+ copy.addEventListener("click", () => {
1369
+ copyUpdateCommand(command).catch((error) => statusText(error.message, "error"));
1370
+ });
1371
+
1372
+ row.appendChild(summary);
1373
+ row.appendChild(details);
1374
+ row.appendChild(copy);
1375
+ root.appendChild(row);
1376
+ }
1377
+
1378
+ function renderUpdateItem(root, item) {
1379
+ const row = document.createElement("div");
1380
+ row.className = "command-row";
1381
+ const summary = document.createElement("div");
1382
+ const name = document.createElement("div");
1383
+ name.className = "command-name";
1384
+ name.textContent = item.relativePath;
1385
+ const state = document.createElement("div");
1386
+ state.className = item.action === "create" || item.action === "update" ? "command-state ok" : "command-state warn";
1387
+ state.textContent = message("dashboard.update.action." + item.action);
1388
+ summary.appendChild(name);
1389
+ summary.appendChild(state);
1390
+
1391
+ const details = document.createElement("div");
1392
+ const meta = document.createElement("div");
1393
+ meta.className = "command-meta";
1394
+ appendCommandMeta(meta, "dashboard.update.source", item.sourceKind);
1395
+ const reason = document.createElement("div");
1396
+ reason.className = "command-note";
1397
+ reason.textContent = message("dashboard.update.reason") + ": " + item.reason;
1398
+ details.appendChild(meta);
1399
+ details.appendChild(reason);
1400
+
1401
+ row.appendChild(summary);
1402
+ row.appendChild(details);
1403
+ root.appendChild(row);
1404
+ }
1405
+
1406
+ function renderUpdateItemList(root, titleKey, emptyKey, items) {
1407
+ const section = document.createElement("section");
1408
+ const heading = document.createElement("h2");
1409
+ heading.textContent = message(titleKey);
1410
+ section.appendChild(heading);
1411
+ if (items.length === 0) {
1412
+ const empty = document.createElement("div");
1413
+ empty.className = "empty";
1414
+ empty.textContent = message(emptyKey);
1415
+ section.appendChild(empty);
1416
+ } else {
1417
+ for (const item of items) renderUpdateItem(section, item);
1418
+ }
1419
+ root.appendChild(section);
1420
+ }
1421
+
1422
+ function renderUpdatePanel() {
1423
+ const root = document.getElementById("dashboard-update");
1424
+ root.textContent = "";
1425
+ const update = dashboardStatus.update;
1426
+
1427
+ const overview = document.createElement("section");
1428
+ const heading = document.createElement("h2");
1429
+ heading.textContent = message("dashboard.update.overview");
1430
+ const grid = document.createElement("div");
1431
+ grid.className = "status-grid";
1432
+ appendStatusItem(grid, "dashboard.update.dryRun", update.ok ? message("dashboard.status.yes") : message("dashboard.status.no"), update.ok ? "ok" : "warn");
1433
+ appendStatusItem(grid, "dashboard.update.applyReady", update.apply_ready ? message("dashboard.status.yes") : message("dashboard.status.no"), update.apply_ready ? "ok" : "warn");
1434
+ appendStatusItem(grid, "dashboard.update.wouldUpdate", String(update.summary.wouldUpdate));
1435
+ appendStatusItem(grid, "dashboard.update.wouldCreate", String(update.summary.wouldCreate));
1436
+ appendStatusItem(grid, "dashboard.update.blockedLocalChanges", String(update.summary.blockedLocalChanges), update.summary.blockedLocalChanges === 0 ? "ok" : "warn");
1437
+ appendStatusItem(grid, "dashboard.update.manualReview", String(update.summary.manualReview), update.summary.manualReview === 0 ? "ok" : "warn");
1438
+ appendStatusItem(grid, "dashboard.update.unchanged", String(update.summary.unchanged));
1439
+ overview.appendChild(heading);
1440
+ overview.appendChild(grid);
1441
+ if (update.error) {
1442
+ const error = document.createElement("div");
1443
+ error.className = "command-note";
1444
+ error.textContent = message("dashboard.update.error") + ": " + update.error;
1445
+ overview.appendChild(error);
1446
+ }
1447
+ root.appendChild(overview);
1448
+
1449
+ const commands = document.createElement("section");
1450
+ const commandsHeading = document.createElement("h2");
1451
+ commandsHeading.textContent = message("dashboard.update.commands");
1452
+ commands.appendChild(commandsHeading);
1453
+ renderUpdateCommand(commands, update.dry_run_command, "dashboard.update.command.dryRun", "dashboard.update.reason.dryRun", update.ok);
1454
+ renderUpdateCommand(commands, update.apply_command, "dashboard.update.command.apply", "dashboard.update.reason.apply", update.ok && update.apply_ready);
1455
+ root.appendChild(commands);
1456
+
1457
+ renderUpdateItemList(root, "dashboard.update.blockers", "dashboard.update.noBlockers", update.blockers);
1458
+ renderUpdateItemList(root, "dashboard.update.changes", "dashboard.update.noChanges", update.changes);
1459
+ }
1460
+
1461
+ function formatDuration(value) {
1462
+ if (typeof value !== "number") return message("value.none");
1463
+ if (value < 1000) return String(value) + " ms";
1464
+ return (value / 1000).toFixed(2) + " s";
1465
+ }
1466
+
1467
+ function renderRunOutput(root, titleKey, output) {
1468
+ const section = document.createElement("section");
1469
+ const heading = document.createElement("h2");
1470
+ heading.textContent = message(titleKey);
1471
+ section.appendChild(heading);
1472
+ const meta = document.createElement("div");
1473
+ meta.className = "command-meta";
1474
+ appendCommandMeta(meta, "dashboard.runs.bytes", output.bytes);
1475
+ appendCommandMeta(meta, "dashboard.runs.truncated", formatBoolean(output.truncated));
1476
+ section.appendChild(meta);
1477
+ if (output.tail) {
1478
+ const pre = document.createElement("pre");
1479
+ pre.className = "doc-comment";
1480
+ pre.textContent = output.tail;
1481
+ section.appendChild(pre);
1482
+ } else {
1483
+ const empty = document.createElement("div");
1484
+ empty.className = "empty";
1485
+ empty.textContent = message("dashboard.runs.emptyOutput");
1486
+ section.appendChild(empty);
1487
+ }
1488
+ root.appendChild(section);
1489
+ }
1490
+
1491
+ function renderRunsPanel() {
1492
+ const root = document.getElementById("dashboard-runs");
1493
+ root.textContent = "";
1494
+ const run = dashboardStatus.run_history;
1495
+
1496
+ const overview = document.createElement("section");
1497
+ const heading = document.createElement("h2");
1498
+ heading.textContent = message("dashboard.runs.heading");
1499
+ overview.appendChild(heading);
1500
+
1501
+ if (!run.exists) {
1502
+ const empty = document.createElement("div");
1503
+ empty.className = "empty";
1504
+ empty.textContent = message("dashboard.runs.empty");
1505
+ overview.appendChild(empty);
1506
+ root.appendChild(overview);
1507
+ return;
1508
+ }
1509
+
1510
+ if (!run.valid) {
1511
+ const error = document.createElement("div");
1512
+ error.className = "command-note";
1513
+ error.textContent = message("dashboard.runs.invalid") + ": " + run.error;
1514
+ overview.appendChild(error);
1515
+ root.appendChild(overview);
1516
+ return;
1517
+ }
1518
+
1519
+ const grid = document.createElement("div");
1520
+ grid.className = "status-grid";
1521
+ appendStatusItem(grid, "dashboard.runs.intent", run.intent);
1522
+ appendStatusItem(grid, "dashboard.runs.status", run.status, run.status === "passed" ? "ok" : "warn");
1523
+ appendStatusItem(grid, "dashboard.runs.exitCode", run.exit_code === null ? message("value.none") : String(run.exit_code));
1524
+ appendStatusItem(grid, "dashboard.runs.timedOut", formatBoolean(run.timed_out), run.timed_out ? "warn" : "ok");
1525
+ appendStatusItem(grid, "dashboard.runs.startedAt", run.started_at || message("value.none"));
1526
+ appendStatusItem(grid, "dashboard.runs.finishedAt", run.finished_at || message("value.none"));
1527
+ appendStatusItem(grid, "dashboard.runs.duration", formatDuration(run.duration_ms));
1528
+ appendStatusItem(grid, "dashboard.runs.cwd", run.cwd || message("value.none"));
1529
+ appendStatusItem(grid, "dashboard.runs.mode", run.mode || message("value.none"));
1530
+ appendStatusItem(grid, "dashboard.runs.timeout", String(run.timeout_seconds));
1531
+ appendStatusItem(grid, "dashboard.runs.receiptPath", run.receipt_path || run.path);
1532
+ overview.appendChild(grid);
1533
+
1534
+ const meta = document.createElement("div");
1535
+ meta.className = "command-meta";
1536
+ appendCommandMeta(meta, "dashboard.runs.lifecycle", run.lifecycle);
1537
+ appendCommandMeta(meta, "dashboard.runs.runPolicy", run.run_policy);
1538
+ appendCommandMeta(meta, "dashboard.runs.successExitCodes", formatList(run.success_exit_codes.map(String)));
1539
+ appendCommandMeta(meta, "dashboard.runs.signal", run.signal || message("value.none"));
1540
+ appendCommandMeta(meta, "dashboard.runs.killMethod", run.kill_method || message("value.none"));
1541
+ overview.appendChild(meta);
1542
+
1543
+ if (run.command_line.length > 0) {
1544
+ const command = document.createElement("div");
1545
+ command.className = "verification-command";
1546
+ command.textContent = run.command_line.join(" ");
1547
+ overview.appendChild(command);
1548
+ }
1549
+
1550
+ if (run.error) {
1551
+ const error = document.createElement("div");
1552
+ error.className = "command-note";
1553
+ error.textContent = message("dashboard.runs.error") + ": " + run.error;
1554
+ overview.appendChild(error);
1555
+ }
1556
+
1557
+ root.appendChild(overview);
1558
+ renderRunOutput(root, "dashboard.runs.stdout", run.stdout);
1559
+ renderRunOutput(root, "dashboard.runs.stderr", run.stderr);
1560
+ }
1561
+
1562
+ function skillAlignmentKey(route) {
1563
+ if (!route.exists) return "dashboard.skills.missing";
1564
+ return route.aligned ? "dashboard.skills.aligned" : "dashboard.skills.mismatch";
1565
+ }
1566
+
1567
+ function renderSkillsPanel() {
1568
+ const root = document.getElementById("dashboard-skills");
1569
+ root.textContent = "";
1570
+ const overview = document.createElement("section");
1571
+ const heading = document.createElement("h2");
1572
+ heading.textContent = message("dashboard.skills.heading");
1573
+ const grid = document.createElement("div");
1574
+ grid.className = "status-grid";
1575
+ appendStatusItem(grid, "dashboard.skills.indexPath", dashboardStatus.skills.index_path);
1576
+ appendStatusItem(grid, "dashboard.skills.routes", String(dashboardStatus.skills.count));
1577
+ overview.appendChild(heading);
1578
+ overview.appendChild(grid);
1579
+ root.appendChild(overview);
1580
+
1581
+ const section = document.createElement("section");
1582
+ const routesHeading = document.createElement("h2");
1583
+ routesHeading.textContent = message("dashboard.skills.routes");
1584
+ section.appendChild(routesHeading);
1585
+
1586
+ if (!dashboardStatus.skills.exists || dashboardStatus.skills.routes.length === 0) {
1587
+ const empty = document.createElement("div");
1588
+ empty.className = "empty";
1589
+ empty.textContent = message("dashboard.skills.empty");
1590
+ section.appendChild(empty);
1591
+ root.appendChild(section);
1592
+ return;
1593
+ }
1594
+
1595
+ for (const route of dashboardStatus.skills.routes) {
1596
+ const row = document.createElement("div");
1597
+ row.className = "command-row";
1598
+ const summary = document.createElement("div");
1599
+ const name = document.createElement("div");
1600
+ name.className = "command-name";
1601
+ name.textContent = route.skill;
1602
+ const state = document.createElement("div");
1603
+ state.className = route.exists && route.aligned ? "command-state ok" : "command-state warn";
1604
+ state.textContent = message(skillAlignmentKey(route));
1605
+ summary.appendChild(name);
1606
+ summary.appendChild(state);
1607
+
1608
+ const details = document.createElement("div");
1609
+ const trigger = document.createElement("div");
1610
+ trigger.className = "command-description";
1611
+ trigger.textContent = route.trigger;
1612
+ const meta = document.createElement("div");
1613
+ meta.className = "command-meta";
1614
+ appendCommandMeta(meta, "dashboard.skills.path", route.skill_path);
1615
+ appendCommandMeta(meta, "dashboard.skills.requiredInput", route.required_input);
1616
+ appendCommandMeta(meta, "dashboard.skills.editScope", route.edit_scope);
1617
+ appendCommandMeta(meta, "dashboard.skills.risk", route.risk);
1618
+ appendCommandMeta(meta, "dashboard.skills.verificationIntents", formatList(route.verification_intents));
1619
+ appendCommandMeta(meta, "dashboard.skills.declaredCommandIntents", formatList(route.declared_command_intents));
1620
+ details.appendChild(trigger);
1621
+ details.appendChild(meta);
1622
+ if (route.expected_output) {
1623
+ const output = document.createElement("div");
1624
+ output.className = "command-note";
1625
+ output.textContent = message("dashboard.skills.expectedOutput") + ": " + route.expected_output;
1626
+ details.appendChild(output);
1627
+ }
1628
+
1629
+ row.appendChild(summary);
1630
+ row.appendChild(details);
1631
+ section.appendChild(row);
1632
+ }
1633
+
1634
+ root.appendChild(section);
1635
+ }
1636
+
1637
+ async function loadDocuments() {
1638
+ const response = await fetch("/api/docs/review" + docStatusQuery(), {
1639
+ headers: { "x-mustflow-dashboard-token": dashboardToken }
1640
+ });
1641
+ if (!response.ok) throw new Error(await response.text());
1642
+ docReview = await response.json();
1643
+ statusKey("dashboard.docs.reloaded", "ok");
1644
+ renderChrome();
1645
+ renderDocuments();
1646
+ }
1647
+
1648
+ async function save() {
1649
+ const updates = Array.from(pending, ([id, value]) => ({ id, value }));
1650
+ const response = await fetch("/api/preferences", {
1651
+ method: "POST",
1652
+ headers: {
1653
+ "content-type": "application/json",
1654
+ "x-mustflow-dashboard-token": dashboardToken
1655
+ },
1656
+ body: JSON.stringify({ updates })
1657
+ });
1658
+ if (!response.ok) throw new Error(await response.text());
1659
+ snapshot = await response.json();
1660
+ pending = new Map();
1661
+ document.getElementById("save").disabled = true;
1662
+ statusKey("dashboard.ui.saved", "ok");
1663
+ render();
1664
+ }
1665
+
1666
+ async function markDocument(path, status) {
1667
+ const reviewerId = document.getElementById("doc-reviewer-id").value.trim();
1668
+ if (!reviewerId) {
1669
+ statusKey("dashboard.docs.missingReviewerId", "error");
1670
+ return;
1671
+ }
1672
+
1673
+ const response = await fetch("/api/docs/review" + docStatusQuery(), {
1674
+ method: "POST",
1675
+ headers: {
1676
+ "content-type": "application/json",
1677
+ "x-mustflow-dashboard-token": dashboardToken
1678
+ },
1679
+ body: JSON.stringify({
1680
+ path,
1681
+ status,
1682
+ reviewerKind: document.getElementById("doc-reviewer-kind").value,
1683
+ reviewerId,
1684
+ summary: document.getElementById("doc-review-summary").value.trim()
1685
+ })
1686
+ });
1687
+ if (!response.ok) throw new Error(await response.text());
1688
+ docReview = await response.json();
1689
+ statusKey("dashboard.docs.updated", "ok");
1690
+ renderChrome();
1691
+ renderDocuments();
1692
+ }
1693
+
1694
+ function renderDocFilters() {
1695
+ const statusSelect = document.getElementById("doc-status-filter");
1696
+ const currentStatus = statusSelect.value || "active";
1697
+ statusSelect.textContent = "";
1698
+ for (const value of docStatusFilters) {
1699
+ const option = document.createElement("option");
1700
+ option.value = value;
1701
+ option.textContent = message("dashboard.docs.filter." + value);
1702
+ option.selected = value === currentStatus;
1703
+ statusSelect.appendChild(option);
1704
+ }
1705
+
1706
+ const kindSelect = document.getElementById("doc-reviewer-kind");
1707
+ const currentKind = kindSelect.value || "human";
1708
+ kindSelect.textContent = "";
1709
+ for (const value of reviewerKinds) {
1710
+ const option = document.createElement("option");
1711
+ option.value = value;
1712
+ option.textContent = message("dashboard.docs.reviewerKind." + value);
1713
+ option.selected = value === currentKind;
1714
+ kindSelect.appendChild(option);
1715
+ }
1716
+ }
1717
+
1718
+ function documentMatchesPathFilter(entry, query) {
1719
+ const normalizedQuery = query.trim().toLowerCase();
1720
+ if (!normalizedQuery) return true;
1721
+ const path = String(entry.path || "");
1722
+ const fileName = path.split(/[\\\\/]/u).pop() || path;
1723
+ return path.toLowerCase().includes(normalizedQuery) || fileName.toLowerCase().includes(normalizedQuery);
1724
+ }
1725
+
1726
+ function currentReviewerId() {
1727
+ return document.getElementById("doc-reviewer-id").value.trim();
1728
+ }
1729
+
1730
+ function renderDocuments() {
1731
+ const root = document.getElementById("docs-review-list");
1732
+ root.textContent = "";
1733
+
1734
+ if (docReview.documents.length === 0) {
1735
+ const empty = document.createElement("div");
1736
+ empty.className = "empty";
1737
+ empty.textContent = message("dashboard.docs.empty");
1738
+ root.appendChild(empty);
1739
+ return;
1740
+ }
1741
+
1742
+ const pathFilter = document.getElementById("doc-path-filter").value;
1743
+ const documents = docReview.documents.filter((entry) => documentMatchesPathFilter(entry, pathFilter));
1744
+ if (documents.length === 0) {
1745
+ const empty = document.createElement("div");
1746
+ empty.className = "empty";
1747
+ empty.textContent = message("dashboard.docs.noSearchMatches");
1748
+ root.appendChild(empty);
1749
+ return;
1750
+ }
1751
+
1752
+ for (const entry of documents) {
1753
+ const row = document.createElement("div");
1754
+ row.className = "doc-row";
1755
+ const details = document.createElement("div");
1756
+ const docPath = document.createElement("div");
1757
+ docPath.className = "doc-path";
1758
+ docPath.textContent = entry.path;
1759
+ const meta = document.createElement("div");
1760
+ meta.className = "doc-meta";
1761
+ meta.textContent = entry.reason;
1762
+ details.appendChild(docPath);
1763
+ details.appendChild(meta);
1764
+ if (entry.review_comment) {
1765
+ const comment = document.createElement("pre");
1766
+ comment.className = "doc-comment";
1767
+ comment.textContent = message("dashboard.docs.comment") + ":\\n" + entry.review_comment;
1768
+ details.appendChild(comment);
1769
+ }
1770
+
1771
+ const status = document.createElement("div");
1772
+ status.className = "doc-status";
1773
+ status.textContent = message("dashboard.docs.status." + entry.status);
1774
+
1775
+ const actions = document.createElement("div");
1776
+ actions.className = "doc-actions";
1777
+ const reviewerIdMissing = currentReviewerId().length === 0;
1778
+ for (const [nextStatus, labelKey, tooltipKey] of [
1779
+ ["approved", "dashboard.docs.action.approve", "dashboard.docs.action.approve.tooltip"],
1780
+ ["needs_human", "dashboard.docs.action.needsReview", "dashboard.docs.action.needsReview.tooltip"],
1781
+ ["ignored", "dashboard.docs.action.ignore", "dashboard.docs.action.ignore.tooltip"]
1782
+ ]) {
1783
+ const button = document.createElement("button");
1784
+ button.type = "button";
1785
+ button.textContent = message(labelKey);
1786
+ const actionLabel = reviewerIdMissing ? message("dashboard.docs.missingReviewerId") : message(tooltipKey);
1787
+ button.title = actionLabel;
1788
+ button.setAttribute("aria-label", actionLabel);
1789
+ button.disabled = reviewerIdMissing || entry.status === nextStatus;
1790
+ button.addEventListener("click", () => {
1791
+ markDocument(entry.path, nextStatus).catch((error) => statusText(error.message, "error"));
1792
+ });
1793
+ actions.appendChild(button);
1794
+ }
1795
+
1796
+ row.appendChild(details);
1797
+ row.appendChild(status);
1798
+ row.appendChild(actions);
1799
+ root.appendChild(row);
1800
+ }
1801
+ }
1802
+
1803
+ document.getElementById("dashboard-language").addEventListener("change", (event) => {
1804
+ currentLocale = event.target.value;
1805
+ window.localStorage.setItem("mustflow.dashboard.language", currentLocale);
1806
+ renderLocaleSelector();
1807
+ renderChrome();
1808
+ renderDocFilters();
1809
+ renderStatusPanel();
1810
+ renderVerificationPanel();
1811
+ renderCommandPanel();
1812
+ renderReleasePanel();
1813
+ renderUpdatePanel();
1814
+ renderRunsPanel();
1815
+ renderSkillsPanel();
1816
+ render();
1817
+ renderDocuments();
1818
+ });
1819
+
1820
+ document.getElementById("reload").addEventListener("click", () => {
1821
+ const action = currentTab === "documents" ? loadDocuments() : currentTab === "settings" ? loadSnapshot() : loadStatus();
1822
+ action.catch((error) => statusText(error.message, "error"));
1823
+ });
1824
+ document.getElementById("save").addEventListener("click", () => {
1825
+ save().catch((error) => statusText(error.message, "error"));
1826
+ });
1827
+ document.getElementById("open-mustflow").addEventListener("click", () => {
1828
+ openMustflowFolder().catch((error) => statusText(error.message, "error"));
1829
+ });
1830
+ document.getElementById("doc-status-filter").addEventListener("change", () => {
1831
+ loadDocuments().catch((error) => statusText(error.message, "error"));
1832
+ });
1833
+ document.getElementById("doc-path-filter").addEventListener("input", () => {
1834
+ renderDocuments();
1835
+ });
1836
+ document.getElementById("doc-reviewer-id").addEventListener("input", () => {
1837
+ renderDocuments();
1838
+ });
1839
+ for (const tab of document.querySelectorAll(".tab")) {
1840
+ tab.addEventListener("click", () => {
1841
+ currentTab = tab.dataset.tab;
1842
+ renderTabState();
1843
+ if (currentTab === "documents") {
1844
+ loadDocuments().catch((error) => statusText(error.message, "error"));
1845
+ } else if (currentTab === "status" || currentTab === "verification" || currentTab === "commands" || currentTab === "release" || currentTab === "update" || currentTab === "runs" || currentTab === "skills") {
1846
+ loadStatus().catch((error) => statusText(error.message, "error"));
1847
+ }
1848
+ });
1849
+ }
1850
+ renderLocaleSelector();
1851
+ renderDocFilters();
1852
+ renderChrome();
1853
+ renderTabState();
1854
+ renderStatusPanel();
1855
+ renderVerificationPanel();
1856
+ renderCommandPanel();
1857
+ renderReleasePanel();
1858
+ renderUpdatePanel();
1859
+ renderRunsPanel();
1860
+ renderSkillsPanel();
1861
+ render();
1862
+ renderDocuments();
1863
+ </script>
1864
+ </body>
1865
+ </html>`;
1866
+ }