forgecraft-mcp 1.4.0 → 1.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (418) hide show
  1. package/LICENSE +67 -0
  2. package/README.md +527 -525
  3. package/dist/analyzers/anchors/anchor-loader.d.ts +47 -0
  4. package/dist/analyzers/anchors/anchor-loader.d.ts.map +1 -0
  5. package/dist/analyzers/anchors/anchor-loader.js +113 -0
  6. package/dist/analyzers/anchors/anchor-loader.js.map +1 -0
  7. package/dist/analyzers/anti-pattern.d.ts.map +1 -1
  8. package/dist/analyzers/anti-pattern.js +38 -26
  9. package/dist/analyzers/anti-pattern.js.map +1 -1
  10. package/dist/analyzers/completeness-helpers.d.ts +5 -0
  11. package/dist/analyzers/completeness-helpers.d.ts.map +1 -1
  12. package/dist/analyzers/completeness-helpers.js +17 -0
  13. package/dist/analyzers/completeness-helpers.js.map +1 -1
  14. package/dist/analyzers/completeness.d.ts.map +1 -1
  15. package/dist/analyzers/completeness.js +4 -4
  16. package/dist/analyzers/completeness.js.map +1 -1
  17. package/dist/analyzers/gs-scorer.d.ts +3 -1
  18. package/dist/analyzers/gs-scorer.d.ts.map +1 -1
  19. package/dist/analyzers/gs-scorer.js +5 -2
  20. package/dist/analyzers/gs-scorer.js.map +1 -1
  21. package/dist/analyzers/package-json.d.ts.map +1 -1
  22. package/dist/analyzers/package-json.js +194 -34
  23. package/dist/analyzers/package-json.js.map +1 -1
  24. package/dist/analyzers/scorers/composable-scorer.d.ts +4 -2
  25. package/dist/analyzers/scorers/composable-scorer.d.ts.map +1 -1
  26. package/dist/analyzers/scorers/composable-scorer.js +50 -2
  27. package/dist/analyzers/scorers/composable-scorer.js.map +1 -1
  28. package/dist/analyzers/scorers/executable-scorer.d.ts +3 -2
  29. package/dist/analyzers/scorers/executable-scorer.d.ts.map +1 -1
  30. package/dist/analyzers/scorers/executable-scorer.js +64 -4
  31. package/dist/analyzers/scorers/executable-scorer.js.map +1 -1
  32. package/dist/analyzers/scorers/scorer-utils.d.ts +5 -3
  33. package/dist/analyzers/scorers/scorer-utils.d.ts.map +1 -1
  34. package/dist/analyzers/scorers/scorer-utils.js +34 -9
  35. package/dist/analyzers/scorers/scorer-utils.js.map +1 -1
  36. package/dist/analyzers/scorers/self-describing-scorer.d.ts +7 -4
  37. package/dist/analyzers/scorers/self-describing-scorer.d.ts.map +1 -1
  38. package/dist/analyzers/scorers/self-describing-scorer.js +17 -18
  39. package/dist/analyzers/scorers/self-describing-scorer.js.map +1 -1
  40. package/dist/cli/help.js +51 -51
  41. package/dist/disciplines/catalog.d.ts +16 -0
  42. package/dist/disciplines/catalog.d.ts.map +1 -0
  43. package/dist/disciplines/catalog.js +196 -0
  44. package/dist/disciplines/catalog.js.map +1 -0
  45. package/dist/disciplines/runner.d.ts +13 -0
  46. package/dist/disciplines/runner.d.ts.map +1 -0
  47. package/dist/disciplines/runner.js +35 -0
  48. package/dist/disciplines/runner.js.map +1 -0
  49. package/dist/registry/composer.d.ts.map +1 -1
  50. package/dist/registry/composer.js +9 -4
  51. package/dist/registry/composer.js.map +1 -1
  52. package/dist/registry/loader-tag.d.ts.map +1 -1
  53. package/dist/registry/loader-tag.js +1 -0
  54. package/dist/registry/loader-tag.js.map +1 -1
  55. package/dist/registry/remote-gates.js +1 -1
  56. package/dist/registry/remote-gates.js.map +1 -1
  57. package/dist/registry/renderer-skeletons.js +92 -92
  58. package/dist/registry/sentinel-renderer.js +299 -20
  59. package/dist/registry/sentinel-renderer.js.map +1 -1
  60. package/dist/sentinel/detect.d.ts +41 -0
  61. package/dist/sentinel/detect.d.ts.map +1 -0
  62. package/dist/sentinel/detect.js +122 -0
  63. package/dist/sentinel/detect.js.map +1 -0
  64. package/dist/sentinel/write.d.ts +54 -0
  65. package/dist/sentinel/write.d.ts.map +1 -0
  66. package/dist/sentinel/write.js +75 -0
  67. package/dist/sentinel/write.js.map +1 -0
  68. package/dist/shared/cnt-health.d.ts +16 -0
  69. package/dist/shared/cnt-health.d.ts.map +1 -1
  70. package/dist/shared/cnt-health.js +55 -8
  71. package/dist/shared/cnt-health.js.map +1 -1
  72. package/dist/shared/config.d.ts +14 -0
  73. package/dist/shared/config.d.ts.map +1 -1
  74. package/dist/shared/config.js +45 -0
  75. package/dist/shared/config.js.map +1 -1
  76. package/dist/shared/gs-score-logger.js +6 -6
  77. package/dist/shared/hook-installer.d.ts +58 -0
  78. package/dist/shared/hook-installer.d.ts.map +1 -0
  79. package/dist/shared/hook-installer.js +316 -0
  80. package/dist/shared/hook-installer.js.map +1 -0
  81. package/dist/shared/project-gates-helpers.d.ts +9 -0
  82. package/dist/shared/project-gates-helpers.d.ts.map +1 -1
  83. package/dist/shared/project-gates-helpers.js +35 -0
  84. package/dist/shared/project-gates-helpers.js.map +1 -1
  85. package/dist/shared/types/config.d.ts +7 -1
  86. package/dist/shared/types/config.d.ts.map +1 -1
  87. package/dist/shared/types/gates.d.ts +34 -0
  88. package/dist/shared/types/gates.d.ts.map +1 -1
  89. package/dist/shared/types/project.d.ts +68 -2
  90. package/dist/shared/types/project.d.ts.map +1 -1
  91. package/dist/shared/types/project.js +1 -0
  92. package/dist/shared/types/project.js.map +1 -1
  93. package/dist/shared/types/templates.d.ts +8 -1
  94. package/dist/shared/types/templates.d.ts.map +1 -1
  95. package/dist/shared/types/verify.d.ts +51 -1
  96. package/dist/shared/types/verify.d.ts.map +1 -1
  97. package/dist/shared/types/verify.js +37 -1
  98. package/dist/shared/types/verify.js.map +1 -1
  99. package/dist/tools/add-hook.d.ts.map +1 -1
  100. package/dist/tools/add-hook.js +8 -1
  101. package/dist/tools/add-hook.js.map +1 -1
  102. package/dist/tools/add-module.js +123 -123
  103. package/dist/tools/advice-registry.d.ts.map +1 -1
  104. package/dist/tools/advice-registry.js +108 -18
  105. package/dist/tools/advice-registry.js.map +1 -1
  106. package/dist/tools/advise-session-advisor.d.ts +16 -0
  107. package/dist/tools/advise-session-advisor.d.ts.map +1 -0
  108. package/dist/tools/advise-session-advisor.js +89 -0
  109. package/dist/tools/advise-session-advisor.js.map +1 -0
  110. package/dist/tools/advise-session-signals.d.ts +21 -0
  111. package/dist/tools/advise-session-signals.d.ts.map +1 -0
  112. package/dist/tools/advise-session-signals.js +113 -0
  113. package/dist/tools/advise-session-signals.js.map +1 -0
  114. package/dist/tools/advise-session.d.ts +22 -0
  115. package/dist/tools/advise-session.d.ts.map +1 -0
  116. package/dist/tools/advise-session.js +31 -0
  117. package/dist/tools/advise-session.js.map +1 -0
  118. package/dist/tools/analyze-harness.d.ts +18 -0
  119. package/dist/tools/analyze-harness.d.ts.map +1 -0
  120. package/dist/tools/analyze-harness.js +298 -0
  121. package/dist/tools/analyze-harness.js.map +1 -0
  122. package/dist/tools/audit.d.ts.map +1 -1
  123. package/dist/tools/audit.js +19 -0
  124. package/dist/tools/audit.js.map +1 -1
  125. package/dist/tools/change-request.d.ts +53 -0
  126. package/dist/tools/change-request.d.ts.map +1 -0
  127. package/dist/tools/change-request.js +395 -0
  128. package/dist/tools/change-request.js.map +1 -0
  129. package/dist/tools/check-cascade-contracts.d.ts +13 -0
  130. package/dist/tools/check-cascade-contracts.d.ts.map +1 -1
  131. package/dist/tools/check-cascade-contracts.js +73 -2
  132. package/dist/tools/check-cascade-contracts.js.map +1 -1
  133. package/dist/tools/check-cascade-report.js +64 -64
  134. package/dist/tools/check-cascade-steps.d.ts +3 -0
  135. package/dist/tools/check-cascade-steps.d.ts.map +1 -1
  136. package/dist/tools/check-cascade-steps.js +104 -15
  137. package/dist/tools/check-cascade-steps.js.map +1 -1
  138. package/dist/tools/check-cascade.d.ts +4 -3
  139. package/dist/tools/check-cascade.d.ts.map +1 -1
  140. package/dist/tools/check-cascade.js +30 -12
  141. package/dist/tools/check-cascade.js.map +1 -1
  142. package/dist/tools/check-derivation-chain.d.ts +37 -0
  143. package/dist/tools/check-derivation-chain.d.ts.map +1 -0
  144. package/dist/tools/check-derivation-chain.js +418 -0
  145. package/dist/tools/check-derivation-chain.js.map +1 -0
  146. package/dist/tools/check-spec-consistency.d.ts +25 -0
  147. package/dist/tools/check-spec-consistency.d.ts.map +1 -0
  148. package/dist/tools/check-spec-consistency.js +339 -0
  149. package/dist/tools/check-spec-consistency.js.map +1 -0
  150. package/dist/tools/check-t4.d.ts +54 -0
  151. package/dist/tools/check-t4.d.ts.map +1 -0
  152. package/dist/tools/check-t4.js +305 -0
  153. package/dist/tools/check-t4.js.map +1 -0
  154. package/dist/tools/close-cycle.d.ts +11 -0
  155. package/dist/tools/close-cycle.d.ts.map +1 -1
  156. package/dist/tools/close-cycle.js +364 -4
  157. package/dist/tools/close-cycle.js.map +1 -1
  158. package/dist/tools/cnt-add-routing.d.ts +31 -0
  159. package/dist/tools/cnt-add-routing.d.ts.map +1 -0
  160. package/dist/tools/cnt-add-routing.js +99 -0
  161. package/dist/tools/cnt-add-routing.js.map +1 -0
  162. package/dist/tools/configure-mcp.d.ts.map +1 -1
  163. package/dist/tools/configure-mcp.js +52 -2
  164. package/dist/tools/configure-mcp.js.map +1 -1
  165. package/dist/tools/consolidate-status.d.ts +31 -0
  166. package/dist/tools/consolidate-status.d.ts.map +1 -1
  167. package/dist/tools/consolidate-status.js +105 -0
  168. package/dist/tools/consolidate-status.js.map +1 -1
  169. package/dist/tools/executable-gates.d.ts +52 -0
  170. package/dist/tools/executable-gates.d.ts.map +1 -0
  171. package/dist/tools/executable-gates.js +333 -0
  172. package/dist/tools/executable-gates.js.map +1 -0
  173. package/dist/tools/extract-adrs-from-spec.d.ts +33 -0
  174. package/dist/tools/extract-adrs-from-spec.d.ts.map +1 -0
  175. package/dist/tools/extract-adrs-from-spec.js +410 -0
  176. package/dist/tools/extract-adrs-from-spec.js.map +1 -0
  177. package/dist/tools/extract-adrs-history.d.ts +47 -0
  178. package/dist/tools/extract-adrs-history.d.ts.map +1 -0
  179. package/dist/tools/extract-adrs-history.js +265 -0
  180. package/dist/tools/extract-adrs-history.js.map +1 -0
  181. package/dist/tools/forgecraft-dispatch-extended.d.ts.map +1 -1
  182. package/dist/tools/forgecraft-dispatch-extended.js +137 -0
  183. package/dist/tools/forgecraft-dispatch-extended.js.map +1 -1
  184. package/dist/tools/forgecraft-dispatch.d.ts.map +1 -1
  185. package/dist/tools/forgecraft-dispatch.js +16 -0
  186. package/dist/tools/forgecraft-dispatch.js.map +1 -1
  187. package/dist/tools/forgecraft-schema-params.d.ts +174 -2
  188. package/dist/tools/forgecraft-schema-params.d.ts.map +1 -1
  189. package/dist/tools/forgecraft-schema-params.js +197 -0
  190. package/dist/tools/forgecraft-schema-params.js.map +1 -1
  191. package/dist/tools/forgecraft-schema.d.ts +179 -7
  192. package/dist/tools/forgecraft-schema.d.ts.map +1 -1
  193. package/dist/tools/forgecraft-schema.js +37 -0
  194. package/dist/tools/forgecraft-schema.js.map +1 -1
  195. package/dist/tools/generate-adr.js +6 -6
  196. package/dist/tools/generate-adr.js.map +1 -1
  197. package/dist/tools/generate-decision.d.ts +77 -0
  198. package/dist/tools/generate-decision.d.ts.map +1 -0
  199. package/dist/tools/generate-decision.js +162 -0
  200. package/dist/tools/generate-decision.js.map +1 -0
  201. package/dist/tools/generate-env-probe.d.ts +49 -0
  202. package/dist/tools/generate-env-probe.d.ts.map +1 -0
  203. package/dist/tools/generate-env-probe.js +365 -0
  204. package/dist/tools/generate-env-probe.js.map +1 -0
  205. package/dist/tools/generate-harness.d.ts +53 -0
  206. package/dist/tools/generate-harness.d.ts.map +1 -0
  207. package/dist/tools/generate-harness.js +395 -0
  208. package/dist/tools/generate-harness.js.map +1 -0
  209. package/dist/tools/generate-roadmap.d.ts +1 -1
  210. package/dist/tools/generate-roadmap.d.ts.map +1 -1
  211. package/dist/tools/generate-roadmap.js +38 -4
  212. package/dist/tools/generate-roadmap.js.map +1 -1
  213. package/dist/tools/generate-session-prompt.d.ts +3 -3
  214. package/dist/tools/generate-session-prompt.d.ts.map +1 -1
  215. package/dist/tools/generate-session-prompt.js +9 -1
  216. package/dist/tools/generate-session-prompt.js.map +1 -1
  217. package/dist/tools/generate-slo-probe.d.ts +53 -0
  218. package/dist/tools/generate-slo-probe.d.ts.map +1 -0
  219. package/dist/tools/generate-slo-probe.js +366 -0
  220. package/dist/tools/generate-slo-probe.js.map +1 -0
  221. package/dist/tools/layer-status-gates.d.ts +24 -0
  222. package/dist/tools/layer-status-gates.d.ts.map +1 -0
  223. package/dist/tools/layer-status-gates.js +151 -0
  224. package/dist/tools/layer-status-gates.js.map +1 -0
  225. package/dist/tools/layer-status.d.ts +126 -0
  226. package/dist/tools/layer-status.d.ts.map +1 -0
  227. package/dist/tools/layer-status.js +647 -0
  228. package/dist/tools/layer-status.js.map +1 -0
  229. package/dist/tools/list.d.ts.map +1 -1
  230. package/dist/tools/list.js +9 -5
  231. package/dist/tools/list.js.map +1 -1
  232. package/dist/tools/postcondition-coverage.d.ts +57 -0
  233. package/dist/tools/postcondition-coverage.d.ts.map +1 -0
  234. package/dist/tools/postcondition-coverage.js +256 -0
  235. package/dist/tools/postcondition-coverage.js.map +1 -0
  236. package/dist/tools/probe-runners.d.ts +21 -0
  237. package/dist/tools/probe-runners.d.ts.map +1 -0
  238. package/dist/tools/probe-runners.js +246 -0
  239. package/dist/tools/probe-runners.js.map +1 -0
  240. package/dist/tools/probe-templates.d.ts +27 -0
  241. package/dist/tools/probe-templates.d.ts.map +1 -0
  242. package/dist/tools/probe-templates.js +279 -0
  243. package/dist/tools/probe-templates.js.map +1 -0
  244. package/dist/tools/propose-session.d.ts +28 -0
  245. package/dist/tools/propose-session.d.ts.map +1 -0
  246. package/dist/tools/propose-session.js +333 -0
  247. package/dist/tools/propose-session.js.map +1 -0
  248. package/dist/tools/refresh-output.js +14 -14
  249. package/dist/tools/review-stubs.d.ts +29 -0
  250. package/dist/tools/review-stubs.d.ts.map +1 -0
  251. package/dist/tools/review-stubs.js +173 -0
  252. package/dist/tools/review-stubs.js.map +1 -0
  253. package/dist/tools/roadmap-builder.d.ts +49 -1
  254. package/dist/tools/roadmap-builder.d.ts.map +1 -1
  255. package/dist/tools/roadmap-builder.js +210 -5
  256. package/dist/tools/roadmap-builder.js.map +1 -1
  257. package/dist/tools/run-env-probe.d.ts +57 -0
  258. package/dist/tools/run-env-probe.d.ts.map +1 -0
  259. package/dist/tools/run-env-probe.js +270 -0
  260. package/dist/tools/run-env-probe.js.map +1 -0
  261. package/dist/tools/run-harness.d.ts +52 -0
  262. package/dist/tools/run-harness.d.ts.map +1 -0
  263. package/dist/tools/run-harness.js +279 -0
  264. package/dist/tools/run-harness.js.map +1 -0
  265. package/dist/tools/run-slo-probe.d.ts +50 -0
  266. package/dist/tools/run-slo-probe.d.ts.map +1 -0
  267. package/dist/tools/run-slo-probe.js +281 -0
  268. package/dist/tools/run-slo-probe.js.map +1 -0
  269. package/dist/tools/scaffold-spec-stubs.js +115 -115
  270. package/dist/tools/scaffold-templates.js +62 -62
  271. package/dist/tools/scaffold-writer.d.ts.map +1 -1
  272. package/dist/tools/scaffold-writer.js +9 -0
  273. package/dist/tools/scaffold-writer.js.map +1 -1
  274. package/dist/tools/score-rubric.d.ts +19 -0
  275. package/dist/tools/score-rubric.d.ts.map +1 -0
  276. package/dist/tools/score-rubric.js +411 -0
  277. package/dist/tools/score-rubric.js.map +1 -0
  278. package/dist/tools/session-prompt-builders.d.ts +20 -0
  279. package/dist/tools/session-prompt-builders.d.ts.map +1 -1
  280. package/dist/tools/session-prompt-builders.js +78 -5
  281. package/dist/tools/session-prompt-builders.js.map +1 -1
  282. package/dist/tools/session-prompt-sections.d.ts +4 -2
  283. package/dist/tools/session-prompt-sections.d.ts.map +1 -1
  284. package/dist/tools/session-prompt-sections.js +22 -10
  285. package/dist/tools/session-prompt-sections.js.map +1 -1
  286. package/dist/tools/setup-artifact-writers.d.ts +69 -4
  287. package/dist/tools/setup-artifact-writers.d.ts.map +1 -1
  288. package/dist/tools/setup-artifact-writers.js +681 -5
  289. package/dist/tools/setup-artifact-writers.js.map +1 -1
  290. package/dist/tools/setup-cnt-builders.d.ts.map +1 -1
  291. package/dist/tools/setup-cnt-builders.js +162 -34
  292. package/dist/tools/setup-cnt-builders.js.map +1 -1
  293. package/dist/tools/setup-monitoring.d.ts +41 -0
  294. package/dist/tools/setup-monitoring.d.ts.map +1 -0
  295. package/dist/tools/setup-monitoring.js +364 -0
  296. package/dist/tools/setup-monitoring.js.map +1 -0
  297. package/dist/tools/setup-phase1.d.ts.map +1 -1
  298. package/dist/tools/setup-phase1.js +14 -1
  299. package/dist/tools/setup-phase1.js.map +1 -1
  300. package/dist/tools/setup-phase2.d.ts +14 -0
  301. package/dist/tools/setup-phase2.d.ts.map +1 -1
  302. package/dist/tools/setup-phase2.js +130 -3
  303. package/dist/tools/setup-phase2.js.map +1 -1
  304. package/dist/tools/setup-project.d.ts +8 -0
  305. package/dist/tools/setup-project.d.ts.map +1 -1
  306. package/dist/tools/setup-project.js +52 -2
  307. package/dist/tools/setup-project.js.map +1 -1
  308. package/dist/tools/spec-parser-tags.d.ts.map +1 -1
  309. package/dist/tools/spec-parser-tags.js +1 -0
  310. package/dist/tools/spec-parser-tags.js.map +1 -1
  311. package/dist/tools/verify-formatter.d.ts.map +1 -1
  312. package/dist/tools/verify-formatter.js +15 -1
  313. package/dist/tools/verify-formatter.js.map +1 -1
  314. package/dist/tools/verify.d.ts.map +1 -1
  315. package/dist/tools/verify.js +3 -0
  316. package/dist/tools/verify.js.map +1 -1
  317. package/package.json +98 -89
  318. package/templates/analytics/instructions.yaml +37 -37
  319. package/templates/analytics/mcp-servers.yaml +11 -11
  320. package/templates/analytics/structure.yaml +25 -25
  321. package/templates/api/harness/uc-template.hurl +20 -0
  322. package/templates/api/instructions.yaml +231 -231
  323. package/templates/api/mcp-servers.yaml +22 -22
  324. package/templates/api/nfr.yaml +23 -23
  325. package/templates/api/review.yaml +103 -103
  326. package/templates/api/structure.yaml +34 -34
  327. package/templates/api/verification.yaml +132 -132
  328. package/templates/cli/instructions.yaml +31 -31
  329. package/templates/cli/mcp-servers.yaml +11 -11
  330. package/templates/cli/review.yaml +53 -53
  331. package/templates/cli/structure.yaml +16 -16
  332. package/templates/data-lineage/instructions.yaml +28 -28
  333. package/templates/data-lineage/mcp-servers.yaml +22 -22
  334. package/templates/data-pipeline/instructions.yaml +84 -84
  335. package/templates/data-pipeline/mcp-servers.yaml +13 -13
  336. package/templates/data-pipeline/nfr.yaml +39 -39
  337. package/templates/data-pipeline/structure.yaml +23 -23
  338. package/templates/docs-manifest.yaml +227 -0
  339. package/templates/fintech/hooks.yaml +55 -55
  340. package/templates/fintech/instructions.yaml +112 -112
  341. package/templates/fintech/mcp-servers.yaml +13 -13
  342. package/templates/fintech/nfr.yaml +46 -46
  343. package/templates/fintech/playbook.yaml +210 -210
  344. package/templates/fintech/verification.yaml +239 -239
  345. package/templates/game/harness/uc-template.sim.ts +29 -0
  346. package/templates/game/instructions.yaml +289 -289
  347. package/templates/game/mcp-servers.yaml +38 -38
  348. package/templates/game/nfr.yaml +64 -64
  349. package/templates/game/playbook.yaml +214 -214
  350. package/templates/game/review.yaml +97 -97
  351. package/templates/game/structure.yaml +67 -67
  352. package/templates/game/verification.yaml +174 -174
  353. package/templates/healthcare/instructions.yaml +42 -42
  354. package/templates/healthcare/mcp-servers.yaml +13 -13
  355. package/templates/healthcare/nfr.yaml +47 -47
  356. package/templates/hipaa/instructions.yaml +41 -41
  357. package/templates/hipaa/mcp-servers.yaml +13 -13
  358. package/templates/infra/instructions.yaml +104 -104
  359. package/templates/infra/mcp-servers.yaml +20 -20
  360. package/templates/infra/nfr.yaml +46 -46
  361. package/templates/infra/review.yaml +65 -65
  362. package/templates/infra/structure.yaml +25 -25
  363. package/templates/library/instructions.yaml +36 -36
  364. package/templates/library/mcp-servers.yaml +20 -20
  365. package/templates/library/review.yaml +56 -56
  366. package/templates/library/structure.yaml +19 -19
  367. package/templates/medallion-architecture/instructions.yaml +41 -41
  368. package/templates/medallion-architecture/mcp-servers.yaml +22 -22
  369. package/templates/ml/instructions.yaml +85 -85
  370. package/templates/ml/mcp-servers.yaml +11 -11
  371. package/templates/ml/nfr.yaml +39 -39
  372. package/templates/ml/structure.yaml +25 -25
  373. package/templates/ml/verification.yaml +156 -156
  374. package/templates/mobile/instructions.yaml +44 -44
  375. package/templates/mobile/mcp-servers.yaml +11 -11
  376. package/templates/mobile/nfr.yaml +49 -49
  377. package/templates/mobile/structure.yaml +27 -27
  378. package/templates/mobile/verification.yaml +121 -121
  379. package/templates/observability-xray/instructions.yaml +40 -40
  380. package/templates/observability-xray/mcp-servers.yaml +15 -15
  381. package/templates/realtime/instructions.yaml +42 -42
  382. package/templates/realtime/mcp-servers.yaml +13 -13
  383. package/templates/soc2/instructions.yaml +41 -41
  384. package/templates/soc2/mcp-servers.yaml +24 -24
  385. package/templates/social/instructions.yaml +43 -43
  386. package/templates/social/mcp-servers.yaml +24 -24
  387. package/templates/state-machine/instructions.yaml +42 -42
  388. package/templates/state-machine/mcp-servers.yaml +11 -11
  389. package/templates/tools-registry.yaml +164 -164
  390. package/templates/universal/claude-md-blocks/layer-navigation.md +20 -0
  391. package/templates/universal/claude-md-blocks/nfr-contracts.md +22 -0
  392. package/templates/universal/hooks.yaml +879 -723
  393. package/templates/universal/instructions.yaml +1692 -1692
  394. package/templates/universal/mcp-servers.yaml +50 -50
  395. package/templates/universal/nfr.yaml +197 -197
  396. package/templates/universal/reference.yaml +326 -326
  397. package/templates/universal/review.yaml +204 -204
  398. package/templates/universal/skills.yaml +262 -262
  399. package/templates/universal/structure.yaml +67 -67
  400. package/templates/universal/verification.yaml +416 -416
  401. package/templates/web-next/hooks.yaml +114 -0
  402. package/templates/web-next/instructions.yaml +106 -0
  403. package/templates/web-react/harness/uc-template.spec.ts +35 -0
  404. package/templates/web-react/hooks.yaml +156 -44
  405. package/templates/web-react/instructions.yaml +296 -207
  406. package/templates/web-react/mcp-servers.yaml +20 -20
  407. package/templates/web-react/nfr.yaml +27 -27
  408. package/templates/web-react/review.yaml +94 -94
  409. package/templates/web-react/structure.yaml +46 -46
  410. package/templates/web-react/verification.yaml +126 -126
  411. package/templates/web-static/hooks.yaml +85 -0
  412. package/templates/web-static/instructions.yaml +204 -115
  413. package/templates/web-static/mcp-servers.yaml +20 -20
  414. package/templates/web3/instructions.yaml +44 -44
  415. package/templates/web3/mcp-servers.yaml +11 -11
  416. package/templates/web3/verification.yaml +159 -159
  417. package/templates/zero-trust/instructions.yaml +41 -41
  418. package/templates/zero-trust/mcp-servers.yaml +15 -15
@@ -0,0 +1,647 @@
1
+ /**
2
+ * layer_status tool handler.
3
+ *
4
+ * Reports L1–L4 completion per use case by reading docs/use-cases.md
5
+ * and scanning for harness probes, infra config, and monitoring artifacts.
6
+ * Works on any project with docs/use-cases.md — does not require forgecraft.yaml.
7
+ */
8
+ import { z } from "zod";
9
+ import { existsSync, readFileSync, readdirSync, statSync } from "node:fs";
10
+ import { join, resolve } from "node:path";
11
+ import { computePostconditionCoverage, formatCoverageTable, } from "./postcondition-coverage.js";
12
+ import { detectL1GateViolations, } from "./layer-status-gates.js";
13
+ // ── Harness run helpers ───────────────────────────────────────────────
14
+ /**
15
+ * Read harness-run.json for full summary (passed/failed/notFound + timestamp).
16
+ * Returns null when missing or unparseable.
17
+ */
18
+ function readHarnessRunForSummary(projectDir) {
19
+ const runJsonPath = join(projectDir, ".forgecraft", "harness-run.json");
20
+ if (!existsSync(runJsonPath))
21
+ return null;
22
+ try {
23
+ const raw = readFileSync(runJsonPath, "utf-8");
24
+ return JSON.parse(raw);
25
+ }
26
+ catch {
27
+ return null;
28
+ }
29
+ }
30
+ /**
31
+ * Check tests/harness/ and .forgecraft/harness-run.json for probe file count
32
+ * and last run timestamp.
33
+ */
34
+ export function buildHarnessRunSummary(projectDir) {
35
+ const harnessDir = join(projectDir, "tests", "harness");
36
+ let probeFilesFound = 0;
37
+ if (existsSync(harnessDir)) {
38
+ try {
39
+ const entries = readdirSync(harnessDir);
40
+ probeFilesFound = entries.filter((e) => e.endsWith(".spec.ts") ||
41
+ e.endsWith(".hurl") ||
42
+ e.endsWith(".sh") ||
43
+ e.endsWith(".sim.ts")).length;
44
+ }
45
+ catch {
46
+ // ignore
47
+ }
48
+ }
49
+ let lastRunTimestamp = null;
50
+ const runJsonPath = join(projectDir, ".forgecraft", "harness-run.json");
51
+ if (existsSync(runJsonPath)) {
52
+ try {
53
+ const raw = readFileSync(runJsonPath, "utf-8");
54
+ const parsed = JSON.parse(raw);
55
+ lastRunTimestamp = parsed.timestamp ?? null;
56
+ }
57
+ catch {
58
+ // ignore
59
+ }
60
+ }
61
+ return { probeFilesFound, lastRunTimestamp };
62
+ }
63
+ // ── Schema ───────────────────────────────────────────────────────────
64
+ export const layerStatusSchema = z.object({
65
+ project_dir: z
66
+ .string()
67
+ .describe("Absolute path to the project root directory."),
68
+ });
69
+ // ── UC parsing ────────────────────────────────────────────────────────
70
+ /**
71
+ * Parse use case records from docs/use-cases.md content.
72
+ * Extracts UC-NNN id and title from `## UC-NNN: Title` headers.
73
+ */
74
+ export function parseUseCases(content) {
75
+ const ucs = [];
76
+ const lines = content.split("\n");
77
+ for (const line of lines) {
78
+ const match = /^##\s+(UC-\d{3}):\s+(.+)$/.exec(line.trim());
79
+ if (match) {
80
+ ucs.push({ id: match[1], title: match[2].trim() });
81
+ }
82
+ }
83
+ return ucs;
84
+ }
85
+ // ── L1 check ─────────────────────────────────────────────────────────
86
+ /**
87
+ * Check whether any test file in the project references a given UC id.
88
+ */
89
+ function hasTestsForUc(projectDir, ucId) {
90
+ const testDirs = ["tests", "test", "src", "__tests__", "spec"];
91
+ const lowerId = ucId.toLowerCase();
92
+ for (const dir of testDirs) {
93
+ const dirPath = join(projectDir, dir);
94
+ if (!existsSync(dirPath))
95
+ continue;
96
+ if (scanDirForText(dirPath, lowerId, 0))
97
+ return true;
98
+ }
99
+ return false;
100
+ }
101
+ /**
102
+ * Recursively scan a directory for files containing the given text.
103
+ * Limited to depth 4 to avoid traversing large trees.
104
+ */
105
+ function scanDirForText(dirPath, text, depth) {
106
+ if (depth > 4)
107
+ return false;
108
+ let entries;
109
+ try {
110
+ entries = readdirSync(dirPath);
111
+ }
112
+ catch {
113
+ return false;
114
+ }
115
+ for (const entry of entries) {
116
+ const full = join(dirPath, entry);
117
+ try {
118
+ const stat = statSync(full);
119
+ if (stat.isDirectory()) {
120
+ if (scanDirForText(full, text, depth + 1))
121
+ return true;
122
+ }
123
+ else if (entry.endsWith(".ts") ||
124
+ entry.endsWith(".js") ||
125
+ entry.endsWith(".test.ts")) {
126
+ const content = readFileSync(full, "utf-8");
127
+ if (content.toLowerCase().includes(text))
128
+ return true;
129
+ }
130
+ }
131
+ catch {
132
+ // skip unreadable entries
133
+ }
134
+ }
135
+ return false;
136
+ }
137
+ /**
138
+ * Build L1 status for all parsed use cases.
139
+ * L1 = UC is documented. Test coverage is surfaced as a sub-check.
140
+ */
141
+ export function buildL1Status(projectDir, ucs) {
142
+ return ucs.map((uc) => ({
143
+ ...uc,
144
+ documented: true,
145
+ testsFound: hasTestsForUc(projectDir, uc.id),
146
+ }));
147
+ }
148
+ // ── L2 check ─────────────────────────────────────────────────────────
149
+ /**
150
+ * Read probe types from a harness YAML file.
151
+ * Non-throwing — returns empty array on parse failure.
152
+ */
153
+ function readProbeTypes(probePath) {
154
+ try {
155
+ const raw = readFileSync(probePath, "utf-8");
156
+ const types = [];
157
+ for (const line of raw.split("\n")) {
158
+ const m = /^\s+type:\s+(\S+)/.exec(line);
159
+ if (m)
160
+ types.push(m[1]);
161
+ }
162
+ return [...new Set(types)];
163
+ }
164
+ catch {
165
+ return [];
166
+ }
167
+ }
168
+ /**
169
+ * Read per-UC results from harness-run.json.
170
+ * Returns a map of ucId -> status string, or empty map on failure.
171
+ */
172
+ function readHarnessRunResults(projectDir) {
173
+ const runJsonPath = join(projectDir, ".forgecraft", "harness-run.json");
174
+ if (!existsSync(runJsonPath))
175
+ return new Map();
176
+ try {
177
+ const raw = readFileSync(runJsonPath, "utf-8");
178
+ const parsed = JSON.parse(raw);
179
+ const map = new Map();
180
+ for (const r of parsed.results ?? []) {
181
+ map.set(r.ucId.toUpperCase(), r.status);
182
+ }
183
+ return map;
184
+ }
185
+ catch {
186
+ return new Map();
187
+ }
188
+ }
189
+ /**
190
+ * Check tests/harness/ for happy-path and error probe files for a UC.
191
+ */
192
+ function readHarnessProbeFiles(harnessDir, ucId) {
193
+ const lower = ucId.toLowerCase().replace(/_/g, "-");
194
+ const EXTENSIONS = [".spec.ts", ".hurl", ".sh", ".sim.ts"];
195
+ if (!existsSync(harnessDir)) {
196
+ return { hasHappyProbe: false, errorProbeCount: 0 };
197
+ }
198
+ let entries = [];
199
+ try {
200
+ entries = readdirSync(harnessDir);
201
+ }
202
+ catch {
203
+ return { hasHappyProbe: false, errorProbeCount: 0 };
204
+ }
205
+ const hasHappyProbe = EXTENSIONS.some((ext) => entries.includes(`${lower}-happy${ext}`));
206
+ const errorProbeCount = entries.filter((e) => {
207
+ const base = e.replace(/\.(spec\.ts|hurl|sh|sim\.ts)$/, "");
208
+ return base.startsWith(`${lower}-error-`);
209
+ }).length;
210
+ return { hasHappyProbe, errorProbeCount };
211
+ }
212
+ /**
213
+ * Build L2 status for all use cases.
214
+ * L2 = .forgecraft/harness/uc-NNN.yaml exists.
215
+ */
216
+ export function buildL2Status(projectDir, ucs) {
217
+ const harnessDir = join(projectDir, "tests", "harness");
218
+ const runResults = readHarnessRunResults(projectDir);
219
+ return ucs.map((uc) => {
220
+ const probeFile = join(projectDir, ".forgecraft", "harness", `${uc.id.toLowerCase()}.yaml`);
221
+ const hasProbe = existsSync(probeFile);
222
+ const { hasHappyProbe, errorProbeCount } = readHarnessProbeFiles(harnessDir, uc.id);
223
+ const lastRunStatus = runResults.get(uc.id.toUpperCase()) ?? null;
224
+ return {
225
+ ...uc,
226
+ hasProbe,
227
+ probeTypes: hasProbe ? readProbeTypes(probeFile) : [],
228
+ hasHappyProbe,
229
+ errorProbeCount,
230
+ lastRunStatus,
231
+ };
232
+ });
233
+ }
234
+ // ── L3 check ─────────────────────────────────────────────────────────
235
+ const L3_CHECKS = [
236
+ ["CI config", [".github/workflows", ".gitlab-ci.yml", "Procfile"]],
237
+ ["Test command", ["package.json", "Makefile", "Cargo.toml"]],
238
+ ["Env schema", [".env.example", ".env.schema", "src/config"]],
239
+ [
240
+ "Deployment config",
241
+ ["Dockerfile", "docker-compose.yml", "render.yaml", "fly.toml"],
242
+ ],
243
+ ];
244
+ /**
245
+ * Evaluate L3 (environment/infrastructure) readiness.
246
+ */
247
+ export function buildL3Status(projectDir) {
248
+ const checks = {};
249
+ for (const [label, paths] of L3_CHECKS) {
250
+ checks[label] = paths.some((p) => existsSync(join(projectDir, p)));
251
+ }
252
+ const passing = Object.values(checks).filter(Boolean).length;
253
+ const total = Object.keys(checks).length;
254
+ let status = passing === 0 ? "not-started" : passing === total ? "complete" : "partial";
255
+ // Incorporate env-probe-run.json evidence
256
+ const envProbeRunPath = join(projectDir, ".forgecraft", "env-probe-run.json");
257
+ let envProbeEvidence = null;
258
+ if (existsSync(envProbeRunPath)) {
259
+ try {
260
+ envProbeEvidence = JSON.parse(readFileSync(envProbeRunPath, "utf-8"));
261
+ }
262
+ catch {
263
+ /* ignore */
264
+ }
265
+ }
266
+ if (envProbeEvidence !== null) {
267
+ if (envProbeEvidence.passed > 0 && envProbeEvidence.failed === 0) {
268
+ status = "complete";
269
+ }
270
+ else if (envProbeEvidence.failed > 0) {
271
+ status = "partial";
272
+ }
273
+ }
274
+ return { status, checks, envProbeEvidence };
275
+ }
276
+ // ── L4 check ─────────────────────────────────────────────────────────
277
+ const L4_HEALTH_PATHS = [
278
+ ".forgecraft/health",
279
+ "src/health",
280
+ "health",
281
+ "src/monitoring",
282
+ ];
283
+ const L4_DRIFT_PATHS = [".forgecraft/monitoring", "src/drift", "monitoring"];
284
+ /**
285
+ * Evaluate L4 (self-monitoring/drift detection) readiness.
286
+ */
287
+ export function buildL4Status(projectDir) {
288
+ const healthProbes = L4_HEALTH_PATHS.some((p) => existsSync(join(projectDir, p)));
289
+ const driftDetection = L4_DRIFT_PATHS.some((p) => existsSync(join(projectDir, p)));
290
+ const checks = {
291
+ "Health probes": healthProbes,
292
+ "Drift detection": driftDetection,
293
+ };
294
+ const passing = Object.values(checks).filter(Boolean).length;
295
+ let status = passing === 0 ? "not-started" : passing === 2 ? "complete" : "partial";
296
+ // Incorporate slo-probe-run.json evidence
297
+ const sloProbeRunPath = join(projectDir, ".forgecraft", "slo-probe-run.json");
298
+ let sloProbeEvidence = null;
299
+ if (existsSync(sloProbeRunPath)) {
300
+ try {
301
+ sloProbeEvidence = JSON.parse(readFileSync(sloProbeRunPath, "utf-8"));
302
+ }
303
+ catch {
304
+ /* ignore */
305
+ }
306
+ }
307
+ if (sloProbeEvidence !== null) {
308
+ if (sloProbeEvidence.passed > 0 && sloProbeEvidence.failed === 0) {
309
+ status = "complete";
310
+ }
311
+ else if (sloProbeEvidence.failed > 0) {
312
+ status = "partial";
313
+ }
314
+ }
315
+ return { status, checks, sloProbeEvidence };
316
+ }
317
+ // ── Core data builder ─────────────────────────────────────────────────
318
+ /**
319
+ * Build the full layer report for a project directory.
320
+ * All reads are non-throwing — missing artifacts produce empty/default fields.
321
+ *
322
+ * @param projectDir - Absolute path to project root
323
+ * @returns Structured layer report
324
+ */
325
+ /**
326
+ * Parse UC records from canonical docs/use-cases/ directory.
327
+ * Each file is named UC-NNN-slug.md; the title is taken from the first H1.
328
+ */
329
+ function parseUseCaseDirectory(projectDir) {
330
+ const ucDir = join(projectDir, "docs", "use-cases");
331
+ if (!existsSync(ucDir))
332
+ return [];
333
+ let files;
334
+ try {
335
+ files = readdirSync(ucDir).filter((f) => /^UC-\d{3,4}-.+\.md$/i.test(f));
336
+ }
337
+ catch {
338
+ return [];
339
+ }
340
+ const ucs = [];
341
+ for (const file of files.sort()) {
342
+ const idMatch = /^(UC-\d{3,4})/i.exec(file);
343
+ if (!idMatch)
344
+ continue;
345
+ const id = idMatch[1].toUpperCase();
346
+ let title = file
347
+ .replace(/^UC-\d{3,4}-/, "")
348
+ .replace(/\.md$/, "")
349
+ .replace(/-/g, " ");
350
+ try {
351
+ const content = readFileSync(join(ucDir, file), "utf-8");
352
+ const h1 = /^#\s+(.+)$/m.exec(content);
353
+ if (h1)
354
+ title = h1[1].trim();
355
+ }
356
+ catch {
357
+ // use filename-derived title
358
+ }
359
+ ucs.push({ id, title });
360
+ }
361
+ return ucs;
362
+ }
363
+ export function buildLayerReport(projectDir) {
364
+ let ucs = [];
365
+ // Try canonical directory first (docs/use-cases/UC-*.md), then legacy monolith
366
+ const ucDir = join(projectDir, "docs", "use-cases");
367
+ const useCasesPath = join(projectDir, "docs", "use-cases.md");
368
+ const dirUcs = parseUseCaseDirectory(projectDir);
369
+ if (dirUcs.length > 0) {
370
+ ucs = dirUcs;
371
+ }
372
+ else if (existsSync(useCasesPath)) {
373
+ try {
374
+ const content = readFileSync(useCasesPath, "utf-8");
375
+ ucs = parseUseCases(content);
376
+ }
377
+ catch {
378
+ // leave ucs empty
379
+ }
380
+ }
381
+ void ucDir; // referenced above via parseUseCaseDirectory
382
+ const l1 = buildL1Status(projectDir, ucs);
383
+ const l2 = buildL2Status(projectDir, ucs);
384
+ const { status: l3, checks: l3Checks, envProbeEvidence, } = buildL3Status(projectDir);
385
+ const { status: l4, checks: l4Checks, sloProbeEvidence, } = buildL4Status(projectDir);
386
+ // Derive project name from forgecraft.yaml or fallback to dirname
387
+ const projectName = deriveProjectName(projectDir);
388
+ const l1GateViolations = detectL1GateViolations(projectDir);
389
+ return {
390
+ projectName,
391
+ projectDir,
392
+ generatedAt: new Date().toISOString(),
393
+ ucs,
394
+ l1,
395
+ l2,
396
+ l3,
397
+ l3Checks,
398
+ l4,
399
+ l4Checks,
400
+ l1GateViolations,
401
+ envProbeEvidence,
402
+ sloProbeEvidence,
403
+ };
404
+ }
405
+ /**
406
+ * Read project name from forgecraft.yaml if present, otherwise use dirname.
407
+ */
408
+ function deriveProjectName(projectDir) {
409
+ const yamlPath = join(projectDir, "forgecraft.yaml");
410
+ if (existsSync(yamlPath)) {
411
+ try {
412
+ const content = readFileSync(yamlPath, "utf-8");
413
+ const m = /^project_name:\s*(.+)/m.exec(content);
414
+ if (m)
415
+ return m[1].trim();
416
+ }
417
+ catch {
418
+ // fallback
419
+ }
420
+ }
421
+ return projectDir.split(/[\\/]/).filter(Boolean).pop() ?? "project";
422
+ }
423
+ // ── Formatter ─────────────────────────────────────────────────────────
424
+ /**
425
+ * Format a LayerReport as a human-readable markdown block.
426
+ */
427
+ export function formatLayerReport(report) {
428
+ const lines = [
429
+ `## Layer Status — ${report.projectName}`,
430
+ ``,
431
+ `_Generated: ${report.generatedAt}_`,
432
+ ``,
433
+ ];
434
+ const total = report.ucs.length;
435
+ if (total === 0) {
436
+ lines.push("_No use cases found in docs/use-cases.md_");
437
+ lines.push("");
438
+ lines.push("To begin tracking: create `docs/use-cases.md` with `## UC-001: ...` headers.");
439
+ appendLayerSummaryNoUcs(lines, report);
440
+ return lines.join("\n");
441
+ }
442
+ // L1
443
+ const unboundUcs = report.l1.filter((u) => !u.testsFound);
444
+ const testBindingPct = total > 0 ? Math.round(((total - unboundUcs.length) / total) * 100) : 100;
445
+ lines.push("### L1: Blueprint");
446
+ lines.push(`${total}/${total} use cases documented`);
447
+ lines.push(`${total - unboundUcs.length}/${total} use cases have test binding (${testBindingPct}%)`);
448
+ lines.push("");
449
+ lines.push("| UC | Title | Documented | Tests Found |");
450
+ lines.push("|---|---|---|---|");
451
+ for (const uc of report.l1) {
452
+ const tests = uc.testsFound ? "✅" : "❌";
453
+ lines.push(`| ${uc.id} | ${uc.title} | ✅ | ${tests} |`);
454
+ }
455
+ lines.push("");
456
+ if (unboundUcs.length > 0) {
457
+ lines.push(`> ⚠️ **${unboundUcs.length} use case(s) have no test binding** — tests pass but these UCs have no test file that references their ID.`);
458
+ lines.push(`> This means the UCs are documentation, not contracts. Add a test that imports or references \`${unboundUcs[0].id}\` (even as a describe label) to establish the binding.`);
459
+ lines.push(`> Unbound: ${unboundUcs.map((u) => u.id).join(", ")}`);
460
+ lines.push("");
461
+ }
462
+ // L1 gate violations
463
+ if (report.l1GateViolations.length > 0) {
464
+ lines.push("**Active L1 gate violations:**");
465
+ for (const v of report.l1GateViolations) {
466
+ lines.push(`- ❌ ${v.gateId}: ${v.message}`);
467
+ }
468
+ lines.push("");
469
+ }
470
+ // L2
471
+ const l2Passing = report.l2.filter((u) => u.hasProbe).length;
472
+ const l2Pct = total > 0 ? Math.round((l2Passing / total) * 100) : 0;
473
+ const harnessSummary = buildHarnessRunSummary(report.projectDir ?? "");
474
+ const lastRunStr = harnessSummary.lastRunTimestamp ?? "never run";
475
+ // Scenario counts across all UCs
476
+ const happyCount = report.l2.filter((u) => u.hasHappyProbe).length;
477
+ const errorTotal = report.l2.reduce((sum, u) => sum + u.errorProbeCount, 0);
478
+ lines.push("### L2: Behavioral Harness");
479
+ lines.push(`${l2Passing}/${total} use cases have harness specs (.forgecraft/harness/)`);
480
+ lines.push(`${harnessSummary.probeFilesFound}/${total} have executable probe files (tests/harness/)`);
481
+ lines.push(`Last harness run: ${lastRunStr}`);
482
+ lines.push("");
483
+ lines.push("| UC | Title | Happy | Error Paths | Last Run |");
484
+ lines.push("|---|---|---|---|---|");
485
+ for (const uc of report.l2) {
486
+ const happyCell = uc.hasHappyProbe
487
+ ? "✅"
488
+ : uc.hasProbe
489
+ ? "❌ missing"
490
+ : "❌ missing";
491
+ const errorCell = uc.errorProbeCount > 0
492
+ ? `${uc.errorProbeCount} probe${uc.errorProbeCount === 1 ? "" : "s"}`
493
+ : "0 probes ⚠️";
494
+ const lastRunCell = uc.lastRunStatus
495
+ ? uc.lastRunStatus === "pass"
496
+ ? "✅ pass"
497
+ : `❌ ${uc.lastRunStatus}`
498
+ : "—";
499
+ lines.push(`| ${uc.id} | ${uc.title} | ${happyCell} | ${errorCell} | ${lastRunCell} |`);
500
+ }
501
+ lines.push("");
502
+ lines.push(`**Scenario coverage**: ${happyCount}/${total} happy paths | ${errorTotal}/${total * 3} error paths`);
503
+ if (harnessSummary.lastRunTimestamp) {
504
+ const harnessRun = readHarnessRunForSummary(report.projectDir ?? "");
505
+ if (harnessRun) {
506
+ lines.push(`**Last harness run**: ${harnessRun.timestamp} (${harnessRun.passed} passed / ${harnessRun.failed} failed / ${harnessRun.notFound} not run)`);
507
+ }
508
+ }
509
+ lines.push("");
510
+ // Postcondition coverage
511
+ const coverage = computePostconditionCoverage(report.projectDir ?? "", report.ucs);
512
+ const hollowCount = coverage.filter((c) => c.hollow).length;
513
+ const uncoveredCount = coverage.filter((c) => c.coverageRatio < 0.4 && c.probeFiles.length > 0).length;
514
+ lines.push("**Postcondition Coverage** (assertions in probe files vs. spec postconditions):");
515
+ lines.push(formatCoverageTable(coverage));
516
+ if (hollowCount > 0) {
517
+ lines.push(`⚠️ ${hollowCount} hollow probe(s) — pass with zero assertions. Add assertion checks.`);
518
+ }
519
+ if (uncoveredCount > 0) {
520
+ lines.push(`⚠️ ${uncoveredCount} UC(s) have probes but assertion count < 40% of postconditions.`);
521
+ }
522
+ lines.push("");
523
+ lines.push(`**L2 coverage: ${l2Pct}% — ${total - l2Passing} use case(s) need probe definitions**`);
524
+ lines.push("");
525
+ lines.push("To add a probe: create `.forgecraft/harness/uc-NNN.yaml` with at least one probe entry.");
526
+ lines.push("");
527
+ // L3
528
+ lines.push("### L3: Environment & Infrastructure");
529
+ for (const [label, passing] of Object.entries(report.l3Checks)) {
530
+ lines.push(`- ${passing ? "✅" : "❌"} ${label}`);
531
+ }
532
+ if (report.envProbeEvidence !== null) {
533
+ const ev = report.envProbeEvidence;
534
+ lines.push(`- Env probe evidence: ✅ ${ev.passed} passed / ${ev.failed} failed (last run: ${ev.timestamp})`);
535
+ }
536
+ else {
537
+ lines.push(`- Env probe evidence: ⚠️ not yet run — call run_env_probe`);
538
+ }
539
+ lines.push("");
540
+ // L4
541
+ lines.push("### L4: Self-Monitoring");
542
+ for (const [label, passing] of Object.entries(report.l4Checks)) {
543
+ lines.push(`- ${passing ? "✅" : "❌"} ${label}`);
544
+ }
545
+ if (report.sloProbeEvidence !== null) {
546
+ const ev = report.sloProbeEvidence;
547
+ lines.push(`- SLO probe evidence: ✅ ${ev.passed} passed / ${ev.failed} failed (last run: ${ev.timestamp})`);
548
+ }
549
+ else {
550
+ lines.push(`- SLO probe evidence: ⚠️ not yet run — call run_slo_probe`);
551
+ }
552
+ lines.push("");
553
+ // Summary
554
+ const l3Score = report.l3 === "complete"
555
+ ? "complete"
556
+ : report.l3 === "partial"
557
+ ? "partial"
558
+ : "not-started";
559
+ const l4Score = report.l4 === "complete"
560
+ ? "complete"
561
+ : report.l4 === "partial"
562
+ ? "partial"
563
+ : "not-started";
564
+ const l1Pct = 100;
565
+ lines.push("### Summary");
566
+ lines.push("| Layer | Status | Score |");
567
+ lines.push("|---|---|---|");
568
+ lines.push(`| L1 Blueprint | ${total}/${total} | ${l1Pct}% |`);
569
+ lines.push(`| L2 Harness | ${l2Passing}/${total} | ${l2Pct}% |`);
570
+ lines.push(`| L3 Environment | ${l3Score} | — |`);
571
+ lines.push(`| L4 Monitoring | ${l4Score} | — |`);
572
+ lines.push("");
573
+ // Next action
574
+ const nextAction = deriveNextAction(report, l2Passing, total);
575
+ lines.push(`**Next action**: ${nextAction}`);
576
+ return lines.join("\n");
577
+ }
578
+ /**
579
+ * Append layer summary for projects with no use cases.
580
+ */
581
+ function appendLayerSummaryNoUcs(lines, report) {
582
+ lines.push("");
583
+ lines.push("### L3: Environment & Infrastructure");
584
+ for (const [label, passing] of Object.entries(report.l3Checks)) {
585
+ lines.push(`- ${passing ? "✅" : "❌"} ${label}`);
586
+ }
587
+ if (report.envProbeEvidence !== null) {
588
+ const ev = report.envProbeEvidence;
589
+ lines.push(`- Env probe evidence: ✅ ${ev.passed} passed / ${ev.failed} failed (last run: ${ev.timestamp})`);
590
+ }
591
+ else {
592
+ lines.push(`- Env probe evidence: ⚠️ not yet run — call run_env_probe`);
593
+ }
594
+ lines.push("");
595
+ lines.push("### L4: Self-Monitoring");
596
+ for (const [label, passing] of Object.entries(report.l4Checks)) {
597
+ lines.push(`- ${passing ? "✅" : "❌"} ${label}`);
598
+ }
599
+ if (report.sloProbeEvidence !== null) {
600
+ const ev = report.sloProbeEvidence;
601
+ lines.push(`- SLO probe evidence: ✅ ${ev.passed} passed / ${ev.failed} failed (last run: ${ev.timestamp})`);
602
+ }
603
+ else {
604
+ lines.push(`- SLO probe evidence: ⚠️ not yet run — call run_slo_probe`);
605
+ }
606
+ }
607
+ /**
608
+ * Derive the highest-impact next action from the current layer report.
609
+ */
610
+ function deriveNextAction(report, l2Passing, total) {
611
+ if (total === 0) {
612
+ return "Create docs/use-cases.md with formal UC entries to begin layer tracking.";
613
+ }
614
+ if (l2Passing < total) {
615
+ const missing = report.l2
616
+ .filter((u) => !u.hasProbe)
617
+ .map((u) => u.id)
618
+ .slice(0, 3)
619
+ .join(", ");
620
+ return `Add L2 harness probes for: ${missing}. Create .forgecraft/harness/uc-NNN.yaml.`;
621
+ }
622
+ if (report.l3 === "not-started") {
623
+ return "Add L3 infrastructure config: CI workflow, Dockerfile, or .env.example.";
624
+ }
625
+ if (report.l3 === "partial") {
626
+ return "Complete L3 environment coverage: add missing CI, env schema, or deployment config.";
627
+ }
628
+ if (report.l4 === "not-started") {
629
+ return "Add L4 monitoring: create .forgecraft/health/ or src/health/ with probe definitions.";
630
+ }
631
+ return "All layers complete. Run close_cycle to finalize the cycle.";
632
+ }
633
+ // ── Handler ───────────────────────────────────────────────────────────
634
+ /**
635
+ * Handler for the layer_status action.
636
+ *
637
+ * @param args - Validated input with project_dir
638
+ * @returns MCP-style tool result with formatted layer report
639
+ */
640
+ export async function layerStatusHandler(args) {
641
+ const projectDir = resolve(args.project_dir);
642
+ const report = buildLayerReport(projectDir);
643
+ return {
644
+ content: [{ type: "text", text: formatLayerReport(report) }],
645
+ };
646
+ }
647
+ //# sourceMappingURL=layer-status.js.map