@harness-engineering/cli 1.13.0 → 1.14.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 (367) hide show
  1. package/dist/agents/skills/claude-code/add-harness-component/skill.yaml +1 -0
  2. package/dist/agents/skills/claude-code/align-documentation/skill.yaml +1 -0
  3. package/dist/agents/skills/claude-code/check-mechanical-constraints/skill.yaml +1 -0
  4. package/dist/agents/skills/claude-code/cleanup-dead-code/skill.yaml +1 -0
  5. package/dist/agents/skills/claude-code/detect-doc-drift/skill.yaml +1 -0
  6. package/dist/agents/skills/claude-code/enforce-architecture/skill.yaml +1 -0
  7. package/dist/agents/skills/claude-code/harness-accessibility/skill.yaml +1 -0
  8. package/dist/agents/skills/claude-code/harness-api-design/SKILL.md +304 -0
  9. package/dist/agents/skills/claude-code/harness-api-design/skill.yaml +74 -0
  10. package/dist/agents/skills/claude-code/harness-architecture-advisor/skill.yaml +1 -0
  11. package/dist/agents/skills/claude-code/harness-auth/SKILL.md +279 -0
  12. package/dist/agents/skills/claude-code/harness-auth/skill.yaml +81 -0
  13. package/dist/agents/skills/claude-code/harness-autopilot/skill.yaml +1 -0
  14. package/dist/agents/skills/claude-code/harness-brainstorming/SKILL.md +39 -0
  15. package/dist/agents/skills/claude-code/harness-brainstorming/skill.yaml +1 -0
  16. package/dist/agents/skills/claude-code/harness-caching/SKILL.md +309 -0
  17. package/dist/agents/skills/claude-code/harness-caching/skill.yaml +73 -0
  18. package/dist/agents/skills/claude-code/harness-chaos/SKILL.md +295 -0
  19. package/dist/agents/skills/claude-code/harness-chaos/skill.yaml +72 -0
  20. package/dist/agents/skills/claude-code/harness-code-review/SKILL.md +44 -0
  21. package/dist/agents/skills/claude-code/harness-code-review/skill.yaml +1 -0
  22. package/dist/agents/skills/claude-code/harness-codebase-cleanup/skill.yaml +1 -0
  23. package/dist/agents/skills/claude-code/harness-compliance/SKILL.md +303 -0
  24. package/dist/agents/skills/claude-code/harness-compliance/skill.yaml +78 -0
  25. package/dist/agents/skills/claude-code/harness-containerization/SKILL.md +284 -0
  26. package/dist/agents/skills/claude-code/harness-containerization/skill.yaml +80 -0
  27. package/dist/agents/skills/claude-code/harness-data-pipeline/SKILL.md +274 -0
  28. package/dist/agents/skills/claude-code/harness-data-pipeline/skill.yaml +81 -0
  29. package/dist/agents/skills/claude-code/harness-data-validation/SKILL.md +343 -0
  30. package/dist/agents/skills/claude-code/harness-data-validation/skill.yaml +75 -0
  31. package/dist/agents/skills/claude-code/harness-database/SKILL.md +258 -0
  32. package/dist/agents/skills/claude-code/harness-database/skill.yaml +80 -0
  33. package/dist/agents/skills/claude-code/harness-debugging/skill.yaml +1 -0
  34. package/dist/agents/skills/claude-code/harness-dependency-health/skill.yaml +1 -0
  35. package/dist/agents/skills/claude-code/harness-deployment/SKILL.md +255 -0
  36. package/dist/agents/skills/claude-code/harness-deployment/skill.yaml +77 -0
  37. package/dist/agents/skills/claude-code/harness-design/skill.yaml +1 -0
  38. package/dist/agents/skills/claude-code/harness-design-mobile/skill.yaml +1 -0
  39. package/dist/agents/skills/claude-code/harness-design-system/skill.yaml +1 -0
  40. package/dist/agents/skills/claude-code/harness-design-web/skill.yaml +1 -0
  41. package/dist/agents/skills/claude-code/harness-diagnostics/skill.yaml +1 -0
  42. package/dist/agents/skills/claude-code/harness-docs-pipeline/skill.yaml +1 -0
  43. package/dist/agents/skills/claude-code/harness-dx/SKILL.md +276 -0
  44. package/dist/agents/skills/claude-code/harness-dx/skill.yaml +76 -0
  45. package/dist/agents/skills/claude-code/harness-e2e/SKILL.md +245 -0
  46. package/dist/agents/skills/claude-code/harness-e2e/skill.yaml +78 -0
  47. package/dist/agents/skills/claude-code/harness-event-driven/SKILL.md +280 -0
  48. package/dist/agents/skills/claude-code/harness-event-driven/skill.yaml +77 -0
  49. package/dist/agents/skills/claude-code/harness-execution/SKILL.md +44 -0
  50. package/dist/agents/skills/claude-code/harness-execution/skill.yaml +1 -0
  51. package/dist/agents/skills/claude-code/harness-feature-flags/SKILL.md +287 -0
  52. package/dist/agents/skills/claude-code/harness-feature-flags/skill.yaml +74 -0
  53. package/dist/agents/skills/claude-code/harness-git-workflow/skill.yaml +1 -0
  54. package/dist/agents/skills/claude-code/harness-hotspot-detector/skill.yaml +1 -0
  55. package/dist/agents/skills/claude-code/harness-i18n/skill.yaml +1 -0
  56. package/dist/agents/skills/claude-code/harness-i18n-process/skill.yaml +1 -0
  57. package/dist/agents/skills/claude-code/harness-i18n-workflow/skill.yaml +1 -0
  58. package/dist/agents/skills/claude-code/harness-impact-analysis/skill.yaml +1 -0
  59. package/dist/agents/skills/claude-code/harness-incident-response/SKILL.md +223 -0
  60. package/dist/agents/skills/claude-code/harness-incident-response/skill.yaml +78 -0
  61. package/dist/agents/skills/claude-code/harness-infrastructure-as-code/SKILL.md +279 -0
  62. package/dist/agents/skills/claude-code/harness-infrastructure-as-code/skill.yaml +80 -0
  63. package/dist/agents/skills/claude-code/harness-integration-test/SKILL.md +271 -0
  64. package/dist/agents/skills/claude-code/harness-integration-test/skill.yaml +73 -0
  65. package/dist/agents/skills/claude-code/harness-integrity/skill.yaml +1 -0
  66. package/dist/agents/skills/claude-code/harness-knowledge-mapper/skill.yaml +1 -0
  67. package/dist/agents/skills/claude-code/harness-load-testing/SKILL.md +274 -0
  68. package/dist/agents/skills/claude-code/harness-load-testing/skill.yaml +79 -0
  69. package/dist/agents/skills/claude-code/harness-ml-ops/SKILL.md +341 -0
  70. package/dist/agents/skills/claude-code/harness-ml-ops/skill.yaml +79 -0
  71. package/dist/agents/skills/claude-code/harness-mobile-patterns/SKILL.md +326 -0
  72. package/dist/agents/skills/claude-code/harness-mobile-patterns/skill.yaml +82 -0
  73. package/dist/agents/skills/claude-code/harness-mutation-test/SKILL.md +251 -0
  74. package/dist/agents/skills/claude-code/harness-mutation-test/skill.yaml +70 -0
  75. package/dist/agents/skills/claude-code/harness-observability/SKILL.md +283 -0
  76. package/dist/agents/skills/claude-code/harness-observability/skill.yaml +78 -0
  77. package/dist/agents/skills/claude-code/harness-onboarding/skill.yaml +1 -0
  78. package/dist/agents/skills/claude-code/harness-parallel-agents/skill.yaml +1 -0
  79. package/dist/agents/skills/claude-code/harness-perf/skill.yaml +1 -0
  80. package/dist/agents/skills/claude-code/harness-perf-tdd/skill.yaml +1 -0
  81. package/dist/agents/skills/claude-code/harness-planning/SKILL.md +39 -0
  82. package/dist/agents/skills/claude-code/harness-planning/skill.yaml +1 -0
  83. package/dist/agents/skills/claude-code/harness-pre-commit-review/skill.yaml +1 -0
  84. package/dist/agents/skills/claude-code/harness-product-spec/SKILL.md +285 -0
  85. package/dist/agents/skills/claude-code/harness-product-spec/skill.yaml +72 -0
  86. package/dist/agents/skills/claude-code/harness-property-test/SKILL.md +281 -0
  87. package/dist/agents/skills/claude-code/harness-property-test/skill.yaml +71 -0
  88. package/dist/agents/skills/claude-code/harness-refactoring/skill.yaml +1 -0
  89. package/dist/agents/skills/claude-code/harness-release-readiness/SKILL.md +3 -3
  90. package/dist/agents/skills/claude-code/harness-release-readiness/skill.yaml +1 -0
  91. package/dist/agents/skills/claude-code/harness-resilience/SKILL.md +255 -0
  92. package/dist/agents/skills/claude-code/harness-resilience/skill.yaml +76 -0
  93. package/dist/agents/skills/claude-code/harness-roadmap/skill.yaml +1 -0
  94. package/dist/agents/skills/claude-code/harness-secrets/SKILL.md +293 -0
  95. package/dist/agents/skills/claude-code/harness-secrets/skill.yaml +76 -0
  96. package/dist/agents/skills/claude-code/harness-security-review/skill.yaml +1 -0
  97. package/dist/agents/skills/claude-code/harness-security-scan/skill.yaml +1 -0
  98. package/dist/agents/skills/claude-code/harness-skill-authoring/skill.yaml +1 -0
  99. package/dist/agents/skills/claude-code/harness-soundness-review/skill.yaml +1 -0
  100. package/dist/agents/skills/claude-code/harness-sql-review/SKILL.md +315 -0
  101. package/dist/agents/skills/claude-code/harness-sql-review/skill.yaml +74 -0
  102. package/dist/agents/skills/claude-code/harness-state-management/skill.yaml +1 -0
  103. package/dist/agents/skills/claude-code/harness-tdd/skill.yaml +1 -0
  104. package/dist/agents/skills/claude-code/harness-test-advisor/skill.yaml +1 -0
  105. package/dist/agents/skills/claude-code/harness-test-data/SKILL.md +268 -0
  106. package/dist/agents/skills/claude-code/harness-test-data/skill.yaml +74 -0
  107. package/dist/agents/skills/claude-code/harness-ux-copy/SKILL.md +271 -0
  108. package/dist/agents/skills/claude-code/harness-ux-copy/skill.yaml +77 -0
  109. package/dist/agents/skills/claude-code/harness-verification/SKILL.md +35 -0
  110. package/dist/agents/skills/claude-code/harness-verification/skill.yaml +1 -0
  111. package/dist/agents/skills/claude-code/harness-verify/skill.yaml +1 -0
  112. package/dist/agents/skills/claude-code/harness-visual-regression/SKILL.md +257 -0
  113. package/dist/agents/skills/claude-code/harness-visual-regression/skill.yaml +74 -0
  114. package/dist/agents/skills/claude-code/initialize-harness-project/SKILL.md +11 -3
  115. package/dist/agents/skills/claude-code/initialize-harness-project/skill.yaml +1 -0
  116. package/dist/agents/skills/claude-code/validate-context-engineering/skill.yaml +1 -0
  117. package/dist/agents/skills/gemini-cli/add-harness-component/skill.yaml +1 -0
  118. package/dist/agents/skills/gemini-cli/align-documentation/skill.yaml +1 -0
  119. package/dist/agents/skills/gemini-cli/check-mechanical-constraints/skill.yaml +1 -0
  120. package/dist/agents/skills/gemini-cli/cleanup-dead-code/skill.yaml +1 -0
  121. package/dist/agents/skills/gemini-cli/detect-doc-drift/skill.yaml +1 -0
  122. package/dist/agents/skills/gemini-cli/enforce-architecture/skill.yaml +1 -0
  123. package/dist/agents/skills/gemini-cli/harness-accessibility/skill.yaml +1 -0
  124. package/dist/agents/skills/gemini-cli/harness-api-design/SKILL.md +304 -0
  125. package/dist/agents/skills/gemini-cli/harness-api-design/skill.yaml +74 -0
  126. package/dist/agents/skills/gemini-cli/harness-architecture-advisor/skill.yaml +1 -0
  127. package/dist/agents/skills/gemini-cli/harness-auth/SKILL.md +279 -0
  128. package/dist/agents/skills/gemini-cli/harness-auth/skill.yaml +81 -0
  129. package/dist/agents/skills/gemini-cli/harness-autopilot/skill.yaml +1 -0
  130. package/dist/agents/skills/gemini-cli/harness-brainstorming/SKILL.md +39 -0
  131. package/dist/agents/skills/gemini-cli/harness-brainstorming/skill.yaml +1 -0
  132. package/dist/agents/skills/gemini-cli/harness-caching/SKILL.md +309 -0
  133. package/dist/agents/skills/gemini-cli/harness-caching/skill.yaml +73 -0
  134. package/dist/agents/skills/gemini-cli/harness-chaos/SKILL.md +295 -0
  135. package/dist/agents/skills/gemini-cli/harness-chaos/skill.yaml +72 -0
  136. package/dist/agents/skills/gemini-cli/harness-code-review/SKILL.md +44 -0
  137. package/dist/agents/skills/gemini-cli/harness-code-review/skill.yaml +1 -0
  138. package/dist/agents/skills/gemini-cli/harness-codebase-cleanup/skill.yaml +1 -0
  139. package/dist/agents/skills/gemini-cli/harness-compliance/SKILL.md +303 -0
  140. package/dist/agents/skills/gemini-cli/harness-compliance/skill.yaml +78 -0
  141. package/dist/agents/skills/gemini-cli/harness-containerization/SKILL.md +284 -0
  142. package/dist/agents/skills/gemini-cli/harness-containerization/skill.yaml +80 -0
  143. package/dist/agents/skills/gemini-cli/harness-data-pipeline/SKILL.md +274 -0
  144. package/dist/agents/skills/gemini-cli/harness-data-pipeline/skill.yaml +81 -0
  145. package/dist/agents/skills/gemini-cli/harness-data-validation/SKILL.md +343 -0
  146. package/dist/agents/skills/gemini-cli/harness-data-validation/skill.yaml +75 -0
  147. package/dist/agents/skills/gemini-cli/harness-database/SKILL.md +258 -0
  148. package/dist/agents/skills/gemini-cli/harness-database/skill.yaml +80 -0
  149. package/dist/agents/skills/gemini-cli/harness-debugging/skill.yaml +1 -0
  150. package/dist/agents/skills/gemini-cli/harness-dependency-health/skill.yaml +1 -0
  151. package/dist/agents/skills/gemini-cli/harness-deployment/SKILL.md +255 -0
  152. package/dist/agents/skills/gemini-cli/harness-deployment/skill.yaml +77 -0
  153. package/dist/agents/skills/gemini-cli/harness-design/skill.yaml +1 -0
  154. package/dist/agents/skills/gemini-cli/harness-design-mobile/skill.yaml +1 -0
  155. package/dist/agents/skills/gemini-cli/harness-design-system/skill.yaml +1 -0
  156. package/dist/agents/skills/gemini-cli/harness-design-web/skill.yaml +1 -0
  157. package/dist/agents/skills/gemini-cli/harness-diagnostics/skill.yaml +1 -0
  158. package/dist/agents/skills/gemini-cli/harness-docs-pipeline/skill.yaml +1 -0
  159. package/dist/agents/skills/gemini-cli/harness-dx/SKILL.md +276 -0
  160. package/dist/agents/skills/gemini-cli/harness-dx/skill.yaml +76 -0
  161. package/dist/agents/skills/gemini-cli/harness-e2e/SKILL.md +245 -0
  162. package/dist/agents/skills/gemini-cli/harness-e2e/skill.yaml +78 -0
  163. package/dist/agents/skills/gemini-cli/harness-event-driven/SKILL.md +280 -0
  164. package/dist/agents/skills/gemini-cli/harness-event-driven/skill.yaml +77 -0
  165. package/dist/agents/skills/gemini-cli/harness-execution/SKILL.md +44 -0
  166. package/dist/agents/skills/gemini-cli/harness-execution/skill.yaml +1 -0
  167. package/dist/agents/skills/gemini-cli/harness-feature-flags/SKILL.md +287 -0
  168. package/dist/agents/skills/gemini-cli/harness-feature-flags/skill.yaml +74 -0
  169. package/dist/agents/skills/gemini-cli/harness-git-workflow/skill.yaml +1 -0
  170. package/dist/agents/skills/gemini-cli/harness-hotspot-detector/skill.yaml +1 -0
  171. package/dist/agents/skills/gemini-cli/harness-i18n/skill.yaml +1 -0
  172. package/dist/agents/skills/gemini-cli/harness-i18n-process/skill.yaml +1 -0
  173. package/dist/agents/skills/gemini-cli/harness-i18n-workflow/skill.yaml +1 -0
  174. package/dist/agents/skills/gemini-cli/harness-impact-analysis/skill.yaml +1 -0
  175. package/dist/agents/skills/gemini-cli/harness-incident-response/SKILL.md +223 -0
  176. package/dist/agents/skills/gemini-cli/harness-incident-response/skill.yaml +78 -0
  177. package/dist/agents/skills/gemini-cli/harness-infrastructure-as-code/SKILL.md +279 -0
  178. package/dist/agents/skills/gemini-cli/harness-infrastructure-as-code/skill.yaml +80 -0
  179. package/dist/agents/skills/gemini-cli/harness-integration-test/SKILL.md +271 -0
  180. package/dist/agents/skills/gemini-cli/harness-integration-test/skill.yaml +73 -0
  181. package/dist/agents/skills/gemini-cli/harness-integrity/skill.yaml +1 -0
  182. package/dist/agents/skills/gemini-cli/harness-knowledge-mapper/skill.yaml +1 -0
  183. package/dist/agents/skills/gemini-cli/harness-load-testing/SKILL.md +274 -0
  184. package/dist/agents/skills/gemini-cli/harness-load-testing/skill.yaml +79 -0
  185. package/dist/agents/skills/gemini-cli/harness-ml-ops/SKILL.md +341 -0
  186. package/dist/agents/skills/gemini-cli/harness-ml-ops/skill.yaml +79 -0
  187. package/dist/agents/skills/gemini-cli/harness-mobile-patterns/SKILL.md +326 -0
  188. package/dist/agents/skills/gemini-cli/harness-mobile-patterns/skill.yaml +82 -0
  189. package/dist/agents/skills/gemini-cli/harness-mutation-test/SKILL.md +251 -0
  190. package/dist/agents/skills/gemini-cli/harness-mutation-test/skill.yaml +70 -0
  191. package/dist/agents/skills/gemini-cli/harness-observability/SKILL.md +283 -0
  192. package/dist/agents/skills/gemini-cli/harness-observability/skill.yaml +78 -0
  193. package/dist/agents/skills/gemini-cli/harness-onboarding/skill.yaml +1 -0
  194. package/dist/agents/skills/gemini-cli/harness-parallel-agents/skill.yaml +1 -0
  195. package/dist/agents/skills/gemini-cli/harness-perf/skill.yaml +1 -0
  196. package/dist/agents/skills/gemini-cli/harness-perf-tdd/skill.yaml +1 -0
  197. package/dist/agents/skills/gemini-cli/harness-planning/SKILL.md +39 -0
  198. package/dist/agents/skills/gemini-cli/harness-planning/skill.yaml +1 -0
  199. package/dist/agents/skills/gemini-cli/harness-pre-commit-review/skill.yaml +1 -0
  200. package/dist/agents/skills/gemini-cli/harness-product-spec/SKILL.md +285 -0
  201. package/dist/agents/skills/gemini-cli/harness-product-spec/skill.yaml +72 -0
  202. package/dist/agents/skills/gemini-cli/harness-property-test/SKILL.md +281 -0
  203. package/dist/agents/skills/gemini-cli/harness-property-test/skill.yaml +71 -0
  204. package/dist/agents/skills/gemini-cli/harness-refactoring/skill.yaml +1 -0
  205. package/dist/agents/skills/gemini-cli/harness-release-readiness/SKILL.md +3 -3
  206. package/dist/agents/skills/gemini-cli/harness-release-readiness/skill.yaml +1 -0
  207. package/dist/agents/skills/gemini-cli/harness-resilience/SKILL.md +255 -0
  208. package/dist/agents/skills/gemini-cli/harness-resilience/skill.yaml +76 -0
  209. package/dist/agents/skills/gemini-cli/harness-roadmap/skill.yaml +1 -0
  210. package/dist/agents/skills/gemini-cli/harness-secrets/SKILL.md +293 -0
  211. package/dist/agents/skills/gemini-cli/harness-secrets/skill.yaml +76 -0
  212. package/dist/agents/skills/gemini-cli/harness-security-review/SKILL.md +240 -0
  213. package/dist/agents/skills/gemini-cli/harness-security-review/skill.yaml +1 -0
  214. package/dist/agents/skills/gemini-cli/harness-security-scan/skill.yaml +1 -0
  215. package/dist/agents/skills/gemini-cli/harness-skill-authoring/skill.yaml +1 -0
  216. package/dist/agents/skills/gemini-cli/harness-soundness-review/skill.yaml +1 -0
  217. package/dist/agents/skills/gemini-cli/harness-sql-review/SKILL.md +315 -0
  218. package/dist/agents/skills/gemini-cli/harness-sql-review/skill.yaml +74 -0
  219. package/dist/agents/skills/gemini-cli/harness-state-management/skill.yaml +1 -0
  220. package/dist/agents/skills/gemini-cli/harness-tdd/skill.yaml +1 -0
  221. package/dist/agents/skills/gemini-cli/harness-test-advisor/skill.yaml +1 -0
  222. package/dist/agents/skills/gemini-cli/harness-test-data/SKILL.md +268 -0
  223. package/dist/agents/skills/gemini-cli/harness-test-data/skill.yaml +74 -0
  224. package/dist/agents/skills/gemini-cli/harness-ux-copy/SKILL.md +271 -0
  225. package/dist/agents/skills/gemini-cli/harness-ux-copy/skill.yaml +77 -0
  226. package/dist/agents/skills/gemini-cli/harness-verification/SKILL.md +35 -0
  227. package/dist/agents/skills/gemini-cli/harness-verification/skill.yaml +1 -0
  228. package/dist/agents/skills/gemini-cli/harness-verify/skill.yaml +1 -0
  229. package/dist/agents/skills/gemini-cli/harness-visual-regression/SKILL.md +257 -0
  230. package/dist/agents/skills/gemini-cli/harness-visual-regression/skill.yaml +74 -0
  231. package/dist/agents/skills/gemini-cli/initialize-harness-project/SKILL.md +11 -3
  232. package/dist/agents/skills/gemini-cli/initialize-harness-project/skill.yaml +1 -0
  233. package/dist/agents/skills/gemini-cli/validate-context-engineering/skill.yaml +1 -0
  234. package/dist/agents-md-YTYQDA3P.js +8 -0
  235. package/dist/{architecture-ESOOE26S.js → architecture-JQZYM4US.js} +4 -4
  236. package/dist/bin/harness-mcp.js +16 -15
  237. package/dist/bin/harness.js +31 -30
  238. package/dist/{check-phase-gate-S2MZKLFQ.js → check-phase-gate-L3RADYWO.js} +4 -3
  239. package/dist/{chunk-WPPDRIJL.js → chunk-3C2MLBPJ.js} +4 -4
  240. package/dist/chunk-6KTUUFRN.js +217 -0
  241. package/dist/{chunk-MI5XJQDY.js → chunk-7IP4JIFL.js} +24 -10
  242. package/dist/{chunk-C2ERUR3L.js → chunk-7MJAPE3Z.js} +165 -49
  243. package/dist/{chunk-KELT6K6M.js → chunk-ABQHQ6I5.js} +1861 -1418
  244. package/dist/{chunk-L2KLU56K.js → chunk-AOZRDOIP.js} +2 -2
  245. package/dist/{chunk-QPEH2QPG.js → chunk-DBSOCI3G.js} +53 -54
  246. package/dist/{chunk-MHBMTPW7.js → chunk-ERS5EVUZ.js} +9 -0
  247. package/dist/{chunk-JSTQ3AWB.js → chunk-FIAPHX37.js} +1 -1
  248. package/dist/{chunk-2YPZKGAG.js → chunk-FTMXDOR6.js} +1 -1
  249. package/dist/{chunk-72GHBOL2.js → chunk-GZKSBLQL.js} +1 -1
  250. package/dist/{chunk-K6XAPGML.js → chunk-H7Y5CKTM.js} +1 -1
  251. package/dist/{chunk-HD4IBGLA.js → chunk-N5G5QMS3.js} +24 -1
  252. package/dist/{chunk-LD3DKUK5.js → chunk-NLVUVUGD.js} +1 -1
  253. package/dist/{chunk-3KOLLWWE.js → chunk-O5OJVPL6.js} +26 -211
  254. package/dist/{chunk-NKDM3FMH.js → chunk-OD3S2NHN.js} +1 -1
  255. package/dist/{chunk-5VY23YK3.js → chunk-OSXBPAMK.js} +2 -2
  256. package/dist/{chunk-MACVXDZK.js → chunk-OXLLOSSR.js} +45 -47
  257. package/dist/{chunk-GNGELAXY.js → chunk-RCWZBSK5.js} +2 -2
  258. package/dist/{chunk-PSNN4LWX.js → chunk-S2FXOWOR.js} +3 -3
  259. package/dist/{chunk-VUCPTQ6G.js → chunk-SD3SQOZ2.js} +1 -1
  260. package/dist/{chunk-7PZWR4LI.js → chunk-TPOTOBR7.js} +9 -9
  261. package/dist/{chunk-RZSUJBZZ.js → chunk-XKECDXJS.js} +452 -353
  262. package/dist/{chunk-VRFZWGMS.js → chunk-XYLGHKG6.js} +5 -1
  263. package/dist/{chunk-6N4R6FVX.js → chunk-YBJ262QL.js} +1 -1
  264. package/dist/{chunk-2VU4MFM3.js → chunk-YPYGXRDR.js} +7 -7
  265. package/dist/{chunk-Q6AB7W5Z.js → chunk-YQ6KC6TE.js} +1 -1
  266. package/dist/{chunk-7KQSUZVG.js → chunk-YZD2MRNQ.js} +1528 -1010
  267. package/dist/ci-workflow-EQZFVX3P.js +8 -0
  268. package/dist/{create-skill-WPXHSLX2.js → create-skill-XSWHMSM5.js} +2 -2
  269. package/dist/{dist-M6BQODWC.js → dist-B26DFXMP.js} +573 -480
  270. package/dist/{dist-L7LAAQAS.js → dist-DZ63LLUD.js} +1 -1
  271. package/dist/{dist-WF4C7A4A.js → dist-HWXF2C3R.js} +18 -2
  272. package/dist/{dist-D4RYGUZE.js → dist-USY2C5JL.js} +3 -1
  273. package/dist/{docs-BPYCN2DR.js → docs-7ECGYMAV.js} +5 -3
  274. package/dist/engine-EG4EH4IX.js +8 -0
  275. package/dist/{entropy-4VDVV5CR.js → entropy-5USWKLVS.js} +3 -3
  276. package/dist/{feedback-63QB5RCA.js → feedback-UTBXZZHF.js} +1 -1
  277. package/dist/{generate-agent-definitions-QABOJG56.js → generate-agent-definitions-3PM5EU7V.js} +5 -5
  278. package/dist/{glob-helper-5OHBUQAI.js → glob-helper-R5FXNUPS.js} +1 -1
  279. package/dist/{graph-loader-KO4GJ5N2.js → graph-loader-2M2HXDQI.js} +1 -1
  280. package/dist/index.d.ts +183 -17
  281. package/dist/index.js +32 -30
  282. package/dist/loader-ZPALXIVR.js +10 -0
  283. package/dist/mcp-362EZHF4.js +35 -0
  284. package/dist/{performance-26BH47O4.js → performance-OQAFMJUD.js} +3 -3
  285. package/dist/{review-pipeline-GHR3WFBI.js → review-pipeline-C4GCFVGP.js} +1 -1
  286. package/dist/runtime-7YLVK453.js +9 -0
  287. package/dist/{security-UQFUZXEN.js → security-PZOX7AQS.js} +1 -1
  288. package/dist/skill-executor-XZLYZYAK.js +8 -0
  289. package/dist/templates/axum/Cargo.toml.hbs +8 -0
  290. package/dist/templates/axum/src/main.rs +12 -0
  291. package/dist/templates/axum/template.json +16 -0
  292. package/dist/templates/django/manage.py.hbs +19 -0
  293. package/dist/templates/django/requirements.txt.hbs +1 -0
  294. package/dist/templates/django/src/settings.py.hbs +44 -0
  295. package/dist/templates/django/src/urls.py +6 -0
  296. package/dist/templates/django/src/wsgi.py.hbs +9 -0
  297. package/dist/templates/django/template.json +21 -0
  298. package/dist/templates/express/package.json.hbs +15 -0
  299. package/dist/templates/express/src/app.ts +12 -0
  300. package/dist/templates/express/src/lib/.gitkeep +0 -0
  301. package/dist/templates/express/template.json +16 -0
  302. package/dist/templates/fastapi/requirements.txt.hbs +2 -0
  303. package/dist/templates/fastapi/src/main.py +8 -0
  304. package/dist/templates/fastapi/template.json +20 -0
  305. package/dist/templates/gin/go.mod.hbs +5 -0
  306. package/dist/templates/gin/main.go +15 -0
  307. package/dist/templates/gin/template.json +19 -0
  308. package/dist/templates/go-base/.golangci.yml +16 -0
  309. package/dist/templates/go-base/AGENTS.md.hbs +35 -0
  310. package/dist/templates/go-base/go.mod.hbs +3 -0
  311. package/dist/templates/go-base/harness.config.json.hbs +17 -0
  312. package/dist/templates/go-base/main.go +7 -0
  313. package/dist/templates/go-base/template.json +14 -0
  314. package/dist/templates/java-base/AGENTS.md.hbs +35 -0
  315. package/dist/templates/java-base/checkstyle.xml +20 -0
  316. package/dist/templates/java-base/harness.config.json.hbs +16 -0
  317. package/dist/templates/java-base/pom.xml.hbs +39 -0
  318. package/dist/templates/java-base/src/main/java/App.java.hbs +5 -0
  319. package/dist/templates/java-base/template.json +13 -0
  320. package/dist/templates/nestjs/nest-cli.json +5 -0
  321. package/dist/templates/nestjs/package.json.hbs +18 -0
  322. package/dist/templates/nestjs/src/app.module.ts +8 -0
  323. package/dist/templates/nestjs/src/lib/.gitkeep +0 -0
  324. package/dist/templates/nestjs/src/main.ts +11 -0
  325. package/dist/templates/nestjs/template.json +16 -0
  326. package/dist/templates/nextjs/template.json +15 -1
  327. package/dist/templates/python-base/.python-version +1 -0
  328. package/dist/templates/python-base/AGENTS.md.hbs +32 -0
  329. package/dist/templates/python-base/harness.config.json.hbs +16 -0
  330. package/dist/templates/python-base/pyproject.toml.hbs +18 -0
  331. package/dist/templates/python-base/ruff.toml +5 -0
  332. package/dist/templates/python-base/src/__init__.py +0 -0
  333. package/dist/templates/python-base/template.json +13 -0
  334. package/dist/templates/react-vite/index.html +12 -0
  335. package/dist/templates/react-vite/package.json.hbs +18 -0
  336. package/dist/templates/react-vite/src/App.tsx +7 -0
  337. package/dist/templates/react-vite/src/lib/.gitkeep +0 -0
  338. package/dist/templates/react-vite/src/main.tsx +9 -0
  339. package/dist/templates/react-vite/template.json +19 -0
  340. package/dist/templates/react-vite/vite.config.ts +6 -0
  341. package/dist/templates/rust-base/AGENTS.md.hbs +35 -0
  342. package/dist/templates/rust-base/Cargo.toml.hbs +6 -0
  343. package/dist/templates/rust-base/clippy.toml +2 -0
  344. package/dist/templates/rust-base/harness.config.json.hbs +17 -0
  345. package/dist/templates/rust-base/src/main.rs +3 -0
  346. package/dist/templates/rust-base/template.json +14 -0
  347. package/dist/templates/spring-boot/pom.xml.hbs +50 -0
  348. package/dist/templates/spring-boot/src/main/java/Application.java.hbs +19 -0
  349. package/dist/templates/spring-boot/template.json +15 -0
  350. package/dist/templates/vue/index.html +12 -0
  351. package/dist/templates/vue/package.json.hbs +16 -0
  352. package/dist/templates/vue/src/App.vue +7 -0
  353. package/dist/templates/vue/src/lib/.gitkeep +0 -0
  354. package/dist/templates/vue/src/main.ts +4 -0
  355. package/dist/templates/vue/template.json +19 -0
  356. package/dist/templates/vue/vite.config.ts +6 -0
  357. package/dist/{validate-N7QJOKFZ.js → validate-FD3Z6VJD.js} +4 -4
  358. package/dist/validate-cross-check-WNJM6H2D.js +8 -0
  359. package/package.json +6 -6
  360. package/dist/agents-md-P2RHSUV7.js +0 -8
  361. package/dist/ci-workflow-4NYBUG6R.js +0 -8
  362. package/dist/engine-LXLIWQQ3.js +0 -8
  363. package/dist/loader-Z2IT7QX3.js +0 -10
  364. package/dist/mcp-KQHEL5IF.js +0 -34
  365. package/dist/runtime-PDWD7UIK.js +0 -9
  366. package/dist/skill-executor-RG45LUO5.js +0 -8
  367. package/dist/validate-cross-check-EDQ5QGTM.js +0 -8
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  detectEntropyDefinition,
3
3
  handleDetectEntropy
4
- } from "./chunk-MACVXDZK.js";
4
+ } from "./chunk-OXLLOSSR.js";
5
5
  import {
6
6
  checkPerformanceDefinition,
7
7
  getCriticalPathsDefinition,
@@ -11,7 +11,7 @@ import {
11
11
  handleGetPerfBaselines,
12
12
  handleUpdatePerfBaselines,
13
13
  updatePerfBaselinesDefinition
14
- } from "./chunk-2VU4MFM3.js";
14
+ } from "./chunk-YPYGXRDR.js";
15
15
  import {
16
16
  analyzeDiffDefinition,
17
17
  createSelfReviewDefinition,
@@ -19,15 +19,15 @@ import {
19
19
  handleCreateSelfReview,
20
20
  handleRequestPeerReview,
21
21
  requestPeerReviewDefinition
22
- } from "./chunk-7PZWR4LI.js";
22
+ } from "./chunk-TPOTOBR7.js";
23
23
  import {
24
24
  handleRunSecurityScan,
25
25
  runSecurityScanDefinition
26
- } from "./chunk-5VY23YK3.js";
26
+ } from "./chunk-OSXBPAMK.js";
27
27
  import {
28
28
  handleRunCodeReview,
29
29
  runCodeReviewDefinition
30
- } from "./chunk-LD3DKUK5.js";
30
+ } from "./chunk-NLVUVUGD.js";
31
31
  import {
32
32
  GENERATED_HEADER_CLAUDE,
33
33
  GENERATED_HEADER_GEMINI,
@@ -38,21 +38,24 @@ import {
38
38
  import {
39
39
  handleValidateProject,
40
40
  validateToolDefinition
41
- } from "./chunk-PSNN4LWX.js";
41
+ } from "./chunk-S2FXOWOR.js";
42
42
  import {
43
43
  loadGraphStore
44
- } from "./chunk-2YPZKGAG.js";
44
+ } from "./chunk-FTMXDOR6.js";
45
45
  import {
46
46
  checkDependenciesDefinition,
47
47
  handleCheckDependencies
48
- } from "./chunk-WPPDRIJL.js";
48
+ } from "./chunk-3C2MLBPJ.js";
49
49
  import {
50
50
  resolveProjectConfig
51
- } from "./chunk-K6XAPGML.js";
51
+ } from "./chunk-H7Y5CKTM.js";
52
52
  import {
53
53
  checkDocsDefinition,
54
54
  handleCheckDocs
55
- } from "./chunk-MI5XJQDY.js";
55
+ } from "./chunk-7IP4JIFL.js";
56
+ import {
57
+ resolveConfig
58
+ } from "./chunk-O5OJVPL6.js";
56
59
  import {
57
60
  resultToMcpResponse
58
61
  } from "./chunk-IDZNPTYD.js";
@@ -60,13 +63,14 @@ import {
60
63
  sanitizePath
61
64
  } from "./chunk-W6Y7ZW3Y.js";
62
65
  import {
66
+ resolveAllSkillsDirs,
63
67
  resolveCommunitySkillsDir,
64
68
  resolveGlobalSkillsDir,
65
69
  resolvePersonasDir,
66
70
  resolveProjectSkillsDir,
67
71
  resolveSkillsDir,
68
72
  resolveTemplatesDir
69
- } from "./chunk-HD4IBGLA.js";
73
+ } from "./chunk-N5G5QMS3.js";
70
74
  import {
71
75
  CLIError,
72
76
  ExitCode,
@@ -74,11 +78,11 @@ import {
74
78
  } from "./chunk-3WGJMBKH.js";
75
79
  import {
76
80
  SkillMetadataSchema
77
- } from "./chunk-VRFZWGMS.js";
81
+ } from "./chunk-XYLGHKG6.js";
78
82
  import {
79
83
  Err,
80
84
  Ok
81
- } from "./chunk-MHBMTPW7.js";
85
+ } from "./chunk-ERS5EVUZ.js";
82
86
 
83
87
  // src/mcp/server.ts
84
88
  import { Server } from "@modelcontextprotocol/sdk/server/index.js";
@@ -105,7 +109,7 @@ var generateLinterDefinition = {
105
109
  };
106
110
  async function handleGenerateLinter(input) {
107
111
  try {
108
- const { generate } = await import("./dist-L7LAAQAS.js");
112
+ const { generate } = await import("./dist-DZ63LLUD.js");
109
113
  const result = await generate({
110
114
  configPath: sanitizePath(input.configPath),
111
115
  ...input.outputDir !== void 0 && { outputDir: sanitizePath(input.outputDir) }
@@ -139,7 +143,7 @@ var validateLinterConfigDefinition = {
139
143
  };
140
144
  async function handleValidateLinterConfig(input) {
141
145
  try {
142
- const { validate } = await import("./dist-L7LAAQAS.js");
146
+ const { validate } = await import("./dist-DZ63LLUD.js");
143
147
  const result = await validate({ configPath: sanitizePath(input.configPath) });
144
148
  if ("success" in result && result.success) {
145
149
  return { content: [{ type: "text", text: JSON.stringify(result) }] };
@@ -159,7 +163,179 @@ async function handleValidateLinterConfig(input) {
159
163
  }
160
164
 
161
165
  // src/mcp/tools/init.ts
166
+ import * as path2 from "path";
167
+ import * as fs2 from "fs";
168
+
169
+ // src/templates/post-write.ts
170
+ import * as fs from "fs";
162
171
  import * as path from "path";
172
+
173
+ // src/templates/agents-append.ts
174
+ var FRAMEWORK_SECTIONS = {
175
+ nextjs: {
176
+ title: "Next.js Conventions",
177
+ content: [
178
+ "- Use the App Router (`src/app/`) for all routes",
179
+ '- Server Components by default; add `"use client"` only when needed',
180
+ "- Use `next/image` for images and `next/link` for navigation",
181
+ "- API routes go in `src/app/api/`",
182
+ "- Run `next dev` for development, `next build` for production"
183
+ ].join("\n")
184
+ },
185
+ "react-vite": {
186
+ title: "React + Vite Conventions",
187
+ content: [
188
+ "- Component files use `.tsx` extension in `src/`",
189
+ "- Use Vite for dev server and bundling (`npm run dev`)",
190
+ "- Prefer function components with hooks",
191
+ "- CSS modules or styled-components for styling",
192
+ "- Tests use Vitest (`npm test`)"
193
+ ].join("\n")
194
+ },
195
+ vue: {
196
+ title: "Vue Conventions",
197
+ content: [
198
+ "- Single File Components (`.vue`) in `src/`",
199
+ "- Use `<script setup>` with Composition API",
200
+ "- Vite for dev server and bundling (`npm run dev`)",
201
+ "- Vue Router for routing, Pinia for state management",
202
+ "- Tests use Vitest (`npm test`)"
203
+ ].join("\n")
204
+ },
205
+ express: {
206
+ title: "Express Conventions",
207
+ content: [
208
+ "- Entry point at `src/app.ts`",
209
+ "- Routes in `src/routes/`, middleware in `src/middleware/`",
210
+ "- Use `express.json()` for body parsing",
211
+ "- Error handling via centralized error middleware",
212
+ "- Tests use Vitest with supertest (`npm test`)"
213
+ ].join("\n")
214
+ },
215
+ nestjs: {
216
+ title: "NestJS Conventions",
217
+ content: [
218
+ "- Module-based architecture: each feature in its own module",
219
+ "- Use decorators (`@Controller`, `@Injectable`, `@Module`)",
220
+ "- Entry point at `src/main.ts`, root module at `src/app.module.ts`",
221
+ "- Use Nest CLI for generating components (`nest g`)",
222
+ "- Tests use Vitest (`npm test`)"
223
+ ].join("\n")
224
+ },
225
+ fastapi: {
226
+ title: "FastAPI Conventions",
227
+ content: [
228
+ "- Entry point at `src/main.py` with FastAPI app instance",
229
+ "- Use Pydantic models for request/response validation",
230
+ "- Async endpoints preferred; sync is acceptable for CPU-bound work",
231
+ "- Run with `uvicorn src.main:app --reload` for development",
232
+ "- Tests use pytest (`pytest`)"
233
+ ].join("\n")
234
+ },
235
+ django: {
236
+ title: "Django Conventions",
237
+ content: [
238
+ "- Settings at `src/settings.py`, URLs at `src/urls.py`",
239
+ "- Use `manage.py` for management commands",
240
+ "- Apps in `src/` directory; each app has models, views, urls",
241
+ "- Run with `python manage.py runserver` for development",
242
+ "- Tests use pytest with pytest-django (`pytest`)"
243
+ ].join("\n")
244
+ },
245
+ gin: {
246
+ title: "Gin Conventions",
247
+ content: [
248
+ "- Entry point at `main.go` with Gin router setup",
249
+ "- Group routes by feature using `router.Group()`",
250
+ "- Use middleware for logging, auth, error recovery",
251
+ "- Run with `go run main.go` for development",
252
+ "- Tests use `go test ./...`"
253
+ ].join("\n")
254
+ },
255
+ axum: {
256
+ title: "Axum Conventions",
257
+ content: [
258
+ "- Entry point at `src/main.rs` with Axum router",
259
+ "- Use extractors for request parsing (`Path`, `Query`, `Json`)",
260
+ "- Shared state via `Extension` or `State`",
261
+ "- Run with `cargo run` for development",
262
+ "- Tests use `cargo test`"
263
+ ].join("\n")
264
+ },
265
+ "spring-boot": {
266
+ title: "Spring Boot Conventions",
267
+ content: [
268
+ "- Entry point annotated with `@SpringBootApplication`",
269
+ "- Controllers in `controller/` package, services in `service/`",
270
+ "- Use constructor injection for dependencies",
271
+ "- Run with `mvn spring-boot:run` for development",
272
+ "- Tests use JUnit 5 with Spring Boot Test (`mvn test`)"
273
+ ].join("\n")
274
+ }
275
+ };
276
+ function buildFrameworkSection(framework) {
277
+ const entry = FRAMEWORK_SECTIONS[framework];
278
+ if (!entry) return "";
279
+ return `## ${entry.title}
280
+
281
+ <!-- framework: ${framework} -->
282
+ ${entry.content}
283
+ `;
284
+ }
285
+ function appendFrameworkSection(existingContent, framework, _language) {
286
+ if (!framework) return existingContent;
287
+ const startMarker = `<!-- harness:framework-conventions:${framework} -->`;
288
+ const endMarker = `<!-- /harness:framework-conventions:${framework} -->`;
289
+ if (existingContent.includes(startMarker)) return existingContent;
290
+ const section = buildFrameworkSection(framework);
291
+ if (!section) return existingContent;
292
+ const block = `
293
+ ${startMarker}
294
+ ${section}${endMarker}
295
+ `;
296
+ return existingContent.trimEnd() + "\n" + block;
297
+ }
298
+
299
+ // src/templates/post-write.ts
300
+ function persistToolingConfig(targetDir, resolveResult, framework) {
301
+ const configPath = path.join(targetDir, "harness.config.json");
302
+ if (!fs.existsSync(configPath)) return;
303
+ try {
304
+ const config = JSON.parse(fs.readFileSync(configPath, "utf-8"));
305
+ const overlayMeta = resolveResult.overlayMetadata;
306
+ if (framework) {
307
+ config.template = config.template || {};
308
+ config.template.framework = framework;
309
+ }
310
+ if (overlayMeta?.tooling) {
311
+ config.tooling = { ...config.tooling, ...overlayMeta.tooling };
312
+ delete config.tooling.lockFile;
313
+ } else if (resolveResult.metadata.tooling && !config.tooling) {
314
+ config.tooling = { ...resolveResult.metadata.tooling };
315
+ delete config.tooling.lockFile;
316
+ }
317
+ if (config.template?.level === null || config.template?.level === void 0) {
318
+ delete config.template.level;
319
+ }
320
+ fs.writeFileSync(configPath, JSON.stringify(config, null, 2) + "\n");
321
+ } catch {
322
+ }
323
+ }
324
+ function appendFrameworkAgents(targetDir, framework, language) {
325
+ if (!framework) return;
326
+ const agentsPath = path.join(targetDir, "AGENTS.md");
327
+ if (!fs.existsSync(agentsPath)) return;
328
+ try {
329
+ const existing = fs.readFileSync(agentsPath, "utf-8");
330
+ const updated = appendFrameworkSection(existing, framework, language);
331
+ if (updated !== existing) {
332
+ fs.writeFileSync(agentsPath, updated);
333
+ }
334
+ } catch {
335
+ }
336
+ }
337
+
338
+ // src/mcp/tools/init.ts
163
339
  var initProjectDefinition = {
164
340
  name: "init_project",
165
341
  description: "Scaffold a new harness engineering project from a template",
@@ -171,54 +347,109 @@ var initProjectDefinition = {
171
347
  level: {
172
348
  type: "string",
173
349
  enum: ["basic", "intermediate", "advanced"],
174
- description: "Adoption level"
350
+ description: "Adoption level (JS/TS only)"
175
351
  },
176
- framework: { type: "string", description: "Framework overlay (e.g., nextjs)" }
352
+ framework: { type: "string", description: "Framework overlay (e.g., nextjs, fastapi, gin)" },
353
+ language: {
354
+ type: "string",
355
+ enum: ["typescript", "python", "go", "rust", "java"],
356
+ description: "Target language"
357
+ }
177
358
  },
178
359
  required: ["path"]
179
360
  }
180
361
  };
362
+ function mcpText(text, isError = false) {
363
+ return { content: [{ type: "text", text }], isError };
364
+ }
365
+ function findFrameworkLanguage(engine, framework) {
366
+ const templates = engine.listTemplates();
367
+ if (!templates.ok || !templates.value) return void 0;
368
+ return templates.value.find((t) => t.framework === framework)?.language;
369
+ }
370
+ function tryDetectFramework(engine, safePath, input) {
371
+ if (input.framework || input.language || !fs2.existsSync(safePath)) return null;
372
+ const result = engine.detectFramework(safePath);
373
+ if (!result.ok || !result.value || result.value.length === 0) return null;
374
+ const candidates = result.value.map((c) => `${c.framework} (${c.language}, score: ${c.score})`).join(", ");
375
+ return mcpText(
376
+ `Detected frameworks: ${candidates}
377
+
378
+ Re-invoke with --framework <name> to scaffold, or specify --language for a bare scaffold.`
379
+ );
380
+ }
381
+ function checkFrameworkLanguageConflict(engine, input) {
382
+ if (!input.framework || !input.language) return null;
383
+ const fwLang = findFrameworkLanguage(engine, input.framework);
384
+ if (fwLang && fwLang !== input.language) {
385
+ return mcpText(
386
+ `Framework "${input.framework}" is a ${fwLang} framework, but language "${input.language}" was specified. Use language "${fwLang}" instead.`,
387
+ true
388
+ );
389
+ }
390
+ return null;
391
+ }
392
+ function inferLanguage(engine, input) {
393
+ if (input.language) return input.language;
394
+ if (!input.framework) return void 0;
395
+ return findFrameworkLanguage(engine, input.framework);
396
+ }
397
+ function scaffoldMcp(engine, safePath, i, language) {
398
+ const isNonJs = language && language !== "typescript";
399
+ const level = isNonJs ? void 0 : i.level ?? "basic";
400
+ const resolveResult = engine.resolveTemplate(level, i.framework, language);
401
+ if (!resolveResult.ok) return resultToMcpResponse(resolveResult);
402
+ const renderResult = engine.render(resolveResult.value, {
403
+ projectName: i.name ?? path2.basename(safePath),
404
+ level: level ?? "",
405
+ ...i.framework !== void 0 && { framework: i.framework },
406
+ ...language !== void 0 && { language }
407
+ });
408
+ if (!renderResult.ok) return resultToMcpResponse(renderResult);
409
+ const writeResult = engine.write(renderResult.value, safePath, {
410
+ overwrite: false,
411
+ ...language !== void 0 && { language }
412
+ });
413
+ if (writeResult.ok) {
414
+ persistToolingConfig(safePath, resolveResult.value, i.framework);
415
+ appendFrameworkAgents(safePath, i.framework, language);
416
+ }
417
+ if (writeResult.ok && writeResult.value.skippedConfigs.length > 0) {
418
+ const skippedMsg = writeResult.value.skippedConfigs.map((f) => ` - ${f}`).join("\n");
419
+ return mcpText(
420
+ `Files written: ${writeResult.value.written.join(", ")}
421
+
422
+ Skipped existing config files (add harness dependencies manually):
423
+ ${skippedMsg}`
424
+ );
425
+ }
426
+ return resultToMcpResponse(writeResult);
427
+ }
181
428
  async function handleInitProject(input) {
429
+ const i = input;
182
430
  try {
183
- const { TemplateEngine } = await import("./engine-LXLIWQQ3.js");
184
- const templatesDir = resolveTemplatesDir();
185
- const engine = new TemplateEngine(templatesDir);
186
- const level = input.level ?? "basic";
187
- const resolveResult = engine.resolveTemplate(level, input.framework);
188
- if (!resolveResult.ok) return resultToMcpResponse(resolveResult);
189
- const safePath = sanitizePath(input.path);
190
- const renderResult = engine.render(resolveResult.value, {
191
- projectName: input.name ?? path.basename(safePath),
192
- level,
193
- ...input.framework !== void 0 && { framework: input.framework }
194
- });
195
- if (!renderResult.ok) return resultToMcpResponse(renderResult);
196
- const writeResult = engine.write(renderResult.value, safePath, {
197
- overwrite: false
198
- });
199
- return resultToMcpResponse(writeResult);
431
+ const { TemplateEngine } = await import("./engine-EG4EH4IX.js");
432
+ const engine = new TemplateEngine(resolveTemplatesDir());
433
+ const safePath = sanitizePath(i.path);
434
+ const detected = tryDetectFramework(engine, safePath, i);
435
+ if (detected) return detected;
436
+ const conflict = checkFrameworkLanguageConflict(engine, i);
437
+ if (conflict) return conflict;
438
+ return scaffoldMcp(engine, safePath, i, inferLanguage(engine, i));
200
439
  } catch (error) {
201
- return {
202
- content: [
203
- {
204
- type: "text",
205
- text: `Init failed: ${error instanceof Error ? error.message : String(error)}`
206
- }
207
- ],
208
- isError: true
209
- };
440
+ return mcpText(`Init failed: ${error instanceof Error ? error.message : String(error)}`, true);
210
441
  }
211
442
  }
212
443
 
213
444
  // src/mcp/tools/persona.ts
214
- import * as path2 from "path";
445
+ import * as path3 from "path";
215
446
  var listPersonasDefinition = {
216
447
  name: "list_personas",
217
448
  description: "List available agent personas",
218
449
  inputSchema: { type: "object", properties: {} }
219
450
  };
220
451
  async function handleListPersonas() {
221
- const { listPersonas } = await import("./loader-Z2IT7QX3.js");
452
+ const { listPersonas } = await import("./loader-ZPALXIVR.js");
222
453
  const result = listPersonas(resolvePersonasDir());
223
454
  return resultToMcpResponse(result);
224
455
  }
@@ -242,12 +473,12 @@ async function handleGeneratePersonaArtifacts(input) {
242
473
  if (!/^[a-z0-9][a-z0-9._-]*$/i.test(input.name)) {
243
474
  return resultToMcpResponse(Err(new Error(`Invalid persona name: ${input.name}`)));
244
475
  }
245
- const { loadPersona } = await import("./loader-Z2IT7QX3.js");
246
- const { generateRuntime } = await import("./runtime-PDWD7UIK.js");
247
- const { generateAgentsMd } = await import("./agents-md-P2RHSUV7.js");
248
- const { generateCIWorkflow } = await import("./ci-workflow-4NYBUG6R.js");
476
+ const { loadPersona } = await import("./loader-ZPALXIVR.js");
477
+ const { generateRuntime } = await import("./runtime-7YLVK453.js");
478
+ const { generateAgentsMd } = await import("./agents-md-YTYQDA3P.js");
479
+ const { generateCIWorkflow } = await import("./ci-workflow-EQZFVX3P.js");
249
480
  const personasDir = resolvePersonasDir();
250
- const filePath = path2.join(personasDir, `${input.name}.yaml`);
481
+ const filePath = path3.join(personasDir, `${input.name}.yaml`);
251
482
  if (!filePath.startsWith(personasDir)) {
252
483
  return resultToMcpResponse(Err(new Error(`Invalid persona path: ${input.name}`)));
253
484
  }
@@ -300,11 +531,11 @@ async function handleRunPersona(input) {
300
531
  if (!/^[a-z0-9][a-z0-9._-]*$/i.test(input.persona)) {
301
532
  return resultToMcpResponse(Err(new Error(`Invalid persona name: ${input.persona}`)));
302
533
  }
303
- const { loadPersona } = await import("./loader-Z2IT7QX3.js");
534
+ const { loadPersona } = await import("./loader-ZPALXIVR.js");
304
535
  const { runPersona } = await import("./runner-VMYLHWOC.js");
305
- const { executeSkill } = await import("./skill-executor-RG45LUO5.js");
536
+ const { executeSkill } = await import("./skill-executor-XZLYZYAK.js");
306
537
  const personasDir = resolvePersonasDir();
307
- const filePath = path2.join(personasDir, `${input.persona}.yaml`);
538
+ const filePath = path3.join(personasDir, `${input.persona}.yaml`);
308
539
  if (!filePath.startsWith(personasDir)) {
309
540
  return resultToMcpResponse(Err(new Error(`Invalid persona path: ${input.persona}`)));
310
541
  }
@@ -466,8 +697,243 @@ async function handleRunAgentTask(input) {
466
697
  }
467
698
 
468
699
  // src/mcp/tools/skill.ts
469
- import * as fs from "fs";
470
- import * as path3 from "path";
700
+ import * as fs5 from "fs";
701
+ import * as path6 from "path";
702
+
703
+ // src/skill/dispatcher.ts
704
+ var TIER_1_SKILLS = /* @__PURE__ */ new Set([
705
+ "harness-brainstorming",
706
+ "harness-planning",
707
+ "harness-execution",
708
+ "harness-autopilot",
709
+ "harness-tdd",
710
+ "harness-debugging",
711
+ "harness-refactoring"
712
+ ]);
713
+ function isTier1Skill(skillName) {
714
+ return TIER_1_SKILLS.has(skillName);
715
+ }
716
+ function scoreSkill(entry, queryTerms, profile, recentFiles) {
717
+ const matchedKeywords = entry.keywords.filter(
718
+ (kw) => queryTerms.some(
719
+ (term) => kw.toLowerCase().includes(term.toLowerCase()) || term.toLowerCase().includes(kw.toLowerCase())
720
+ )
721
+ );
722
+ const keywordScore = queryTerms.length > 0 ? matchedKeywords.length / queryTerms.length : 0;
723
+ let stackScore = 0;
724
+ if (profile && entry.stackSignals.length > 0) {
725
+ const matchedSignals = entry.stackSignals.filter((signal) => {
726
+ if (profile.signals[signal]) return true;
727
+ return profile.detectedDomains.some(
728
+ (domain) => entry.keywords.some((kw) => kw.toLowerCase() === domain.toLowerCase())
729
+ );
730
+ });
731
+ stackScore = matchedSignals.length / entry.stackSignals.length;
732
+ }
733
+ let recencyBoost = 0;
734
+ if (recentFiles.length > 0) {
735
+ const hasRecentMatch = entry.stackSignals.some((signal) => {
736
+ const cleanSignal = signal.replace(/\*/g, "").replace(/\*\*/g, "");
737
+ return recentFiles.some((f) => f.includes(cleanSignal));
738
+ });
739
+ recencyBoost = hasRecentMatch ? 1 : 0;
740
+ }
741
+ return 0.5 * keywordScore + 0.3 * stackScore + 0.2 * recencyBoost;
742
+ }
743
+ function suggest(index, taskDescription, profile, recentFiles, config) {
744
+ const queryTerms = taskDescription.toLowerCase().split(/\s+/).filter((t) => t.length > 2);
745
+ const scored = [];
746
+ for (const [name, entry] of Object.entries(index.skills)) {
747
+ if (config?.neverSuggest?.includes(name)) continue;
748
+ const score = scoreSkill(entry, queryTerms, profile, recentFiles);
749
+ const isForced = config?.alwaysSuggest?.includes(name);
750
+ if (score >= 0.4 || isForced) {
751
+ scored.push({
752
+ name,
753
+ description: entry.description,
754
+ score: isForced ? Math.max(score, 1) : score
755
+ });
756
+ }
757
+ }
758
+ return scored.sort((a, b) => b.score - a.score).slice(0, 3);
759
+ }
760
+ function formatSuggestions(suggestions) {
761
+ if (suggestions.length === 0) return "";
762
+ const lines = suggestions.map((s) => `- **${s.name}** \u2014 ${s.description}`);
763
+ return [
764
+ "",
765
+ "---",
766
+ "## Suggested Domain Skills",
767
+ "Based on your task and project stack, these catalog skills may be relevant:",
768
+ ...lines,
769
+ "",
770
+ 'To load a skill: call search_skills("<skill-name>") for full details.',
771
+ "---"
772
+ ].join("\n");
773
+ }
774
+
775
+ // src/skill/index-builder.ts
776
+ import fs3 from "fs";
777
+ import path4 from "path";
778
+ import crypto from "crypto";
779
+ import { parse } from "yaml";
780
+ function computeSkillsDirHash(skillsDirs) {
781
+ const hash = crypto.createHash("sha256");
782
+ for (const dir of skillsDirs) {
783
+ if (!fs3.existsSync(dir)) continue;
784
+ for (const entry of fs3.readdirSync(dir, { withFileTypes: true })) {
785
+ if (!entry.isDirectory()) continue;
786
+ const yamlPath = path4.join(dir, entry.name, "skill.yaml");
787
+ if (!fs3.existsSync(yamlPath)) continue;
788
+ const stat = fs3.statSync(yamlPath);
789
+ hash.update(`${yamlPath}:${stat.mtimeMs}`);
790
+ }
791
+ }
792
+ return hash.digest("hex");
793
+ }
794
+ function parseSkillEntry(yamlPath, source, tierOverrides) {
795
+ const raw = fs3.readFileSync(yamlPath, "utf-8");
796
+ const parsed = parse(raw);
797
+ const result = SkillMetadataSchema.safeParse(parsed);
798
+ if (!result.success) return null;
799
+ const meta = result.data;
800
+ const effectiveTier = tierOverrides?.[meta.name] ?? meta.tier;
801
+ if (meta.internal) return null;
802
+ if (effectiveTier !== 3 && source !== "community") return null;
803
+ return {
804
+ tier: effectiveTier ?? 3,
805
+ description: meta.description,
806
+ keywords: meta.keywords ?? [],
807
+ stackSignals: meta.stack_signals ?? [],
808
+ cognitiveMode: meta.cognitive_mode,
809
+ phases: (meta.phases ?? []).map((p) => p.name),
810
+ source
811
+ };
812
+ }
813
+ function scanDirectory(dir, source, index, tierOverrides) {
814
+ if (!fs3.existsSync(dir)) return;
815
+ for (const entry of fs3.readdirSync(dir, { withFileTypes: true })) {
816
+ if (!entry.isDirectory()) continue;
817
+ if (index.skills[entry.name]) continue;
818
+ const yamlPath = path4.join(dir, entry.name, "skill.yaml");
819
+ if (!fs3.existsSync(yamlPath)) continue;
820
+ try {
821
+ const parsed = parseSkillEntry(yamlPath, source, tierOverrides);
822
+ if (parsed) index.skills[entry.name] = parsed;
823
+ } catch {
824
+ continue;
825
+ }
826
+ }
827
+ }
828
+ function buildIndex(platform, _projectRoot, tierOverrides) {
829
+ const skillsDirs = resolveAllSkillsDirs(platform);
830
+ const sourceMap = ["project", "community", "bundled"];
831
+ const index = {
832
+ version: 1,
833
+ hash: computeSkillsDirHash(skillsDirs),
834
+ generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
835
+ skills: {}
836
+ };
837
+ for (let i = 0; i < skillsDirs.length; i++) {
838
+ scanDirectory(skillsDirs[i], sourceMap[i] ?? "bundled", index, tierOverrides);
839
+ }
840
+ return index;
841
+ }
842
+ function loadOrRebuildIndex(platform, projectRoot, tierOverrides) {
843
+ const indexPath = path4.join(projectRoot, ".harness", "skills-index.json");
844
+ const skillsDirs = resolveAllSkillsDirs(platform);
845
+ const currentHash = computeSkillsDirHash(skillsDirs);
846
+ if (fs3.existsSync(indexPath)) {
847
+ try {
848
+ const existing = JSON.parse(fs3.readFileSync(indexPath, "utf-8"));
849
+ if (existing.hash === currentHash) return existing;
850
+ } catch {
851
+ }
852
+ }
853
+ const index = buildIndex(platform, projectRoot, tierOverrides);
854
+ fs3.mkdirSync(path4.dirname(indexPath), { recursive: true });
855
+ fs3.writeFileSync(indexPath, JSON.stringify(index, null, 2));
856
+ return index;
857
+ }
858
+
859
+ // src/skill/stack-profile.ts
860
+ import fs4 from "fs";
861
+ import path5 from "path";
862
+ var SIGNAL_DOMAIN_MAP = {
863
+ "prisma/schema.prisma": ["database"],
864
+ "drizzle.config.ts": ["database"],
865
+ "knexfile.js": ["database"],
866
+ "knexfile.ts": ["database"],
867
+ migrations: ["database"],
868
+ Dockerfile: ["containerization"],
869
+ "docker-compose.yml": ["containerization"],
870
+ "docker-compose.yaml": ["containerization"],
871
+ k8s: ["containerization"],
872
+ kubernetes: ["containerization"],
873
+ helm: ["containerization"],
874
+ ".github/workflows": ["deployment"],
875
+ ".gitlab-ci.yml": ["deployment"],
876
+ Jenkinsfile: ["deployment"],
877
+ terraform: ["infrastructure-as-code"],
878
+ "Pulumi.yaml": ["infrastructure-as-code"],
879
+ "cdk.json": ["infrastructure-as-code"],
880
+ "openapi.yaml": ["api-design"],
881
+ "openapi.json": ["api-design"],
882
+ "swagger.yaml": ["api-design"],
883
+ "swagger.json": ["api-design"],
884
+ "schema.graphql": ["api-design"],
885
+ ".env": ["secrets"],
886
+ ".env.example": ["secrets"],
887
+ "vault.hcl": ["secrets"],
888
+ e2e: ["e2e"],
889
+ cypress: ["e2e"],
890
+ "playwright.config.ts": ["e2e"],
891
+ "playwright.config.js": ["e2e"],
892
+ "stryker.conf.js": ["mutation-test"],
893
+ "stryker.conf.mjs": ["mutation-test"],
894
+ k6: ["load-testing"],
895
+ "artillery.yml": ["load-testing"],
896
+ "dbt_project.yml": ["data-pipeline"],
897
+ airflow: ["data-pipeline"],
898
+ ios: ["mobile-patterns"],
899
+ android: ["mobile-patterns"],
900
+ "pubspec.yaml": ["mobile-patterns"],
901
+ "App.tsx": ["mobile-patterns"],
902
+ runbooks: ["incident-response"],
903
+ "docs/runbooks": ["incident-response"]
904
+ };
905
+ function generateStackProfile(projectRoot) {
906
+ const signals = {};
907
+ const domainSet = /* @__PURE__ */ new Set();
908
+ for (const [pattern, domains] of Object.entries(SIGNAL_DOMAIN_MAP)) {
909
+ const fullPath = path5.join(projectRoot, pattern);
910
+ const exists = fs4.existsSync(fullPath);
911
+ signals[pattern] = exists;
912
+ if (exists) {
913
+ for (const domain of domains) domainSet.add(domain);
914
+ }
915
+ }
916
+ return {
917
+ generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
918
+ signals,
919
+ detectedDomains: [...domainSet].sort()
920
+ };
921
+ }
922
+ function loadOrGenerateProfile(projectRoot) {
923
+ const profilePath = path5.join(projectRoot, ".harness", "stack-profile.json");
924
+ if (fs4.existsSync(profilePath)) {
925
+ try {
926
+ return JSON.parse(fs4.readFileSync(profilePath, "utf-8"));
927
+ } catch {
928
+ }
929
+ }
930
+ const profile = generateStackProfile(projectRoot);
931
+ fs4.mkdirSync(path5.dirname(profilePath), { recursive: true });
932
+ fs4.writeFileSync(profilePath, JSON.stringify(profile, null, 2));
933
+ return profile;
934
+ }
935
+
936
+ // src/mcp/tools/skill.ts
471
937
  var runSkillDefinition = {
472
938
  name: "run_skill",
473
939
  description: "Load and return the content of a skill (SKILL.md), optionally with project state context",
@@ -492,23 +958,23 @@ async function handleRunSkill(input) {
492
958
  if (!/^[a-z0-9][a-z0-9._-]*$/i.test(input.skill)) {
493
959
  return resultToMcpResponse(Err(new Error(`Invalid skill name: ${input.skill}`)));
494
960
  }
495
- const skillDir = path3.join(skillsDir, input.skill);
961
+ const skillDir = path6.join(skillsDir, input.skill);
496
962
  if (!skillDir.startsWith(skillsDir)) {
497
963
  return resultToMcpResponse(Err(new Error(`Invalid skill path: ${input.skill}`)));
498
964
  }
499
- if (!fs.existsSync(skillDir)) {
965
+ if (!fs5.existsSync(skillDir)) {
500
966
  return resultToMcpResponse(Err(new Error(`Skill not found: ${input.skill}`)));
501
967
  }
502
- const skillMdPath = path3.join(skillDir, "SKILL.md");
503
- if (!fs.existsSync(skillMdPath)) {
968
+ const skillMdPath = path6.join(skillDir, "SKILL.md");
969
+ if (!fs5.existsSync(skillMdPath)) {
504
970
  return resultToMcpResponse(Err(new Error(`SKILL.md not found for skill: ${input.skill}`)));
505
971
  }
506
- let content = fs.readFileSync(skillMdPath, "utf-8");
972
+ let content = fs5.readFileSync(skillMdPath, "utf-8");
507
973
  if (input.path) {
508
974
  const projectPath = sanitizePath(input.path);
509
- const stateFile = path3.join(projectPath, ".harness", "state.json");
510
- if (fs.existsSync(stateFile)) {
511
- const stateContent = fs.readFileSync(stateFile, "utf-8");
975
+ const stateFile = path6.join(projectPath, ".harness", "state.json");
976
+ if (fs5.existsSync(stateFile)) {
977
+ const stateContent = fs5.readFileSync(stateFile, "utf-8");
512
978
  content += `
513
979
 
514
980
  ---
@@ -519,6 +985,23 @@ ${stateContent}
519
985
  `;
520
986
  }
521
987
  }
988
+ if (isTier1Skill(input.skill)) {
989
+ try {
990
+ const projectRoot = input.path ? sanitizePath(input.path) : process.cwd();
991
+ const platform = "claude-code";
992
+ const configResult = resolveConfig();
993
+ const skillsConfig = configResult.ok ? configResult.value.skills : void 0;
994
+ const index = loadOrRebuildIndex(platform, projectRoot, skillsConfig?.tierOverrides);
995
+ const profile = loadOrGenerateProfile(projectRoot);
996
+ const taskDesc = [input.skill, input.phase].filter(Boolean).join(" ");
997
+ const suggestions = suggest(index, taskDesc, profile, [], skillsConfig);
998
+ const suggestionText = formatSuggestions(suggestions);
999
+ if (suggestionText) {
1000
+ content += suggestionText;
1001
+ }
1002
+ } catch {
1003
+ }
1004
+ }
522
1005
  return resultToMcpResponse(Ok(content));
523
1006
  }
524
1007
  var createSkillDefinition = {
@@ -548,7 +1031,7 @@ var createSkillDefinition = {
548
1031
  };
549
1032
  async function handleCreateSkill(input) {
550
1033
  try {
551
- const { generateSkillFiles } = await import("./create-skill-WPXHSLX2.js");
1034
+ const { generateSkillFiles } = await import("./create-skill-XSWHMSM5.js");
552
1035
  const result = generateSkillFiles({
553
1036
  name: input.name,
554
1037
  description: input.description,
@@ -570,22 +1053,22 @@ async function handleCreateSkill(input) {
570
1053
  }
571
1054
 
572
1055
  // src/mcp/resources/skills.ts
573
- import * as fs2 from "fs";
574
- import * as path4 from "path";
1056
+ import * as fs6 from "fs";
1057
+ import * as path7 from "path";
575
1058
  import * as yaml from "yaml";
576
1059
  async function getSkillsResource(projectRoot) {
577
- const skillsDir = path4.join(projectRoot, "agents", "skills", "claude-code");
1060
+ const skillsDir = path7.join(projectRoot, "agents", "skills", "claude-code");
578
1061
  const skills = [];
579
- if (!fs2.existsSync(skillsDir)) {
1062
+ if (!fs6.existsSync(skillsDir)) {
580
1063
  return JSON.stringify(skills, null, 2);
581
1064
  }
582
- const entries = fs2.readdirSync(skillsDir, { withFileTypes: true });
1065
+ const entries = fs6.readdirSync(skillsDir, { withFileTypes: true });
583
1066
  for (const entry of entries) {
584
1067
  if (!entry.isDirectory()) continue;
585
- const skillYamlPath = path4.join(skillsDir, entry.name, "skill.yaml");
586
- if (!fs2.existsSync(skillYamlPath)) continue;
1068
+ const skillYamlPath = path7.join(skillsDir, entry.name, "skill.yaml");
1069
+ if (!fs6.existsSync(skillYamlPath)) continue;
587
1070
  try {
588
- const content = fs2.readFileSync(skillYamlPath, "utf-8");
1071
+ const content = fs6.readFileSync(skillYamlPath, "utf-8");
589
1072
  const parsed = yaml.parse(content);
590
1073
  skills.push({
591
1074
  name: parsed.name,
@@ -601,14 +1084,14 @@ async function getSkillsResource(projectRoot) {
601
1084
  }
602
1085
 
603
1086
  // src/mcp/resources/rules.ts
604
- import * as fs3 from "fs";
605
- import * as path5 from "path";
1087
+ import * as fs7 from "fs";
1088
+ import * as path8 from "path";
606
1089
  async function getRulesResource(projectRoot) {
607
1090
  const rules = [];
608
- const configPath = path5.join(projectRoot, "harness.config.json");
609
- if (fs3.existsSync(configPath)) {
1091
+ const configPath = path8.join(projectRoot, "harness.config.json");
1092
+ if (fs7.existsSync(configPath)) {
610
1093
  try {
611
- const config = JSON.parse(fs3.readFileSync(configPath, "utf-8"));
1094
+ const config = JSON.parse(fs7.readFileSync(configPath, "utf-8"));
612
1095
  if (config.layers) {
613
1096
  rules.push({ type: "layer-enforcement", config: config.layers });
614
1097
  }
@@ -621,10 +1104,10 @@ async function getRulesResource(projectRoot) {
621
1104
  } catch {
622
1105
  }
623
1106
  }
624
- const linterPath = path5.join(projectRoot, ".harness", "linter.json");
625
- if (fs3.existsSync(linterPath)) {
1107
+ const linterPath = path8.join(projectRoot, ".harness", "linter.json");
1108
+ if (fs7.existsSync(linterPath)) {
626
1109
  try {
627
- const linterConfig = JSON.parse(fs3.readFileSync(linterPath, "utf-8"));
1110
+ const linterConfig = JSON.parse(fs7.readFileSync(linterPath, "utf-8"));
628
1111
  rules.push({ type: "linter", config: linterConfig });
629
1112
  } catch {
630
1113
  }
@@ -633,32 +1116,37 @@ async function getRulesResource(projectRoot) {
633
1116
  }
634
1117
 
635
1118
  // src/mcp/resources/project.ts
636
- import * as fs4 from "fs";
637
- import * as path6 from "path";
1119
+ import * as fs8 from "fs";
1120
+ import * as path9 from "path";
638
1121
  async function getProjectResource(projectRoot) {
639
- const agentsPath = path6.join(projectRoot, "AGENTS.md");
640
- if (fs4.existsSync(agentsPath)) {
641
- return fs4.readFileSync(agentsPath, "utf-8");
1122
+ const agentsPath = path9.join(projectRoot, "AGENTS.md");
1123
+ if (fs8.existsSync(agentsPath)) {
1124
+ return fs8.readFileSync(agentsPath, "utf-8");
642
1125
  }
643
1126
  return "# No AGENTS.md found";
644
1127
  }
645
1128
 
646
1129
  // src/mcp/resources/learnings.ts
647
- import * as fs5 from "fs";
648
- import * as path7 from "path";
1130
+ import * as fs9 from "fs";
1131
+ import * as path10 from "path";
649
1132
  async function getLearningsResource(projectRoot) {
650
1133
  const sections = [];
651
- const reviewPath = path7.join(projectRoot, ".harness", "review-learnings.md");
652
- if (fs5.existsSync(reviewPath)) {
653
- sections.push("## Review Learnings\n\n" + fs5.readFileSync(reviewPath, "utf-8"));
1134
+ const reviewPath = path10.join(projectRoot, ".harness", "review-learnings.md");
1135
+ if (fs9.existsSync(reviewPath)) {
1136
+ sections.push("## Review Learnings\n\n" + fs9.readFileSync(reviewPath, "utf-8"));
654
1137
  }
655
- const antiPath = path7.join(projectRoot, ".harness", "anti-patterns.md");
656
- if (fs5.existsSync(antiPath)) {
657
- sections.push("## Anti-Pattern Log\n\n" + fs5.readFileSync(antiPath, "utf-8"));
1138
+ const antiPath = path10.join(projectRoot, ".harness", "anti-patterns.md");
1139
+ if (fs9.existsSync(antiPath)) {
1140
+ sections.push("## Anti-Pattern Log\n\n" + fs9.readFileSync(antiPath, "utf-8"));
658
1141
  }
659
1142
  return sections.length > 0 ? sections.join("\n\n---\n\n") : "No learnings files found.";
660
1143
  }
661
1144
 
1145
+ // src/mcp/utils.ts
1146
+ function mcpError(text) {
1147
+ return { content: [{ type: "text", text }], isError: true };
1148
+ }
1149
+
662
1150
  // src/mcp/tools/state.ts
663
1151
  var manageStateDefinition = {
664
1152
  name: "manage_state",
@@ -677,7 +1165,12 @@ var manageStateDefinition = {
677
1165
  "reset",
678
1166
  "gate",
679
1167
  "save-handoff",
680
- "load-handoff"
1168
+ "load-handoff",
1169
+ "append_entry",
1170
+ "update_entry_status",
1171
+ "read_section",
1172
+ "read_sections",
1173
+ "archive_session"
681
1174
  ],
682
1175
  description: "Action to perform"
683
1176
  },
@@ -694,138 +1187,175 @@ var manageStateDefinition = {
694
1187
  session: {
695
1188
  type: "string",
696
1189
  description: "Session slug for session-scoped state (takes priority over stream when provided)"
1190
+ },
1191
+ section: {
1192
+ type: "string",
1193
+ enum: ["terminology", "decisions", "constraints", "risks", "openQuestions", "evidence"],
1194
+ description: "Session section name (terminology, decisions, constraints, risks, openQuestions, evidence)"
1195
+ },
1196
+ authorSkill: {
1197
+ type: "string",
1198
+ description: "Name of the skill authoring the entry (required for append_entry)"
1199
+ },
1200
+ content: {
1201
+ type: "string",
1202
+ description: "Entry content text (required for append_entry)"
1203
+ },
1204
+ entryId: {
1205
+ type: "string",
1206
+ description: "ID of the entry to update (required for update_entry_status)"
1207
+ },
1208
+ newStatus: {
1209
+ type: "string",
1210
+ enum: ["active", "resolved", "superseded"],
1211
+ description: "New status for the entry: active, resolved, or superseded (required for update_entry_status)"
697
1212
  }
698
1213
  },
699
1214
  required: ["path", "action"]
700
1215
  }
701
1216
  };
1217
+ async function handleShow(projectPath, input) {
1218
+ const { loadState } = await import("./dist-HWXF2C3R.js");
1219
+ return resultToMcpResponse(await loadState(projectPath, input.stream, input.session));
1220
+ }
1221
+ async function handleLearn(projectPath, input) {
1222
+ if (!input.learning) return mcpError("Error: learning is required for learn action");
1223
+ const { appendLearning } = await import("./dist-HWXF2C3R.js");
1224
+ const result = await appendLearning(
1225
+ projectPath,
1226
+ input.learning,
1227
+ input.skillName,
1228
+ input.outcome,
1229
+ input.stream,
1230
+ input.session
1231
+ );
1232
+ if (!result.ok) return resultToMcpResponse(result);
1233
+ return resultToMcpResponse(Ok({ recorded: true }));
1234
+ }
1235
+ async function handleFailure(projectPath, input) {
1236
+ if (!input.description) return mcpError("Error: description is required for failure action");
1237
+ if (!input.failureType) return mcpError("Error: failureType is required for failure action");
1238
+ const { appendFailure } = await import("./dist-HWXF2C3R.js");
1239
+ const result = await appendFailure(
1240
+ projectPath,
1241
+ input.description,
1242
+ input.skillName ?? "unknown",
1243
+ input.failureType,
1244
+ input.stream,
1245
+ input.session
1246
+ );
1247
+ if (!result.ok) return resultToMcpResponse(result);
1248
+ return resultToMcpResponse(Ok({ recorded: true }));
1249
+ }
1250
+ async function handleArchive(projectPath, input) {
1251
+ const { archiveFailures } = await import("./dist-HWXF2C3R.js");
1252
+ const result = await archiveFailures(projectPath, input.stream, input.session);
1253
+ if (!result.ok) return resultToMcpResponse(result);
1254
+ return resultToMcpResponse(Ok({ archived: true }));
1255
+ }
1256
+ async function handleReset(projectPath, input) {
1257
+ const { saveState, DEFAULT_STATE } = await import("./dist-HWXF2C3R.js");
1258
+ const result = await saveState(projectPath, { ...DEFAULT_STATE }, input.stream, input.session);
1259
+ if (!result.ok) return resultToMcpResponse(result);
1260
+ return resultToMcpResponse(Ok({ reset: true }));
1261
+ }
1262
+ async function handleGate(projectPath, _input) {
1263
+ const { runMechanicalGate } = await import("./dist-HWXF2C3R.js");
1264
+ return resultToMcpResponse(await runMechanicalGate(projectPath));
1265
+ }
1266
+ async function handleSaveHandoff(projectPath, input) {
1267
+ if (!input.handoff) return mcpError("Error: handoff is required for save-handoff action");
1268
+ const { saveHandoff } = await import("./dist-HWXF2C3R.js");
1269
+ const result = await saveHandoff(
1270
+ projectPath,
1271
+ input.handoff,
1272
+ input.stream,
1273
+ input.session
1274
+ );
1275
+ return resultToMcpResponse(result.ok ? Ok({ saved: true }) : result);
1276
+ }
1277
+ async function handleLoadHandoff(projectPath, input) {
1278
+ const { loadHandoff } = await import("./dist-HWXF2C3R.js");
1279
+ return resultToMcpResponse(await loadHandoff(projectPath, input.stream, input.session));
1280
+ }
1281
+ async function handleAppendEntry(projectPath, input) {
1282
+ if (!input.session) return mcpError("Error: session is required for append_entry action");
1283
+ if (!input.section) return mcpError("Error: section is required for append_entry action");
1284
+ if (!input.authorSkill) return mcpError("Error: authorSkill is required for append_entry action");
1285
+ if (!input.content) return mcpError("Error: content is required for append_entry action");
1286
+ const { appendSessionEntry } = await import("./dist-HWXF2C3R.js");
1287
+ const result = await appendSessionEntry(
1288
+ projectPath,
1289
+ input.session,
1290
+ input.section,
1291
+ input.authorSkill,
1292
+ input.content
1293
+ );
1294
+ return resultToMcpResponse(result);
1295
+ }
1296
+ async function handleUpdateEntryStatus(projectPath, input) {
1297
+ if (!input.session) return mcpError("Error: session is required for update_entry_status action");
1298
+ if (!input.section) return mcpError("Error: section is required for update_entry_status action");
1299
+ if (!input.entryId) return mcpError("Error: entryId is required for update_entry_status action");
1300
+ if (!input.newStatus)
1301
+ return mcpError("Error: newStatus is required for update_entry_status action");
1302
+ const { updateSessionEntryStatus } = await import("./dist-HWXF2C3R.js");
1303
+ const result = await updateSessionEntryStatus(
1304
+ projectPath,
1305
+ input.session,
1306
+ input.section,
1307
+ input.entryId,
1308
+ input.newStatus
1309
+ );
1310
+ return resultToMcpResponse(result);
1311
+ }
1312
+ async function handleReadSection(projectPath, input) {
1313
+ if (!input.session) return mcpError("Error: session is required for read_section action");
1314
+ if (!input.section) return mcpError("Error: section is required for read_section action");
1315
+ const { readSessionSection } = await import("./dist-HWXF2C3R.js");
1316
+ const result = await readSessionSection(
1317
+ projectPath,
1318
+ input.session,
1319
+ input.section
1320
+ );
1321
+ return resultToMcpResponse(result);
1322
+ }
1323
+ async function handleReadSections(projectPath, input) {
1324
+ if (!input.session) return mcpError("Error: session is required for read_sections action");
1325
+ const { readSessionSections } = await import("./dist-HWXF2C3R.js");
1326
+ const result = await readSessionSections(projectPath, input.session);
1327
+ return resultToMcpResponse(result);
1328
+ }
1329
+ async function handleArchiveSession(projectPath, input) {
1330
+ if (!input.session) return mcpError("Error: session is required for archive_session action");
1331
+ const { archiveSession } = await import("./dist-HWXF2C3R.js");
1332
+ const result = await archiveSession(projectPath, input.session);
1333
+ if (!result.ok) return resultToMcpResponse(result);
1334
+ return resultToMcpResponse(Ok({ archived: true }));
1335
+ }
1336
+ var ACTION_HANDLERS = {
1337
+ show: handleShow,
1338
+ learn: handleLearn,
1339
+ failure: handleFailure,
1340
+ archive: handleArchive,
1341
+ reset: handleReset,
1342
+ gate: handleGate,
1343
+ "save-handoff": handleSaveHandoff,
1344
+ "load-handoff": handleLoadHandoff,
1345
+ append_entry: handleAppendEntry,
1346
+ update_entry_status: handleUpdateEntryStatus,
1347
+ read_section: handleReadSection,
1348
+ read_sections: handleReadSections,
1349
+ archive_session: handleArchiveSession
1350
+ };
702
1351
  async function handleManageState(input) {
703
1352
  try {
704
- const {
705
- loadState,
706
- saveState,
707
- appendLearning,
708
- appendFailure,
709
- archiveFailures,
710
- runMechanicalGate,
711
- DEFAULT_STATE
712
- } = await import("./dist-WF4C7A4A.js");
713
1353
  const projectPath = sanitizePath(input.path);
714
- switch (input.action) {
715
- case "show": {
716
- const result = await loadState(projectPath, input.stream, input.session);
717
- return resultToMcpResponse(result);
718
- }
719
- case "learn": {
720
- if (!input.learning) {
721
- return {
722
- content: [
723
- { type: "text", text: "Error: learning is required for learn action" }
724
- ],
725
- isError: true
726
- };
727
- }
728
- const result = await appendLearning(
729
- projectPath,
730
- input.learning,
731
- input.skillName,
732
- input.outcome,
733
- input.stream,
734
- input.session
735
- );
736
- if (!result.ok) return resultToMcpResponse(result);
737
- return resultToMcpResponse(Ok({ recorded: true }));
738
- }
739
- case "failure": {
740
- if (!input.description) {
741
- return {
742
- content: [
743
- { type: "text", text: "Error: description is required for failure action" }
744
- ],
745
- isError: true
746
- };
747
- }
748
- if (!input.failureType) {
749
- return {
750
- content: [
751
- {
752
- type: "text",
753
- text: "Error: failureType is required for failure action"
754
- }
755
- ],
756
- isError: true
757
- };
758
- }
759
- const result = await appendFailure(
760
- projectPath,
761
- input.description,
762
- input.skillName ?? "unknown",
763
- input.failureType,
764
- input.stream,
765
- input.session
766
- );
767
- if (!result.ok) return resultToMcpResponse(result);
768
- return resultToMcpResponse(Ok({ recorded: true }));
769
- }
770
- case "archive": {
771
- const result = await archiveFailures(projectPath, input.stream, input.session);
772
- if (!result.ok) return resultToMcpResponse(result);
773
- return resultToMcpResponse(Ok({ archived: true }));
774
- }
775
- case "reset": {
776
- const result = await saveState(
777
- projectPath,
778
- { ...DEFAULT_STATE },
779
- input.stream,
780
- input.session
781
- );
782
- if (!result.ok) return resultToMcpResponse(result);
783
- return resultToMcpResponse(Ok({ reset: true }));
784
- }
785
- case "gate": {
786
- const result = await runMechanicalGate(projectPath);
787
- return resultToMcpResponse(result);
788
- }
789
- case "save-handoff": {
790
- if (!input.handoff) {
791
- return {
792
- content: [
793
- { type: "text", text: "Error: handoff is required for save-handoff action" }
794
- ],
795
- isError: true
796
- };
797
- }
798
- const { saveHandoff } = await import("./dist-WF4C7A4A.js");
799
- const result = await saveHandoff(
800
- projectPath,
801
- input.handoff,
802
- input.stream,
803
- input.session
804
- );
805
- return resultToMcpResponse(result.ok ? Ok({ saved: true }) : result);
806
- }
807
- case "load-handoff": {
808
- const { loadHandoff } = await import("./dist-WF4C7A4A.js");
809
- const result = await loadHandoff(projectPath, input.stream, input.session);
810
- return resultToMcpResponse(result);
811
- }
812
- default: {
813
- return {
814
- content: [{ type: "text", text: `Error: unknown action` }],
815
- isError: true
816
- };
817
- }
818
- }
1354
+ const handler = ACTION_HANDLERS[input.action];
1355
+ if (!handler) return mcpError("Error: unknown action");
1356
+ return await handler(projectPath, input);
819
1357
  } catch (error) {
820
- return {
821
- content: [
822
- {
823
- type: "text",
824
- text: `Error: ${error instanceof Error ? error.message : String(error)}`
825
- }
826
- ],
827
- isError: true
828
- };
1358
+ return mcpError(`Error: ${error instanceof Error ? error.message : String(error)}`);
829
1359
  }
830
1360
  }
831
1361
  var listStreamsDefinition = {
@@ -841,7 +1371,7 @@ var listStreamsDefinition = {
841
1371
  };
842
1372
  async function handleListStreams(input) {
843
1373
  try {
844
- const { listStreams, loadStreamIndex } = await import("./dist-WF4C7A4A.js");
1374
+ const { listStreams, loadStreamIndex } = await import("./dist-HWXF2C3R.js");
845
1375
  const projectPath = sanitizePath(input.path);
846
1376
  const indexResult = await loadStreamIndex(projectPath);
847
1377
  const streamsResult = await listStreams(projectPath);
@@ -879,7 +1409,7 @@ var checkPhaseGateDefinition = {
879
1409
  };
880
1410
  async function handleCheckPhaseGate(input) {
881
1411
  try {
882
- const { runCheckPhaseGate } = await import("./check-phase-gate-S2MZKLFQ.js");
1412
+ const { runCheckPhaseGate } = await import("./check-phase-gate-L3RADYWO.js");
883
1413
  const result = await runCheckPhaseGate({ cwd: sanitizePath(input.path) });
884
1414
  if (result.ok) {
885
1415
  return { content: [{ type: "text", text: JSON.stringify(result.value) }] };
@@ -899,7 +1429,7 @@ async function handleCheckPhaseGate(input) {
899
1429
  }
900
1430
 
901
1431
  // src/mcp/tools/cross-check.ts
902
- import * as path8 from "path";
1432
+ import * as path11 from "path";
903
1433
  var validateCrossCheckDefinition = {
904
1434
  name: "validate_cross_check",
905
1435
  description: "Validate plan-to-implementation coverage: checks that specs have plans and plans have implementations, detects staleness",
@@ -935,15 +1465,15 @@ async function handleValidateCrossCheck(input) {
935
1465
  };
936
1466
  }
937
1467
  try {
938
- const { runCrossCheck } = await import("./validate-cross-check-EDQ5QGTM.js");
939
- const specsDir = path8.resolve(projectPath, input.specsDir ?? "docs/specs");
1468
+ const { runCrossCheck } = await import("./validate-cross-check-WNJM6H2D.js");
1469
+ const specsDir = path11.resolve(projectPath, input.specsDir ?? "docs/specs");
940
1470
  if (!specsDir.startsWith(projectPath)) {
941
1471
  return {
942
1472
  content: [{ type: "text", text: "Error: specsDir escapes project root" }],
943
1473
  isError: true
944
1474
  };
945
1475
  }
946
- const plansDir = path8.resolve(projectPath, input.plansDir ?? "docs/plans");
1476
+ const plansDir = path11.resolve(projectPath, input.plansDir ?? "docs/plans");
947
1477
  if (!plansDir.startsWith(projectPath)) {
948
1478
  return {
949
1479
  content: [{ type: "text", text: "Error: plansDir escapes project root" }],
@@ -974,15 +1504,15 @@ async function handleValidateCrossCheck(input) {
974
1504
 
975
1505
  // src/commands/generate-slash-commands.ts
976
1506
  import { Command } from "commander";
977
- import fs7 from "fs";
978
- import path10 from "path";
1507
+ import fs11 from "fs";
1508
+ import path13 from "path";
979
1509
  import os from "os";
980
1510
  import readline from "readline";
981
1511
 
982
1512
  // src/slash-commands/normalize.ts
983
- import fs6 from "fs";
984
- import path9 from "path";
985
- import { parse as parse2 } from "yaml";
1513
+ import fs10 from "fs";
1514
+ import path12 from "path";
1515
+ import { parse as parse3 } from "yaml";
986
1516
 
987
1517
  // src/slash-commands/normalize-name.ts
988
1518
  function normalizeName(skillName) {
@@ -998,116 +1528,125 @@ function normalizeName(skillName) {
998
1528
  }
999
1529
 
1000
1530
  // src/slash-commands/normalize.ts
1531
+ function readSkillYaml(yamlPath) {
1532
+ let raw;
1533
+ try {
1534
+ raw = fs10.readFileSync(yamlPath, "utf-8");
1535
+ } catch {
1536
+ return null;
1537
+ }
1538
+ return SkillMetadataSchema.safeParse(parse3(raw));
1539
+ }
1540
+ function shouldSkipSkill(meta, platforms) {
1541
+ const matchesPlatform = platforms.some((p) => meta.platforms.includes(p));
1542
+ if (!matchesPlatform) return true;
1543
+ if (meta.tier === 3 || meta.internal) return true;
1544
+ return false;
1545
+ }
1546
+ function checkNameCollision(normalized, metaName, source, nameMap) {
1547
+ const existing = nameMap.get(normalized);
1548
+ if (!existing) {
1549
+ nameMap.set(normalized, { skillName: metaName, source });
1550
+ return "ok";
1551
+ }
1552
+ if (existing.source === source) {
1553
+ throw new Error(
1554
+ `Name collision: skills "${existing.skillName}" and "${metaName}" both normalize to "${normalized}"`
1555
+ );
1556
+ }
1557
+ return "skip";
1558
+ }
1559
+ function buildContextLines(meta) {
1560
+ const lines = [];
1561
+ if (meta.cognitive_mode) lines.push(`Cognitive mode: ${meta.cognitive_mode}`);
1562
+ if (meta.type) lines.push(`Type: ${meta.type}`);
1563
+ if (meta.state?.persistent) {
1564
+ const files = meta.state.files?.join(", ") ?? "";
1565
+ lines.push(`State: persistent${files ? ` (files: ${files})` : ""}`);
1566
+ }
1567
+ return lines;
1568
+ }
1569
+ function buildObjectiveLines(meta) {
1570
+ const lines = [meta.description];
1571
+ if (meta.phases && meta.phases.length > 0) {
1572
+ lines.push("", "Phases:");
1573
+ for (const phase of meta.phases) {
1574
+ const req = phase.required !== false ? "" : " (optional)";
1575
+ lines.push(`- ${phase.name}: ${phase.description}${req}`);
1576
+ }
1577
+ }
1578
+ return lines;
1579
+ }
1580
+ function buildProcessLines(meta) {
1581
+ if (meta.mcp?.tool) {
1582
+ return [
1583
+ `1. Try: invoke mcp__harness__${meta.mcp.tool} with skill: "${meta.name}"`,
1584
+ `2. If MCP unavailable: read SKILL.md and follow its workflow directly`,
1585
+ `3. Pass through any arguments provided by the user`
1586
+ ];
1587
+ }
1588
+ return [
1589
+ `1. Read SKILL.md and follow its workflow directly`,
1590
+ `2. Pass through any arguments provided by the user`
1591
+ ];
1592
+ }
1593
+ function buildSpec(meta, normalized, entry, skillsDir, source) {
1594
+ const skillMdPath = path12.join(skillsDir, entry.name, "SKILL.md");
1595
+ const skillMdContent = fs10.existsSync(skillMdPath) ? fs10.readFileSync(skillMdPath, "utf-8") : "";
1596
+ const skillMdRelative = path12.relative(process.cwd(), skillMdPath).replaceAll("\\", "/");
1597
+ const skillYamlRelative = path12.relative(process.cwd(), path12.join(skillsDir, entry.name, "skill.yaml")).replaceAll("\\", "/");
1598
+ const args = (meta.cli?.args ?? []).map((a) => ({
1599
+ name: a.name,
1600
+ description: a.description ?? "",
1601
+ required: a.required ?? false
1602
+ }));
1603
+ const tools = [...meta.tools ?? []];
1604
+ if (!tools.includes("Read")) tools.push("Read");
1605
+ const executionContextLines = [];
1606
+ if (skillMdContent) {
1607
+ executionContextLines.push(`@${skillMdRelative}`, `@${skillYamlRelative}`);
1608
+ }
1609
+ return {
1610
+ name: normalized,
1611
+ namespace: "harness",
1612
+ fullName: `harness:${normalized}`,
1613
+ description: meta.description,
1614
+ version: meta.version,
1615
+ ...meta.cognitive_mode ? { cognitiveMode: meta.cognitive_mode } : {},
1616
+ tools,
1617
+ args,
1618
+ skillYamlName: meta.name,
1619
+ sourceDir: entry.name,
1620
+ skillsBaseDir: skillsDir,
1621
+ source,
1622
+ prompt: {
1623
+ context: buildContextLines(meta).join("\n"),
1624
+ objective: buildObjectiveLines(meta).join("\n"),
1625
+ executionContext: executionContextLines.join("\n"),
1626
+ process: buildProcessLines(meta).join("\n")
1627
+ }
1628
+ };
1629
+ }
1001
1630
  function normalizeSkills(skillSources, platforms) {
1002
1631
  const specs = [];
1003
1632
  const nameMap = /* @__PURE__ */ new Map();
1004
1633
  for (const { dir: skillsDir, source } of skillSources) {
1005
- if (!fs6.existsSync(skillsDir)) continue;
1006
- const entries = fs6.readdirSync(skillsDir, { withFileTypes: true }).filter((d) => d.isDirectory());
1634
+ if (!fs10.existsSync(skillsDir)) continue;
1635
+ const entries = fs10.readdirSync(skillsDir, { withFileTypes: true }).filter((d) => d.isDirectory());
1007
1636
  for (const entry of entries) {
1008
- const yamlPath = path9.join(skillsDir, entry.name, "skill.yaml");
1009
- if (!fs6.existsSync(yamlPath)) continue;
1010
- let raw;
1011
- try {
1012
- raw = fs6.readFileSync(yamlPath, "utf-8");
1013
- } catch {
1014
- continue;
1015
- }
1016
- const parsed = parse2(raw);
1017
- const result = SkillMetadataSchema.safeParse(parsed);
1637
+ const yamlPath = path12.join(skillsDir, entry.name, "skill.yaml");
1638
+ if (!fs10.existsSync(yamlPath)) continue;
1639
+ const result = readSkillYaml(yamlPath);
1640
+ if (!result) continue;
1018
1641
  if (!result.success) {
1019
1642
  console.warn(`Skipping ${entry.name}: invalid skill.yaml`);
1020
1643
  continue;
1021
1644
  }
1022
1645
  const meta = result.data;
1023
- const matchesPlatform = platforms.some((p) => meta.platforms.includes(p));
1024
- if (!matchesPlatform) continue;
1646
+ if (shouldSkipSkill(meta, platforms)) continue;
1025
1647
  const normalized = normalizeName(meta.name);
1026
- const existing = nameMap.get(normalized);
1027
- if (existing) {
1028
- if (existing.source === source) {
1029
- throw new Error(
1030
- `Name collision: skills "${existing.skillName}" and "${meta.name}" both normalize to "${normalized}"`
1031
- );
1032
- }
1033
- continue;
1034
- }
1035
- nameMap.set(normalized, { skillName: meta.name, source });
1036
- const skillMdPath = path9.join(skillsDir, entry.name, "SKILL.md");
1037
- const skillMdContent = fs6.existsSync(skillMdPath) ? fs6.readFileSync(skillMdPath, "utf-8") : "";
1038
- const skillMdRelative = path9.relative(
1039
- process.cwd(),
1040
- path9.join(skillsDir, entry.name, "SKILL.md")
1041
- );
1042
- const skillYamlRelative = path9.relative(
1043
- process.cwd(),
1044
- path9.join(skillsDir, entry.name, "skill.yaml")
1045
- );
1046
- const args = (meta.cli?.args ?? []).map((a) => ({
1047
- name: a.name,
1048
- description: a.description ?? "",
1049
- required: a.required ?? false
1050
- }));
1051
- const tools = [...meta.tools ?? []];
1052
- if (!tools.includes("Read")) {
1053
- tools.push("Read");
1054
- }
1055
- const contextLines = [];
1056
- if (meta.cognitive_mode) {
1057
- contextLines.push(`Cognitive mode: ${meta.cognitive_mode}`);
1058
- }
1059
- if (meta.type) {
1060
- contextLines.push(`Type: ${meta.type}`);
1061
- }
1062
- if (meta.state?.persistent) {
1063
- const files = meta.state.files?.join(", ") ?? "";
1064
- contextLines.push(`State: persistent${files ? ` (files: ${files})` : ""}`);
1065
- }
1066
- const objectiveLines = [meta.description];
1067
- if (meta.phases && meta.phases.length > 0) {
1068
- objectiveLines.push("");
1069
- objectiveLines.push("Phases:");
1070
- for (const phase of meta.phases) {
1071
- const req = phase.required !== false ? "" : " (optional)";
1072
- objectiveLines.push(`- ${phase.name}: ${phase.description}${req}`);
1073
- }
1074
- }
1075
- const executionContextLines = [];
1076
- if (skillMdContent) {
1077
- executionContextLines.push(`@${skillMdRelative}`);
1078
- executionContextLines.push(`@${skillYamlRelative}`);
1079
- }
1080
- const processLines = [];
1081
- if (meta.mcp?.tool) {
1082
- processLines.push(
1083
- `1. Try: invoke mcp__harness__${meta.mcp.tool} with skill: "${meta.name}"`
1084
- );
1085
- processLines.push(`2. If MCP unavailable: read SKILL.md and follow its workflow directly`);
1086
- processLines.push(`3. Pass through any arguments provided by the user`);
1087
- } else {
1088
- processLines.push(`1. Read SKILL.md and follow its workflow directly`);
1089
- processLines.push(`2. Pass through any arguments provided by the user`);
1090
- }
1091
- specs.push({
1092
- name: normalized,
1093
- namespace: "harness",
1094
- fullName: `harness:${normalized}`,
1095
- description: meta.description,
1096
- version: meta.version,
1097
- ...meta.cognitive_mode ? { cognitiveMode: meta.cognitive_mode } : {},
1098
- tools,
1099
- args,
1100
- skillYamlName: meta.name,
1101
- sourceDir: entry.name,
1102
- skillsBaseDir: skillsDir,
1103
- source,
1104
- prompt: {
1105
- context: contextLines.join("\n"),
1106
- objective: objectiveLines.join("\n"),
1107
- executionContext: executionContextLines.join("\n"),
1108
- process: processLines.join("\n")
1109
- }
1110
- });
1648
+ if (checkNameCollision(normalized, meta.name, source, nameMap) === "skip") continue;
1649
+ specs.push(buildSpec(meta, normalized, entry, skillsDir, source));
1111
1650
  }
1112
1651
  }
1113
1652
  return specs;
@@ -1207,13 +1746,13 @@ function renderGemini(spec, skillMdContent, skillYamlContent) {
1207
1746
  // src/commands/generate-slash-commands.ts
1208
1747
  function resolveOutputDir(platform, opts) {
1209
1748
  if (opts.output) {
1210
- return path10.join(opts.output, "harness");
1749
+ return path13.join(opts.output, "harness");
1211
1750
  }
1212
1751
  if (opts.global) {
1213
1752
  const home = os.homedir();
1214
- return platform === "claude-code" ? path10.join(home, ".claude", "commands", "harness") : path10.join(home, ".gemini", "commands", "harness");
1753
+ return platform === "claude-code" ? path13.join(home, ".claude", "commands", "harness") : path13.join(home, ".gemini", "commands", "harness");
1215
1754
  }
1216
- return platform === "claude-code" ? path10.join("agents", "commands", "claude-code", "harness") : path10.join("agents", "commands", "gemini-cli", "harness");
1755
+ return platform === "claude-code" ? path13.join("agents", "commands", "claude-code", "harness") : path13.join("agents", "commands", "gemini-cli", "harness");
1217
1756
  }
1218
1757
  function fileExtension(platform) {
1219
1758
  return platform === "claude-code" ? ".md" : ".toml";
@@ -1228,26 +1767,29 @@ Remove ${files.length} orphaned command(s)? (y/N) `, (answer) => {
1228
1767
  });
1229
1768
  });
1230
1769
  }
1231
- function generateSlashCommands(opts) {
1232
- const skillSources = [];
1770
+ function resolveSkillSources(opts) {
1233
1771
  if (opts.skillsDir) {
1234
- skillSources.push({ dir: opts.skillsDir, source: "project" });
1235
- } else {
1236
- const projectDir = resolveProjectSkillsDir();
1237
- if (projectDir) {
1238
- skillSources.push({ dir: projectDir, source: "project" });
1239
- }
1240
- const communityDir = resolveCommunitySkillsDir();
1241
- if (fs7.existsSync(communityDir)) {
1242
- skillSources.push({ dir: communityDir, source: "community" });
1243
- }
1244
- if (opts.includeGlobal || skillSources.length === 0) {
1245
- const globalDir = resolveGlobalSkillsDir();
1246
- if (!projectDir || path10.resolve(globalDir) !== path10.resolve(projectDir)) {
1247
- skillSources.push({ dir: globalDir, source: "global" });
1248
- }
1772
+ return [{ dir: opts.skillsDir, source: "project" }];
1773
+ }
1774
+ const sources = [];
1775
+ const projectDir = resolveProjectSkillsDir();
1776
+ if (projectDir) {
1777
+ sources.push({ dir: projectDir, source: "project" });
1778
+ }
1779
+ const communityDir = resolveCommunitySkillsDir();
1780
+ if (fs11.existsSync(communityDir)) {
1781
+ sources.push({ dir: communityDir, source: "community" });
1782
+ }
1783
+ if (opts.includeGlobal || sources.length === 0) {
1784
+ const globalDir = resolveGlobalSkillsDir();
1785
+ if (!projectDir || path13.resolve(globalDir) !== path13.resolve(projectDir)) {
1786
+ sources.push({ dir: globalDir, source: "global" });
1249
1787
  }
1250
1788
  }
1789
+ return sources;
1790
+ }
1791
+ function generateSlashCommands(opts) {
1792
+ const skillSources = resolveSkillSources(opts);
1251
1793
  const specs = normalizeSkills(skillSources, opts.platforms);
1252
1794
  const results = [];
1253
1795
  for (const platform of opts.platforms) {
@@ -1265,7 +1807,7 @@ function generateSlashCommands(opts) {
1265
1807
  executionContext: spec.prompt.executionContext.split("\n").map((line) => {
1266
1808
  if (line.startsWith("@")) {
1267
1809
  const relPath = line.slice(1);
1268
- return `@${path10.resolve(relPath)}`;
1810
+ return `@${path13.resolve(relPath)}`;
1269
1811
  }
1270
1812
  return line;
1271
1813
  }).join("\n")
@@ -1273,10 +1815,10 @@ function generateSlashCommands(opts) {
1273
1815
  } : spec;
1274
1816
  rendered.set(filename, renderClaudeCode(renderSpec));
1275
1817
  } else {
1276
- const mdPath = path10.join(spec.skillsBaseDir, spec.sourceDir, "SKILL.md");
1277
- const yamlPath = path10.join(spec.skillsBaseDir, spec.sourceDir, "skill.yaml");
1278
- const mdContent = fs7.existsSync(mdPath) ? fs7.readFileSync(mdPath, "utf-8") : "";
1279
- const yamlContent = fs7.existsSync(yamlPath) ? fs7.readFileSync(yamlPath, "utf-8") : "";
1818
+ const mdPath = path13.join(spec.skillsBaseDir, spec.sourceDir, "SKILL.md");
1819
+ const yamlPath = path13.join(spec.skillsBaseDir, spec.sourceDir, "skill.yaml");
1820
+ const mdContent = fs11.existsSync(mdPath) ? fs11.readFileSync(mdPath, "utf-8") : "";
1821
+ const yamlContent = fs11.existsSync(yamlPath) ? fs11.readFileSync(yamlPath, "utf-8") : "";
1280
1822
  rendered.set(filename, renderGemini(spec, mdContent, yamlContent));
1281
1823
  }
1282
1824
  }
@@ -1302,9 +1844,9 @@ async function handleOrphanDeletion(results, opts) {
1302
1844
  const shouldDelete = opts.yes || await confirmDeletion(result.removed);
1303
1845
  if (shouldDelete) {
1304
1846
  for (const filename of result.removed) {
1305
- const filePath = path10.join(result.outputDir, filename);
1306
- if (fs7.existsSync(filePath)) {
1307
- fs7.unlinkSync(filePath);
1847
+ const filePath = path13.join(result.outputDir, filename);
1848
+ if (fs11.existsSync(filePath)) {
1849
+ fs11.unlinkSync(filePath);
1308
1850
  }
1309
1851
  }
1310
1852
  }
@@ -1430,7 +1972,7 @@ async function handleGenerateSlashCommands(input) {
1430
1972
  // src/mcp/resources/state.ts
1431
1973
  async function getStateResource(projectRoot) {
1432
1974
  try {
1433
- const { loadState, migrateToStreams } = await import("./dist-WF4C7A4A.js");
1975
+ const { loadState, migrateToStreams } = await import("./dist-HWXF2C3R.js");
1434
1976
  await migrateToStreams(projectRoot);
1435
1977
  const result = await loadState(projectRoot);
1436
1978
  if (result.ok) {
@@ -1454,8 +1996,7 @@ async function getStateResource(projectRoot) {
1454
1996
  }
1455
1997
  }
1456
1998
 
1457
- // src/mcp/tools/graph.ts
1458
- import * as path11 from "path";
1999
+ // src/mcp/tools/graph/shared.ts
1459
2000
  function graphNotFoundError() {
1460
2001
  return {
1461
2002
  content: [
@@ -1467,6 +2008,8 @@ function graphNotFoundError() {
1467
2008
  isError: true
1468
2009
  };
1469
2010
  }
2011
+
2012
+ // src/mcp/tools/graph/query-graph.ts
1470
2013
  var queryGraphDefinition = {
1471
2014
  name: "query_graph",
1472
2015
  description: "Query the project knowledge graph using ContextQL. Traverses from root nodes outward, filtering by node/edge types.",
@@ -1517,7 +2060,7 @@ async function handleQueryGraph(input) {
1517
2060
  const projectPath = sanitizePath(input.path);
1518
2061
  const store = await loadGraphStore(projectPath);
1519
2062
  if (!store) return graphNotFoundError();
1520
- const { ContextQL } = await import("./dist-M6BQODWC.js");
2063
+ const { ContextQL } = await import("./dist-B26DFXMP.js");
1521
2064
  const cql = new ContextQL(store);
1522
2065
  const result = cql.execute({
1523
2066
  rootNodeIds: input.rootNodeIds,
@@ -1583,6 +2126,8 @@ async function handleQueryGraph(input) {
1583
2126
  };
1584
2127
  }
1585
2128
  }
2129
+
2130
+ // src/mcp/tools/graph/search-similar.ts
1586
2131
  var searchSimilarDefinition = {
1587
2132
  name: "search_similar",
1588
2133
  description: "Search the knowledge graph for nodes similar to a query string using keyword and semantic fusion.",
@@ -1606,7 +2151,7 @@ async function handleSearchSimilar(input) {
1606
2151
  const projectPath = sanitizePath(input.path);
1607
2152
  const store = await loadGraphStore(projectPath);
1608
2153
  if (!store) return graphNotFoundError();
1609
- const { FusionLayer } = await import("./dist-M6BQODWC.js");
2154
+ const { FusionLayer } = await import("./dist-B26DFXMP.js");
1610
2155
  const fusion = new FusionLayer(store);
1611
2156
  const results = fusion.search(input.query, input.topK ?? 10);
1612
2157
  if (input.mode === "summary") {
@@ -1638,6 +2183,8 @@ async function handleSearchSimilar(input) {
1638
2183
  };
1639
2184
  }
1640
2185
  }
2186
+
2187
+ // src/mcp/tools/graph/find-context-for.ts
1641
2188
  var findContextForDefinition = {
1642
2189
  name: "find_context_for",
1643
2190
  description: "Find relevant context for a given intent by searching the graph and expanding around top results. Returns assembled context within a token budget.",
@@ -1659,7 +2206,7 @@ async function handleFindContextFor(input) {
1659
2206
  const projectPath = sanitizePath(input.path);
1660
2207
  const store = await loadGraphStore(projectPath);
1661
2208
  if (!store) return graphNotFoundError();
1662
- const { FusionLayer, ContextQL } = await import("./dist-M6BQODWC.js");
2209
+ const { FusionLayer, ContextQL } = await import("./dist-B26DFXMP.js");
1663
2210
  const fusion = new FusionLayer(store);
1664
2211
  const cql = new ContextQL(store);
1665
2212
  const tokenBudget = input.tokenBudget ?? 4e3;
@@ -1725,6 +2272,8 @@ async function handleFindContextFor(input) {
1725
2272
  };
1726
2273
  }
1727
2274
  }
2275
+
2276
+ // src/mcp/tools/graph/get-relationships.ts
1728
2277
  var getRelationshipsDefinition = {
1729
2278
  name: "get_relationships",
1730
2279
  description: "Get relationships for a specific node in the knowledge graph, with configurable direction and depth.",
@@ -1753,7 +2302,7 @@ async function handleGetRelationships(input) {
1753
2302
  const projectPath = sanitizePath(input.path);
1754
2303
  const store = await loadGraphStore(projectPath);
1755
2304
  if (!store) return graphNotFoundError();
1756
- const { ContextQL } = await import("./dist-M6BQODWC.js");
2305
+ const { ContextQL } = await import("./dist-B26DFXMP.js");
1757
2306
  const cql = new ContextQL(store);
1758
2307
  const direction = input.direction ?? "both";
1759
2308
  const bidirectional = direction === "both" || direction === "inbound";
@@ -1820,6 +2369,8 @@ async function handleGetRelationships(input) {
1820
2369
  };
1821
2370
  }
1822
2371
  }
2372
+
2373
+ // src/mcp/tools/graph/get-impact.ts
1823
2374
  var getImpactDefinition = {
1824
2375
  name: "get_impact",
1825
2376
  description: "Analyze the impact of changing a node or file. Returns affected tests, docs, code, and other nodes grouped by type.",
@@ -1857,7 +2408,7 @@ async function handleGetImpact(input) {
1857
2408
  const projectPath = sanitizePath(input.path);
1858
2409
  const store = await loadGraphStore(projectPath);
1859
2410
  if (!store) return graphNotFoundError();
1860
- const { ContextQL } = await import("./dist-M6BQODWC.js");
2411
+ const { ContextQL } = await import("./dist-B26DFXMP.js");
1861
2412
  let targetNodeId = input.nodeId;
1862
2413
  if (!targetNodeId && input.filePath) {
1863
2414
  const fileNodes = store.findNodes({ type: "file" });
@@ -1966,6 +2517,9 @@ async function handleGetImpact(input) {
1966
2517
  };
1967
2518
  }
1968
2519
  }
2520
+
2521
+ // src/mcp/tools/graph/ingest-source.ts
2522
+ import * as path14 from "path";
1969
2523
  var ingestSourceDefinition = {
1970
2524
  name: "ingest_source",
1971
2525
  description: "Ingest sources into the project knowledge graph. Supports code analysis, knowledge documents, git history, or all at once.",
@@ -1985,10 +2539,10 @@ var ingestSourceDefinition = {
1985
2539
  async function handleIngestSource(input) {
1986
2540
  try {
1987
2541
  const projectPath = sanitizePath(input.path);
1988
- const graphDir = path11.join(projectPath, ".harness", "graph");
1989
- const { GraphStore, CodeIngestor, TopologicalLinker, KnowledgeIngestor, GitIngestor } = await import("./dist-M6BQODWC.js");
1990
- const fs10 = await import("fs/promises");
1991
- await fs10.mkdir(graphDir, { recursive: true });
2542
+ const graphDir = path14.join(projectPath, ".harness", "graph");
2543
+ const { GraphStore, CodeIngestor, TopologicalLinker, KnowledgeIngestor, GitIngestor } = await import("./dist-B26DFXMP.js");
2544
+ const fs14 = await import("fs/promises");
2545
+ await fs14.mkdir(graphDir, { recursive: true });
1992
2546
  const store = new GraphStore();
1993
2547
  await store.load(graphDir);
1994
2548
  const results = [];
@@ -2037,6 +2591,8 @@ async function handleIngestSource(input) {
2037
2591
  };
2038
2592
  }
2039
2593
  }
2594
+
2595
+ // src/mcp/tools/graph/detect-anomalies.ts
2040
2596
  var detectAnomaliesDefinition = {
2041
2597
  name: "detect_anomalies",
2042
2598
  description: "Detect structural anomalies \u2014 statistical outliers across code metrics and topological single points of failure in the import graph",
@@ -2059,7 +2615,7 @@ async function handleDetectAnomalies(input) {
2059
2615
  const projectPath = sanitizePath(input.path);
2060
2616
  const store = await loadGraphStore(projectPath);
2061
2617
  if (!store) return graphNotFoundError();
2062
- const { GraphAnomalyAdapter } = await import("./dist-M6BQODWC.js");
2618
+ const { GraphAnomalyAdapter } = await import("./dist-B26DFXMP.js");
2063
2619
  const adapter = new GraphAnomalyAdapter(store);
2064
2620
  const report = adapter.detect({
2065
2621
  ...input.threshold !== void 0 && { threshold: input.threshold },
@@ -2080,6 +2636,8 @@ async function handleDetectAnomalies(input) {
2080
2636
  };
2081
2637
  }
2082
2638
  }
2639
+
2640
+ // src/mcp/tools/graph/ask-graph.ts
2083
2641
  var askGraphDefinition = {
2084
2642
  name: "ask_graph",
2085
2643
  description: 'Ask a natural language question about the codebase knowledge graph. Supports questions about impact ("what breaks if I change X?"), finding entities ("where is the auth middleware?"), relationships ("what calls UserService?"), explanations ("what is GraphStore?"), and anomalies ("what looks wrong?"). Returns a human-readable summary and raw graph data.',
@@ -2097,7 +2655,7 @@ async function handleAskGraph(input) {
2097
2655
  const projectPath = sanitizePath(input.path);
2098
2656
  const store = await loadGraphStore(projectPath);
2099
2657
  if (!store) return graphNotFoundError();
2100
- const { askGraph } = await import("./dist-M6BQODWC.js");
2658
+ const { askGraph } = await import("./dist-B26DFXMP.js");
2101
2659
  const result = await askGraph(store, input.question);
2102
2660
  return {
2103
2661
  content: [{ type: "text", text: JSON.stringify(result) }]
@@ -2116,8 +2674,8 @@ async function handleAskGraph(input) {
2116
2674
  }
2117
2675
 
2118
2676
  // src/mcp/resources/graph.ts
2119
- import * as fs8 from "fs/promises";
2120
- import * as path12 from "path";
2677
+ import * as fs12 from "fs/promises";
2678
+ import * as path15 from "path";
2121
2679
  var MAX_ITEMS = 5e3;
2122
2680
  function formatStaleness(isoTimestamp) {
2123
2681
  const then = new Date(isoTimestamp).getTime();
@@ -2140,11 +2698,11 @@ async function getGraphResource(projectRoot) {
2140
2698
  message: "No knowledge graph found. Run harness scan to build one."
2141
2699
  });
2142
2700
  }
2143
- const graphDir = path12.join(projectRoot, ".harness", "graph");
2144
- const metadataPath = path12.join(graphDir, "metadata.json");
2701
+ const graphDir = path15.join(projectRoot, ".harness", "graph");
2702
+ const metadataPath = path15.join(graphDir, "metadata.json");
2145
2703
  let lastScanTimestamp = null;
2146
2704
  try {
2147
- const raw = JSON.parse(await fs8.readFile(metadataPath, "utf-8"));
2705
+ const raw = JSON.parse(await fs12.readFile(metadataPath, "utf-8"));
2148
2706
  lastScanTimestamp = raw.lastScanTimestamp ?? null;
2149
2707
  } catch {
2150
2708
  }
@@ -2233,7 +2791,7 @@ var generateAgentDefinitionsDefinition = {
2233
2791
  }
2234
2792
  };
2235
2793
  async function handleGenerateAgentDefinitions(input) {
2236
- const { generateAgentDefinitions } = await import("./generate-agent-definitions-QABOJG56.js");
2794
+ const { generateAgentDefinitions } = await import("./generate-agent-definitions-3PM5EU7V.js");
2237
2795
  const platforms = input.platform === "all" || !input.platform ? ["claude-code", "gemini-cli"] : [input.platform];
2238
2796
  const results = generateAgentDefinitions({
2239
2797
  platforms: [...platforms],
@@ -2244,8 +2802,8 @@ async function handleGenerateAgentDefinitions(input) {
2244
2802
  }
2245
2803
 
2246
2804
  // src/mcp/tools/roadmap.ts
2247
- import * as fs9 from "fs";
2248
- import * as path13 from "path";
2805
+ import * as fs13 from "fs";
2806
+ import * as path16 from "path";
2249
2807
  var manageRoadmapDefinition = {
2250
2808
  name: "manage_roadmap",
2251
2809
  description: "Manage the project roadmap: show, add, update, remove, sync features, or query by filter. Reads and writes docs/roadmap.md.",
@@ -2300,309 +2858,261 @@ var manageRoadmapDefinition = {
2300
2858
  }
2301
2859
  };
2302
2860
  function roadmapPath(projectRoot) {
2303
- return path13.join(projectRoot, "docs", "roadmap.md");
2861
+ return path16.join(projectRoot, "docs", "roadmap.md");
2304
2862
  }
2305
2863
  function readRoadmapFile(projectRoot) {
2306
2864
  const filePath = roadmapPath(projectRoot);
2307
2865
  try {
2308
- return fs9.readFileSync(filePath, "utf-8");
2866
+ return fs13.readFileSync(filePath, "utf-8");
2309
2867
  } catch {
2310
2868
  return null;
2311
2869
  }
2312
2870
  }
2313
2871
  function writeRoadmapFile(projectRoot, content) {
2314
2872
  const filePath = roadmapPath(projectRoot);
2315
- const dir = path13.dirname(filePath);
2316
- fs9.mkdirSync(dir, { recursive: true });
2317
- fs9.writeFileSync(filePath, content, "utf-8");
2873
+ const dir = path16.dirname(filePath);
2874
+ fs13.mkdirSync(dir, { recursive: true });
2875
+ fs13.writeFileSync(filePath, content, "utf-8");
2318
2876
  }
2319
- async function handleManageRoadmap(input) {
2320
- try {
2321
- const { parseRoadmap, serializeRoadmap, syncRoadmap } = await import("./dist-WF4C7A4A.js");
2322
- const { Ok: Ok2 } = await import("./dist-D4RYGUZE.js");
2323
- const projectPath = sanitizePath(input.path);
2324
- switch (input.action) {
2325
- case "show": {
2326
- const raw = readRoadmapFile(projectPath);
2327
- if (raw === null) {
2328
- return {
2329
- content: [
2330
- {
2331
- type: "text",
2332
- text: "Error: docs/roadmap.md not found. Create a roadmap first."
2333
- }
2334
- ],
2335
- isError: true
2336
- };
2337
- }
2338
- const result = parseRoadmap(raw);
2339
- if (!result.ok) return resultToMcpResponse(result);
2340
- let roadmap = result.value;
2341
- if (input.milestone) {
2342
- const milestoneFilter = input.milestone;
2343
- roadmap = {
2344
- ...roadmap,
2345
- milestones: roadmap.milestones.filter(
2346
- (m) => m.name.toLowerCase() === milestoneFilter.toLowerCase()
2347
- )
2348
- };
2349
- }
2350
- if (input.status) {
2351
- const statusFilter = input.status;
2352
- roadmap = {
2353
- ...roadmap,
2354
- milestones: roadmap.milestones.map((m) => ({
2355
- ...m,
2356
- features: m.features.filter((f) => f.status === statusFilter)
2357
- })).filter((m) => m.features.length > 0)
2358
- };
2359
- }
2360
- return resultToMcpResponse(Ok2(roadmap));
2361
- }
2362
- case "add": {
2363
- if (!input.feature) {
2364
- return {
2365
- content: [{ type: "text", text: "Error: feature is required for add action" }],
2366
- isError: true
2367
- };
2368
- }
2369
- if (!input.milestone) {
2370
- return {
2371
- content: [
2372
- { type: "text", text: "Error: milestone is required for add action" }
2373
- ],
2374
- isError: true
2375
- };
2376
- }
2377
- if (!input.status) {
2378
- return {
2379
- content: [{ type: "text", text: "Error: status is required for add action" }],
2380
- isError: true
2381
- };
2382
- }
2383
- if (!input.summary) {
2384
- return {
2385
- content: [{ type: "text", text: "Error: summary is required for add action" }],
2386
- isError: true
2387
- };
2388
- }
2389
- const raw = readRoadmapFile(projectPath);
2390
- if (raw === null) {
2391
- return {
2392
- content: [
2393
- {
2394
- type: "text",
2395
- text: "Error: docs/roadmap.md not found. Create a roadmap first."
2396
- }
2397
- ],
2398
- isError: true
2399
- };
2400
- }
2401
- const result = parseRoadmap(raw);
2402
- if (!result.ok) return resultToMcpResponse(result);
2403
- const roadmap = result.value;
2404
- const milestone = roadmap.milestones.find(
2405
- (m) => m.name.toLowerCase() === input.milestone.toLowerCase()
2406
- );
2407
- if (!milestone) {
2408
- return {
2409
- content: [
2410
- { type: "text", text: `Error: milestone "${input.milestone}" not found` }
2411
- ],
2412
- isError: true
2413
- };
2414
- }
2415
- milestone.features.push({
2416
- name: input.feature,
2417
- status: input.status,
2418
- spec: input.spec ?? null,
2419
- plans: input.plans ?? [],
2420
- blockedBy: input.blocked_by ?? [],
2421
- summary: input.summary
2422
- });
2423
- roadmap.frontmatter.lastManualEdit = (/* @__PURE__ */ new Date()).toISOString();
2424
- writeRoadmapFile(projectPath, serializeRoadmap(roadmap));
2425
- return resultToMcpResponse(Ok2(roadmap));
2426
- }
2427
- case "update": {
2428
- if (!input.feature) {
2429
- return {
2430
- content: [
2431
- { type: "text", text: "Error: feature is required for update action" }
2432
- ],
2433
- isError: true
2434
- };
2435
- }
2436
- const raw = readRoadmapFile(projectPath);
2437
- if (raw === null) {
2438
- return {
2439
- content: [
2440
- {
2441
- type: "text",
2442
- text: "Error: docs/roadmap.md not found. Create a roadmap first."
2443
- }
2444
- ],
2445
- isError: true
2446
- };
2447
- }
2448
- const result = parseRoadmap(raw);
2449
- if (!result.ok) return resultToMcpResponse(result);
2450
- const roadmap = result.value;
2451
- let found = false;
2452
- for (const m of roadmap.milestones) {
2453
- const feature = m.features.find(
2454
- (f) => f.name.toLowerCase() === input.feature.toLowerCase()
2455
- );
2456
- if (feature) {
2457
- if (input.status) feature.status = input.status;
2458
- if (input.summary !== void 0) feature.summary = input.summary;
2459
- if (input.spec !== void 0) feature.spec = input.spec || null;
2460
- if (input.plans !== void 0) feature.plans = input.plans;
2461
- if (input.blocked_by !== void 0) feature.blockedBy = input.blocked_by;
2462
- found = true;
2463
- break;
2464
- }
2465
- }
2466
- if (!found) {
2467
- return {
2468
- content: [
2469
- { type: "text", text: `Error: feature "${input.feature}" not found` }
2470
- ],
2471
- isError: true
2472
- };
2473
- }
2474
- roadmap.frontmatter.lastManualEdit = (/* @__PURE__ */ new Date()).toISOString();
2475
- writeRoadmapFile(projectPath, serializeRoadmap(roadmap));
2476
- return resultToMcpResponse(Ok2(roadmap));
2477
- }
2478
- case "remove": {
2479
- if (!input.feature) {
2480
- return {
2481
- content: [
2482
- { type: "text", text: "Error: feature is required for remove action" }
2483
- ],
2484
- isError: true
2485
- };
2486
- }
2487
- const raw = readRoadmapFile(projectPath);
2488
- if (raw === null) {
2489
- return {
2490
- content: [
2491
- {
2492
- type: "text",
2493
- text: "Error: docs/roadmap.md not found. Create a roadmap first."
2494
- }
2495
- ],
2496
- isError: true
2497
- };
2498
- }
2499
- const result = parseRoadmap(raw);
2500
- if (!result.ok) return resultToMcpResponse(result);
2501
- const roadmap = result.value;
2502
- let found = false;
2503
- for (const m of roadmap.milestones) {
2504
- const idx = m.features.findIndex(
2505
- (f) => f.name.toLowerCase() === input.feature.toLowerCase()
2506
- );
2507
- if (idx !== -1) {
2508
- m.features.splice(idx, 1);
2509
- found = true;
2510
- break;
2511
- }
2512
- }
2513
- if (!found) {
2514
- return {
2515
- content: [
2516
- { type: "text", text: `Error: feature "${input.feature}" not found` }
2517
- ],
2518
- isError: true
2519
- };
2520
- }
2521
- roadmap.frontmatter.lastManualEdit = (/* @__PURE__ */ new Date()).toISOString();
2522
- writeRoadmapFile(projectPath, serializeRoadmap(roadmap));
2523
- return resultToMcpResponse(Ok2(roadmap));
2877
+ function roadmapNotFoundError() {
2878
+ return {
2879
+ content: [
2880
+ {
2881
+ type: "text",
2882
+ text: "Error: docs/roadmap.md not found. Create a roadmap first."
2524
2883
  }
2525
- case "query": {
2526
- if (!input.filter) {
2527
- return {
2528
- content: [
2529
- { type: "text", text: "Error: filter is required for query action" }
2530
- ],
2531
- isError: true
2532
- };
2533
- }
2534
- const raw = readRoadmapFile(projectPath);
2535
- if (raw === null) {
2536
- return {
2537
- content: [
2538
- {
2539
- type: "text",
2540
- text: "Error: docs/roadmap.md not found. Create a roadmap first."
2541
- }
2542
- ],
2543
- isError: true
2544
- };
2545
- }
2546
- const result = parseRoadmap(raw);
2547
- if (!result.ok) return resultToMcpResponse(result);
2548
- const roadmap = result.value;
2549
- const allFeatures = roadmap.milestones.flatMap(
2550
- (m) => m.features.map((f) => ({ ...f, milestone: m.name }))
2884
+ ],
2885
+ isError: true
2886
+ };
2887
+ }
2888
+ function handleShow2(projectPath, input, deps) {
2889
+ const { parseRoadmap, Ok: Ok2 } = deps;
2890
+ const raw = readRoadmapFile(projectPath);
2891
+ if (raw === null) return roadmapNotFoundError();
2892
+ const result = parseRoadmap(raw);
2893
+ if (!result.ok) return resultToMcpResponse(result);
2894
+ let roadmap = result.value;
2895
+ if (input.milestone) {
2896
+ const milestoneFilter = input.milestone;
2897
+ roadmap = {
2898
+ ...roadmap,
2899
+ milestones: roadmap.milestones.filter(
2900
+ (m) => m.name.toLowerCase() === milestoneFilter.toLowerCase()
2901
+ )
2902
+ };
2903
+ }
2904
+ if (input.status) {
2905
+ const statusFilter = input.status;
2906
+ roadmap = {
2907
+ ...roadmap,
2908
+ milestones: roadmap.milestones.map((m) => ({
2909
+ ...m,
2910
+ features: m.features.filter((f) => f.status === statusFilter)
2911
+ })).filter((m) => m.features.length > 0)
2912
+ };
2913
+ }
2914
+ return resultToMcpResponse(Ok2(roadmap));
2915
+ }
2916
+ function handleAdd(projectPath, input, deps) {
2917
+ const { parseRoadmap, serializeRoadmap, Ok: Ok2 } = deps;
2918
+ if (!input.feature) {
2919
+ return {
2920
+ content: [{ type: "text", text: "Error: feature is required for add action" }],
2921
+ isError: true
2922
+ };
2923
+ }
2924
+ if (!input.milestone) {
2925
+ return {
2926
+ content: [{ type: "text", text: "Error: milestone is required for add action" }],
2927
+ isError: true
2928
+ };
2929
+ }
2930
+ if (!input.status) {
2931
+ return {
2932
+ content: [{ type: "text", text: "Error: status is required for add action" }],
2933
+ isError: true
2934
+ };
2935
+ }
2936
+ if (!input.summary) {
2937
+ return {
2938
+ content: [{ type: "text", text: "Error: summary is required for add action" }],
2939
+ isError: true
2940
+ };
2941
+ }
2942
+ const raw = readRoadmapFile(projectPath);
2943
+ if (raw === null) return roadmapNotFoundError();
2944
+ const result = parseRoadmap(raw);
2945
+ if (!result.ok) return resultToMcpResponse(result);
2946
+ const roadmap = result.value;
2947
+ const milestone = roadmap.milestones.find(
2948
+ (m) => m.name.toLowerCase() === input.milestone.toLowerCase()
2949
+ );
2950
+ if (!milestone) {
2951
+ return {
2952
+ content: [{ type: "text", text: `Error: milestone "${input.milestone}" not found` }],
2953
+ isError: true
2954
+ };
2955
+ }
2956
+ milestone.features.push({
2957
+ name: input.feature,
2958
+ status: input.status,
2959
+ spec: input.spec ?? null,
2960
+ plans: input.plans ?? [],
2961
+ blockedBy: input.blocked_by ?? [],
2962
+ summary: input.summary
2963
+ });
2964
+ roadmap.frontmatter.lastManualEdit = (/* @__PURE__ */ new Date()).toISOString();
2965
+ writeRoadmapFile(projectPath, serializeRoadmap(roadmap));
2966
+ return resultToMcpResponse(Ok2(roadmap));
2967
+ }
2968
+ function handleUpdate(projectPath, input, deps) {
2969
+ const { parseRoadmap, serializeRoadmap, Ok: Ok2 } = deps;
2970
+ if (!input.feature) {
2971
+ return {
2972
+ content: [{ type: "text", text: "Error: feature is required for update action" }],
2973
+ isError: true
2974
+ };
2975
+ }
2976
+ const raw = readRoadmapFile(projectPath);
2977
+ if (raw === null) return roadmapNotFoundError();
2978
+ const result = parseRoadmap(raw);
2979
+ if (!result.ok) return resultToMcpResponse(result);
2980
+ const roadmap = result.value;
2981
+ let found = false;
2982
+ for (const m of roadmap.milestones) {
2983
+ const feature = m.features.find((f) => f.name.toLowerCase() === input.feature.toLowerCase());
2984
+ if (feature) {
2985
+ if (input.status) feature.status = input.status;
2986
+ if (input.summary !== void 0) feature.summary = input.summary;
2987
+ if (input.spec !== void 0) feature.spec = input.spec || null;
2988
+ if (input.plans !== void 0) feature.plans = input.plans;
2989
+ if (input.blocked_by !== void 0) feature.blockedBy = input.blocked_by;
2990
+ found = true;
2991
+ break;
2992
+ }
2993
+ }
2994
+ if (!found) {
2995
+ return {
2996
+ content: [{ type: "text", text: `Error: feature "${input.feature}" not found` }],
2997
+ isError: true
2998
+ };
2999
+ }
3000
+ roadmap.frontmatter.lastManualEdit = (/* @__PURE__ */ new Date()).toISOString();
3001
+ writeRoadmapFile(projectPath, serializeRoadmap(roadmap));
3002
+ return resultToMcpResponse(Ok2(roadmap));
3003
+ }
3004
+ function handleRemove(projectPath, input, deps) {
3005
+ const { parseRoadmap, serializeRoadmap, Ok: Ok2 } = deps;
3006
+ if (!input.feature) {
3007
+ return {
3008
+ content: [{ type: "text", text: "Error: feature is required for remove action" }],
3009
+ isError: true
3010
+ };
3011
+ }
3012
+ const raw = readRoadmapFile(projectPath);
3013
+ if (raw === null) return roadmapNotFoundError();
3014
+ const result = parseRoadmap(raw);
3015
+ if (!result.ok) return resultToMcpResponse(result);
3016
+ const roadmap = result.value;
3017
+ let found = false;
3018
+ for (const m of roadmap.milestones) {
3019
+ const idx = m.features.findIndex((f) => f.name.toLowerCase() === input.feature.toLowerCase());
3020
+ if (idx !== -1) {
3021
+ m.features.splice(idx, 1);
3022
+ found = true;
3023
+ break;
3024
+ }
3025
+ }
3026
+ if (!found) {
3027
+ return {
3028
+ content: [{ type: "text", text: `Error: feature "${input.feature}" not found` }],
3029
+ isError: true
3030
+ };
3031
+ }
3032
+ roadmap.frontmatter.lastManualEdit = (/* @__PURE__ */ new Date()).toISOString();
3033
+ writeRoadmapFile(projectPath, serializeRoadmap(roadmap));
3034
+ return resultToMcpResponse(Ok2(roadmap));
3035
+ }
3036
+ function handleQuery(projectPath, input, deps) {
3037
+ const { parseRoadmap, Ok: Ok2 } = deps;
3038
+ if (!input.filter) {
3039
+ return {
3040
+ content: [{ type: "text", text: "Error: filter is required for query action" }],
3041
+ isError: true
3042
+ };
3043
+ }
3044
+ const raw = readRoadmapFile(projectPath);
3045
+ if (raw === null) return roadmapNotFoundError();
3046
+ const result = parseRoadmap(raw);
3047
+ if (!result.ok) return resultToMcpResponse(result);
3048
+ const roadmap = result.value;
3049
+ const allFeatures = roadmap.milestones.flatMap(
3050
+ (m) => m.features.map((f) => ({ ...f, milestone: m.name }))
3051
+ );
3052
+ const filter = input.filter.toLowerCase();
3053
+ let filtered;
3054
+ if (filter.startsWith("milestone:")) {
3055
+ const milestoneName = filter.slice("milestone:".length).trim();
3056
+ filtered = allFeatures.filter((f) => f.milestone.toLowerCase().includes(milestoneName));
3057
+ } else {
3058
+ filtered = allFeatures.filter((f) => f.status === filter);
3059
+ }
3060
+ return resultToMcpResponse(Ok2(filtered));
3061
+ }
3062
+ function handleSync(projectPath, input, deps) {
3063
+ const { parseRoadmap, serializeRoadmap, syncRoadmap, Ok: Ok2 } = deps;
3064
+ const raw = readRoadmapFile(projectPath);
3065
+ if (raw === null) return roadmapNotFoundError();
3066
+ const result = parseRoadmap(raw);
3067
+ if (!result.ok) return resultToMcpResponse(result);
3068
+ const roadmap = result.value;
3069
+ const syncResult = syncRoadmap({
3070
+ projectPath,
3071
+ roadmap,
3072
+ forceSync: input.force_sync ?? false
3073
+ });
3074
+ if (!syncResult.ok) return resultToMcpResponse(syncResult);
3075
+ const changes = syncResult.value;
3076
+ if (changes.length === 0) {
3077
+ return resultToMcpResponse(Ok2({ changes: [], message: "Roadmap is up to date." }));
3078
+ }
3079
+ if (input.apply) {
3080
+ for (const change of changes) {
3081
+ for (const m of roadmap.milestones) {
3082
+ const feature = m.features.find(
3083
+ (f) => f.name.toLowerCase() === change.feature.toLowerCase()
2551
3084
  );
2552
- const filter = input.filter.toLowerCase();
2553
- let filtered;
2554
- if (filter.startsWith("milestone:")) {
2555
- const milestoneName = filter.slice("milestone:".length).trim();
2556
- filtered = allFeatures.filter((f) => f.milestone.toLowerCase().includes(milestoneName));
2557
- } else {
2558
- filtered = allFeatures.filter((f) => f.status === filter);
2559
- }
2560
- return resultToMcpResponse(Ok2(filtered));
2561
- }
2562
- case "sync": {
2563
- const raw = readRoadmapFile(projectPath);
2564
- if (raw === null) {
2565
- return {
2566
- content: [
2567
- {
2568
- type: "text",
2569
- text: "Error: docs/roadmap.md not found. Create a roadmap first."
2570
- }
2571
- ],
2572
- isError: true
2573
- };
2574
- }
2575
- const result = parseRoadmap(raw);
2576
- if (!result.ok) return resultToMcpResponse(result);
2577
- const roadmap = result.value;
2578
- const syncResult = syncRoadmap({
2579
- projectPath,
2580
- roadmap,
2581
- forceSync: input.force_sync ?? false
2582
- });
2583
- if (!syncResult.ok) return resultToMcpResponse(syncResult);
2584
- const changes = syncResult.value;
2585
- if (changes.length === 0) {
2586
- return resultToMcpResponse(Ok2({ changes: [], message: "Roadmap is up to date." }));
2587
- }
2588
- if (input.apply) {
2589
- for (const change of changes) {
2590
- for (const m of roadmap.milestones) {
2591
- const feature = m.features.find(
2592
- (f) => f.name.toLowerCase() === change.feature.toLowerCase()
2593
- );
2594
- if (feature) {
2595
- feature.status = change.to;
2596
- break;
2597
- }
2598
- }
2599
- }
2600
- roadmap.frontmatter.lastSynced = (/* @__PURE__ */ new Date()).toISOString();
2601
- writeRoadmapFile(projectPath, serializeRoadmap(roadmap));
2602
- return resultToMcpResponse(Ok2({ changes, applied: true, roadmap }));
3085
+ if (feature) {
3086
+ feature.status = change.to;
3087
+ break;
2603
3088
  }
2604
- return resultToMcpResponse(Ok2({ changes, applied: false }));
2605
3089
  }
3090
+ }
3091
+ roadmap.frontmatter.lastSynced = (/* @__PURE__ */ new Date()).toISOString();
3092
+ writeRoadmapFile(projectPath, serializeRoadmap(roadmap));
3093
+ return resultToMcpResponse(Ok2({ changes, applied: true, roadmap }));
3094
+ }
3095
+ return resultToMcpResponse(Ok2({ changes, applied: false }));
3096
+ }
3097
+ async function handleManageRoadmap(input) {
3098
+ try {
3099
+ const { parseRoadmap, serializeRoadmap, syncRoadmap } = await import("./dist-HWXF2C3R.js");
3100
+ const { Ok: Ok2 } = await import("./dist-USY2C5JL.js");
3101
+ const projectPath = sanitizePath(input.path);
3102
+ const deps = { parseRoadmap, serializeRoadmap, syncRoadmap, Ok: Ok2 };
3103
+ switch (input.action) {
3104
+ case "show":
3105
+ return handleShow2(projectPath, input, deps);
3106
+ case "add":
3107
+ return handleAdd(projectPath, input, deps);
3108
+ case "update":
3109
+ return handleUpdate(projectPath, input, deps);
3110
+ case "remove":
3111
+ return handleRemove(projectPath, input, deps);
3112
+ case "query":
3113
+ return handleQuery(projectPath, input, deps);
3114
+ case "sync":
3115
+ return handleSync(projectPath, input, deps);
2606
3116
  default: {
2607
3117
  return {
2608
3118
  content: [{ type: "text", text: `Error: unknown action` }],
@@ -2972,226 +3482,119 @@ var emitInteractionDefinition = {
2972
3482
  required: ["path", "type"]
2973
3483
  }
2974
3484
  };
3485
+ function formatZodErrors(issues) {
3486
+ return issues.map((i) => i.path.length > 0 ? `${i.path.join(".")}: ${i.message}` : i.message).join("; ");
3487
+ }
3488
+ async function handleQuestion(validInput, projectPath, id) {
3489
+ if (!validInput.question)
3490
+ return mcpError("Error: question payload is required when type is question");
3491
+ const questionResult = InteractionQuestionWithOptionsSchema.safeParse(validInput.question);
3492
+ if (!questionResult.success)
3493
+ return mcpError(`Error: ${formatZodErrors(questionResult.error.issues)}`);
3494
+ const prompt = renderQuestion(questionResult.data);
3495
+ await recordInteraction(projectPath, id, "question", questionResult.data.text, validInput.stream);
3496
+ return { content: [{ type: "text", text: JSON.stringify({ id, prompt }) }] };
3497
+ }
3498
+ async function handleConfirmation(validInput, projectPath, id) {
3499
+ if (!validInput.confirmation)
3500
+ return mcpError("Error: confirmation payload is required when type is confirmation");
3501
+ const confirmResult = InteractionConfirmationSchema.safeParse(validInput.confirmation);
3502
+ if (!confirmResult.success)
3503
+ return mcpError(
3504
+ `Error: ${confirmResult.error.issues.map((i) => i.message).join("; ")}`
3505
+ );
3506
+ const prompt = renderConfirmation(confirmResult.data);
3507
+ await recordInteraction(
3508
+ projectPath,
3509
+ id,
3510
+ "confirmation",
3511
+ confirmResult.data.text,
3512
+ validInput.stream
3513
+ );
3514
+ return { content: [{ type: "text", text: JSON.stringify({ id, prompt }) }] };
3515
+ }
3516
+ async function handleTransition(validInput, projectPath, id) {
3517
+ if (!validInput.transition)
3518
+ return mcpError("Error: transition payload is required when type is transition");
3519
+ const transitionResult = InteractionTransitionSchema.safeParse(validInput.transition);
3520
+ if (!transitionResult.success)
3521
+ return mcpError(
3522
+ `Error: ${transitionResult.error.issues.map((i) => i.message).join("; ")}`
3523
+ );
3524
+ const transition = transitionResult.data;
3525
+ const prompt = renderTransition(transition);
3526
+ try {
3527
+ const { saveHandoff } = await import("./dist-HWXF2C3R.js");
3528
+ await saveHandoff(
3529
+ projectPath,
3530
+ {
3531
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
3532
+ fromSkill: "emit_interaction",
3533
+ phase: transition.completedPhase,
3534
+ summary: transition.reason,
3535
+ completed: [transition.completedPhase],
3536
+ pending: [transition.suggestedNext],
3537
+ concerns: [],
3538
+ decisions: [],
3539
+ blockers: [],
3540
+ contextKeywords: []
3541
+ },
3542
+ validInput.stream,
3543
+ validInput.session
3544
+ );
3545
+ } catch {
3546
+ }
3547
+ await recordInteraction(
3548
+ projectPath,
3549
+ id,
3550
+ "transition",
3551
+ `${transition.completedPhase} -> ${transition.suggestedNext}`,
3552
+ validInput.stream
3553
+ );
3554
+ const responsePayload = { id, prompt, handoffWritten: true };
3555
+ if (!transition.requiresConfirmation) {
3556
+ responsePayload.autoTransition = true;
3557
+ responsePayload.nextAction = `Invoke harness-${transition.suggestedNext} skill now`;
3558
+ }
3559
+ return { content: [{ type: "text", text: JSON.stringify(responsePayload) }] };
3560
+ }
3561
+ async function handleBatch(validInput, projectPath, id) {
3562
+ if (!validInput.batch) return mcpError("Error: batch payload is required when type is batch");
3563
+ const batchResult = InteractionBatchSchema.safeParse(validInput.batch);
3564
+ if (!batchResult.success)
3565
+ return mcpError(
3566
+ `Error: ${batchResult.error.issues.map((i) => i.message).join("; ")}`
3567
+ );
3568
+ const prompt = renderBatch(batchResult.data);
3569
+ await recordInteraction(projectPath, id, "batch", batchResult.data.text, validInput.stream);
3570
+ return {
3571
+ content: [{ type: "text", text: JSON.stringify({ id, prompt, batchMode: true }) }]
3572
+ };
3573
+ }
3574
+ var INTERACTION_HANDLERS = {
3575
+ question: handleQuestion,
3576
+ confirmation: handleConfirmation,
3577
+ transition: handleTransition,
3578
+ batch: handleBatch
3579
+ };
2975
3580
  async function handleEmitInteraction(input) {
2976
3581
  try {
2977
3582
  const parseResult = EmitInteractionInputSchema.safeParse(input);
2978
- if (!parseResult.success) {
2979
- return {
2980
- content: [
2981
- {
2982
- type: "text",
2983
- text: `Error: ${parseResult.error.issues.map((i) => i.path.length > 0 ? `${i.path.join(".")}: ${i.message}` : i.message).join("; ")}`
2984
- }
2985
- ],
2986
- isError: true
2987
- };
2988
- }
3583
+ if (!parseResult.success)
3584
+ return mcpError(`Error: ${formatZodErrors(parseResult.error.issues)}`);
2989
3585
  const validInput = parseResult.data;
2990
3586
  const projectPath = sanitizePath(validInput.path);
2991
3587
  const id = randomUUID();
2992
- switch (validInput.type) {
2993
- case "question": {
2994
- if (!validInput.question) {
2995
- return {
2996
- content: [
2997
- {
2998
- type: "text",
2999
- text: "Error: question payload is required when type is question"
3000
- }
3001
- ],
3002
- isError: true
3003
- };
3004
- }
3005
- const questionResult = InteractionQuestionWithOptionsSchema.safeParse(validInput.question);
3006
- if (!questionResult.success) {
3007
- return {
3008
- content: [
3009
- {
3010
- type: "text",
3011
- text: `Error: ${questionResult.error.issues.map((i) => i.path.length > 0 ? `${i.path.join(".")}: ${i.message}` : i.message).join("; ")}`
3012
- }
3013
- ],
3014
- isError: true
3015
- };
3016
- }
3017
- const prompt = renderQuestion(questionResult.data);
3018
- await recordInteraction(
3019
- projectPath,
3020
- id,
3021
- "question",
3022
- questionResult.data.text,
3023
- validInput.stream
3024
- );
3025
- return {
3026
- content: [{ type: "text", text: JSON.stringify({ id, prompt }) }]
3027
- };
3028
- }
3029
- case "confirmation": {
3030
- if (!validInput.confirmation) {
3031
- return {
3032
- content: [
3033
- {
3034
- type: "text",
3035
- text: "Error: confirmation payload is required when type is confirmation"
3036
- }
3037
- ],
3038
- isError: true
3039
- };
3040
- }
3041
- const confirmResult = InteractionConfirmationSchema.safeParse(validInput.confirmation);
3042
- if (!confirmResult.success) {
3043
- return {
3044
- content: [
3045
- {
3046
- type: "text",
3047
- text: `Error: ${confirmResult.error.issues.map((i) => i.message).join("; ")}`
3048
- }
3049
- ],
3050
- isError: true
3051
- };
3052
- }
3053
- const prompt = renderConfirmation(confirmResult.data);
3054
- await recordInteraction(
3055
- projectPath,
3056
- id,
3057
- "confirmation",
3058
- confirmResult.data.text,
3059
- validInput.stream
3060
- );
3061
- return {
3062
- content: [{ type: "text", text: JSON.stringify({ id, prompt }) }]
3063
- };
3064
- }
3065
- case "transition": {
3066
- if (!validInput.transition) {
3067
- return {
3068
- content: [
3069
- {
3070
- type: "text",
3071
- text: "Error: transition payload is required when type is transition"
3072
- }
3073
- ],
3074
- isError: true
3075
- };
3076
- }
3077
- const transitionResult = InteractionTransitionSchema.safeParse(validInput.transition);
3078
- if (!transitionResult.success) {
3079
- return {
3080
- content: [
3081
- {
3082
- type: "text",
3083
- text: `Error: ${transitionResult.error.issues.map((i) => i.message).join("; ")}`
3084
- }
3085
- ],
3086
- isError: true
3087
- };
3088
- }
3089
- const transition = transitionResult.data;
3090
- const prompt = renderTransition(transition);
3091
- try {
3092
- const { saveHandoff } = await import("./dist-WF4C7A4A.js");
3093
- await saveHandoff(
3094
- projectPath,
3095
- {
3096
- timestamp: (/* @__PURE__ */ new Date()).toISOString(),
3097
- fromSkill: "emit_interaction",
3098
- phase: transition.completedPhase,
3099
- summary: transition.reason,
3100
- completed: [transition.completedPhase],
3101
- pending: [transition.suggestedNext],
3102
- concerns: [],
3103
- decisions: [],
3104
- blockers: [],
3105
- contextKeywords: []
3106
- },
3107
- validInput.stream,
3108
- validInput.session
3109
- );
3110
- } catch {
3111
- }
3112
- await recordInteraction(
3113
- projectPath,
3114
- id,
3115
- "transition",
3116
- `${transition.completedPhase} -> ${transition.suggestedNext}`,
3117
- validInput.stream
3118
- );
3119
- const responsePayload = { id, prompt, handoffWritten: true };
3120
- if (!transition.requiresConfirmation) {
3121
- responsePayload.autoTransition = true;
3122
- responsePayload.nextAction = `Invoke harness-${transition.suggestedNext} skill now`;
3123
- }
3124
- return {
3125
- content: [
3126
- {
3127
- type: "text",
3128
- text: JSON.stringify(responsePayload)
3129
- }
3130
- ]
3131
- };
3132
- }
3133
- case "batch": {
3134
- if (!validInput.batch) {
3135
- return {
3136
- content: [
3137
- {
3138
- type: "text",
3139
- text: "Error: batch payload is required when type is batch"
3140
- }
3141
- ],
3142
- isError: true
3143
- };
3144
- }
3145
- const batchResult = InteractionBatchSchema.safeParse(validInput.batch);
3146
- if (!batchResult.success) {
3147
- return {
3148
- content: [
3149
- {
3150
- type: "text",
3151
- text: `Error: ${batchResult.error.issues.map((i) => i.message).join("; ")}`
3152
- }
3153
- ],
3154
- isError: true
3155
- };
3156
- }
3157
- const prompt = renderBatch(batchResult.data);
3158
- await recordInteraction(projectPath, id, "batch", batchResult.data.text, validInput.stream);
3159
- return {
3160
- content: [
3161
- {
3162
- type: "text",
3163
- text: JSON.stringify({ id, prompt, batchMode: true })
3164
- }
3165
- ]
3166
- };
3167
- }
3168
- default: {
3169
- return {
3170
- content: [
3171
- {
3172
- type: "text",
3173
- text: `Error: unknown interaction type: ${String(validInput.type)}`
3174
- }
3175
- ],
3176
- isError: true
3177
- };
3178
- }
3179
- }
3588
+ const handler = INTERACTION_HANDLERS[validInput.type];
3589
+ if (!handler) return mcpError(`Error: unknown interaction type: ${String(validInput.type)}`);
3590
+ return await handler(validInput, projectPath, id);
3180
3591
  } catch (error) {
3181
- return {
3182
- content: [
3183
- {
3184
- type: "text",
3185
- text: `Error: ${error instanceof Error ? error.message : String(error)}`
3186
- }
3187
- ],
3188
- isError: true
3189
- };
3592
+ return mcpError(`Error: ${error instanceof Error ? error.message : String(error)}`);
3190
3593
  }
3191
3594
  }
3192
3595
  async function recordInteraction(projectPath, id, type, decision, stream) {
3193
3596
  try {
3194
- const { loadState, saveState } = await import("./dist-WF4C7A4A.js");
3597
+ const { loadState, saveState } = await import("./dist-HWXF2C3R.js");
3195
3598
  const stateResult = await loadState(projectPath, stream);
3196
3599
  if (stateResult.ok) {
3197
3600
  const state = stateResult.value;
@@ -3209,7 +3612,7 @@ async function recordInteraction(projectPath, id, type, decision, stream) {
3209
3612
  // src/mcp/tools/gather-context.ts
3210
3613
  var gatherContextDefinition = {
3211
3614
  name: "gather_context",
3212
- description: "Assemble all working context an agent needs in a single call: state, learnings, handoff, graph context, and project validation. Runs constituents in parallel.",
3615
+ description: "Assemble all working context an agent needs in a single call: state, learnings, handoff, graph context, project validation, and session sections. Runs constituents in parallel.",
3213
3616
  inputSchema: {
3214
3617
  type: "object",
3215
3618
  properties: {
@@ -3230,7 +3633,7 @@ var gatherContextDefinition = {
3230
3633
  type: "array",
3231
3634
  items: {
3232
3635
  type: "string",
3233
- enum: ["state", "learnings", "handoff", "graph", "validation"]
3636
+ enum: ["state", "learnings", "handoff", "graph", "validation", "sessions"]
3234
3637
  },
3235
3638
  description: "Which constituents to include (default: all)"
3236
3639
  },
@@ -3271,10 +3674,10 @@ async function handleGatherContext(input) {
3271
3674
  input.include ?? ["state", "learnings", "handoff", "graph", "validation"]
3272
3675
  );
3273
3676
  const errors = [];
3274
- const statePromise = includeSet.has("state") ? import("./dist-WF4C7A4A.js").then(
3677
+ const statePromise = includeSet.has("state") ? import("./dist-HWXF2C3R.js").then(
3275
3678
  (core) => core.loadState(projectPath, void 0, input.session)
3276
3679
  ) : Promise.resolve(null);
3277
- const learningsPromise = includeSet.has("learnings") ? import("./dist-WF4C7A4A.js").then(
3680
+ const learningsPromise = includeSet.has("learnings") ? import("./dist-HWXF2C3R.js").then(
3278
3681
  (core) => core.loadBudgetedLearnings(projectPath, {
3279
3682
  intent: input.intent,
3280
3683
  tokenBudget: input.learningsBudget ?? 1e3,
@@ -3282,14 +3685,14 @@ async function handleGatherContext(input) {
3282
3685
  ...input.session !== void 0 && { session: input.session }
3283
3686
  })
3284
3687
  ) : Promise.resolve(null);
3285
- const handoffPromise = includeSet.has("handoff") ? import("./dist-WF4C7A4A.js").then(
3688
+ const handoffPromise = includeSet.has("handoff") ? import("./dist-HWXF2C3R.js").then(
3286
3689
  (core) => core.loadHandoff(projectPath, void 0, input.session)
3287
3690
  ) : Promise.resolve(null);
3288
3691
  const graphPromise = includeSet.has("graph") ? (async () => {
3289
- const { loadGraphStore: loadGraphStore2 } = await import("./graph-loader-KO4GJ5N2.js");
3692
+ const { loadGraphStore: loadGraphStore2 } = await import("./graph-loader-2M2HXDQI.js");
3290
3693
  const store = await loadGraphStore2(projectPath);
3291
3694
  if (!store) return null;
3292
- const { FusionLayer, ContextQL } = await import("./dist-M6BQODWC.js");
3695
+ const { FusionLayer, ContextQL } = await import("./dist-B26DFXMP.js");
3293
3696
  const fusion = new FusionLayer(store);
3294
3697
  const cql = new ContextQL(store);
3295
3698
  const tokenBudget = input.tokenBudget ?? 4e3;
@@ -3326,18 +3729,29 @@ async function handleGatherContext(input) {
3326
3729
  context: contextBlocks
3327
3730
  };
3328
3731
  })() : Promise.resolve(null);
3732
+ const sessionsPromise = includeSet.has("sessions") && input.session ? import("./dist-HWXF2C3R.js").then(
3733
+ (core) => core.readSessionSections(projectPath, input.session)
3734
+ ) : Promise.resolve(null);
3329
3735
  const validationPromise = includeSet.has("validation") ? (async () => {
3330
- const { handleValidateProject: handleValidateProject2 } = await import("./validate-N7QJOKFZ.js");
3736
+ const { handleValidateProject: handleValidateProject2 } = await import("./validate-FD3Z6VJD.js");
3331
3737
  const result = await handleValidateProject2({ path: projectPath });
3332
3738
  const first = result.content[0];
3333
3739
  return first ? JSON.parse(first.text) : null;
3334
3740
  })() : Promise.resolve(null);
3335
- const [stateResult, learningsResult, handoffResult, graphResult, validationResult] = await Promise.allSettled([
3741
+ const [
3742
+ stateResult,
3743
+ learningsResult,
3744
+ handoffResult,
3745
+ graphResult,
3746
+ validationResult,
3747
+ sessionsResult
3748
+ ] = await Promise.allSettled([
3336
3749
  statePromise,
3337
3750
  learningsPromise,
3338
3751
  handoffPromise,
3339
3752
  graphPromise,
3340
- validationPromise
3753
+ validationPromise,
3754
+ sessionsPromise
3341
3755
  ]);
3342
3756
  function extract(settled, name) {
3343
3757
  if (settled.status === "rejected") {
@@ -3351,6 +3765,7 @@ async function handleGatherContext(input) {
3351
3765
  const handoffRaw = extract(handoffResult, "handoff");
3352
3766
  const graphContextRaw = extract(graphResult, "graph");
3353
3767
  const validationRaw = extract(validationResult, "validation");
3768
+ const sessionsRaw = extract(sessionsResult, "sessions");
3354
3769
  const state = stateRaw && typeof stateRaw === "object" && "ok" in stateRaw ? stateRaw.ok ? stateRaw.value : (() => {
3355
3770
  errors.push(`state: ${stateRaw.error.message}`);
3356
3771
  return null;
@@ -3367,6 +3782,12 @@ async function handleGatherContext(input) {
3367
3782
  })() : handoffRaw;
3368
3783
  const graphContext = graphContextRaw;
3369
3784
  const validation = validationRaw;
3785
+ const sessionSections = sessionsRaw && typeof sessionsRaw === "object" && "ok" in sessionsRaw ? sessionsRaw.ok ? sessionsRaw.value : (() => {
3786
+ errors.push(
3787
+ `sessions: ${sessionsRaw.error.message}`
3788
+ );
3789
+ return null;
3790
+ })() : sessionsRaw;
3370
3791
  const assembledIn = Date.now() - start;
3371
3792
  const mode = input.mode ?? "summary";
3372
3793
  const outputState = state ?? null;
@@ -3391,6 +3812,7 @@ async function handleGatherContext(input) {
3391
3812
  handoff: outputHandoff,
3392
3813
  graphContext: outputGraphContext,
3393
3814
  validation: outputValidation,
3815
+ sessionSections: sessionSections ?? null,
3394
3816
  meta: {
3395
3817
  assembledIn,
3396
3818
  graphAvailable: graphContext !== null,
@@ -3401,7 +3823,7 @@ async function handleGatherContext(input) {
3401
3823
  };
3402
3824
  if (input.session) {
3403
3825
  try {
3404
- const core = await import("./dist-WF4C7A4A.js");
3826
+ const core = await import("./dist-HWXF2C3R.js");
3405
3827
  core.updateSessionIndex(
3406
3828
  projectPath,
3407
3829
  input.session,
@@ -3471,7 +3893,7 @@ async function handleAssessProject(input) {
3471
3893
  let validateResult = null;
3472
3894
  if (checksToRun.has("validate")) {
3473
3895
  try {
3474
- const { handleValidateProject: handleValidateProject2 } = await import("./validate-N7QJOKFZ.js");
3896
+ const { handleValidateProject: handleValidateProject2 } = await import("./validate-FD3Z6VJD.js");
3475
3897
  const result = await handleValidateProject2({ path: projectPath });
3476
3898
  const first = result.content[0];
3477
3899
  const parsed = first ? JSON.parse(first.text) : {};
@@ -3496,7 +3918,7 @@ async function handleAssessProject(input) {
3496
3918
  parallelChecks.push(
3497
3919
  (async () => {
3498
3920
  try {
3499
- const { handleCheckDependencies: handleCheckDependencies2 } = await import("./architecture-ESOOE26S.js");
3921
+ const { handleCheckDependencies: handleCheckDependencies2 } = await import("./architecture-JQZYM4US.js");
3500
3922
  const result = await handleCheckDependencies2({ path: projectPath });
3501
3923
  const first = result.content[0];
3502
3924
  const parsed = first ? JSON.parse(first.text) : {};
@@ -3523,7 +3945,7 @@ async function handleAssessProject(input) {
3523
3945
  parallelChecks.push(
3524
3946
  (async () => {
3525
3947
  try {
3526
- const { handleCheckDocs: handleCheckDocs2 } = await import("./docs-BPYCN2DR.js");
3948
+ const { handleCheckDocs: handleCheckDocs2 } = await import("./docs-7ECGYMAV.js");
3527
3949
  const result = await handleCheckDocs2({ path: projectPath, scope: "coverage" });
3528
3950
  const first = result.content[0];
3529
3951
  const parsed = first ? JSON.parse(first.text) : {};
@@ -3550,14 +3972,14 @@ async function handleAssessProject(input) {
3550
3972
  parallelChecks.push(
3551
3973
  (async () => {
3552
3974
  try {
3553
- const { handleDetectEntropy: handleDetectEntropy2 } = await import("./entropy-4VDVV5CR.js");
3975
+ const { handleDetectEntropy: handleDetectEntropy2 } = await import("./entropy-5USWKLVS.js");
3554
3976
  const result = await handleDetectEntropy2({ path: projectPath, type: "all" });
3555
3977
  const first = result.content[0];
3556
3978
  const parsed = first ? JSON.parse(first.text) : {};
3557
3979
  const issues = (parsed.drift?.staleReferences?.length ?? 0) + (parsed.drift?.missingTargets?.length ?? 0) + (parsed.deadCode?.unusedImports?.length ?? 0) + (parsed.deadCode?.unusedExports?.length ?? 0) + (parsed.patterns?.violations?.length ?? 0);
3558
3980
  return {
3559
3981
  name: "entropy",
3560
- passed: !result.isError && issues === 0,
3982
+ passed: !("isError" in result && result.isError) && issues === 0,
3561
3983
  issueCount: issues,
3562
3984
  ...issues > 0 ? { topIssue: "Entropy detected -- run detect_entropy for details" } : {},
3563
3985
  ...mode === "detailed" ? { detailed: parsed } : {}
@@ -3577,7 +3999,7 @@ async function handleAssessProject(input) {
3577
3999
  parallelChecks.push(
3578
4000
  (async () => {
3579
4001
  try {
3580
- const { handleRunSecurityScan: handleRunSecurityScan2 } = await import("./security-UQFUZXEN.js");
4002
+ const { handleRunSecurityScan: handleRunSecurityScan2 } = await import("./security-PZOX7AQS.js");
3581
4003
  const result = await handleRunSecurityScan2({ path: projectPath });
3582
4004
  const first = result.content[0];
3583
4005
  const parsed = first ? JSON.parse(first.text) : {};
@@ -3609,14 +4031,14 @@ async function handleAssessProject(input) {
3609
4031
  parallelChecks.push(
3610
4032
  (async () => {
3611
4033
  try {
3612
- const { handleCheckPerformance: handleCheckPerformance2 } = await import("./performance-26BH47O4.js");
4034
+ const { handleCheckPerformance: handleCheckPerformance2 } = await import("./performance-OQAFMJUD.js");
3613
4035
  const result = await handleCheckPerformance2({ path: projectPath });
3614
4036
  const first = result.content[0];
3615
4037
  const parsed = first ? JSON.parse(first.text) : {};
3616
4038
  const issues = parsed.violations?.length ?? parsed.issues?.length ?? 0;
3617
4039
  return {
3618
4040
  name: "perf",
3619
- passed: !result.isError && issues === 0,
4041
+ passed: !("isError" in result && result.isError) && issues === 0,
3620
4042
  issueCount: issues,
3621
4043
  ...issues > 0 ? { topIssue: "Performance issues detected" } : {},
3622
4044
  ...mode === "detailed" ? { detailed: parsed } : {}
@@ -3783,81 +4205,8 @@ async function handleReviewChanges(input) {
3783
4205
  downgraded = true;
3784
4206
  }
3785
4207
  try {
3786
- if (effectiveDepth === "quick") {
3787
- const { handleAnalyzeDiff: handleAnalyzeDiff2 } = await import("./feedback-63QB5RCA.js");
3788
- const result2 = await handleAnalyzeDiff2({ diff, path: projectPath });
3789
- const firstContent = result2.content[0];
3790
- if (!firstContent) throw new Error("Empty analyze_diff response");
3791
- const parsed2 = JSON.parse(firstContent.text);
3792
- return {
3793
- content: [
3794
- {
3795
- type: "text",
3796
- text: JSON.stringify({
3797
- depth: "quick",
3798
- downgraded,
3799
- findings: parsed2.findings ?? parsed2.warnings ?? [],
3800
- fileCount: parsed2.summary?.filesChanged ?? parsed2.files?.length ?? 0,
3801
- lineCount: diffLines,
3802
- ...result2.isError ? { error: parsed2 } : {}
3803
- })
3804
- }
3805
- ]
3806
- };
3807
- }
3808
- if (effectiveDepth === "standard") {
3809
- const { handleAnalyzeDiff: handleAnalyzeDiff2, handleCreateSelfReview: handleCreateSelfReview2 } = await import("./feedback-63QB5RCA.js");
3810
- const [diffResult, reviewResult] = await Promise.all([
3811
- handleAnalyzeDiff2({ diff, path: projectPath }),
3812
- handleCreateSelfReview2({ path: projectPath, diff })
3813
- ]);
3814
- const diffContent = diffResult.content[0];
3815
- const reviewContent = reviewResult.content[0];
3816
- if (!diffContent || !reviewContent) throw new Error("Empty review response");
3817
- const diffParsed = JSON.parse(diffContent.text);
3818
- const reviewParsed = JSON.parse(reviewContent.text);
3819
- const findings = [
3820
- ...diffParsed.findings ?? diffParsed.warnings ?? [],
3821
- ...reviewParsed.findings ?? reviewParsed.items ?? []
3822
- ];
3823
- return {
3824
- content: [
3825
- {
3826
- type: "text",
3827
- text: JSON.stringify({
3828
- depth: "standard",
3829
- downgraded,
3830
- findings,
3831
- diffAnalysis: diffParsed,
3832
- selfReview: reviewParsed,
3833
- fileCount: diffParsed.summary?.filesChanged ?? diffParsed.files?.length ?? 0,
3834
- lineCount: diffLines
3835
- })
3836
- }
3837
- ]
3838
- };
3839
- }
3840
- const { handleRunCodeReview: handleRunCodeReview2 } = await import("./review-pipeline-GHR3WFBI.js");
3841
- const result = await handleRunCodeReview2({ path: projectPath, diff });
3842
- const deepContent = result.content[0];
3843
- if (!deepContent) throw new Error("Empty code review response");
3844
- const parsed = JSON.parse(deepContent.text);
3845
- return {
3846
- content: [
3847
- {
3848
- type: "text",
3849
- text: JSON.stringify({
3850
- depth: "deep",
3851
- downgraded: false,
3852
- findings: parsed.findings ?? [],
3853
- assessment: parsed.assessment,
3854
- findingCount: parsed.findingCount,
3855
- lineCount: diffLines,
3856
- pipeline: parsed
3857
- })
3858
- }
3859
- ]
3860
- };
4208
+ const reviewFn = DEPTH_HANDLERS[effectiveDepth];
4209
+ return await reviewFn(projectPath, diff, diffLines, downgraded);
3861
4210
  } catch (error) {
3862
4211
  return {
3863
4212
  content: [
@@ -3870,6 +4219,97 @@ async function handleReviewChanges(input) {
3870
4219
  };
3871
4220
  }
3872
4221
  }
4222
+ async function runQuickReview(projectPath, diff, diffLines, downgraded) {
4223
+ const { handleAnalyzeDiff: handleAnalyzeDiff2 } = await import("./feedback-UTBXZZHF.js");
4224
+ const result = await handleAnalyzeDiff2({ diff, path: projectPath });
4225
+ const firstContent = result.content[0];
4226
+ if (!firstContent) throw new Error("Empty analyze_diff response");
4227
+ const parsed = JSON.parse(firstContent.text);
4228
+ return {
4229
+ content: [
4230
+ {
4231
+ type: "text",
4232
+ text: JSON.stringify({
4233
+ depth: "quick",
4234
+ downgraded,
4235
+ findings: parsed.findings ?? parsed.warnings ?? [],
4236
+ fileCount: parsed.summary?.filesChanged ?? parsed.files?.length ?? 0,
4237
+ lineCount: diffLines,
4238
+ ...result.isError ? { error: parsed } : {}
4239
+ })
4240
+ }
4241
+ ]
4242
+ };
4243
+ }
4244
+ function extractFindings(parsed, primaryKey, fallbackKey) {
4245
+ return parsed[primaryKey] ?? parsed[fallbackKey] ?? [];
4246
+ }
4247
+ function extractFileCount(diffParsed) {
4248
+ const summary = diffParsed.summary;
4249
+ if (summary?.filesChanged !== void 0) return summary.filesChanged;
4250
+ const files = diffParsed.files;
4251
+ return files?.length ?? 0;
4252
+ }
4253
+ async function runStandardReview(projectPath, diff, diffLines, downgraded) {
4254
+ const { handleAnalyzeDiff: handleAnalyzeDiff2, handleCreateSelfReview: handleCreateSelfReview2 } = await import("./feedback-UTBXZZHF.js");
4255
+ const [diffResult, reviewResult] = await Promise.all([
4256
+ handleAnalyzeDiff2({ diff, path: projectPath }),
4257
+ handleCreateSelfReview2({ path: projectPath, diff })
4258
+ ]);
4259
+ const diffContent = diffResult.content[0];
4260
+ const reviewContent = reviewResult.content[0];
4261
+ if (!diffContent || !reviewContent) throw new Error("Empty review response");
4262
+ const diffParsed = JSON.parse(diffContent.text);
4263
+ const reviewParsed = JSON.parse(reviewContent.text);
4264
+ const findings = [
4265
+ ...extractFindings(diffParsed, "findings", "warnings"),
4266
+ ...extractFindings(reviewParsed, "findings", "items")
4267
+ ];
4268
+ return {
4269
+ content: [
4270
+ {
4271
+ type: "text",
4272
+ text: JSON.stringify({
4273
+ depth: "standard",
4274
+ downgraded,
4275
+ findings,
4276
+ diffAnalysis: diffParsed,
4277
+ selfReview: reviewParsed,
4278
+ fileCount: extractFileCount(diffParsed),
4279
+ lineCount: diffLines
4280
+ })
4281
+ }
4282
+ ]
4283
+ };
4284
+ }
4285
+ async function runDeepReview(projectPath, diff, diffLines, _downgraded) {
4286
+ const { handleRunCodeReview: handleRunCodeReview2 } = await import("./review-pipeline-C4GCFVGP.js");
4287
+ const result = await handleRunCodeReview2({ path: projectPath, diff });
4288
+ const deepContent = result.content[0];
4289
+ if (!deepContent) throw new Error("Empty code review response");
4290
+ const parsed = JSON.parse(deepContent.text);
4291
+ return {
4292
+ content: [
4293
+ {
4294
+ type: "text",
4295
+ text: JSON.stringify({
4296
+ depth: "deep",
4297
+ downgraded: false,
4298
+ findings: parsed.findings ?? [],
4299
+ assessment: parsed.assessment,
4300
+ findingCount: parsed.findingCount,
4301
+ lineCount: diffLines,
4302
+ pipeline: parsed
4303
+ })
4304
+ }
4305
+ ]
4306
+ };
4307
+ }
4308
+ var DEPTH_HANDLERS = {
4309
+ quick: runQuickReview,
4310
+ standard: runStandardReview,
4311
+ deep: runDeepReview
4312
+ };
3873
4313
 
3874
4314
  // src/mcp/tools/task-independence.ts
3875
4315
  var checkTaskIndependenceDefinition = {
@@ -3914,7 +4354,7 @@ async function handleCheckTaskIndependence(input) {
3914
4354
  try {
3915
4355
  const projectPath = sanitizePath(input.path);
3916
4356
  const store = await loadGraphStore(projectPath);
3917
- const { TaskIndependenceAnalyzer } = await import("./dist-M6BQODWC.js");
4357
+ const { TaskIndependenceAnalyzer } = await import("./dist-B26DFXMP.js");
3918
4358
  const analyzer = new TaskIndependenceAnalyzer(store ?? void 0);
3919
4359
  const result = analyzer.analyze({
3920
4360
  tasks: input.tasks,
@@ -4002,7 +4442,7 @@ async function handlePredictConflicts(input) {
4002
4442
  try {
4003
4443
  const projectPath = sanitizePath(input.path);
4004
4444
  const store = await loadGraphStore(projectPath);
4005
- const { ConflictPredictor } = await import("./dist-M6BQODWC.js");
4445
+ const { ConflictPredictor } = await import("./dist-B26DFXMP.js");
4006
4446
  const predictor = new ConflictPredictor(store ?? void 0);
4007
4447
  const result = predictor.predict({
4008
4448
  tasks: input.tasks,
@@ -4108,7 +4548,7 @@ async function handleDetectStaleConstraints(input) {
4108
4548
  isError: true
4109
4549
  };
4110
4550
  }
4111
- const { loadGraphStore: loadGraphStore2 } = await import("./graph-loader-KO4GJ5N2.js");
4551
+ const { loadGraphStore: loadGraphStore2 } = await import("./graph-loader-2M2HXDQI.js");
4112
4552
  const store = await loadGraphStore2(projectPath);
4113
4553
  if (!store) {
4114
4554
  return {
@@ -4129,7 +4569,7 @@ async function handleDetectStaleConstraints(input) {
4129
4569
  ]
4130
4570
  };
4131
4571
  }
4132
- const { detectStaleConstraints } = await import("./dist-WF4C7A4A.js");
4572
+ const { detectStaleConstraints } = await import("./dist-HWXF2C3R.js");
4133
4573
  const result = detectStaleConstraints(
4134
4574
  store,
4135
4575
  windowDays,
@@ -4156,6 +4596,76 @@ async function handleDetectStaleConstraints(input) {
4156
4596
  }
4157
4597
  }
4158
4598
 
4599
+ // src/mcp/tools/search-skills.ts
4600
+ var searchSkillsDefinition = {
4601
+ name: "search_skills",
4602
+ description: "Search the skill catalog for domain-specific skills. Returns ranked results based on keyword and stack-signal matching. Use this to discover catalog skills that are not loaded as slash commands.",
4603
+ inputSchema: {
4604
+ type: "object",
4605
+ properties: {
4606
+ query: {
4607
+ type: "string",
4608
+ description: "Natural language or keyword query to search for skills"
4609
+ },
4610
+ path: {
4611
+ type: "string",
4612
+ description: "Project root path (defaults to cwd)"
4613
+ },
4614
+ platform: {
4615
+ type: "string",
4616
+ enum: ["claude-code", "gemini-cli"],
4617
+ description: "Target platform (defaults to claude-code)"
4618
+ }
4619
+ },
4620
+ required: ["query"]
4621
+ }
4622
+ };
4623
+ async function handleSearchSkills(input) {
4624
+ const query = input.query;
4625
+ const projectRoot = input.path || process.cwd();
4626
+ const platform = input.platform || "claude-code";
4627
+ const configResult = resolveConfig();
4628
+ const tierOverrides = configResult.ok ? configResult.value.skills?.tierOverrides : void 0;
4629
+ const index = loadOrRebuildIndex(platform, projectRoot, tierOverrides);
4630
+ const profile = loadOrGenerateProfile(projectRoot);
4631
+ const queryTerms = query.toLowerCase().split(/\s+/).filter((t) => t.length > 2);
4632
+ const results = [];
4633
+ for (const [name, entry] of Object.entries(index.skills)) {
4634
+ const matchedKeywords = entry.keywords.filter(
4635
+ (kw) => queryTerms.some(
4636
+ (term) => kw.toLowerCase().includes(term.toLowerCase()) || term.toLowerCase().includes(kw.toLowerCase())
4637
+ )
4638
+ );
4639
+ const keywordScore = queryTerms.length > 0 ? matchedKeywords.length / queryTerms.length : 0;
4640
+ let stackScore = 0;
4641
+ if (entry.stackSignals.length > 0) {
4642
+ const matchedSignals = entry.stackSignals.filter((signal) => profile.signals[signal]);
4643
+ stackScore = matchedSignals.length / entry.stackSignals.length;
4644
+ }
4645
+ const score = 0.6 * keywordScore + 0.4 * stackScore;
4646
+ if (score > 0 || queryTerms.length === 0) {
4647
+ results.push({
4648
+ name,
4649
+ description: entry.description,
4650
+ keywords: entry.keywords,
4651
+ phases: entry.phases,
4652
+ score: Math.round(score * 100) / 100,
4653
+ source: entry.source
4654
+ });
4655
+ }
4656
+ }
4657
+ results.sort((a, b) => b.score - a.score);
4658
+ const top5 = results.slice(0, 5);
4659
+ return {
4660
+ content: [
4661
+ {
4662
+ type: "text",
4663
+ text: JSON.stringify({ results: top5 }, null, 2)
4664
+ }
4665
+ ]
4666
+ };
4667
+ }
4668
+
4159
4669
  // src/mcp/server.ts
4160
4670
  var TOOL_DEFINITIONS = [
4161
4671
  validateToolDefinition,
@@ -4202,7 +4712,8 @@ var TOOL_DEFINITIONS = [
4202
4712
  askGraphDefinition,
4203
4713
  checkTaskIndependenceDefinition,
4204
4714
  predictConflictsDefinition,
4205
- detectStaleConstraintsDefinition
4715
+ detectStaleConstraintsDefinition,
4716
+ searchSkillsDefinition
4206
4717
  ];
4207
4718
  var TOOL_HANDLERS = {
4208
4719
  validate_project: handleValidateProject,
@@ -4249,7 +4760,8 @@ var TOOL_HANDLERS = {
4249
4760
  ask_graph: handleAskGraph,
4250
4761
  check_task_independence: handleCheckTaskIndependence,
4251
4762
  predict_conflicts: handlePredictConflicts,
4252
- detect_stale_constraints: handleDetectStaleConstraints
4763
+ detect_stale_constraints: handleDetectStaleConstraints,
4764
+ search_skills: handleSearchSkills
4253
4765
  };
4254
4766
  var RESOURCE_DEFINITIONS = [
4255
4767
  {
@@ -4314,6 +4826,45 @@ var RESOURCE_HANDLERS = {
4314
4826
  function getToolDefinitions() {
4315
4827
  return TOOL_DEFINITIONS;
4316
4828
  }
4829
+ function readConfigInterval(resolvedRoot) {
4830
+ try {
4831
+ const configResult = resolveProjectConfig(resolvedRoot);
4832
+ if (configResult.ok) {
4833
+ const raw = configResult.value.updateCheckInterval;
4834
+ if (typeof raw === "number" && Number.isInteger(raw) && raw >= 0) {
4835
+ return raw;
4836
+ }
4837
+ }
4838
+ } catch {
4839
+ }
4840
+ return void 0;
4841
+ }
4842
+ async function appendUpdateNotification(result, resolvedRoot) {
4843
+ try {
4844
+ const {
4845
+ getUpdateNotification,
4846
+ isUpdateCheckEnabled,
4847
+ shouldRunCheck,
4848
+ readCheckState,
4849
+ spawnBackgroundCheck
4850
+ } = await import("./dist-HWXF2C3R.js");
4851
+ const { CLI_VERSION } = await import("./version-KFFPOQAX.js");
4852
+ const configInterval = readConfigInterval(resolvedRoot);
4853
+ const DEFAULT_INTERVAL = 864e5;
4854
+ if (!isUpdateCheckEnabled(configInterval)) return;
4855
+ const state = readCheckState();
4856
+ if (shouldRunCheck(state, configInterval ?? DEFAULT_INTERVAL)) {
4857
+ spawnBackgroundCheck(CLI_VERSION);
4858
+ }
4859
+ const notification = getUpdateNotification(CLI_VERSION);
4860
+ if (notification) {
4861
+ result.content.push({ type: "text", text: `
4862
+ ---
4863
+ ${notification}` });
4864
+ }
4865
+ } catch {
4866
+ }
4867
+ }
4317
4868
  function createHarnessServer(projectRoot) {
4318
4869
  const resolvedRoot = projectRoot ?? process.cwd();
4319
4870
  let sessionChecked = false;
@@ -4333,42 +4884,7 @@ function createHarnessServer(projectRoot) {
4333
4884
  const result = await handler(args ?? {});
4334
4885
  if (!sessionChecked) {
4335
4886
  sessionChecked = true;
4336
- try {
4337
- const {
4338
- getUpdateNotification,
4339
- isUpdateCheckEnabled,
4340
- shouldRunCheck,
4341
- readCheckState,
4342
- spawnBackgroundCheck
4343
- } = await import("./dist-WF4C7A4A.js");
4344
- const { CLI_VERSION: version } = await import("./version-KFFPOQAX.js");
4345
- let CLI_VERSION = version;
4346
- let configInterval;
4347
- try {
4348
- const configResult = resolveProjectConfig(resolvedRoot);
4349
- if (configResult.ok) {
4350
- const raw = configResult.value.updateCheckInterval;
4351
- if (typeof raw === "number" && Number.isInteger(raw) && raw >= 0) {
4352
- configInterval = raw;
4353
- }
4354
- }
4355
- } catch {
4356
- }
4357
- const DEFAULT_INTERVAL = 864e5;
4358
- if (isUpdateCheckEnabled(configInterval)) {
4359
- const state = readCheckState();
4360
- if (shouldRunCheck(state, configInterval ?? DEFAULT_INTERVAL)) {
4361
- spawnBackgroundCheck(CLI_VERSION);
4362
- }
4363
- const notification = getUpdateNotification(CLI_VERSION);
4364
- if (notification) {
4365
- result.content.push({ type: "text", text: `
4366
- ---
4367
- ${notification}` });
4368
- }
4369
- }
4370
- } catch {
4371
- }
4887
+ await appendUpdateNotification(result, resolvedRoot);
4372
4888
  }
4373
4889
  return result;
4374
4890
  });
@@ -4397,6 +4913,8 @@ async function startServer() {
4397
4913
  }
4398
4914
 
4399
4915
  export {
4916
+ persistToolingConfig,
4917
+ appendFrameworkAgents,
4400
4918
  generateSlashCommands,
4401
4919
  handleOrphanDeletion,
4402
4920
  createGenerateSlashCommandsCommand,