@harness-engineering/cli 1.14.0 → 1.16.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 (499) hide show
  1. package/dist/agents/commands/codex/AGENTS.md +39 -0
  2. package/dist/agents/commands/codex/harness/add-harness-component/SKILL.md +195 -0
  3. package/dist/agents/commands/codex/harness/add-harness-component/agents/openai.yaml +3 -0
  4. package/dist/agents/commands/codex/harness/cleanup-dead-code/SKILL.md +248 -0
  5. package/dist/agents/commands/codex/harness/cleanup-dead-code/agents/openai.yaml +3 -0
  6. package/dist/agents/commands/codex/harness/detect-doc-drift/SKILL.md +182 -0
  7. package/dist/agents/commands/codex/harness/detect-doc-drift/agents/openai.yaml +3 -0
  8. package/dist/agents/commands/codex/harness/enforce-architecture/SKILL.md +299 -0
  9. package/dist/agents/commands/codex/harness/enforce-architecture/agents/openai.yaml +3 -0
  10. package/dist/agents/commands/codex/harness/harness-architecture-advisor/SKILL.md +452 -0
  11. package/dist/agents/commands/codex/harness/harness-architecture-advisor/agents/openai.yaml +3 -0
  12. package/dist/agents/commands/codex/harness/harness-autopilot/SKILL.md +919 -0
  13. package/dist/agents/commands/codex/harness/harness-autopilot/agents/openai.yaml +3 -0
  14. package/dist/agents/commands/codex/harness/harness-brainstorming/SKILL.md +409 -0
  15. package/dist/agents/commands/codex/harness/harness-brainstorming/agents/openai.yaml +3 -0
  16. package/dist/agents/commands/codex/harness/harness-code-review/SKILL.md +860 -0
  17. package/dist/agents/commands/codex/harness/harness-code-review/agents/openai.yaml +3 -0
  18. package/dist/agents/commands/codex/harness/harness-codebase-cleanup/SKILL.md +227 -0
  19. package/dist/agents/commands/codex/harness/harness-codebase-cleanup/agents/openai.yaml +3 -0
  20. package/dist/agents/commands/codex/harness/harness-debugging/SKILL.md +369 -0
  21. package/dist/agents/commands/codex/harness/harness-debugging/agents/openai.yaml +3 -0
  22. package/dist/agents/commands/codex/harness/harness-dependency-health/SKILL.md +182 -0
  23. package/dist/agents/commands/codex/harness/harness-dependency-health/agents/openai.yaml +3 -0
  24. package/dist/agents/commands/codex/harness/harness-docs-pipeline/SKILL.md +463 -0
  25. package/dist/agents/commands/codex/harness/harness-docs-pipeline/agents/openai.yaml +3 -0
  26. package/dist/agents/commands/codex/harness/harness-execution/SKILL.md +513 -0
  27. package/dist/agents/commands/codex/harness/harness-execution/agents/openai.yaml +3 -0
  28. package/dist/agents/commands/codex/harness/harness-hotspot-detector/SKILL.md +164 -0
  29. package/dist/agents/commands/codex/harness/harness-hotspot-detector/agents/openai.yaml +3 -0
  30. package/dist/agents/commands/codex/harness/harness-impact-analysis/SKILL.md +187 -0
  31. package/dist/agents/commands/codex/harness/harness-impact-analysis/agents/openai.yaml +3 -0
  32. package/dist/agents/commands/codex/harness/harness-integrity/SKILL.md +170 -0
  33. package/dist/agents/commands/codex/harness/harness-integrity/agents/openai.yaml +3 -0
  34. package/dist/agents/commands/codex/harness/harness-onboarding/SKILL.md +291 -0
  35. package/dist/agents/commands/codex/harness/harness-onboarding/agents/openai.yaml +3 -0
  36. package/dist/agents/commands/codex/harness/harness-perf/SKILL.md +263 -0
  37. package/dist/agents/commands/codex/harness/harness-perf/agents/openai.yaml +3 -0
  38. package/dist/agents/commands/codex/harness/harness-planning/SKILL.md +582 -0
  39. package/dist/agents/commands/codex/harness/harness-planning/agents/openai.yaml +3 -0
  40. package/dist/agents/commands/codex/harness/harness-refactoring/SKILL.md +172 -0
  41. package/dist/agents/commands/codex/harness/harness-refactoring/agents/openai.yaml +3 -0
  42. package/dist/agents/commands/codex/harness/harness-release-readiness/SKILL.md +692 -0
  43. package/dist/agents/commands/codex/harness/harness-release-readiness/agents/openai.yaml +3 -0
  44. package/dist/agents/commands/codex/harness/harness-roadmap/SKILL.md +598 -0
  45. package/dist/agents/commands/codex/harness/harness-roadmap/agents/openai.yaml +3 -0
  46. package/dist/agents/commands/codex/harness/harness-security-scan/SKILL.md +157 -0
  47. package/dist/agents/commands/codex/harness/harness-security-scan/agents/openai.yaml +3 -0
  48. package/dist/agents/commands/codex/harness/harness-skill-authoring/SKILL.md +295 -0
  49. package/dist/agents/commands/codex/harness/harness-skill-authoring/agents/openai.yaml +3 -0
  50. package/dist/agents/commands/codex/harness/harness-soundness-review/SKILL.md +1270 -0
  51. package/dist/agents/commands/codex/harness/harness-soundness-review/agents/openai.yaml +3 -0
  52. package/dist/agents/commands/codex/harness/harness-supply-chain-audit/SKILL.md +247 -0
  53. package/dist/agents/commands/codex/harness/harness-supply-chain-audit/agents/openai.yaml +3 -0
  54. package/dist/agents/commands/codex/harness/harness-tdd/SKILL.md +180 -0
  55. package/dist/agents/commands/codex/harness/harness-tdd/agents/openai.yaml +3 -0
  56. package/dist/agents/commands/codex/harness/harness-test-advisor/SKILL.md +163 -0
  57. package/dist/agents/commands/codex/harness/harness-test-advisor/agents/openai.yaml +3 -0
  58. package/dist/agents/commands/codex/harness/harness-verification/SKILL.md +424 -0
  59. package/dist/agents/commands/codex/harness/harness-verification/agents/openai.yaml +3 -0
  60. package/dist/agents/commands/codex/harness/harness-verify/SKILL.md +162 -0
  61. package/dist/agents/commands/codex/harness/harness-verify/agents/openai.yaml +3 -0
  62. package/dist/agents/commands/codex/harness/initialize-harness-project/SKILL.md +235 -0
  63. package/dist/agents/commands/codex/harness/initialize-harness-project/agents/openai.yaml +3 -0
  64. package/dist/agents/commands/cursor/harness/add-harness-component.mdc +200 -0
  65. package/dist/agents/commands/cursor/harness/cleanup-dead-code.mdc +253 -0
  66. package/dist/agents/commands/cursor/harness/detect-doc-drift.mdc +187 -0
  67. package/dist/agents/commands/cursor/harness/enforce-architecture.mdc +304 -0
  68. package/dist/agents/commands/cursor/harness/harness-architecture-advisor.mdc +457 -0
  69. package/dist/agents/commands/cursor/harness/harness-autopilot.mdc +924 -0
  70. package/dist/agents/commands/cursor/harness/harness-brainstorming.mdc +414 -0
  71. package/dist/agents/commands/cursor/harness/harness-code-review.mdc +865 -0
  72. package/dist/agents/commands/cursor/harness/harness-codebase-cleanup.mdc +232 -0
  73. package/dist/agents/commands/cursor/harness/harness-debugging.mdc +374 -0
  74. package/dist/agents/commands/cursor/harness/harness-dependency-health.mdc +187 -0
  75. package/dist/agents/commands/cursor/harness/harness-docs-pipeline.mdc +468 -0
  76. package/dist/agents/commands/cursor/harness/harness-execution.mdc +518 -0
  77. package/dist/agents/commands/cursor/harness/harness-hotspot-detector.mdc +169 -0
  78. package/dist/agents/commands/cursor/harness/harness-impact-analysis.mdc +192 -0
  79. package/dist/agents/commands/cursor/harness/harness-integrity.mdc +175 -0
  80. package/dist/agents/commands/cursor/harness/harness-onboarding.mdc +296 -0
  81. package/dist/agents/commands/cursor/harness/harness-perf.mdc +268 -0
  82. package/dist/agents/commands/cursor/harness/harness-planning.mdc +587 -0
  83. package/dist/agents/commands/cursor/harness/harness-refactoring.mdc +177 -0
  84. package/dist/agents/commands/cursor/harness/harness-release-readiness.mdc +697 -0
  85. package/dist/agents/commands/cursor/harness/harness-roadmap.mdc +603 -0
  86. package/dist/agents/commands/cursor/harness/harness-security-scan.mdc +162 -0
  87. package/dist/agents/commands/cursor/harness/harness-skill-authoring.mdc +300 -0
  88. package/dist/agents/commands/cursor/harness/harness-soundness-review.mdc +1275 -0
  89. package/dist/agents/commands/cursor/harness/harness-supply-chain-audit.mdc +252 -0
  90. package/dist/agents/commands/cursor/harness/harness-tdd.mdc +185 -0
  91. package/dist/agents/commands/cursor/harness/harness-test-advisor.mdc +168 -0
  92. package/dist/agents/commands/cursor/harness/harness-verification.mdc +429 -0
  93. package/dist/agents/commands/cursor/harness/harness-verify.mdc +167 -0
  94. package/dist/agents/commands/cursor/harness/initialize-harness-project.mdc +240 -0
  95. package/dist/agents/skills/claude-code/enforce-architecture/SKILL.md +52 -0
  96. package/dist/agents/skills/claude-code/harness-api-design/SKILL.md +52 -0
  97. package/dist/agents/skills/claude-code/harness-architecture-advisor/SKILL.md +52 -0
  98. package/dist/agents/skills/claude-code/harness-auth/SKILL.md +52 -0
  99. package/dist/agents/skills/claude-code/harness-autopilot/SKILL.md +355 -45
  100. package/dist/agents/skills/claude-code/harness-autopilot/skill.yaml +12 -0
  101. package/dist/agents/skills/claude-code/harness-code-review/SKILL.md +97 -3
  102. package/dist/agents/skills/claude-code/harness-code-review/skill.yaml +6 -0
  103. package/dist/agents/skills/claude-code/harness-codebase-cleanup/SKILL.md +2 -4
  104. package/dist/agents/skills/claude-code/harness-database/SKILL.md +52 -0
  105. package/dist/agents/skills/claude-code/harness-deployment/SKILL.md +52 -0
  106. package/dist/agents/skills/claude-code/harness-planning/SKILL.md +99 -3
  107. package/dist/agents/skills/claude-code/harness-planning/skill.yaml +6 -0
  108. package/dist/agents/skills/claude-code/harness-pre-commit-review/SKILL.md +1 -1
  109. package/dist/agents/skills/claude-code/harness-product-spec/SKILL.md +5 -5
  110. package/dist/agents/skills/claude-code/harness-security-review/SKILL.md +27 -7
  111. package/dist/agents/skills/claude-code/harness-security-scan/SKILL.md +52 -0
  112. package/dist/agents/skills/claude-code/harness-supply-chain-audit/SKILL.md +281 -0
  113. package/dist/agents/skills/claude-code/harness-supply-chain-audit/skill.yaml +51 -0
  114. package/dist/agents/skills/codex/add-harness-component/SKILL.md +192 -0
  115. package/dist/agents/skills/codex/add-harness-component/skill.yaml +33 -0
  116. package/dist/agents/skills/codex/align-documentation/SKILL.md +213 -0
  117. package/dist/agents/skills/codex/align-documentation/skill.yaml +32 -0
  118. package/dist/agents/skills/codex/check-mechanical-constraints/SKILL.md +191 -0
  119. package/dist/agents/skills/codex/check-mechanical-constraints/skill.yaml +33 -0
  120. package/dist/agents/skills/codex/cleanup-dead-code/SKILL.md +245 -0
  121. package/dist/agents/skills/codex/cleanup-dead-code/skill.yaml +34 -0
  122. package/dist/agents/skills/codex/detect-doc-drift/SKILL.md +179 -0
  123. package/dist/agents/skills/codex/detect-doc-drift/skill.yaml +31 -0
  124. package/dist/agents/skills/codex/enforce-architecture/SKILL.md +296 -0
  125. package/dist/agents/skills/codex/enforce-architecture/skill.yaml +35 -0
  126. package/dist/agents/skills/codex/harness-accessibility/SKILL.md +281 -0
  127. package/dist/agents/skills/codex/harness-accessibility/skill.yaml +52 -0
  128. package/dist/agents/skills/codex/harness-api-design/SKILL.md +356 -0
  129. package/dist/agents/skills/codex/harness-api-design/skill.yaml +74 -0
  130. package/dist/agents/skills/codex/harness-architecture-advisor/SKILL.md +449 -0
  131. package/dist/agents/skills/codex/harness-architecture-advisor/skill.yaml +49 -0
  132. package/dist/agents/skills/codex/harness-auth/SKILL.md +331 -0
  133. package/dist/agents/skills/codex/harness-auth/skill.yaml +81 -0
  134. package/dist/agents/skills/codex/harness-autopilot/SKILL.md +916 -0
  135. package/dist/agents/skills/codex/harness-autopilot/skill.yaml +67 -0
  136. package/dist/agents/skills/codex/harness-brainstorming/SKILL.md +406 -0
  137. package/dist/agents/skills/codex/harness-brainstorming/skill.yaml +50 -0
  138. package/dist/agents/skills/codex/harness-caching/SKILL.md +309 -0
  139. package/dist/agents/skills/codex/harness-caching/skill.yaml +73 -0
  140. package/dist/agents/skills/codex/harness-chaos/SKILL.md +295 -0
  141. package/dist/agents/skills/codex/harness-chaos/skill.yaml +72 -0
  142. package/dist/agents/skills/codex/harness-code-review/SKILL.md +857 -0
  143. package/dist/agents/skills/codex/harness-code-review/skill.yaml +52 -0
  144. package/dist/agents/skills/codex/harness-codebase-cleanup/SKILL.md +224 -0
  145. package/dist/agents/skills/codex/harness-codebase-cleanup/skill.yaml +65 -0
  146. package/dist/agents/skills/codex/harness-compliance/SKILL.md +303 -0
  147. package/dist/agents/skills/codex/harness-compliance/skill.yaml +78 -0
  148. package/dist/agents/skills/codex/harness-containerization/SKILL.md +284 -0
  149. package/dist/agents/skills/codex/harness-containerization/skill.yaml +80 -0
  150. package/dist/agents/skills/codex/harness-data-pipeline/SKILL.md +274 -0
  151. package/dist/agents/skills/codex/harness-data-pipeline/skill.yaml +81 -0
  152. package/dist/agents/skills/codex/harness-data-validation/SKILL.md +343 -0
  153. package/dist/agents/skills/codex/harness-data-validation/skill.yaml +75 -0
  154. package/dist/agents/skills/codex/harness-database/SKILL.md +310 -0
  155. package/dist/agents/skills/codex/harness-database/skill.yaml +80 -0
  156. package/dist/agents/skills/codex/harness-debugging/SKILL.md +366 -0
  157. package/dist/agents/skills/codex/harness-debugging/skill.yaml +48 -0
  158. package/dist/agents/skills/codex/harness-dependency-health/SKILL.md +179 -0
  159. package/dist/agents/skills/codex/harness-dependency-health/skill.yaml +42 -0
  160. package/dist/agents/skills/codex/harness-deployment/SKILL.md +307 -0
  161. package/dist/agents/skills/codex/harness-deployment/skill.yaml +77 -0
  162. package/dist/agents/skills/codex/harness-design/SKILL.md +265 -0
  163. package/dist/agents/skills/codex/harness-design/skill.yaml +54 -0
  164. package/dist/agents/skills/codex/harness-design-mobile/SKILL.md +336 -0
  165. package/dist/agents/skills/codex/harness-design-mobile/skill.yaml +50 -0
  166. package/dist/agents/skills/codex/harness-design-system/SKILL.md +282 -0
  167. package/dist/agents/skills/codex/harness-design-system/skill.yaml +51 -0
  168. package/dist/agents/skills/codex/harness-design-web/SKILL.md +360 -0
  169. package/dist/agents/skills/codex/harness-design-web/skill.yaml +53 -0
  170. package/dist/agents/skills/codex/harness-diagnostics/SKILL.md +318 -0
  171. package/dist/agents/skills/codex/harness-diagnostics/skill.yaml +51 -0
  172. package/dist/agents/skills/codex/harness-docs-pipeline/SKILL.md +460 -0
  173. package/dist/agents/skills/codex/harness-docs-pipeline/skill.yaml +70 -0
  174. package/dist/agents/skills/codex/harness-dx/SKILL.md +276 -0
  175. package/dist/agents/skills/codex/harness-dx/skill.yaml +76 -0
  176. package/dist/agents/skills/codex/harness-e2e/SKILL.md +245 -0
  177. package/dist/agents/skills/codex/harness-e2e/skill.yaml +78 -0
  178. package/dist/agents/skills/codex/harness-event-driven/SKILL.md +280 -0
  179. package/dist/agents/skills/codex/harness-event-driven/skill.yaml +77 -0
  180. package/dist/agents/skills/codex/harness-execution/SKILL.md +510 -0
  181. package/dist/agents/skills/codex/harness-execution/skill.yaml +52 -0
  182. package/dist/agents/skills/codex/harness-feature-flags/SKILL.md +287 -0
  183. package/dist/agents/skills/codex/harness-feature-flags/skill.yaml +74 -0
  184. package/dist/agents/skills/codex/harness-git-workflow/SKILL.md +268 -0
  185. package/dist/agents/skills/codex/harness-git-workflow/skill.yaml +32 -0
  186. package/dist/agents/skills/codex/harness-hotspot-detector/SKILL.md +161 -0
  187. package/dist/agents/skills/codex/harness-hotspot-detector/skill.yaml +45 -0
  188. package/dist/agents/skills/codex/harness-i18n/SKILL.md +484 -0
  189. package/dist/agents/skills/codex/harness-i18n/skill.yaml +55 -0
  190. package/dist/agents/skills/codex/harness-i18n-process/SKILL.md +388 -0
  191. package/dist/agents/skills/codex/harness-i18n-process/skill.yaml +44 -0
  192. package/dist/agents/skills/codex/harness-i18n-workflow/SKILL.md +512 -0
  193. package/dist/agents/skills/codex/harness-i18n-workflow/skill.yaml +54 -0
  194. package/dist/agents/skills/codex/harness-impact-analysis/SKILL.md +184 -0
  195. package/dist/agents/skills/codex/harness-impact-analysis/skill.yaml +45 -0
  196. package/dist/agents/skills/codex/harness-incident-response/SKILL.md +223 -0
  197. package/dist/agents/skills/codex/harness-incident-response/skill.yaml +78 -0
  198. package/dist/agents/skills/codex/harness-infrastructure-as-code/SKILL.md +279 -0
  199. package/dist/agents/skills/codex/harness-infrastructure-as-code/skill.yaml +80 -0
  200. package/dist/agents/skills/codex/harness-integration-test/SKILL.md +271 -0
  201. package/dist/agents/skills/codex/harness-integration-test/skill.yaml +73 -0
  202. package/dist/agents/skills/codex/harness-integrity/SKILL.md +167 -0
  203. package/dist/agents/skills/codex/harness-integrity/skill.yaml +48 -0
  204. package/dist/agents/skills/codex/harness-knowledge-mapper/SKILL.md +195 -0
  205. package/dist/agents/skills/codex/harness-knowledge-mapper/skill.yaml +50 -0
  206. package/dist/agents/skills/codex/harness-load-testing/SKILL.md +274 -0
  207. package/dist/agents/skills/codex/harness-load-testing/skill.yaml +79 -0
  208. package/dist/agents/skills/codex/harness-ml-ops/SKILL.md +341 -0
  209. package/dist/agents/skills/codex/harness-ml-ops/skill.yaml +79 -0
  210. package/dist/agents/skills/codex/harness-mobile-patterns/SKILL.md +326 -0
  211. package/dist/agents/skills/codex/harness-mobile-patterns/skill.yaml +82 -0
  212. package/dist/agents/skills/codex/harness-mutation-test/SKILL.md +251 -0
  213. package/dist/agents/skills/codex/harness-mutation-test/skill.yaml +70 -0
  214. package/dist/agents/skills/codex/harness-observability/SKILL.md +283 -0
  215. package/dist/agents/skills/codex/harness-observability/skill.yaml +78 -0
  216. package/dist/agents/skills/codex/harness-onboarding/SKILL.md +288 -0
  217. package/dist/agents/skills/codex/harness-onboarding/skill.yaml +31 -0
  218. package/dist/agents/skills/codex/harness-parallel-agents/SKILL.md +256 -0
  219. package/dist/agents/skills/codex/harness-parallel-agents/skill.yaml +34 -0
  220. package/dist/agents/skills/codex/harness-perf/SKILL.md +260 -0
  221. package/dist/agents/skills/codex/harness-perf/skill.yaml +51 -0
  222. package/dist/agents/skills/codex/harness-perf-tdd/SKILL.md +249 -0
  223. package/dist/agents/skills/codex/harness-perf-tdd/skill.yaml +48 -0
  224. package/dist/agents/skills/codex/harness-planning/SKILL.md +579 -0
  225. package/dist/agents/skills/codex/harness-planning/skill.yaml +56 -0
  226. package/dist/agents/skills/codex/harness-pre-commit-review/SKILL.md +324 -0
  227. package/dist/agents/skills/codex/harness-pre-commit-review/skill.yaml +34 -0
  228. package/dist/agents/skills/codex/harness-product-spec/SKILL.md +285 -0
  229. package/dist/agents/skills/codex/harness-product-spec/skill.yaml +72 -0
  230. package/dist/agents/skills/codex/harness-property-test/SKILL.md +281 -0
  231. package/dist/agents/skills/codex/harness-property-test/skill.yaml +71 -0
  232. package/dist/agents/skills/codex/harness-refactoring/SKILL.md +169 -0
  233. package/dist/agents/skills/codex/harness-refactoring/skill.yaml +34 -0
  234. package/dist/agents/skills/codex/harness-release-readiness/SKILL.md +689 -0
  235. package/dist/agents/skills/codex/harness-release-readiness/skill.yaml +58 -0
  236. package/dist/agents/skills/codex/harness-resilience/SKILL.md +255 -0
  237. package/dist/agents/skills/codex/harness-resilience/skill.yaml +76 -0
  238. package/dist/agents/skills/codex/harness-roadmap/SKILL.md +595 -0
  239. package/dist/agents/skills/codex/harness-roadmap/skill.yaml +44 -0
  240. package/dist/agents/skills/codex/harness-secrets/SKILL.md +293 -0
  241. package/dist/agents/skills/codex/harness-secrets/skill.yaml +76 -0
  242. package/dist/agents/skills/codex/harness-security-review/SKILL.md +260 -0
  243. package/dist/agents/skills/codex/harness-security-review/skill.yaml +53 -0
  244. package/dist/agents/skills/codex/harness-security-scan/SKILL.md +154 -0
  245. package/dist/agents/skills/codex/harness-security-scan/skill.yaml +42 -0
  246. package/dist/agents/skills/codex/harness-skill-authoring/SKILL.md +292 -0
  247. package/dist/agents/skills/codex/harness-skill-authoring/skill.yaml +33 -0
  248. package/dist/agents/skills/codex/harness-soundness-review/SKILL.md +1267 -0
  249. package/dist/agents/skills/codex/harness-soundness-review/skill.yaml +49 -0
  250. package/dist/agents/skills/codex/harness-sql-review/SKILL.md +315 -0
  251. package/dist/agents/skills/codex/harness-sql-review/skill.yaml +74 -0
  252. package/dist/agents/skills/codex/harness-state-management/SKILL.md +309 -0
  253. package/dist/agents/skills/codex/harness-state-management/skill.yaml +33 -0
  254. package/dist/agents/skills/codex/harness-supply-chain-audit/SKILL.md +281 -0
  255. package/dist/agents/skills/codex/harness-supply-chain-audit/skill.yaml +51 -0
  256. package/dist/agents/skills/codex/harness-tdd/SKILL.md +177 -0
  257. package/dist/agents/skills/codex/harness-tdd/skill.yaml +49 -0
  258. package/dist/agents/skills/codex/harness-test-advisor/SKILL.md +160 -0
  259. package/dist/agents/skills/codex/harness-test-advisor/skill.yaml +45 -0
  260. package/dist/agents/skills/codex/harness-test-data/SKILL.md +268 -0
  261. package/dist/agents/skills/codex/harness-test-data/skill.yaml +74 -0
  262. package/dist/agents/skills/codex/harness-ux-copy/SKILL.md +271 -0
  263. package/dist/agents/skills/codex/harness-ux-copy/skill.yaml +77 -0
  264. package/dist/agents/skills/codex/harness-verification/SKILL.md +421 -0
  265. package/dist/agents/skills/codex/harness-verification/skill.yaml +43 -0
  266. package/dist/agents/skills/codex/harness-verify/SKILL.md +159 -0
  267. package/dist/agents/skills/codex/harness-verify/skill.yaml +41 -0
  268. package/dist/agents/skills/codex/harness-visual-regression/SKILL.md +257 -0
  269. package/dist/agents/skills/codex/harness-visual-regression/skill.yaml +74 -0
  270. package/dist/agents/skills/codex/initialize-harness-project/SKILL.md +232 -0
  271. package/dist/agents/skills/codex/initialize-harness-project/skill.yaml +32 -0
  272. package/dist/agents/skills/codex/validate-context-engineering/SKILL.md +150 -0
  273. package/dist/agents/skills/codex/validate-context-engineering/skill.yaml +32 -0
  274. package/dist/agents/skills/cursor/add-harness-component/SKILL.md +192 -0
  275. package/dist/agents/skills/cursor/add-harness-component/skill.yaml +33 -0
  276. package/dist/agents/skills/cursor/align-documentation/SKILL.md +213 -0
  277. package/dist/agents/skills/cursor/align-documentation/skill.yaml +32 -0
  278. package/dist/agents/skills/cursor/check-mechanical-constraints/SKILL.md +191 -0
  279. package/dist/agents/skills/cursor/check-mechanical-constraints/skill.yaml +33 -0
  280. package/dist/agents/skills/cursor/cleanup-dead-code/SKILL.md +245 -0
  281. package/dist/agents/skills/cursor/cleanup-dead-code/skill.yaml +34 -0
  282. package/dist/agents/skills/cursor/detect-doc-drift/SKILL.md +179 -0
  283. package/dist/agents/skills/cursor/detect-doc-drift/skill.yaml +31 -0
  284. package/dist/agents/skills/cursor/enforce-architecture/SKILL.md +296 -0
  285. package/dist/agents/skills/cursor/enforce-architecture/skill.yaml +35 -0
  286. package/dist/agents/skills/cursor/harness-accessibility/SKILL.md +281 -0
  287. package/dist/agents/skills/cursor/harness-accessibility/skill.yaml +52 -0
  288. package/dist/agents/skills/cursor/harness-api-design/SKILL.md +356 -0
  289. package/dist/agents/skills/cursor/harness-api-design/skill.yaml +74 -0
  290. package/dist/agents/skills/cursor/harness-architecture-advisor/SKILL.md +449 -0
  291. package/dist/agents/skills/cursor/harness-architecture-advisor/skill.yaml +49 -0
  292. package/dist/agents/skills/cursor/harness-auth/SKILL.md +331 -0
  293. package/dist/agents/skills/cursor/harness-auth/skill.yaml +81 -0
  294. package/dist/agents/skills/cursor/harness-autopilot/SKILL.md +916 -0
  295. package/dist/agents/skills/cursor/harness-autopilot/skill.yaml +67 -0
  296. package/dist/agents/skills/cursor/harness-brainstorming/SKILL.md +406 -0
  297. package/dist/agents/skills/cursor/harness-brainstorming/skill.yaml +50 -0
  298. package/dist/agents/skills/cursor/harness-caching/SKILL.md +309 -0
  299. package/dist/agents/skills/cursor/harness-caching/skill.yaml +73 -0
  300. package/dist/agents/skills/cursor/harness-chaos/SKILL.md +295 -0
  301. package/dist/agents/skills/cursor/harness-chaos/skill.yaml +72 -0
  302. package/dist/agents/skills/cursor/harness-code-review/SKILL.md +857 -0
  303. package/dist/agents/skills/cursor/harness-code-review/skill.yaml +52 -0
  304. package/dist/agents/skills/cursor/harness-codebase-cleanup/SKILL.md +224 -0
  305. package/dist/agents/skills/cursor/harness-codebase-cleanup/skill.yaml +65 -0
  306. package/dist/agents/skills/cursor/harness-compliance/SKILL.md +303 -0
  307. package/dist/agents/skills/cursor/harness-compliance/skill.yaml +78 -0
  308. package/dist/agents/skills/cursor/harness-containerization/SKILL.md +284 -0
  309. package/dist/agents/skills/cursor/harness-containerization/skill.yaml +80 -0
  310. package/dist/agents/skills/cursor/harness-data-pipeline/SKILL.md +274 -0
  311. package/dist/agents/skills/cursor/harness-data-pipeline/skill.yaml +81 -0
  312. package/dist/agents/skills/cursor/harness-data-validation/SKILL.md +343 -0
  313. package/dist/agents/skills/cursor/harness-data-validation/skill.yaml +75 -0
  314. package/dist/agents/skills/cursor/harness-database/SKILL.md +310 -0
  315. package/dist/agents/skills/cursor/harness-database/skill.yaml +80 -0
  316. package/dist/agents/skills/cursor/harness-debugging/SKILL.md +366 -0
  317. package/dist/agents/skills/cursor/harness-debugging/skill.yaml +48 -0
  318. package/dist/agents/skills/cursor/harness-dependency-health/SKILL.md +179 -0
  319. package/dist/agents/skills/cursor/harness-dependency-health/skill.yaml +42 -0
  320. package/dist/agents/skills/cursor/harness-deployment/SKILL.md +307 -0
  321. package/dist/agents/skills/cursor/harness-deployment/skill.yaml +77 -0
  322. package/dist/agents/skills/cursor/harness-design/SKILL.md +265 -0
  323. package/dist/agents/skills/cursor/harness-design/skill.yaml +54 -0
  324. package/dist/agents/skills/cursor/harness-design-mobile/SKILL.md +336 -0
  325. package/dist/agents/skills/cursor/harness-design-mobile/skill.yaml +50 -0
  326. package/dist/agents/skills/cursor/harness-design-system/SKILL.md +282 -0
  327. package/dist/agents/skills/cursor/harness-design-system/skill.yaml +51 -0
  328. package/dist/agents/skills/cursor/harness-design-web/SKILL.md +360 -0
  329. package/dist/agents/skills/cursor/harness-design-web/skill.yaml +53 -0
  330. package/dist/agents/skills/cursor/harness-diagnostics/SKILL.md +318 -0
  331. package/dist/agents/skills/cursor/harness-diagnostics/skill.yaml +51 -0
  332. package/dist/agents/skills/cursor/harness-docs-pipeline/SKILL.md +460 -0
  333. package/dist/agents/skills/cursor/harness-docs-pipeline/skill.yaml +70 -0
  334. package/dist/agents/skills/cursor/harness-dx/SKILL.md +276 -0
  335. package/dist/agents/skills/cursor/harness-dx/skill.yaml +76 -0
  336. package/dist/agents/skills/cursor/harness-e2e/SKILL.md +245 -0
  337. package/dist/agents/skills/cursor/harness-e2e/skill.yaml +78 -0
  338. package/dist/agents/skills/cursor/harness-event-driven/SKILL.md +280 -0
  339. package/dist/agents/skills/cursor/harness-event-driven/skill.yaml +77 -0
  340. package/dist/agents/skills/cursor/harness-execution/SKILL.md +510 -0
  341. package/dist/agents/skills/cursor/harness-execution/skill.yaml +52 -0
  342. package/dist/agents/skills/cursor/harness-feature-flags/SKILL.md +287 -0
  343. package/dist/agents/skills/cursor/harness-feature-flags/skill.yaml +74 -0
  344. package/dist/agents/skills/cursor/harness-git-workflow/SKILL.md +268 -0
  345. package/dist/agents/skills/cursor/harness-git-workflow/skill.yaml +32 -0
  346. package/dist/agents/skills/cursor/harness-hotspot-detector/SKILL.md +161 -0
  347. package/dist/agents/skills/cursor/harness-hotspot-detector/skill.yaml +45 -0
  348. package/dist/agents/skills/cursor/harness-i18n/SKILL.md +484 -0
  349. package/dist/agents/skills/cursor/harness-i18n/skill.yaml +55 -0
  350. package/dist/agents/skills/cursor/harness-i18n-process/SKILL.md +388 -0
  351. package/dist/agents/skills/cursor/harness-i18n-process/skill.yaml +44 -0
  352. package/dist/agents/skills/cursor/harness-i18n-workflow/SKILL.md +512 -0
  353. package/dist/agents/skills/cursor/harness-i18n-workflow/skill.yaml +54 -0
  354. package/dist/agents/skills/cursor/harness-impact-analysis/SKILL.md +184 -0
  355. package/dist/agents/skills/cursor/harness-impact-analysis/skill.yaml +45 -0
  356. package/dist/agents/skills/cursor/harness-incident-response/SKILL.md +223 -0
  357. package/dist/agents/skills/cursor/harness-incident-response/skill.yaml +78 -0
  358. package/dist/agents/skills/cursor/harness-infrastructure-as-code/SKILL.md +279 -0
  359. package/dist/agents/skills/cursor/harness-infrastructure-as-code/skill.yaml +80 -0
  360. package/dist/agents/skills/cursor/harness-integration-test/SKILL.md +271 -0
  361. package/dist/agents/skills/cursor/harness-integration-test/skill.yaml +73 -0
  362. package/dist/agents/skills/cursor/harness-integrity/SKILL.md +167 -0
  363. package/dist/agents/skills/cursor/harness-integrity/skill.yaml +48 -0
  364. package/dist/agents/skills/cursor/harness-knowledge-mapper/SKILL.md +195 -0
  365. package/dist/agents/skills/cursor/harness-knowledge-mapper/skill.yaml +50 -0
  366. package/dist/agents/skills/cursor/harness-load-testing/SKILL.md +274 -0
  367. package/dist/agents/skills/cursor/harness-load-testing/skill.yaml +79 -0
  368. package/dist/agents/skills/cursor/harness-ml-ops/SKILL.md +341 -0
  369. package/dist/agents/skills/cursor/harness-ml-ops/skill.yaml +79 -0
  370. package/dist/agents/skills/cursor/harness-mobile-patterns/SKILL.md +326 -0
  371. package/dist/agents/skills/cursor/harness-mobile-patterns/skill.yaml +82 -0
  372. package/dist/agents/skills/cursor/harness-mutation-test/SKILL.md +251 -0
  373. package/dist/agents/skills/cursor/harness-mutation-test/skill.yaml +70 -0
  374. package/dist/agents/skills/cursor/harness-observability/SKILL.md +283 -0
  375. package/dist/agents/skills/cursor/harness-observability/skill.yaml +78 -0
  376. package/dist/agents/skills/cursor/harness-onboarding/SKILL.md +288 -0
  377. package/dist/agents/skills/cursor/harness-onboarding/skill.yaml +31 -0
  378. package/dist/agents/skills/cursor/harness-parallel-agents/SKILL.md +256 -0
  379. package/dist/agents/skills/cursor/harness-parallel-agents/skill.yaml +34 -0
  380. package/dist/agents/skills/cursor/harness-perf/SKILL.md +260 -0
  381. package/dist/agents/skills/cursor/harness-perf/skill.yaml +51 -0
  382. package/dist/agents/skills/cursor/harness-perf-tdd/SKILL.md +249 -0
  383. package/dist/agents/skills/cursor/harness-perf-tdd/skill.yaml +48 -0
  384. package/dist/agents/skills/cursor/harness-planning/SKILL.md +579 -0
  385. package/dist/agents/skills/cursor/harness-planning/skill.yaml +56 -0
  386. package/dist/agents/skills/cursor/harness-pre-commit-review/SKILL.md +324 -0
  387. package/dist/agents/skills/cursor/harness-pre-commit-review/skill.yaml +34 -0
  388. package/dist/agents/skills/cursor/harness-product-spec/SKILL.md +285 -0
  389. package/dist/agents/skills/cursor/harness-product-spec/skill.yaml +72 -0
  390. package/dist/agents/skills/cursor/harness-property-test/SKILL.md +281 -0
  391. package/dist/agents/skills/cursor/harness-property-test/skill.yaml +71 -0
  392. package/dist/agents/skills/cursor/harness-refactoring/SKILL.md +169 -0
  393. package/dist/agents/skills/cursor/harness-refactoring/skill.yaml +34 -0
  394. package/dist/agents/skills/cursor/harness-release-readiness/SKILL.md +689 -0
  395. package/dist/agents/skills/cursor/harness-release-readiness/skill.yaml +58 -0
  396. package/dist/agents/skills/cursor/harness-resilience/SKILL.md +255 -0
  397. package/dist/agents/skills/cursor/harness-resilience/skill.yaml +76 -0
  398. package/dist/agents/skills/cursor/harness-roadmap/SKILL.md +595 -0
  399. package/dist/agents/skills/cursor/harness-roadmap/skill.yaml +44 -0
  400. package/dist/agents/skills/cursor/harness-secrets/SKILL.md +293 -0
  401. package/dist/agents/skills/cursor/harness-secrets/skill.yaml +76 -0
  402. package/dist/agents/skills/cursor/harness-security-review/SKILL.md +260 -0
  403. package/dist/agents/skills/cursor/harness-security-review/skill.yaml +53 -0
  404. package/dist/agents/skills/cursor/harness-security-scan/SKILL.md +154 -0
  405. package/dist/agents/skills/cursor/harness-security-scan/skill.yaml +42 -0
  406. package/dist/agents/skills/cursor/harness-skill-authoring/SKILL.md +292 -0
  407. package/dist/agents/skills/cursor/harness-skill-authoring/skill.yaml +33 -0
  408. package/dist/agents/skills/cursor/harness-soundness-review/SKILL.md +1267 -0
  409. package/dist/agents/skills/cursor/harness-soundness-review/skill.yaml +49 -0
  410. package/dist/agents/skills/cursor/harness-sql-review/SKILL.md +315 -0
  411. package/dist/agents/skills/cursor/harness-sql-review/skill.yaml +74 -0
  412. package/dist/agents/skills/cursor/harness-state-management/SKILL.md +309 -0
  413. package/dist/agents/skills/cursor/harness-state-management/skill.yaml +33 -0
  414. package/dist/agents/skills/cursor/harness-supply-chain-audit/SKILL.md +281 -0
  415. package/dist/agents/skills/cursor/harness-supply-chain-audit/skill.yaml +51 -0
  416. package/dist/agents/skills/cursor/harness-tdd/SKILL.md +177 -0
  417. package/dist/agents/skills/cursor/harness-tdd/skill.yaml +49 -0
  418. package/dist/agents/skills/cursor/harness-test-advisor/SKILL.md +160 -0
  419. package/dist/agents/skills/cursor/harness-test-advisor/skill.yaml +45 -0
  420. package/dist/agents/skills/cursor/harness-test-data/SKILL.md +268 -0
  421. package/dist/agents/skills/cursor/harness-test-data/skill.yaml +74 -0
  422. package/dist/agents/skills/cursor/harness-ux-copy/SKILL.md +271 -0
  423. package/dist/agents/skills/cursor/harness-ux-copy/skill.yaml +77 -0
  424. package/dist/agents/skills/cursor/harness-verification/SKILL.md +421 -0
  425. package/dist/agents/skills/cursor/harness-verification/skill.yaml +43 -0
  426. package/dist/agents/skills/cursor/harness-verify/SKILL.md +159 -0
  427. package/dist/agents/skills/cursor/harness-verify/skill.yaml +41 -0
  428. package/dist/agents/skills/cursor/harness-visual-regression/SKILL.md +257 -0
  429. package/dist/agents/skills/cursor/harness-visual-regression/skill.yaml +74 -0
  430. package/dist/agents/skills/cursor/initialize-harness-project/SKILL.md +232 -0
  431. package/dist/agents/skills/cursor/initialize-harness-project/skill.yaml +32 -0
  432. package/dist/agents/skills/cursor/validate-context-engineering/SKILL.md +150 -0
  433. package/dist/agents/skills/cursor/validate-context-engineering/skill.yaml +32 -0
  434. package/dist/agents/skills/gemini-cli/enforce-architecture/SKILL.md +52 -0
  435. package/dist/agents/skills/gemini-cli/harness-api-design/SKILL.md +52 -0
  436. package/dist/agents/skills/gemini-cli/harness-architecture-advisor/SKILL.md +52 -0
  437. package/dist/agents/skills/gemini-cli/harness-auth/SKILL.md +52 -0
  438. package/dist/agents/skills/gemini-cli/harness-autopilot/SKILL.md +355 -45
  439. package/dist/agents/skills/gemini-cli/harness-autopilot/skill.yaml +12 -0
  440. package/dist/agents/skills/gemini-cli/harness-code-review/SKILL.md +97 -3
  441. package/dist/agents/skills/gemini-cli/harness-code-review/skill.yaml +6 -0
  442. package/dist/agents/skills/gemini-cli/harness-codebase-cleanup/SKILL.md +2 -4
  443. package/dist/agents/skills/gemini-cli/harness-database/SKILL.md +52 -0
  444. package/dist/agents/skills/gemini-cli/harness-deployment/SKILL.md +52 -0
  445. package/dist/agents/skills/gemini-cli/harness-planning/SKILL.md +99 -3
  446. package/dist/agents/skills/gemini-cli/harness-planning/skill.yaml +6 -0
  447. package/dist/agents/skills/gemini-cli/harness-pre-commit-review/SKILL.md +1 -1
  448. package/dist/agents/skills/gemini-cli/harness-product-spec/SKILL.md +5 -5
  449. package/dist/agents/skills/gemini-cli/harness-security-review/SKILL.md +27 -7
  450. package/dist/agents/skills/gemini-cli/harness-security-scan/SKILL.md +52 -0
  451. package/dist/agents/skills/gemini-cli/harness-supply-chain-audit/SKILL.md +281 -0
  452. package/dist/agents/skills/gemini-cli/harness-supply-chain-audit/skill.yaml +51 -0
  453. package/dist/agents/skills/package.json +1 -0
  454. package/dist/agents/skills/templates/discipline-template.md +49 -0
  455. package/dist/agents/skills/tests/schema.ts +1 -1
  456. package/dist/agents/skills/vitest.config.mts +5 -0
  457. package/dist/{agents-md-YTYQDA3P.js → agents-md-VYDFPIRW.js} +1 -1
  458. package/dist/{architecture-JQZYM4US.js → architecture-K5HSRBGB.js} +2 -2
  459. package/dist/bin/harness-mcp.js +13 -13
  460. package/dist/bin/harness.js +21 -19
  461. package/dist/{check-phase-gate-L3RADYWO.js → check-phase-gate-5AS6SXL6.js} +3 -3
  462. package/dist/{chunk-6KTUUFRN.js → chunk-5ZXHMCPL.js} +1 -1
  463. package/dist/{chunk-RCWZBSK5.js → chunk-6KWBH4EO.js} +1 -1
  464. package/dist/{chunk-ABQHQ6I5.js → chunk-ALFKNAZW.js} +2436 -233
  465. package/dist/{chunk-OXLLOSSR.js → chunk-AV6KMDO5.js} +2 -2
  466. package/dist/{chunk-7IP4JIFL.js → chunk-C7DTKLPW.js} +4 -4
  467. package/dist/{chunk-ZOAWBDWU.js → chunk-CJDVBBPB.js} +5 -1
  468. package/dist/{chunk-YPYGXRDR.js → chunk-DNDBFIZN.js} +18 -4
  469. package/dist/{chunk-XYLGHKG6.js → chunk-HKUX2X7O.js} +11 -2
  470. package/dist/{chunk-YZD2MRNQ.js → chunk-JOP2NDNB.js} +684 -142
  471. package/dist/{chunk-YBJ262QL.js → chunk-LRG3B43J.js} +1 -1
  472. package/dist/{chunk-AOZRDOIP.js → chunk-M6TIO6NF.js} +1 -1
  473. package/dist/{chunk-O5OJVPL6.js → chunk-OCDDCGDE.js} +9 -1
  474. package/dist/{chunk-OSXBPAMK.js → chunk-QDF7COPQ.js} +1 -1
  475. package/dist/{chunk-TPOTOBR7.js → chunk-RWZPHW4H.js} +3 -3
  476. package/dist/{chunk-3C2MLBPJ.js → chunk-SFRGPAK6.js} +1 -1
  477. package/dist/{chunk-XKECDXJS.js → chunk-SHYWICGA.js} +2184 -456
  478. package/dist/{chunk-S2FXOWOR.js → chunk-TF6ZLHJV.js} +2 -2
  479. package/dist/{chunk-NLVUVUGD.js → chunk-ZJMU7MEV.js} +1 -1
  480. package/dist/{ci-workflow-EQZFVX3P.js → ci-workflow-CRWU723U.js} +1 -1
  481. package/dist/{create-skill-XSWHMSM5.js → create-skill-NDXQSTIK.js} +2 -2
  482. package/dist/{dist-HWXF2C3R.js → dist-4LPXJYVZ.js} +105 -1
  483. package/dist/{docs-7ECGYMAV.js → docs-4JRHTLUZ.js} +3 -3
  484. package/dist/{engine-EG4EH4IX.js → engine-3G3VIM6L.js} +1 -1
  485. package/dist/{entropy-5USWKLVS.js → entropy-G6CZ2A6P.js} +2 -2
  486. package/dist/{feedback-UTBXZZHF.js → feedback-QYKQ65HB.js} +1 -1
  487. package/dist/{generate-agent-definitions-3PM5EU7V.js → generate-agent-definitions-SAAOAPT4.js} +3 -3
  488. package/dist/index.d.ts +25 -4
  489. package/dist/index.js +18 -18
  490. package/dist/{loader-ZPALXIVR.js → loader-VCOK3PF7.js} +1 -1
  491. package/dist/{mcp-362EZHF4.js → mcp-YENEPHBW.js} +13 -13
  492. package/dist/{performance-OQAFMJUD.js → performance-UBCFI2UP.js} +4 -2
  493. package/dist/{review-pipeline-C4GCFVGP.js → review-pipeline-IQAVCWAX.js} +1 -1
  494. package/dist/{runtime-7YLVK453.js → runtime-PYFFIESU.js} +1 -1
  495. package/dist/{security-PZOX7AQS.js → security-ZDADTPYW.js} +1 -1
  496. package/dist/{skill-executor-XZLYZYAK.js → skill-executor-XEVDGXUM.js} +2 -2
  497. package/dist/{validate-FD3Z6VJD.js → validate-VRTUHALQ.js} +2 -2
  498. package/dist/{validate-cross-check-WNJM6H2D.js → validate-cross-check-4Y6NHNK3.js} +1 -1
  499. package/package.json +8 -5
@@ -6,11 +6,11 @@ import {
6
6
  OutputMode,
7
7
  createCheckPhaseGateCommand,
8
8
  findFiles
9
- } from "./chunk-6KTUUFRN.js";
9
+ } from "./chunk-5ZXHMCPL.js";
10
10
  import {
11
11
  createGenerateAgentDefinitionsCommand,
12
12
  generateAgentDefinitions
13
- } from "./chunk-RCWZBSK5.js";
13
+ } from "./chunk-6KWBH4EO.js";
14
14
  import {
15
15
  listPersonas,
16
16
  loadPersona
@@ -20,13 +20,13 @@ import {
20
20
  } from "./chunk-TRAPF4IX.js";
21
21
  import {
22
22
  executeSkill
23
- } from "./chunk-AOZRDOIP.js";
23
+ } from "./chunk-M6TIO6NF.js";
24
24
  import {
25
25
  ALLOWED_PERSONA_COMMANDS
26
26
  } from "./chunk-TEFCFC4H.js";
27
27
  import {
28
28
  createCreateSkillCommand
29
- } from "./chunk-YBJ262QL.js";
29
+ } from "./chunk-LRG3B43J.js";
30
30
  import {
31
31
  logger
32
32
  } from "./chunk-EBJQ6N4M.js";
@@ -50,14 +50,14 @@ import {
50
50
  handleGetImpact,
51
51
  handleOrphanDeletion,
52
52
  persistToolingConfig
53
- } from "./chunk-YZD2MRNQ.js";
53
+ } from "./chunk-JOP2NDNB.js";
54
54
  import {
55
55
  VALID_PLATFORMS
56
- } from "./chunk-ZOAWBDWU.js";
56
+ } from "./chunk-CJDVBBPB.js";
57
57
  import {
58
58
  findConfigFile,
59
59
  resolveConfig
60
- } from "./chunk-O5OJVPL6.js";
60
+ } from "./chunk-OCDDCGDE.js";
61
61
  import {
62
62
  resolveGlobalSkillsDir,
63
63
  resolvePersonasDir,
@@ -72,7 +72,7 @@ import {
72
72
  } from "./chunk-3WGJMBKH.js";
73
73
  import {
74
74
  SkillMetadataSchema
75
- } from "./chunk-XYLGHKG6.js";
75
+ } from "./chunk-HKUX2X7O.js";
76
76
  import {
77
77
  CLI_VERSION
78
78
  } from "./chunk-BM3PWGXQ.js";
@@ -96,6 +96,10 @@ import {
96
96
  archiveStream,
97
97
  buildSnapshot,
98
98
  checkDocCoverage,
99
+ checkTaint,
100
+ clearTaint,
101
+ computeOverallSeverity,
102
+ computeScanExitCode,
99
103
  createFixes,
100
104
  createStream,
101
105
  deepMergeConstraints,
@@ -107,8 +111,11 @@ import {
107
111
  extractBundle,
108
112
  generateSuggestions,
109
113
  listStreams,
114
+ listTaintedSessions,
110
115
  loadState,
111
116
  loadStreamIndex,
117
+ mapInjectionFindings,
118
+ mapSecurityFindings,
112
119
  parseDiff,
113
120
  parseManifest,
114
121
  parseSecurityConfig,
@@ -121,20 +128,21 @@ import {
121
128
  runAll,
122
129
  runCIChecks,
123
130
  runReviewPipeline,
131
+ scanForInjection,
124
132
  setActiveStream,
125
133
  validateAgentsMap,
126
134
  validateDependencies,
127
135
  validateKnowledgeMap,
128
136
  writeConfig,
129
137
  writeLockfile
130
- } from "./chunk-ABQHQ6I5.js";
138
+ } from "./chunk-ALFKNAZW.js";
131
139
  import {
132
140
  Err,
133
141
  Ok
134
142
  } from "./chunk-ERS5EVUZ.js";
135
143
 
136
144
  // src/index.ts
137
- import { Command as Command55 } from "commander";
145
+ import { Command as Command70 } from "commander";
138
146
 
139
147
  // src/commands/validate.ts
140
148
  import { Command } from "commander";
@@ -213,7 +221,7 @@ function createValidateCommand() {
213
221
  process.exit(result.error.exitCode);
214
222
  }
215
223
  if (opts.crossCheck) {
216
- const { runCrossCheck: runCrossCheck2 } = await import("./validate-cross-check-WNJM6H2D.js");
224
+ const { runCrossCheck: runCrossCheck2 } = await import("./validate-cross-check-4Y6NHNK3.js");
217
225
  const cwd = process.cwd();
218
226
  const specsDir = path.join(cwd, "docs", "specs");
219
227
  const plansDir = path.join(cwd, "docs", "plans");
@@ -481,10 +489,10 @@ async function runCheckSecurity(cwd, options) {
481
489
  const projectRoot = path4.resolve(cwd);
482
490
  let configData = {};
483
491
  try {
484
- const fs23 = await import("fs");
492
+ const fs34 = await import("fs");
485
493
  const configPath = path4.join(projectRoot, "harness.config.json");
486
- if (fs23.existsSync(configPath)) {
487
- const raw = fs23.readFileSync(configPath, "utf-8");
494
+ if (fs34.existsSync(configPath)) {
495
+ const raw = fs34.readFileSync(configPath, "utf-8");
488
496
  const parsed = JSON.parse(raw);
489
497
  configData = parsed.security ?? {};
490
498
  }
@@ -570,7 +578,7 @@ function registerBenchCommand(perf) {
570
578
  perf.command("bench [glob]").description("Run benchmarks via vitest bench").action(async (glob, _opts, cmd) => {
571
579
  const globalOpts = cmd.optsWithGlobals();
572
580
  const cwd = process.cwd();
573
- const { BenchmarkRunner } = await import("./dist-HWXF2C3R.js");
581
+ const { BenchmarkRunner } = await import("./dist-4LPXJYVZ.js");
574
582
  const runner = new BenchmarkRunner();
575
583
  const benchFiles = runner.discover(cwd, glob);
576
584
  if (benchFiles.length === 0) {
@@ -638,7 +646,7 @@ function registerBaselinesCommands(perf) {
638
646
  baselines.command("update").description("Update baselines from latest benchmark run").action(async (_opts, cmd) => {
639
647
  const globalOpts = cmd.optsWithGlobals();
640
648
  const cwd = process.cwd();
641
- const { BenchmarkRunner } = await import("./dist-HWXF2C3R.js");
649
+ const { BenchmarkRunner } = await import("./dist-4LPXJYVZ.js");
642
650
  const runner = new BenchmarkRunner();
643
651
  const manager = new BaselineManager(cwd);
644
652
  logger.info("Running benchmarks to update baselines...");
@@ -671,7 +679,7 @@ function registerReportCommand(perf) {
671
679
  perf.command("report").description("Full performance report with metrics, trends, and hotspots").action(async (_opts, cmd) => {
672
680
  const globalOpts = cmd.optsWithGlobals();
673
681
  const cwd = process.cwd();
674
- const { EntropyAnalyzer: EntropyAnalyzer2 } = await import("./dist-HWXF2C3R.js");
682
+ const { EntropyAnalyzer: EntropyAnalyzer2 } = await import("./dist-4LPXJYVZ.js");
675
683
  const analyzer = new EntropyAnalyzer2({
676
684
  rootDir: path5.resolve(cwd),
677
685
  analyze: { complexity: true, coupling: true }
@@ -852,33 +860,248 @@ function createCheckDocsCommand() {
852
860
  // src/commands/init.ts
853
861
  import { Command as Command8 } from "commander";
854
862
  import chalk2 from "chalk";
855
- import * as fs2 from "fs";
856
- import * as path8 from "path";
863
+ import * as fs4 from "fs";
864
+ import * as path10 from "path";
857
865
 
858
866
  // src/commands/setup-mcp.ts
859
867
  import { Command as Command7 } from "commander";
860
- import * as fs from "fs";
861
- import * as path7 from "path";
868
+ import * as fs3 from "fs";
869
+ import * as path9 from "path";
862
870
  import * as os from "os";
863
871
  import chalk from "chalk";
864
- var HARNESS_MCP_ENTRY = {
865
- command: "harness-mcp"
866
- };
867
- function readJsonFile(filePath) {
872
+ import * as clack from "@clack/prompts";
873
+
874
+ // src/integrations/config.ts
875
+ import * as fs from "fs";
876
+ import * as path7 from "path";
877
+ function readJsonSafe(filePath) {
868
878
  if (!fs.existsSync(filePath)) return null;
869
879
  try {
870
880
  return JSON.parse(fs.readFileSync(filePath, "utf-8"));
871
881
  } catch {
872
- fs.copyFileSync(filePath, filePath + ".bak");
873
882
  return null;
874
883
  }
875
884
  }
876
- function writeJsonFile(filePath, data) {
885
+ function writeJson(filePath, data) {
877
886
  const dir = path7.dirname(filePath);
878
887
  if (!fs.existsSync(dir)) {
879
888
  fs.mkdirSync(dir, { recursive: true });
880
889
  }
881
- fs.writeFileSync(filePath, JSON.stringify(data, null, 2) + "\n");
890
+ const tmp = filePath + ".tmp";
891
+ fs.writeFileSync(tmp, JSON.stringify(data, null, 2) + "\n");
892
+ fs.renameSync(tmp, filePath);
893
+ }
894
+ function readMcpConfig(filePath) {
895
+ const config = readJsonSafe(filePath);
896
+ if (!config) return { mcpServers: {} };
897
+ if (!config.mcpServers) config.mcpServers = {};
898
+ return config;
899
+ }
900
+ function writeMcpEntry(filePath, name, entry) {
901
+ const config = readMcpConfig(filePath);
902
+ config.mcpServers[name] = entry;
903
+ writeJson(filePath, config);
904
+ }
905
+ function removeMcpEntry(filePath, name) {
906
+ if (!fs.existsSync(filePath)) return;
907
+ const config = readMcpConfig(filePath);
908
+ delete config.mcpServers[name];
909
+ writeJson(filePath, config);
910
+ }
911
+ function readIntegrationsConfig(configPath) {
912
+ const raw = readJsonSafe(configPath);
913
+ if (!raw || !raw.integrations) return { enabled: [], dismissed: [] };
914
+ const integ = raw.integrations;
915
+ return {
916
+ enabled: Array.isArray(integ.enabled) ? integ.enabled : [],
917
+ dismissed: Array.isArray(integ.dismissed) ? integ.dismissed : []
918
+ };
919
+ }
920
+ function writeIntegrationsConfig(configPath, integrations) {
921
+ const raw = readJsonSafe(configPath) ?? {};
922
+ raw.integrations = integrations;
923
+ writeJson(configPath, raw);
924
+ }
925
+
926
+ // src/integrations/toml.ts
927
+ import * as fs2 from "fs";
928
+ import * as path8 from "path";
929
+ function writeTomlMcpEntry(filePath, name, entry) {
930
+ const dir = path8.dirname(filePath);
931
+ if (!fs2.existsSync(dir)) {
932
+ fs2.mkdirSync(dir, { recursive: true });
933
+ }
934
+ const existing = fs2.existsSync(filePath) ? fs2.readFileSync(filePath, "utf-8") : "";
935
+ const blockHeader = `[mcp_servers.${name}]`;
936
+ const newBlock = serializeTomlMcpBlock(name, entry);
937
+ let updated;
938
+ if (existing.includes(blockHeader)) {
939
+ updated = replaceTomlBlock(existing, blockHeader, newBlock);
940
+ } else {
941
+ const separator = existing.length > 0 && !existing.endsWith("\n\n") ? "\n" : "";
942
+ updated = existing + separator + newBlock;
943
+ }
944
+ const tmp = filePath + ".tmp";
945
+ fs2.writeFileSync(tmp, updated);
946
+ fs2.renameSync(tmp, filePath);
947
+ }
948
+ function serializeTomlMcpBlock(name, entry) {
949
+ const lines = [`[mcp_servers.${name}]`];
950
+ lines.push(`command = ${JSON.stringify(entry.command)}`);
951
+ if (entry.args !== void 0) {
952
+ const argsLiteral = "[" + entry.args.map((a) => JSON.stringify(a)).join(", ") + "]";
953
+ lines.push(`args = ${argsLiteral}`);
954
+ }
955
+ if (entry.enabled !== void 0) {
956
+ lines.push(`enabled = ${entry.enabled}`);
957
+ }
958
+ return lines.join("\n") + "\n";
959
+ }
960
+ function replaceTomlBlock(content, blockHeader, newBlock) {
961
+ const lines = content.split("\n");
962
+ const startIdx = lines.findIndex((l) => l.trim() === blockHeader);
963
+ if (startIdx === -1) return content + newBlock;
964
+ let endIdx = lines.length;
965
+ for (let i = startIdx + 1; i < lines.length; i++) {
966
+ if (lines[i]?.match(/^\[(?!\[)/)) {
967
+ endIdx = i;
968
+ break;
969
+ }
970
+ }
971
+ while (endIdx > startIdx + 1 && lines[endIdx - 1]?.trim() === "") {
972
+ endIdx--;
973
+ }
974
+ const newBlockLines = newBlock.trimEnd().split("\n");
975
+ const result = [
976
+ ...lines.slice(0, startIdx),
977
+ ...newBlockLines,
978
+ ...endIdx < lines.length ? ["", ...lines.slice(endIdx)] : []
979
+ ];
980
+ return result.join("\n") + (content.endsWith("\n") ? "\n" : "");
981
+ }
982
+
983
+ // src/commands/setup-mcp.ts
984
+ var HARNESS_MCP_ENTRY = {
985
+ command: "harness-mcp"
986
+ };
987
+ var CURSOR_CURATED_TOOLS = [
988
+ "run_skill",
989
+ "validate_project",
990
+ "emit_interaction",
991
+ "check_docs",
992
+ "manage_roadmap",
993
+ "run_code_review",
994
+ "check_phase_gate",
995
+ "gather_context",
996
+ "find_context_for",
997
+ "get_impact",
998
+ "detect_entropy",
999
+ "run_security_scan",
1000
+ "assess_project",
1001
+ "manage_state",
1002
+ "create_self_review",
1003
+ "analyze_diff",
1004
+ "request_peer_review",
1005
+ "review_changes",
1006
+ "check_dependencies",
1007
+ "search_skills",
1008
+ "code_search",
1009
+ "code_outline",
1010
+ "ask_graph",
1011
+ "query_graph",
1012
+ "detect_anomalies"
1013
+ ];
1014
+ var ALL_MCP_TOOLS = [
1015
+ "validate_project",
1016
+ "check_dependencies",
1017
+ "check_docs",
1018
+ "detect_entropy",
1019
+ "generate_linter",
1020
+ "validate_linter_config",
1021
+ "init_project",
1022
+ "list_personas",
1023
+ "generate_persona_artifacts",
1024
+ "run_persona",
1025
+ "add_component",
1026
+ "run_agent_task",
1027
+ "run_skill",
1028
+ "manage_state",
1029
+ "create_self_review",
1030
+ "analyze_diff",
1031
+ "request_peer_review",
1032
+ "check_phase_gate",
1033
+ "validate_cross_check",
1034
+ "create_skill",
1035
+ "generate_slash_commands",
1036
+ "query_graph",
1037
+ "search_similar",
1038
+ "find_context_for",
1039
+ "get_relationships",
1040
+ "get_impact",
1041
+ "ingest_source",
1042
+ "generate_agent_definitions",
1043
+ "run_security_scan",
1044
+ "check_performance",
1045
+ "get_perf_baselines",
1046
+ "update_perf_baselines",
1047
+ "get_critical_paths",
1048
+ "list_streams",
1049
+ "manage_roadmap",
1050
+ "emit_interaction",
1051
+ "run_code_review",
1052
+ "gather_context",
1053
+ "assess_project",
1054
+ "review_changes",
1055
+ "detect_anomalies",
1056
+ "ask_graph",
1057
+ "check_task_independence",
1058
+ "predict_conflicts",
1059
+ "detect_stale_constraints",
1060
+ "search_skills",
1061
+ "code_outline",
1062
+ "code_search",
1063
+ "code_unfold"
1064
+ ];
1065
+ async function runCursorToolPicker() {
1066
+ try {
1067
+ const selected = await clack.multiselect({
1068
+ message: "Select tools to register for Cursor (25 recommended; Cursor supports ~40 across all servers)",
1069
+ options: ALL_MCP_TOOLS.map((tool) => {
1070
+ const opt = { value: tool, label: tool };
1071
+ if (CURSOR_CURATED_TOOLS.includes(tool)) opt.hint = "recommended";
1072
+ return opt;
1073
+ }),
1074
+ initialValues: CURSOR_CURATED_TOOLS
1075
+ });
1076
+ if (clack.isCancel(selected)) {
1077
+ return CURSOR_CURATED_TOOLS;
1078
+ }
1079
+ return selected;
1080
+ } catch {
1081
+ return CURSOR_CURATED_TOOLS;
1082
+ }
1083
+ }
1084
+ function writeCursorMcpEntryWithTools(configPath, tools) {
1085
+ writeMcpEntry(configPath, "harness", {
1086
+ command: "harness",
1087
+ args: ["mcp", "--tools", ...tools]
1088
+ });
1089
+ }
1090
+ function readJsonFile(filePath) {
1091
+ if (!fs3.existsSync(filePath)) return null;
1092
+ try {
1093
+ return JSON.parse(fs3.readFileSync(filePath, "utf-8"));
1094
+ } catch {
1095
+ fs3.copyFileSync(filePath, filePath + ".bak");
1096
+ return null;
1097
+ }
1098
+ }
1099
+ function writeJsonFile(filePath, data) {
1100
+ const dir = path9.dirname(filePath);
1101
+ if (!fs3.existsSync(dir)) {
1102
+ fs3.mkdirSync(dir, { recursive: true });
1103
+ }
1104
+ fs3.writeFileSync(filePath, JSON.stringify(data, null, 2) + "\n");
882
1105
  }
883
1106
  function configureMcpServer(configPath) {
884
1107
  const config = readJsonFile(configPath) ?? {};
@@ -893,7 +1116,7 @@ function configureMcpServer(configPath) {
893
1116
  return true;
894
1117
  }
895
1118
  function addGeminiTrustedFolder(cwd) {
896
- const trustedPath = path7.join(os.homedir(), ".gemini", "trustedFolders.json");
1119
+ const trustedPath = path9.join(os.homedir(), ".gemini", "trustedFolders.json");
897
1120
  const folders = readJsonFile(trustedPath) ?? {};
898
1121
  if (folders[cwd] === "TRUST_FOLDER") {
899
1122
  return false;
@@ -907,7 +1130,7 @@ function setupMcp(cwd, client) {
907
1130
  const skipped = [];
908
1131
  let trustedFolder = false;
909
1132
  if (client === "all" || client === "claude") {
910
- const configPath = path7.join(cwd, ".mcp.json");
1133
+ const configPath = path9.join(cwd, ".mcp.json");
911
1134
  if (configureMcpServer(configPath)) {
912
1135
  configured.push("Claude Code");
913
1136
  } else {
@@ -915,7 +1138,7 @@ function setupMcp(cwd, client) {
915
1138
  }
916
1139
  }
917
1140
  if (client === "all" || client === "gemini") {
918
- const configPath = path7.join(cwd, ".gemini", "settings.json");
1141
+ const configPath = path9.join(cwd, ".gemini", "settings.json");
919
1142
  if (configureMcpServer(configPath)) {
920
1143
  configured.push("Gemini CLI");
921
1144
  } else {
@@ -923,44 +1146,96 @@ function setupMcp(cwd, client) {
923
1146
  }
924
1147
  trustedFolder = addGeminiTrustedFolder(cwd);
925
1148
  }
1149
+ if (client === "all" || client === "codex") {
1150
+ const configPath = path9.join(cwd, ".codex", "config.toml");
1151
+ const alreadyConfigured = (() => {
1152
+ if (!fs3.existsSync(configPath)) return false;
1153
+ const content = fs3.readFileSync(configPath, "utf-8");
1154
+ return content.includes("[mcp_servers.harness]");
1155
+ })();
1156
+ if (alreadyConfigured) {
1157
+ skipped.push("Codex CLI");
1158
+ } else {
1159
+ writeTomlMcpEntry(configPath, "harness", {
1160
+ command: "harness",
1161
+ args: ["mcp"],
1162
+ enabled: true
1163
+ });
1164
+ configured.push("Codex CLI");
1165
+ }
1166
+ }
1167
+ if (client === "all" || client === "cursor") {
1168
+ const configPath = path9.join(cwd, ".cursor", "mcp.json");
1169
+ const existing = readJsonFile(configPath);
1170
+ if (existing?.mcpServers?.["harness"]) {
1171
+ skipped.push("Cursor");
1172
+ } else {
1173
+ writeMcpEntry(configPath, "harness", { command: "harness", args: ["mcp"] });
1174
+ configured.push("Cursor");
1175
+ }
1176
+ }
926
1177
  return { configured, skipped, trustedFolder };
927
1178
  }
1179
+ async function resolveCursorWithPicker(cwd, pick) {
1180
+ const configured = [];
1181
+ const skipped = [];
1182
+ const cursorConfigPath = path9.join(cwd, ".cursor", "mcp.json");
1183
+ const existing = readJsonFile(cursorConfigPath);
1184
+ if (existing?.mcpServers?.["harness"] && !pick) {
1185
+ skipped.push("Cursor");
1186
+ } else {
1187
+ const tools = pick ? await runCursorToolPicker() : CURSOR_CURATED_TOOLS;
1188
+ writeCursorMcpEntryWithTools(cursorConfigPath, tools);
1189
+ configured.push("Cursor");
1190
+ }
1191
+ return { configured, skipped };
1192
+ }
1193
+ function printMcpResult(configured, skipped, trustedFolder) {
1194
+ console.log("");
1195
+ if (configured.length > 0) {
1196
+ logger.success("MCP server configured!");
1197
+ console.log("");
1198
+ for (const name of configured) {
1199
+ console.log(` ${chalk.green("+")} ${name}`);
1200
+ }
1201
+ }
1202
+ if (trustedFolder) {
1203
+ console.log("");
1204
+ logger.info("Added project to Gemini trusted folders (~/.gemini/trustedFolders.json)");
1205
+ }
1206
+ if (skipped.length > 0) {
1207
+ console.log("");
1208
+ logger.info("Already configured:");
1209
+ for (const name of skipped) {
1210
+ console.log(` ${chalk.dim("-")} ${name}`);
1211
+ }
1212
+ }
1213
+ console.log("");
1214
+ console.log(chalk.bold("The harness MCP server provides:"));
1215
+ console.log(
1216
+ ` - ${ALL_MCP_TOOLS.length} tools for validation, entropy detection, skill execution, graph querying, and more`
1217
+ );
1218
+ console.log(
1219
+ " - 8 resources for project context, skills, rules, learnings, state, and graph data"
1220
+ );
1221
+ console.log("");
1222
+ console.log(`Run ${chalk.cyan("harness skill list")} to see available skills.`);
1223
+ console.log("");
1224
+ }
928
1225
  function createSetupMcpCommand() {
929
- return new Command7("setup-mcp").description("Configure MCP server for AI agent integration").option("--client <client>", "Client to configure (claude, gemini, all)", "all").action(async (opts, cmd) => {
1226
+ return new Command7("setup-mcp").description("Configure MCP server for AI agent integration").option("--client <client>", "Client to configure (claude, gemini, codex, cursor, all)", "all").option("--pick", "Launch interactive tool picker (Cursor only)").option("--yes", "Bypass interactive picker and use curated 25-tool set (Cursor only)").action(async (opts, cmd) => {
930
1227
  const globalOpts = cmd.optsWithGlobals();
931
1228
  const cwd = process.cwd();
932
- const { configured, skipped, trustedFolder } = setupMcp(cwd, opts.client);
1229
+ let configured;
1230
+ let skipped;
1231
+ let trustedFolder = false;
1232
+ if (opts.client === "cursor" && (opts.pick || opts.yes)) {
1233
+ ({ configured, skipped } = await resolveCursorWithPicker(cwd, opts.pick));
1234
+ } else {
1235
+ ({ configured, skipped, trustedFolder } = setupMcp(cwd, opts.client));
1236
+ }
933
1237
  if (!globalOpts.quiet) {
934
- console.log("");
935
- if (configured.length > 0) {
936
- logger.success("MCP server configured!");
937
- console.log("");
938
- for (const name of configured) {
939
- console.log(` ${chalk.green("+")} ${name}`);
940
- }
941
- }
942
- if (trustedFolder) {
943
- console.log("");
944
- logger.info("Added project to Gemini trusted folders (~/.gemini/trustedFolders.json)");
945
- }
946
- if (skipped.length > 0) {
947
- console.log("");
948
- logger.info("Already configured:");
949
- for (const name of skipped) {
950
- console.log(` ${chalk.dim("-")} ${name}`);
951
- }
952
- }
953
- console.log("");
954
- console.log(chalk.bold("The harness MCP server provides:"));
955
- console.log(
956
- " - 31 tools for validation, entropy detection, skill execution, graph querying, and more"
957
- );
958
- console.log(
959
- " - 8 resources for project context, skills, rules, learnings, state, and graph data"
960
- );
961
- console.log("");
962
- console.log(`Run ${chalk.cyan("harness skill list")} to see available skills.`);
963
- console.log("");
1238
+ printMcpResult(configured, skipped, trustedFolder);
964
1239
  }
965
1240
  process.exit(ExitCode.SUCCESS);
966
1241
  });
@@ -969,10 +1244,10 @@ function createSetupMcpCommand() {
969
1244
  // src/commands/init.ts
970
1245
  async function runInit(options) {
971
1246
  const cwd = options.cwd ?? process.cwd();
972
- const name = options.name ?? path8.basename(cwd);
1247
+ const name = options.name ?? path10.basename(cwd);
973
1248
  const force = options.force ?? false;
974
- const configPath = path8.join(cwd, "harness.config.json");
975
- if (!force && fs2.existsSync(configPath)) {
1249
+ const configPath = path10.join(cwd, "harness.config.json");
1250
+ if (!force && fs4.existsSync(configPath)) {
976
1251
  return Err(
977
1252
  new CLIError("Project already initialized. Use --force to overwrite.", ExitCode.ERROR)
978
1253
  );
@@ -1090,7 +1365,7 @@ function createInitCommand() {
1090
1365
 
1091
1366
  // src/commands/cleanup.ts
1092
1367
  import { Command as Command9 } from "commander";
1093
- import * as path9 from "path";
1368
+ import * as path11 from "path";
1094
1369
  async function runCleanup(options) {
1095
1370
  const cwd = options.cwd ?? process.cwd();
1096
1371
  const type = options.type ?? "all";
@@ -1105,11 +1380,11 @@ async function runCleanup(options) {
1105
1380
  patternViolations: [],
1106
1381
  totalIssues: 0
1107
1382
  };
1108
- const rootDir = path9.resolve(cwd, config.rootDir);
1109
- const docsDir = path9.resolve(cwd, config.docsDir);
1383
+ const rootDir = path11.resolve(cwd, config.rootDir);
1384
+ const docsDir = path11.resolve(cwd, config.docsDir);
1110
1385
  const entropyConfig = {
1111
1386
  rootDir,
1112
- entryPoints: [path9.join(rootDir, "src/index.ts")],
1387
+ entryPoints: [path11.join(rootDir, "src/index.ts")],
1113
1388
  docPaths: [docsDir],
1114
1389
  analyze: {
1115
1390
  drift: type === "all" || type === "drift",
@@ -1209,7 +1484,7 @@ function createCleanupCommand() {
1209
1484
 
1210
1485
  // src/commands/fix-drift.ts
1211
1486
  import { Command as Command10 } from "commander";
1212
- import * as path10 from "path";
1487
+ import * as path12 from "path";
1213
1488
  async function runFixDrift(options) {
1214
1489
  const cwd = options.cwd ?? process.cwd();
1215
1490
  const dryRun = options.dryRun !== false;
@@ -1218,11 +1493,11 @@ async function runFixDrift(options) {
1218
1493
  return Err(configResult.error);
1219
1494
  }
1220
1495
  const config = configResult.value;
1221
- const rootDir = path10.resolve(cwd, config.rootDir);
1222
- const docsDir = path10.resolve(cwd, config.docsDir);
1496
+ const rootDir = path12.resolve(cwd, config.rootDir);
1497
+ const docsDir = path12.resolve(cwd, config.docsDir);
1223
1498
  const entropyConfig = {
1224
1499
  rootDir,
1225
- entryPoints: [path10.join(rootDir, "src/index.ts")],
1500
+ entryPoints: [path12.join(rootDir, "src/index.ts")],
1226
1501
  docPaths: [docsDir],
1227
1502
  analyze: {
1228
1503
  drift: true,
@@ -1375,7 +1650,7 @@ import { Command as Command13 } from "commander";
1375
1650
 
1376
1651
  // src/commands/agent/run.ts
1377
1652
  import { Command as Command11 } from "commander";
1378
- import * as path11 from "path";
1653
+ import * as path13 from "path";
1379
1654
  import * as childProcess from "child_process";
1380
1655
  async function runAgentTask(task, options) {
1381
1656
  const configResult = resolveConfig(options.configPath);
@@ -1447,7 +1722,7 @@ function createCommandExecutor() {
1447
1722
  }
1448
1723
  async function runPersonaMode(opts, quiet) {
1449
1724
  const personasDir = resolvePersonasDir();
1450
- const filePath = path11.join(personasDir, `${opts.persona}.yaml`);
1725
+ const filePath = path13.join(personasDir, `${opts.persona}.yaml`);
1451
1726
  const personaResult = loadPersona(filePath);
1452
1727
  if (!personaResult.ok) {
1453
1728
  logger.error(personaResult.error.message);
@@ -1619,8 +1894,8 @@ function createAgentCommand() {
1619
1894
 
1620
1895
  // src/commands/add.ts
1621
1896
  import { Command as Command14 } from "commander";
1622
- import * as fs3 from "fs";
1623
- import * as path12 from "path";
1897
+ import * as fs5 from "fs";
1898
+ import * as path14 from "path";
1624
1899
  var LAYER_INDEX_TEMPLATE = (name) => `// ${name} layer
1625
1900
  // Add your ${name} exports here
1626
1901
 
@@ -1664,62 +1939,62 @@ async function runAdd(componentType, name, options) {
1664
1939
  try {
1665
1940
  switch (componentType) {
1666
1941
  case "layer": {
1667
- const layerDir = path12.join(cwd, "src", name);
1668
- if (!fs3.existsSync(layerDir)) {
1669
- fs3.mkdirSync(layerDir, { recursive: true });
1942
+ const layerDir = path14.join(cwd, "src", name);
1943
+ if (!fs5.existsSync(layerDir)) {
1944
+ fs5.mkdirSync(layerDir, { recursive: true });
1670
1945
  created.push(`src/${name}/`);
1671
1946
  }
1672
- const indexPath = path12.join(layerDir, "index.ts");
1673
- if (!fs3.existsSync(indexPath)) {
1674
- fs3.writeFileSync(indexPath, LAYER_INDEX_TEMPLATE(name));
1947
+ const indexPath = path14.join(layerDir, "index.ts");
1948
+ if (!fs5.existsSync(indexPath)) {
1949
+ fs5.writeFileSync(indexPath, LAYER_INDEX_TEMPLATE(name));
1675
1950
  created.push(`src/${name}/index.ts`);
1676
1951
  }
1677
1952
  break;
1678
1953
  }
1679
1954
  case "module": {
1680
- const modulePath = path12.join(cwd, "src", `${name}.ts`);
1681
- if (fs3.existsSync(modulePath)) {
1955
+ const modulePath = path14.join(cwd, "src", `${name}.ts`);
1956
+ if (fs5.existsSync(modulePath)) {
1682
1957
  return Err(new CLIError(`Module ${name} already exists`, ExitCode.ERROR));
1683
1958
  }
1684
- fs3.writeFileSync(modulePath, MODULE_TEMPLATE(name));
1959
+ fs5.writeFileSync(modulePath, MODULE_TEMPLATE(name));
1685
1960
  created.push(`src/${name}.ts`);
1686
1961
  break;
1687
1962
  }
1688
1963
  case "doc": {
1689
1964
  const configDocsDir = configResult.ok ? configResult.value.docsDir : "./docs";
1690
- const docsDir = path12.resolve(cwd, configDocsDir);
1691
- if (!fs3.existsSync(docsDir)) {
1692
- fs3.mkdirSync(docsDir, { recursive: true });
1965
+ const docsDir = path14.resolve(cwd, configDocsDir);
1966
+ if (!fs5.existsSync(docsDir)) {
1967
+ fs5.mkdirSync(docsDir, { recursive: true });
1693
1968
  }
1694
- const docPath = path12.join(docsDir, `${name}.md`);
1695
- if (fs3.existsSync(docPath)) {
1969
+ const docPath = path14.join(docsDir, `${name}.md`);
1970
+ if (fs5.existsSync(docPath)) {
1696
1971
  return Err(new CLIError(`Doc ${name} already exists`, ExitCode.ERROR));
1697
1972
  }
1698
- fs3.writeFileSync(docPath, DOC_TEMPLATE(name));
1973
+ fs5.writeFileSync(docPath, DOC_TEMPLATE(name));
1699
1974
  created.push(`${configDocsDir.replace(/^\.[\\/]/, "")}/${name}.md`);
1700
1975
  break;
1701
1976
  }
1702
1977
  case "skill": {
1703
- const { generateSkillFiles: generateSkillFiles2 } = await import("./create-skill-XSWHMSM5.js");
1978
+ const { generateSkillFiles: generateSkillFiles2 } = await import("./create-skill-NDXQSTIK.js");
1704
1979
  generateSkillFiles2({
1705
1980
  name,
1706
1981
  description: `${name} skill`,
1707
- outputDir: path12.join(cwd, "agents", "skills", "claude-code")
1982
+ outputDir: path14.join(cwd, "agents", "skills", "claude-code")
1708
1983
  });
1709
1984
  created.push(`agents/skills/claude-code/${name}/skill.yaml`);
1710
1985
  created.push(`agents/skills/claude-code/${name}/SKILL.md`);
1711
1986
  break;
1712
1987
  }
1713
1988
  case "persona": {
1714
- const personasDir = path12.join(cwd, "agents", "personas");
1715
- if (!fs3.existsSync(personasDir)) {
1716
- fs3.mkdirSync(personasDir, { recursive: true });
1989
+ const personasDir = path14.join(cwd, "agents", "personas");
1990
+ if (!fs5.existsSync(personasDir)) {
1991
+ fs5.mkdirSync(personasDir, { recursive: true });
1717
1992
  }
1718
- const personaPath = path12.join(personasDir, `${name}.yaml`);
1719
- if (fs3.existsSync(personaPath)) {
1993
+ const personaPath = path14.join(personasDir, `${name}.yaml`);
1994
+ if (fs5.existsSync(personaPath)) {
1720
1995
  return Err(new CLIError(`Persona ${name} already exists`, ExitCode.ERROR));
1721
1996
  }
1722
- fs3.writeFileSync(
1997
+ fs5.writeFileSync(
1723
1998
  personaPath,
1724
1999
  `name: ${name}
1725
2000
  description: ${name} persona
@@ -1905,46 +2180,46 @@ function createListCommand() {
1905
2180
 
1906
2181
  // src/commands/persona/generate.ts
1907
2182
  import { Command as Command19 } from "commander";
1908
- import * as fs4 from "fs";
1909
- import * as path13 from "path";
2183
+ import * as fs6 from "fs";
2184
+ import * as path15 from "path";
1910
2185
  function createGenerateCommand2() {
1911
2186
  return new Command19("generate").description("Generate artifacts from a persona config").argument("<name>", "Persona name (e.g., architecture-enforcer)").option("--output-dir <dir>", "Output directory", ".").option("--only <type>", "Generate only: ci, agents-md, runtime").action(async (name, opts, cmd) => {
1912
2187
  const globalOpts = cmd.optsWithGlobals();
1913
2188
  const personasDir = resolvePersonasDir();
1914
- const filePath = path13.join(personasDir, `${name}.yaml`);
2189
+ const filePath = path15.join(personasDir, `${name}.yaml`);
1915
2190
  const personaResult = loadPersona(filePath);
1916
2191
  if (!personaResult.ok) {
1917
2192
  logger.error(personaResult.error.message);
1918
2193
  process.exit(ExitCode.ERROR);
1919
2194
  }
1920
2195
  const persona = personaResult.value;
1921
- const outputDir = path13.resolve(opts.outputDir);
2196
+ const outputDir = path15.resolve(opts.outputDir);
1922
2197
  const slug = toKebabCase(persona.name);
1923
2198
  const only = opts.only;
1924
2199
  const generated = [];
1925
2200
  if (!only || only === "runtime") {
1926
2201
  const result = generateRuntime(persona);
1927
2202
  if (result.ok) {
1928
- const outPath = path13.join(outputDir, `${slug}.runtime.json`);
1929
- fs4.mkdirSync(path13.dirname(outPath), { recursive: true });
1930
- fs4.writeFileSync(outPath, result.value);
2203
+ const outPath = path15.join(outputDir, `${slug}.runtime.json`);
2204
+ fs6.mkdirSync(path15.dirname(outPath), { recursive: true });
2205
+ fs6.writeFileSync(outPath, result.value);
1931
2206
  generated.push(outPath);
1932
2207
  }
1933
2208
  }
1934
2209
  if (!only || only === "agents-md") {
1935
2210
  const result = generateAgentsMd(persona);
1936
2211
  if (result.ok) {
1937
- const outPath = path13.join(outputDir, `${slug}.agents.md`);
1938
- fs4.writeFileSync(outPath, result.value);
2212
+ const outPath = path15.join(outputDir, `${slug}.agents.md`);
2213
+ fs6.writeFileSync(outPath, result.value);
1939
2214
  generated.push(outPath);
1940
2215
  }
1941
2216
  }
1942
2217
  if (!only || only === "ci") {
1943
2218
  const result = generateCIWorkflow(persona, "github");
1944
2219
  if (result.ok) {
1945
- const outPath = path13.join(outputDir, ".github", "workflows", `${slug}.yml`);
1946
- fs4.mkdirSync(path13.dirname(outPath), { recursive: true });
1947
- fs4.writeFileSync(outPath, result.value);
2220
+ const outPath = path15.join(outputDir, ".github", "workflows", `${slug}.yml`);
2221
+ fs6.mkdirSync(path15.dirname(outPath), { recursive: true });
2222
+ fs6.writeFileSync(outPath, result.value);
1948
2223
  generated.push(outPath);
1949
2224
  }
1950
2225
  }
@@ -1969,13 +2244,13 @@ import { Command as Command28 } from "commander";
1969
2244
 
1970
2245
  // src/commands/skill/list.ts
1971
2246
  import { Command as Command21 } from "commander";
1972
- import * as fs6 from "fs";
1973
- import * as path15 from "path";
2247
+ import * as fs8 from "fs";
2248
+ import * as path17 from "path";
1974
2249
  import { parse } from "yaml";
1975
2250
 
1976
2251
  // src/registry/lockfile.ts
1977
- import * as fs5 from "fs";
1978
- import * as path14 from "path";
2252
+ import * as fs7 from "fs";
2253
+ import * as path16 from "path";
1979
2254
  function createEmptyLockfile() {
1980
2255
  return { version: 1, skills: {} };
1981
2256
  }
@@ -1995,10 +2270,10 @@ function sortedStringify(obj) {
1995
2270
  );
1996
2271
  }
1997
2272
  function readLockfile2(filePath) {
1998
- if (!fs5.existsSync(filePath)) {
2273
+ if (!fs7.existsSync(filePath)) {
1999
2274
  return createEmptyLockfile();
2000
2275
  }
2001
- const raw = fs5.readFileSync(filePath, "utf-8");
2276
+ const raw = fs7.readFileSync(filePath, "utf-8");
2002
2277
  let parsed;
2003
2278
  try {
2004
2279
  parsed = JSON.parse(raw);
@@ -2015,9 +2290,9 @@ function readLockfile2(filePath) {
2015
2290
  return parsed;
2016
2291
  }
2017
2292
  function writeLockfile2(filePath, lockfile) {
2018
- const dir = path14.dirname(filePath);
2019
- fs5.mkdirSync(dir, { recursive: true });
2020
- fs5.writeFileSync(filePath, sortedStringify(lockfile) + "\n", "utf-8");
2293
+ const dir = path16.dirname(filePath);
2294
+ fs7.mkdirSync(dir, { recursive: true });
2295
+ fs7.writeFileSync(filePath, sortedStringify(lockfile) + "\n", "utf-8");
2021
2296
  }
2022
2297
  function updateLockfileEntry(lockfile, name, entry) {
2023
2298
  return {
@@ -2041,14 +2316,14 @@ function removeLockfileEntry(lockfile, name) {
2041
2316
 
2042
2317
  // src/commands/skill/list.ts
2043
2318
  function scanDirectory(dirPath, source) {
2044
- if (!fs6.existsSync(dirPath)) return [];
2045
- const entries = fs6.readdirSync(dirPath, { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => d.name);
2319
+ if (!fs8.existsSync(dirPath)) return [];
2320
+ const entries = fs8.readdirSync(dirPath, { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => d.name);
2046
2321
  const skills = [];
2047
2322
  for (const name of entries) {
2048
- const yamlPath = path15.join(dirPath, name, "skill.yaml");
2049
- if (!fs6.existsSync(yamlPath)) continue;
2323
+ const yamlPath = path17.join(dirPath, name, "skill.yaml");
2324
+ if (!fs8.existsSync(yamlPath)) continue;
2050
2325
  try {
2051
- const raw = fs6.readFileSync(yamlPath, "utf-8");
2326
+ const raw = fs8.readFileSync(yamlPath, "utf-8");
2052
2327
  const parsed = parse(raw);
2053
2328
  const result = SkillMetadataSchema.safeParse(parsed);
2054
2329
  if (result.success) {
@@ -2066,10 +2341,10 @@ function scanDirectory(dirPath, source) {
2066
2341
  }
2067
2342
  function collectCommunitySkills(seen, allSkills) {
2068
2343
  const globalDir = resolveGlobalSkillsDir();
2069
- const skillsDir = path15.dirname(globalDir);
2070
- const communityBase = path15.join(skillsDir, "community");
2071
- const communityPlatformDir = path15.join(communityBase, "claude-code");
2072
- const lockfilePath = path15.join(communityBase, "skills-lock.json");
2344
+ const skillsDir = path17.dirname(globalDir);
2345
+ const communityBase = path17.join(skillsDir, "community");
2346
+ const communityPlatformDir = path17.join(communityBase, "claude-code");
2347
+ const lockfilePath = path17.join(communityBase, "skills-lock.json");
2073
2348
  const lockfile = readLockfile2(lockfilePath);
2074
2349
  const communitySkills = scanDirectory(communityPlatformDir, "community");
2075
2350
  for (const skill of communitySkills) {
@@ -2155,20 +2430,20 @@ function createListCommand2() {
2155
2430
 
2156
2431
  // src/commands/skill/run.ts
2157
2432
  import { Command as Command22 } from "commander";
2158
- import * as fs7 from "fs";
2159
- import * as path16 from "path";
2433
+ import * as fs9 from "fs";
2434
+ import * as path18 from "path";
2160
2435
  import { parse as parse2 } from "yaml";
2161
2436
 
2162
2437
  // src/skill/complexity.ts
2163
2438
  import { execFileSync as execFileSync2 } from "child_process";
2164
2439
  function evaluateSignals(signals) {
2165
- if (signals.fileCount >= 3) return "full";
2166
- if (signals.newDir) return "full";
2167
- if (signals.newDep) return "full";
2168
- if (signals.fileCount <= 1) return "light";
2169
- if (signals.testOnly) return "light";
2170
- if (signals.docsOnly) return "light";
2171
- return "full";
2440
+ if (signals.fileCount >= 3) return "thorough";
2441
+ if (signals.newDir) return "thorough";
2442
+ if (signals.newDep) return "thorough";
2443
+ if (signals.fileCount <= 1) return "fast";
2444
+ if (signals.testOnly) return "fast";
2445
+ if (signals.docsOnly) return "fast";
2446
+ return "thorough";
2172
2447
  }
2173
2448
  function detectComplexity(projectPath) {
2174
2449
  try {
@@ -2201,7 +2476,7 @@ function detectComplexity(projectPath) {
2201
2476
  };
2202
2477
  return evaluateSignals(signals);
2203
2478
  } catch {
2204
- return "full";
2479
+ return "thorough";
2205
2480
  }
2206
2481
  }
2207
2482
 
@@ -2211,8 +2486,8 @@ function buildPreamble(options) {
2211
2486
  if (options.complexity && options.phases && options.phases.length > 0) {
2212
2487
  const lines = [`## Active Phases (complexity: ${options.complexity})`];
2213
2488
  for (const phase of options.phases) {
2214
- if (options.complexity === "light" && !phase.required) {
2215
- lines.push(`- ~~${phase.name.toUpperCase()}~~ (skipped in light mode)`);
2489
+ if (options.complexity === "fast" && !phase.required) {
2490
+ lines.push(`- ~~${phase.name.toUpperCase()}~~ (skipped in fast mode)`);
2216
2491
  } else {
2217
2492
  lines.push(`- ${phase.name.toUpperCase()} (${phase.required ? "required" : "optional"})`);
2218
2493
  }
@@ -2244,10 +2519,10 @@ ${options.priorState}`);
2244
2519
 
2245
2520
  // src/commands/skill/run.ts
2246
2521
  function loadSkillMetadata(skillDir) {
2247
- const yamlPath = path16.join(skillDir, "skill.yaml");
2248
- if (!fs7.existsSync(yamlPath)) return null;
2522
+ const yamlPath = path18.join(skillDir, "skill.yaml");
2523
+ if (!fs9.existsSync(yamlPath)) return null;
2249
2524
  try {
2250
- const result = SkillMetadataSchema.safeParse(parse2(fs7.readFileSync(yamlPath, "utf-8")));
2525
+ const result = SkillMetadataSchema.safeParse(parse2(fs9.readFileSync(yamlPath, "utf-8")));
2251
2526
  return result.success ? result.data : null;
2252
2527
  } catch {
2253
2528
  return null;
@@ -2255,26 +2530,26 @@ function loadSkillMetadata(skillDir) {
2255
2530
  }
2256
2531
  function resolveComplexity(metadata, requested, projectPath) {
2257
2532
  if (!metadata?.phases || metadata.phases.length === 0) return void 0;
2258
- if (requested === "auto") return detectComplexity(projectPath);
2533
+ if (requested === "standard") return detectComplexity(projectPath);
2259
2534
  return requested;
2260
2535
  }
2261
2536
  function loadPrinciples(projectPath) {
2262
- const principlesPath = path16.join(projectPath, "docs", "principles.md");
2263
- return fs7.existsSync(principlesPath) ? fs7.readFileSync(principlesPath, "utf-8") : void 0;
2537
+ const principlesPath = path18.join(projectPath, "docs", "principles.md");
2538
+ return fs9.existsSync(principlesPath) ? fs9.readFileSync(principlesPath, "utf-8") : void 0;
2264
2539
  }
2265
2540
  function readMostRecentFileInDir(dirPath) {
2266
- const files = fs7.readdirSync(dirPath).map((f) => ({ name: f, mtime: fs7.statSync(path16.join(dirPath, f)).mtimeMs })).sort((a, b) => b.mtime - a.mtime);
2267
- if (files.length > 0) return fs7.readFileSync(path16.join(dirPath, files[0].name), "utf-8");
2541
+ const files = fs9.readdirSync(dirPath).map((f) => ({ name: f, mtime: fs9.statSync(path18.join(dirPath, f)).mtimeMs })).sort((a, b) => b.mtime - a.mtime);
2542
+ if (files.length > 0) return fs9.readFileSync(path18.join(dirPath, files[0].name), "utf-8");
2268
2543
  return void 0;
2269
2544
  }
2270
2545
  function loadPriorState(metadata, projectPath) {
2271
2546
  if (!metadata?.state.persistent || metadata.state.files.length === 0) return void 0;
2272
2547
  for (const stateFilePath of metadata.state.files) {
2273
- const fullPath = path16.join(projectPath, stateFilePath);
2274
- if (!fs7.existsSync(fullPath)) continue;
2275
- const stat = fs7.statSync(fullPath);
2548
+ const fullPath = path18.join(projectPath, stateFilePath);
2549
+ if (!fs9.existsSync(fullPath)) continue;
2550
+ const stat = fs9.statSync(fullPath);
2276
2551
  if (stat.isDirectory()) return readMostRecentFileInDir(fullPath);
2277
- return fs7.readFileSync(fullPath, "utf-8");
2552
+ return fs9.readFileSync(fullPath, "utf-8");
2278
2553
  }
2279
2554
  return void 0;
2280
2555
  }
@@ -2294,9 +2569,9 @@ function resolvePhaseState(metadata, projectPath, phase) {
2294
2569
  }
2295
2570
  function appendProjectState(content, metadata, projectPath, hasPathOpt) {
2296
2571
  if (!metadata?.state.persistent || !hasPathOpt) return content;
2297
- const stateFile = path16.join(projectPath, ".harness", "state.json");
2298
- if (!fs7.existsSync(stateFile)) return content;
2299
- const stateContent = fs7.readFileSync(stateFile, "utf-8");
2572
+ const stateFile = path18.join(projectPath, ".harness", "state.json");
2573
+ if (!fs9.existsSync(stateFile)) return content;
2574
+ const stateContent = fs9.readFileSync(stateFile, "utf-8");
2300
2575
  return content + `
2301
2576
 
2302
2577
  ---
@@ -2307,19 +2582,19 @@ ${stateContent}
2307
2582
  `;
2308
2583
  }
2309
2584
  function createRunCommand2() {
2310
- return new Command22("run").description("Run a skill (outputs SKILL.md content with context preamble)").argument("<name>", "Skill name (e.g., harness-tdd)").option("--path <path>", "Project root path for context injection").option("--complexity <level>", "Complexity: auto, light, full", "auto").option("--phase <name>", "Start at a specific phase (for re-entry)").option("--party", "Enable multi-perspective evaluation").action(async (name, opts, _cmd) => {
2585
+ return new Command22("run").description("Run a skill (outputs SKILL.md content with context preamble)").argument("<name>", "Skill name (e.g., harness-tdd)").option("--path <path>", "Project root path for context injection").option("--complexity <level>", "Rigor level: fast, standard, thorough", "standard").option("--phase <name>", "Start at a specific phase (for re-entry)").option("--party", "Enable multi-perspective evaluation").action(async (name, opts, _cmd) => {
2311
2586
  const skillsDir = resolveSkillsDir();
2312
- const skillDir = path16.join(skillsDir, name);
2313
- if (!fs7.existsSync(skillDir)) {
2587
+ const skillDir = path18.join(skillsDir, name);
2588
+ if (!fs9.existsSync(skillDir)) {
2314
2589
  logger.error(`Skill not found: ${name}`);
2315
2590
  process.exit(ExitCode.ERROR);
2316
2591
  return;
2317
2592
  }
2318
2593
  const metadata = loadSkillMetadata(skillDir);
2319
- const projectPath = opts.path ? path16.resolve(opts.path) : process.cwd();
2594
+ const projectPath = opts.path ? path18.resolve(opts.path) : process.cwd();
2320
2595
  const complexity = resolveComplexity(
2321
2596
  metadata,
2322
- opts.complexity ?? "auto",
2597
+ opts.complexity ?? "standard",
2323
2598
  projectPath
2324
2599
  );
2325
2600
  const principles = loadPrinciples(projectPath);
@@ -2343,14 +2618,14 @@ function createRunCommand2() {
2343
2618
  ...stateWarning !== void 0 && { stateWarning },
2344
2619
  party: opts.party
2345
2620
  });
2346
- const skillMdPath = path16.join(skillDir, "SKILL.md");
2347
- if (!fs7.existsSync(skillMdPath)) {
2621
+ const skillMdPath = path18.join(skillDir, "SKILL.md");
2622
+ if (!fs9.existsSync(skillMdPath)) {
2348
2623
  logger.error(`SKILL.md not found for skill: ${name}`);
2349
2624
  process.exit(ExitCode.ERROR);
2350
2625
  return;
2351
2626
  }
2352
2627
  const content = appendProjectState(
2353
- fs7.readFileSync(skillMdPath, "utf-8"),
2628
+ fs9.readFileSync(skillMdPath, "utf-8"),
2354
2629
  metadata,
2355
2630
  projectPath,
2356
2631
  !!opts.path
@@ -2362,8 +2637,8 @@ function createRunCommand2() {
2362
2637
 
2363
2638
  // src/commands/skill/validate.ts
2364
2639
  import { Command as Command23 } from "commander";
2365
- import * as fs8 from "fs";
2366
- import * as path17 from "path";
2640
+ import * as fs10 from "fs";
2641
+ import * as path19 from "path";
2367
2642
  import { parse as parse3 } from "yaml";
2368
2643
  var REQUIRED_SECTIONS = [
2369
2644
  "## When to Use",
@@ -2373,11 +2648,11 @@ var REQUIRED_SECTIONS = [
2373
2648
  "## Examples"
2374
2649
  ];
2375
2650
  function validateSkillMd(name, skillMdPath, skillType, errors) {
2376
- if (!fs8.existsSync(skillMdPath)) {
2651
+ if (!fs10.existsSync(skillMdPath)) {
2377
2652
  errors.push(`${name}: missing SKILL.md`);
2378
2653
  return;
2379
2654
  }
2380
- const mdContent = fs8.readFileSync(skillMdPath, "utf-8");
2655
+ const mdContent = fs10.readFileSync(skillMdPath, "utf-8");
2381
2656
  for (const section of REQUIRED_SECTIONS) {
2382
2657
  if (!mdContent.includes(section)) {
2383
2658
  errors.push(`${name}/SKILL.md: missing section "${section}"`);
@@ -2394,20 +2669,20 @@ function validateSkillMd(name, skillMdPath, skillType, errors) {
2394
2669
  }
2395
2670
  }
2396
2671
  function validateSkillEntry(name, skillsDir, errors) {
2397
- const skillDir = path17.join(skillsDir, name);
2398
- const yamlPath = path17.join(skillDir, "skill.yaml");
2399
- if (!fs8.existsSync(yamlPath)) {
2672
+ const skillDir = path19.join(skillsDir, name);
2673
+ const yamlPath = path19.join(skillDir, "skill.yaml");
2674
+ if (!fs10.existsSync(yamlPath)) {
2400
2675
  errors.push(`${name}: missing skill.yaml`);
2401
2676
  return false;
2402
2677
  }
2403
2678
  try {
2404
- const raw = fs8.readFileSync(yamlPath, "utf-8");
2679
+ const raw = fs10.readFileSync(yamlPath, "utf-8");
2405
2680
  const result = SkillMetadataSchema.safeParse(parse3(raw));
2406
2681
  if (!result.success) {
2407
2682
  errors.push(`${name}/skill.yaml: ${result.error.message}`);
2408
2683
  return false;
2409
2684
  }
2410
- validateSkillMd(name, path17.join(skillDir, "SKILL.md"), result.data.type, errors);
2685
+ validateSkillMd(name, path19.join(skillDir, "SKILL.md"), result.data.type, errors);
2411
2686
  return true;
2412
2687
  } catch (e) {
2413
2688
  errors.push(`${name}: parse error \u2014 ${e instanceof Error ? e.message : String(e)}`);
@@ -2418,12 +2693,12 @@ function createValidateCommand3() {
2418
2693
  return new Command23("validate").description("Validate all skill.yaml files and SKILL.md structure").action(async (_opts, cmd) => {
2419
2694
  const globalOpts = cmd.optsWithGlobals();
2420
2695
  const skillsDir = resolveSkillsDir();
2421
- if (!fs8.existsSync(skillsDir)) {
2696
+ if (!fs10.existsSync(skillsDir)) {
2422
2697
  logger.info("No skills directory found.");
2423
2698
  process.exit(ExitCode.SUCCESS);
2424
2699
  return;
2425
2700
  }
2426
- const entries = fs8.readdirSync(skillsDir, { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => d.name);
2701
+ const entries = fs10.readdirSync(skillsDir, { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => d.name);
2427
2702
  const errors = [];
2428
2703
  let validated = 0;
2429
2704
  for (const name of entries) {
@@ -2446,27 +2721,27 @@ function createValidateCommand3() {
2446
2721
 
2447
2722
  // src/commands/skill/info.ts
2448
2723
  import { Command as Command24 } from "commander";
2449
- import * as fs9 from "fs";
2450
- import * as path18 from "path";
2724
+ import * as fs11 from "fs";
2725
+ import * as path20 from "path";
2451
2726
  import { parse as parse4 } from "yaml";
2452
2727
  function createInfoCommand() {
2453
2728
  return new Command24("info").description("Show metadata for a skill").argument("<name>", "Skill name (e.g., harness-tdd)").action(async (name, _opts, cmd) => {
2454
2729
  const globalOpts = cmd.optsWithGlobals();
2455
2730
  const skillsDir = resolveSkillsDir();
2456
- const skillDir = path18.join(skillsDir, name);
2457
- if (!fs9.existsSync(skillDir)) {
2731
+ const skillDir = path20.join(skillsDir, name);
2732
+ if (!fs11.existsSync(skillDir)) {
2458
2733
  logger.error(`Skill not found: ${name}`);
2459
2734
  process.exit(ExitCode.ERROR);
2460
2735
  return;
2461
2736
  }
2462
- const yamlPath = path18.join(skillDir, "skill.yaml");
2463
- if (!fs9.existsSync(yamlPath)) {
2737
+ const yamlPath = path20.join(skillDir, "skill.yaml");
2738
+ if (!fs11.existsSync(yamlPath)) {
2464
2739
  logger.error(`skill.yaml not found for skill: ${name}`);
2465
2740
  process.exit(ExitCode.ERROR);
2466
2741
  return;
2467
2742
  }
2468
2743
  try {
2469
- const raw = fs9.readFileSync(yamlPath, "utf-8");
2744
+ const raw = fs11.readFileSync(yamlPath, "utf-8");
2470
2745
  const parsed = parse4(raw);
2471
2746
  const result = SkillMetadataSchema.safeParse(parsed);
2472
2747
  if (!result.success) {
@@ -2509,8 +2784,8 @@ function createInfoCommand() {
2509
2784
  import { Command as Command25 } from "commander";
2510
2785
 
2511
2786
  // src/registry/npm-client.ts
2512
- import * as fs10 from "fs";
2513
- import * as path19 from "path";
2787
+ import * as fs12 from "fs";
2788
+ import * as path21 from "path";
2514
2789
  import * as os2 from "os";
2515
2790
  var NPM_REGISTRY = "https://registry.npmjs.org";
2516
2791
  var FETCH_TIMEOUT_MS = 3e4;
@@ -2533,10 +2808,10 @@ function extractSkillName(packageName) {
2533
2808
  function readNpmrcToken(registryUrl) {
2534
2809
  const { hostname, pathname } = new URL(registryUrl);
2535
2810
  const registryPath = `//${hostname}${pathname.replace(/\/$/, "")}/:_authToken=`;
2536
- const candidates = [path19.join(process.cwd(), ".npmrc"), path19.join(os2.homedir(), ".npmrc")];
2811
+ const candidates = [path21.join(process.cwd(), ".npmrc"), path21.join(os2.homedir(), ".npmrc")];
2537
2812
  for (const npmrcPath of candidates) {
2538
2813
  try {
2539
- const content = fs10.readFileSync(npmrcPath, "utf-8");
2814
+ const content = fs12.readFileSync(npmrcPath, "utf-8");
2540
2815
  for (const line of content.split("\n")) {
2541
2816
  const trimmed = line.trim();
2542
2817
  if (trimmed.startsWith(registryPath)) {
@@ -2681,8 +2956,8 @@ Found ${results.length} skill(s):
2681
2956
 
2682
2957
  // src/commands/skill/create.ts
2683
2958
  import { Command as Command26 } from "commander";
2684
- import * as path20 from "path";
2685
- import * as fs11 from "fs";
2959
+ import * as path22 from "path";
2960
+ import * as fs13 from "fs";
2686
2961
  import YAML from "yaml";
2687
2962
  var KEBAB_CASE_RE = /^[a-z][a-z0-9]*(-[a-z0-9]+)*$/;
2688
2963
  function buildReadme(name, description) {
@@ -2766,22 +3041,22 @@ function runCreate(name, opts) {
2766
3041
  if (!KEBAB_CASE_RE.test(name)) {
2767
3042
  throw new Error(`Invalid skill name "${name}". Must be kebab-case (e.g., my-skill).`);
2768
3043
  }
2769
- const baseDir = opts.outputDir ?? path20.join(process.cwd(), "agents", "skills", "claude-code");
2770
- const skillDir = path20.join(baseDir, name);
2771
- if (fs11.existsSync(skillDir)) {
3044
+ const baseDir = opts.outputDir ?? path22.join(process.cwd(), "agents", "skills", "claude-code");
3045
+ const skillDir = path22.join(baseDir, name);
3046
+ if (fs13.existsSync(skillDir)) {
2772
3047
  throw new Error(`Skill directory already exists: ${skillDir}`);
2773
3048
  }
2774
- fs11.mkdirSync(skillDir, { recursive: true });
3049
+ fs13.mkdirSync(skillDir, { recursive: true });
2775
3050
  const description = opts.description || `A community skill: ${name}`;
2776
3051
  const skillYaml = buildSkillYaml(name, opts);
2777
- const skillYamlPath = path20.join(skillDir, "skill.yaml");
2778
- fs11.writeFileSync(skillYamlPath, YAML.stringify(skillYaml));
3052
+ const skillYamlPath = path22.join(skillDir, "skill.yaml");
3053
+ fs13.writeFileSync(skillYamlPath, YAML.stringify(skillYaml));
2779
3054
  const skillMd = buildSkillMd(name, description);
2780
- const skillMdPath = path20.join(skillDir, "SKILL.md");
2781
- fs11.writeFileSync(skillMdPath, skillMd);
3055
+ const skillMdPath = path22.join(skillDir, "SKILL.md");
3056
+ fs13.writeFileSync(skillMdPath, skillMd);
2782
3057
  const readme = buildReadme(name, description);
2783
- const readmePath = path20.join(skillDir, "README.md");
2784
- fs11.writeFileSync(readmePath, readme);
3058
+ const readmePath = path22.join(skillDir, "README.md");
3059
+ fs13.writeFileSync(readmePath, readme);
2785
3060
  return {
2786
3061
  name,
2787
3062
  directory: skillDir,
@@ -2809,7 +3084,7 @@ function createCreateCommand() {
2809
3084
  logger.info(`
2810
3085
  Next steps:`);
2811
3086
  logger.info(
2812
- ` 1. Edit ${path20.join(result.directory, "SKILL.md")} with your skill content`
3087
+ ` 1. Edit ${path22.join(result.directory, "SKILL.md")} with your skill content`
2813
3088
  );
2814
3089
  logger.info(` 2. Run: harness skill validate ${name}`);
2815
3090
  logger.info(` 3. Run: harness skills publish`);
@@ -2823,28 +3098,28 @@ Next steps:`);
2823
3098
 
2824
3099
  // src/commands/skill/publish.ts
2825
3100
  import { Command as Command27 } from "commander";
2826
- import * as fs14 from "fs";
2827
- import * as path23 from "path";
3101
+ import * as fs16 from "fs";
3102
+ import * as path25 from "path";
2828
3103
  import { execFileSync as execFileSync3 } from "child_process";
2829
3104
 
2830
3105
  // src/registry/validator.ts
2831
- import * as fs13 from "fs";
2832
- import * as path22 from "path";
3106
+ import * as fs15 from "fs";
3107
+ import * as path24 from "path";
2833
3108
  import { parse as parse5 } from "yaml";
2834
3109
  import semver from "semver";
2835
3110
 
2836
3111
  // src/registry/bundled-skills.ts
2837
- import * as fs12 from "fs";
2838
- import * as path21 from "path";
3112
+ import * as fs14 from "fs";
3113
+ import * as path23 from "path";
2839
3114
  function getBundledSkillNames(bundledSkillsDir) {
2840
- if (!fs12.existsSync(bundledSkillsDir)) {
3115
+ if (!fs14.existsSync(bundledSkillsDir)) {
2841
3116
  return /* @__PURE__ */ new Set();
2842
3117
  }
2843
- const entries = fs12.readdirSync(bundledSkillsDir);
3118
+ const entries = fs14.readdirSync(bundledSkillsDir);
2844
3119
  const names = /* @__PURE__ */ new Set();
2845
3120
  for (const entry of entries) {
2846
3121
  try {
2847
- const stat = fs12.statSync(path21.join(bundledSkillsDir, String(entry)));
3122
+ const stat = fs14.statSync(path23.join(bundledSkillsDir, String(entry)));
2848
3123
  if (stat.isDirectory()) {
2849
3124
  names.add(String(entry));
2850
3125
  }
@@ -2857,14 +3132,14 @@ function getBundledSkillNames(bundledSkillsDir) {
2857
3132
  // src/registry/validator.ts
2858
3133
  async function validateForPublish(skillDir, registryUrl) {
2859
3134
  const errors = [];
2860
- const skillYamlPath = path22.join(skillDir, "skill.yaml");
2861
- if (!fs13.existsSync(skillYamlPath)) {
3135
+ const skillYamlPath = path24.join(skillDir, "skill.yaml");
3136
+ if (!fs15.existsSync(skillYamlPath)) {
2862
3137
  errors.push("skill.yaml not found. Create one with: harness skill create <name>");
2863
3138
  return { valid: false, errors };
2864
3139
  }
2865
3140
  let skillMeta;
2866
3141
  try {
2867
- const raw = fs13.readFileSync(skillYamlPath, "utf-8");
3142
+ const raw = fs15.readFileSync(skillYamlPath, "utf-8");
2868
3143
  const parsed = parse5(raw);
2869
3144
  const result = SkillMetadataSchema.safeParse(parsed);
2870
3145
  if (!result.success) {
@@ -2886,11 +3161,11 @@ async function validateForPublish(skillDir, registryUrl) {
2886
3161
  if (!skillMeta.triggers || skillMeta.triggers.length === 0) {
2887
3162
  errors.push("At least one trigger is required. Add triggers to skill.yaml.");
2888
3163
  }
2889
- const skillMdPath = path22.join(skillDir, "SKILL.md");
2890
- if (!fs13.existsSync(skillMdPath)) {
3164
+ const skillMdPath = path24.join(skillDir, "SKILL.md");
3165
+ if (!fs15.existsSync(skillMdPath)) {
2891
3166
  errors.push("SKILL.md not found. Create it with content describing your skill.");
2892
3167
  } else {
2893
- const content = fs13.readFileSync(skillMdPath, "utf-8");
3168
+ const content = fs15.readFileSync(skillMdPath, "utf-8");
2894
3169
  if (!content.includes("## When to Use")) {
2895
3170
  errors.push('SKILL.md must contain a "## When to Use" section.');
2896
3171
  }
@@ -2970,11 +3245,11 @@ ${errorList}`);
2970
3245
  }
2971
3246
  const meta = validation.skillMeta;
2972
3247
  const pkg = derivePackageJson(meta);
2973
- const pkgPath = path23.join(skillDir, "package.json");
2974
- fs14.writeFileSync(pkgPath, JSON.stringify(pkg, null, 2) + "\n");
2975
- const readmePath = path23.join(skillDir, "README.md");
2976
- if (!fs14.existsSync(readmePath)) {
2977
- const skillMdContent = fs14.readFileSync(path23.join(skillDir, "SKILL.md"), "utf-8");
3248
+ const pkgPath = path25.join(skillDir, "package.json");
3249
+ fs16.writeFileSync(pkgPath, JSON.stringify(pkg, null, 2) + "\n");
3250
+ const readmePath = path25.join(skillDir, "README.md");
3251
+ if (!fs16.existsSync(readmePath)) {
3252
+ const skillMdContent = fs16.readFileSync(path25.join(skillDir, "SKILL.md"), "utf-8");
2978
3253
  const readme = `# ${pkg.name}
2979
3254
 
2980
3255
  ${meta.description}
@@ -2988,7 +3263,7 @@ harness install ${meta.name}
2988
3263
  ---
2989
3264
 
2990
3265
  ${skillMdContent}`;
2991
- fs14.writeFileSync(readmePath, readme);
3266
+ fs16.writeFileSync(readmePath, readme);
2992
3267
  }
2993
3268
  if (opts.dryRun) {
2994
3269
  return {
@@ -3055,11 +3330,11 @@ import { Command as Command33 } from "commander";
3055
3330
 
3056
3331
  // src/commands/state/show.ts
3057
3332
  import { Command as Command29 } from "commander";
3058
- import * as path24 from "path";
3333
+ import * as path26 from "path";
3059
3334
  function createShowCommand() {
3060
3335
  return new Command29("show").description("Show current project state").option("--path <path>", "Project root path", ".").option("--stream <name>", "Target a specific stream").action(async (opts, cmd) => {
3061
3336
  const globalOpts = cmd.optsWithGlobals();
3062
- const projectPath = path24.resolve(opts.path);
3337
+ const projectPath = path26.resolve(opts.path);
3063
3338
  const result = await loadState(projectPath, opts.stream);
3064
3339
  if (!result.ok) {
3065
3340
  logger.error(result.error.message);
@@ -3100,12 +3375,12 @@ Decisions: ${state.decisions.length}`);
3100
3375
 
3101
3376
  // src/commands/state/reset.ts
3102
3377
  import { Command as Command30 } from "commander";
3103
- import * as fs15 from "fs";
3104
- import * as path25 from "path";
3378
+ import * as fs17 from "fs";
3379
+ import * as path27 from "path";
3105
3380
  import * as readline from "readline";
3106
3381
  function createResetCommand() {
3107
3382
  return new Command30("reset").description("Reset project state (deletes .harness/state.json)").option("--path <path>", "Project root path", ".").option("--stream <name>", "Target a specific stream").option("--yes", "Skip confirmation prompt").action(async (opts, _cmd) => {
3108
- const projectPath = path25.resolve(opts.path);
3383
+ const projectPath = path27.resolve(opts.path);
3109
3384
  let statePath;
3110
3385
  if (opts.stream) {
3111
3386
  const streamResult = await resolveStreamPath(projectPath, { stream: opts.stream });
@@ -3114,19 +3389,19 @@ function createResetCommand() {
3114
3389
  process.exit(ExitCode.ERROR);
3115
3390
  return;
3116
3391
  }
3117
- statePath = path25.join(streamResult.value, "state.json");
3392
+ statePath = path27.join(streamResult.value, "state.json");
3118
3393
  } else {
3119
- statePath = path25.join(projectPath, ".harness", "state.json");
3394
+ statePath = path27.join(projectPath, ".harness", "state.json");
3120
3395
  }
3121
- if (!fs15.existsSync(statePath)) {
3396
+ if (!fs17.existsSync(statePath)) {
3122
3397
  logger.info("No state file found. Nothing to reset.");
3123
3398
  process.exit(ExitCode.SUCCESS);
3124
3399
  return;
3125
3400
  }
3126
3401
  if (!opts.yes) {
3127
3402
  const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
3128
- const answer = await new Promise((resolve29) => {
3129
- rl.question("Reset project state? This cannot be undone. [y/N] ", resolve29);
3403
+ const answer = await new Promise((resolve31) => {
3404
+ rl.question("Reset project state? This cannot be undone. [y/N] ", resolve31);
3130
3405
  });
3131
3406
  rl.close();
3132
3407
  if (answer.toLowerCase() !== "y" && answer.toLowerCase() !== "yes") {
@@ -3136,7 +3411,7 @@ function createResetCommand() {
3136
3411
  }
3137
3412
  }
3138
3413
  try {
3139
- fs15.unlinkSync(statePath);
3414
+ fs17.unlinkSync(statePath);
3140
3415
  logger.success("Project state reset.");
3141
3416
  } catch (e) {
3142
3417
  logger.error(`Failed to reset state: ${e instanceof Error ? e.message : String(e)}`);
@@ -3149,10 +3424,10 @@ function createResetCommand() {
3149
3424
 
3150
3425
  // src/commands/state/learn.ts
3151
3426
  import { Command as Command31 } from "commander";
3152
- import * as path26 from "path";
3427
+ import * as path28 from "path";
3153
3428
  function createLearnCommand() {
3154
3429
  return new Command31("learn").description("Append a learning to .harness/learnings.md").argument("<message>", "The learning to record").option("--path <path>", "Project root path", ".").option("--stream <name>", "Target a specific stream").action(async (message, opts, _cmd) => {
3155
- const projectPath = path26.resolve(opts.path);
3430
+ const projectPath = path28.resolve(opts.path);
3156
3431
  const result = await appendLearning(projectPath, message, void 0, void 0, opts.stream);
3157
3432
  if (!result.ok) {
3158
3433
  logger.error(result.error.message);
@@ -3166,12 +3441,12 @@ function createLearnCommand() {
3166
3441
 
3167
3442
  // src/commands/state/streams.ts
3168
3443
  import { Command as Command32 } from "commander";
3169
- import * as path27 from "path";
3444
+ import * as path29 from "path";
3170
3445
  function createStreamsCommand() {
3171
3446
  const command = new Command32("streams").description("Manage state streams");
3172
3447
  command.command("list").description("List all known streams").option("--path <path>", "Project root path", ".").action(async (opts, cmd) => {
3173
3448
  const globalOpts = cmd.optsWithGlobals();
3174
- const projectPath = path27.resolve(opts.path);
3449
+ const projectPath = path29.resolve(opts.path);
3175
3450
  const indexResult = await loadStreamIndex(projectPath);
3176
3451
  const result = await listStreams(projectPath);
3177
3452
  if (!result.ok) {
@@ -3195,7 +3470,7 @@ function createStreamsCommand() {
3195
3470
  process.exit(ExitCode.SUCCESS);
3196
3471
  });
3197
3472
  command.command("create <name>").description("Create a new stream").option("--path <path>", "Project root path", ".").option("--branch <branch>", "Associate with a git branch").action(async (name, opts) => {
3198
- const projectPath = path27.resolve(opts.path);
3473
+ const projectPath = path29.resolve(opts.path);
3199
3474
  const result = await createStream(projectPath, name, opts.branch);
3200
3475
  if (!result.ok) {
3201
3476
  logger.error(result.error.message);
@@ -3206,7 +3481,7 @@ function createStreamsCommand() {
3206
3481
  process.exit(ExitCode.SUCCESS);
3207
3482
  });
3208
3483
  command.command("archive <name>").description("Archive a stream").option("--path <path>", "Project root path", ".").action(async (name, opts) => {
3209
- const projectPath = path27.resolve(opts.path);
3484
+ const projectPath = path29.resolve(opts.path);
3210
3485
  const result = await archiveStream(projectPath, name);
3211
3486
  if (!result.ok) {
3212
3487
  logger.error(result.error.message);
@@ -3217,7 +3492,7 @@ function createStreamsCommand() {
3217
3492
  process.exit(ExitCode.SUCCESS);
3218
3493
  });
3219
3494
  command.command("activate <name>").description("Set the active stream").option("--path <path>", "Project root path", ".").action(async (name, opts) => {
3220
- const projectPath = path27.resolve(opts.path);
3495
+ const projectPath = path29.resolve(opts.path);
3221
3496
  const result = await setActiveStream(projectPath, name);
3222
3497
  if (!result.ok) {
3223
3498
  logger.error(result.error.message);
@@ -3240,59 +3515,518 @@ function createStateCommand() {
3240
3515
  return command;
3241
3516
  }
3242
3517
 
3243
- // src/commands/ci/index.ts
3244
- import { Command as Command36 } from "commander";
3245
-
3246
- // src/commands/ci/check.ts
3518
+ // src/commands/setup.ts
3247
3519
  import { Command as Command34 } from "commander";
3248
- var VALID_CHECKS = [
3249
- "validate",
3250
- "deps",
3251
- "docs",
3252
- "entropy",
3253
- "security",
3254
- "perf",
3255
- "phase-gate",
3256
- "arch"
3257
- ];
3258
- async function runCICheck(options) {
3259
- const configResult = resolveConfig(options.configPath);
3260
- if (!configResult.ok) {
3261
- return configResult;
3520
+ import * as fs19 from "fs";
3521
+ import * as os4 from "os";
3522
+ import * as path31 from "path";
3523
+ import chalk3 from "chalk";
3524
+
3525
+ // src/utils/first-run.ts
3526
+ import * as fs18 from "fs";
3527
+ import * as os3 from "os";
3528
+ import * as path30 from "path";
3529
+ var HARNESS_DIR = path30.join(os3.homedir(), ".harness");
3530
+ var MARKER_FILE = path30.join(HARNESS_DIR, ".setup-complete");
3531
+ function isFirstRun() {
3532
+ return !fs18.existsSync(MARKER_FILE);
3533
+ }
3534
+ function markSetupComplete() {
3535
+ fs18.mkdirSync(HARNESS_DIR, { recursive: true });
3536
+ fs18.writeFileSync(MARKER_FILE, "", "utf-8");
3537
+ }
3538
+ function printFirstRunWelcome() {
3539
+ try {
3540
+ if (!isFirstRun()) return;
3541
+ if (process.env.CI) return;
3542
+ if (process.argv.includes("--quiet")) return;
3543
+ process.stderr.write("Welcome to harness! Run `harness setup` to get started.\n");
3544
+ } catch {
3262
3545
  }
3263
- const input = {
3264
- projectRoot: process.cwd(),
3265
- config: configResult.value
3546
+ }
3547
+
3548
+ // src/utils/node-version.ts
3549
+ import semver2 from "semver";
3550
+ var REQUIRED_NODE_VERSION = ">=22.0.0";
3551
+ function checkNodeVersion() {
3552
+ return {
3553
+ satisfies: semver2.satisfies(process.version, REQUIRED_NODE_VERSION),
3554
+ current: process.version,
3555
+ required: ">=22"
3266
3556
  };
3267
- if (options.skip) input.skip = options.skip;
3268
- if (options.failOn) input.failOn = options.failOn;
3269
- const result = await runCIChecks(input);
3270
- if (!result.ok) {
3271
- return {
3272
- ok: false,
3273
- error: new CLIError(result.error.message, ExitCode.ERROR)
3274
- };
3557
+ }
3558
+
3559
+ // src/integrations/registry.ts
3560
+ var INTEGRATION_REGISTRY = [
3561
+ // --- Tier 0: zero-config (free, no API key) ---
3562
+ {
3563
+ name: "context7",
3564
+ displayName: "Context7",
3565
+ description: "Live version-pinned docs for 9,000+ libraries",
3566
+ tier: 0,
3567
+ mcpConfig: {
3568
+ command: "npx",
3569
+ args: ["-y", "@upstash/context7-mcp"]
3570
+ },
3571
+ platforms: ["claude-code", "gemini-cli"]
3572
+ },
3573
+ {
3574
+ name: "sequential-thinking",
3575
+ displayName: "Sequential Thinking",
3576
+ description: "Structured multi-step reasoning",
3577
+ tier: 0,
3578
+ mcpConfig: {
3579
+ command: "npx",
3580
+ args: ["-y", "@modelcontextprotocol/server-sequential-thinking"]
3581
+ },
3582
+ platforms: ["claude-code", "gemini-cli"]
3583
+ },
3584
+ {
3585
+ name: "playwright",
3586
+ displayName: "Playwright",
3587
+ description: "Browser automation for E2E testing",
3588
+ tier: 0,
3589
+ mcpConfig: {
3590
+ command: "npx",
3591
+ args: ["-y", "@playwright/mcp"]
3592
+ },
3593
+ platforms: ["claude-code", "gemini-cli"]
3594
+ },
3595
+ // --- Tier 1: API-key required ---
3596
+ {
3597
+ name: "perplexity",
3598
+ displayName: "Perplexity",
3599
+ description: "Real-time web search and deep research",
3600
+ tier: 1,
3601
+ envVar: "PERPLEXITY_API_KEY",
3602
+ mcpConfig: {
3603
+ command: "npx",
3604
+ args: ["-y", "perplexity-mcp"],
3605
+ env: { PERPLEXITY_API_KEY: "${PERPLEXITY_API_KEY}" }
3606
+ // harness-ignore SEC-SEC-002: env var placeholder, not a hardcoded secret
3607
+ },
3608
+ installHint: "Get an API key at https://perplexity.ai/settings/api",
3609
+ platforms: ["claude-code", "gemini-cli"]
3610
+ },
3611
+ {
3612
+ name: "augment-code",
3613
+ displayName: "Augment Code",
3614
+ description: "Semantic code search across codebase",
3615
+ tier: 1,
3616
+ envVar: "AUGMENT_SESSION_AUTH",
3617
+ mcpConfig: {
3618
+ command: "auggie",
3619
+ args: ["--mcp", "--mcp-auto-workspace"],
3620
+ env: { AUGMENT_SESSION_AUTH: "${AUGMENT_SESSION_AUTH}" }
3621
+ },
3622
+ installHint: "Install auggie CLI: npm i -g @augmentcode/auggie@latest && auggie login",
3623
+ platforms: ["claude-code", "gemini-cli"]
3275
3624
  }
3276
- return { ok: true, value: result.value };
3625
+ ];
3626
+
3627
+ // src/commands/setup.ts
3628
+ function checkNodeVersion2() {
3629
+ const result = checkNodeVersion();
3630
+ if (result.satisfies) {
3631
+ return { status: "pass", message: `Node.js ${result.current} (requires ${result.required})` };
3632
+ }
3633
+ return { status: "fail", message: `Node.js ${result.current} \u2014 requires ${result.required}` };
3277
3634
  }
3278
- function parseSkip(skip) {
3279
- if (!skip) return [];
3280
- return skip.split(",").map((s) => s.trim()).filter((s) => VALID_CHECKS.includes(s));
3635
+ function runSlashCommandGeneration() {
3636
+ try {
3637
+ const results = generateSlashCommands({
3638
+ global: true,
3639
+ platforms: ["claude-code", "gemini-cli", "codex", "cursor"],
3640
+ yes: true,
3641
+ includeGlobal: false,
3642
+ skillsDir: "",
3643
+ dryRun: false
3644
+ });
3645
+ const outputDirs = results.map((r) => r.outputDir).join(", ");
3646
+ return { status: "pass", message: `Generated global slash commands -> ${outputDirs}` };
3647
+ } catch (error) {
3648
+ const msg = error instanceof Error ? error.message : String(error);
3649
+ return { status: "fail", message: `Slash command generation failed \u2014 ${msg}` };
3650
+ }
3281
3651
  }
3282
- function parseFailOn(failOn) {
3283
- if (failOn === "warning") return "warning";
3284
- return "error";
3652
+ function detectClient(dirName) {
3653
+ return fs19.existsSync(path31.join(os4.homedir(), dirName));
3285
3654
  }
3286
- function createCheckCommand() {
3287
- return new Command34("check").description("Run all harness checks for CI (validate, deps, docs, entropy, phase-gate, arch)").option("--skip <checks>", "Comma-separated checks to skip (e.g., entropy,docs)").option("--fail-on <severity>", "Fail on severity level: error (default) or warning", "error").action(async (opts, cmd) => {
3288
- const globalOpts = cmd.optsWithGlobals();
3289
- const mode = resolveOutputMode(globalOpts);
3290
- const skip = parseSkip(opts.skip);
3291
- const failOn = parseFailOn(opts.failOn);
3292
- const result = await runCICheck({
3293
- configPath: globalOpts.config,
3294
- skip,
3295
- failOn
3655
+ async function runMcpSetup(cwd) {
3656
+ const results = [];
3657
+ const clients = [
3658
+ { name: "Claude Code", dir: ".claude", client: "claude", configTarget: ".mcp.json" },
3659
+ {
3660
+ name: "Gemini CLI",
3661
+ dir: ".gemini",
3662
+ client: "gemini",
3663
+ configTarget: ".gemini/settings.json"
3664
+ },
3665
+ { name: "Codex CLI", dir: ".codex", client: "codex", configTarget: ".codex/config.toml" },
3666
+ { name: "Cursor", dir: ".cursor", client: "cursor", configTarget: ".cursor/mcp.json" }
3667
+ ];
3668
+ for (const { name, dir, client, configTarget } of clients) {
3669
+ if (!detectClient(dir)) {
3670
+ results.push({
3671
+ status: "warn",
3672
+ message: `${name} not detected \u2014 skipped MCP configuration`
3673
+ });
3674
+ continue;
3675
+ }
3676
+ try {
3677
+ setupMcp(cwd, client);
3678
+ results.push({ status: "pass", message: `Configured MCP for ${name} -> ${configTarget}` });
3679
+ } catch (error) {
3680
+ const msg = error instanceof Error ? error.message : String(error);
3681
+ results.push({
3682
+ status: "fail",
3683
+ message: `MCP configuration failed for ${name} \u2014 ${msg}`
3684
+ });
3685
+ }
3686
+ }
3687
+ return results;
3688
+ }
3689
+ function formatStep(result) {
3690
+ const icon = result.status === "pass" ? chalk3.green("\u2713") : result.status === "warn" ? chalk3.yellow("\u26A0") : chalk3.red("\u2717");
3691
+ return ` ${icon} ${result.message}`;
3692
+ }
3693
+ function configureTier0Integrations(cwd) {
3694
+ try {
3695
+ const mcpPath = path31.join(cwd, ".mcp.json");
3696
+ const config = readMcpConfig(mcpPath);
3697
+ const tier0 = INTEGRATION_REGISTRY.filter((i) => i.tier === 0);
3698
+ const added = [];
3699
+ for (const integration of tier0) {
3700
+ if (config.mcpServers[integration.name]) continue;
3701
+ writeMcpEntry(mcpPath, integration.name, integration.mcpConfig);
3702
+ added.push(integration.displayName);
3703
+ }
3704
+ const geminiDir = path31.join(cwd, ".gemini");
3705
+ if (fs19.existsSync(geminiDir)) {
3706
+ const geminiPath = path31.join(geminiDir, "settings.json");
3707
+ const geminiConfig = readMcpConfig(geminiPath);
3708
+ for (const integration of tier0) {
3709
+ if (!geminiConfig.mcpServers[integration.name]) {
3710
+ writeMcpEntry(geminiPath, integration.name, integration.mcpConfig);
3711
+ }
3712
+ }
3713
+ }
3714
+ if (added.length === 0) {
3715
+ return { status: "pass", message: "Tier 0 MCP integrations already configured" };
3716
+ }
3717
+ return {
3718
+ status: "pass",
3719
+ message: `Configured ${added.length} MCP integrations: ${added.join(", ")}`
3720
+ };
3721
+ } catch (error) {
3722
+ const msg = error instanceof Error ? error.message : String(error);
3723
+ return { status: "fail", message: `Tier 0 integration configuration failed \u2014 ${msg}` };
3724
+ }
3725
+ }
3726
+ async function runSetup(cwd) {
3727
+ const steps = [];
3728
+ const nodeResult = checkNodeVersion2();
3729
+ steps.push(nodeResult);
3730
+ if (nodeResult.status === "fail") {
3731
+ return { steps, success: false };
3732
+ }
3733
+ const slashResult = runSlashCommandGeneration();
3734
+ steps.push(slashResult);
3735
+ const mcpResults = await runMcpSetup(cwd);
3736
+ steps.push(...mcpResults);
3737
+ const tier0Result = configureTier0Integrations(cwd);
3738
+ steps.push(tier0Result);
3739
+ const success = steps.every((s) => s.status !== "fail");
3740
+ if (success) {
3741
+ markSetupComplete();
3742
+ }
3743
+ return { steps, success };
3744
+ }
3745
+ function createSetupCommand() {
3746
+ return new Command34("setup").description("Configure harness environment: slash commands, MCP, and more").action(async () => {
3747
+ const cwd = process.cwd();
3748
+ console.log("");
3749
+ console.log(` ${chalk3.bold("harness setup")}`);
3750
+ console.log("");
3751
+ const { steps, success } = await runSetup(cwd);
3752
+ for (const step of steps) {
3753
+ console.log(formatStep(step));
3754
+ }
3755
+ console.log("");
3756
+ if (success) {
3757
+ console.log(" Setup complete. Next steps:");
3758
+ console.log(" - Open a project directory and run /harness:initialize-project");
3759
+ console.log(" - Or run harness init --name my-project to scaffold a new one");
3760
+ console.log(" - Run harness doctor anytime to check your environment");
3761
+ console.log("");
3762
+ }
3763
+ process.exit(success ? ExitCode.SUCCESS : ExitCode.VALIDATION_FAILED);
3764
+ });
3765
+ }
3766
+
3767
+ // src/commands/doctor.ts
3768
+ import { Command as Command35 } from "commander";
3769
+ import * as fs20 from "fs";
3770
+ import * as os5 from "os";
3771
+ import * as path32 from "path";
3772
+ import chalk4 from "chalk";
3773
+ function checkNodeVersion3() {
3774
+ const result = checkNodeVersion();
3775
+ if (result.satisfies) {
3776
+ return {
3777
+ name: "node",
3778
+ status: "pass",
3779
+ message: `Node.js ${result.current} (requires ${result.required})`
3780
+ };
3781
+ }
3782
+ return {
3783
+ name: "node",
3784
+ status: "fail",
3785
+ message: `Node.js ${result.current} (requires ${result.required})`,
3786
+ fix: "Install Node.js >= 22: https://nodejs.org/"
3787
+ };
3788
+ }
3789
+ function countCommandFiles(dir, ext) {
3790
+ try {
3791
+ return fs20.readdirSync(dir).filter((f) => f.endsWith(ext)).length;
3792
+ } catch {
3793
+ return 0;
3794
+ }
3795
+ }
3796
+ function checkSlashCommands() {
3797
+ const platforms = [
3798
+ {
3799
+ name: "Claude Code",
3800
+ dir: path32.join(os5.homedir(), ".claude", "commands", "harness"),
3801
+ ext: ".md",
3802
+ client: "claude-code"
3803
+ },
3804
+ {
3805
+ name: "Gemini CLI",
3806
+ dir: path32.join(os5.homedir(), ".gemini", "commands", "harness"),
3807
+ ext: ".toml",
3808
+ client: "gemini-cli"
3809
+ }
3810
+ ];
3811
+ return platforms.map(({ name, dir, ext, client }) => {
3812
+ const count = countCommandFiles(dir, ext);
3813
+ if (count > 0) {
3814
+ return {
3815
+ name: `slash-commands-${client}`,
3816
+ status: "pass",
3817
+ message: `Slash commands installed -> ${dir} (${count} commands)`
3818
+ };
3819
+ }
3820
+ return {
3821
+ name: `slash-commands-${client}`,
3822
+ status: "fail",
3823
+ message: `No slash commands found for ${name}`,
3824
+ fix: "Run: harness setup"
3825
+ };
3826
+ });
3827
+ }
3828
+ function checkMcpConfig(cwd) {
3829
+ const results = [];
3830
+ const claudeConfig = readMcpConfig(path32.join(cwd, ".mcp.json"));
3831
+ if (claudeConfig.mcpServers?.["harness"]) {
3832
+ results.push({
3833
+ name: "mcp-claude",
3834
+ status: "pass",
3835
+ message: "MCP configured for Claude Code"
3836
+ });
3837
+ } else {
3838
+ results.push({
3839
+ name: "mcp-claude",
3840
+ status: "fail",
3841
+ message: "MCP not configured for Claude Code",
3842
+ fix: "Run: harness setup-mcp --client claude"
3843
+ });
3844
+ }
3845
+ const geminiDir = path32.join(cwd, ".gemini");
3846
+ if (fs20.existsSync(geminiDir)) {
3847
+ const geminiConfig = readMcpConfig(path32.join(geminiDir, "settings.json"));
3848
+ if (geminiConfig.mcpServers?.["harness"]) {
3849
+ results.push({
3850
+ name: "mcp-gemini",
3851
+ status: "pass",
3852
+ message: "MCP configured for Gemini CLI"
3853
+ });
3854
+ } else {
3855
+ results.push({
3856
+ name: "mcp-gemini",
3857
+ status: "fail",
3858
+ message: "MCP not configured for Gemini CLI",
3859
+ fix: "Run: harness setup-mcp --client gemini"
3860
+ });
3861
+ }
3862
+ }
3863
+ return results;
3864
+ }
3865
+ function loadMcpPresence(cwd) {
3866
+ const mcpPath = path32.join(cwd, ".mcp.json");
3867
+ const geminiDir = path32.join(cwd, ".gemini");
3868
+ const hasGemini = fs20.existsSync(geminiDir);
3869
+ return {
3870
+ mcpConfig: readMcpConfig(mcpPath),
3871
+ geminiConfig: hasGemini ? readMcpConfig(path32.join(geminiDir, "settings.json")) : null,
3872
+ hasGemini
3873
+ };
3874
+ }
3875
+ function checkTier0Presence(def, presence) {
3876
+ const inClaude = !!presence.mcpConfig.mcpServers?.[def.name];
3877
+ const inGemini = !!presence.geminiConfig?.mcpServers?.[def.name];
3878
+ if (!inClaude) {
3879
+ return {
3880
+ name: `integration-${def.name}`,
3881
+ status: "fail",
3882
+ message: `${def.displayName} not configured. Run \`harness setup\` to fix.`,
3883
+ fix: "Run: harness setup"
3884
+ };
3885
+ }
3886
+ if (presence.hasGemini && !inGemini) {
3887
+ return {
3888
+ name: `integration-${def.name}`,
3889
+ status: "warn",
3890
+ message: `${def.displayName} missing from Gemini CLI config. Run \`harness setup\` to fix.`,
3891
+ fix: "Run: harness setup"
3892
+ };
3893
+ }
3894
+ return {
3895
+ name: `integration-${def.name}`,
3896
+ status: "pass",
3897
+ message: `${def.displayName} configured`
3898
+ };
3899
+ }
3900
+ function checkIntegrations(cwd) {
3901
+ const results = [];
3902
+ const presence = loadMcpPresence(cwd);
3903
+ const configPath = path32.join(cwd, "harness.config.json");
3904
+ const integrationsConfig = readIntegrationsConfig(configPath);
3905
+ for (const def of INTEGRATION_REGISTRY.filter((d) => d.tier === 0)) {
3906
+ results.push(checkTier0Presence(def, presence));
3907
+ }
3908
+ for (const def of INTEGRATION_REGISTRY.filter((d) => d.tier === 1)) {
3909
+ const enabled = integrationsConfig.enabled.includes(def.name);
3910
+ const dismissed = integrationsConfig.dismissed.includes(def.name);
3911
+ if (enabled && def.envVar && !process.env[def.envVar]) {
3912
+ results.push({
3913
+ name: `integration-${def.name}-env`,
3914
+ status: "warn",
3915
+ message: `${def.displayName} enabled but ${def.envVar} not set.`,
3916
+ ...def.installHint !== void 0 && { fix: def.installHint }
3917
+ });
3918
+ } else if (!enabled && !dismissed) {
3919
+ results.push({
3920
+ name: `integration-${def.name}`,
3921
+ status: "info",
3922
+ message: `${def.displayName} enables ${def.description.toLowerCase()}. Run \`harness integrations add ${def.name}\`.`
3923
+ });
3924
+ }
3925
+ }
3926
+ return results;
3927
+ }
3928
+ function runDoctor(cwd) {
3929
+ const checks = [];
3930
+ checks.push(checkNodeVersion3());
3931
+ checks.push(...checkSlashCommands());
3932
+ checks.push(...checkMcpConfig(cwd));
3933
+ checks.push(...checkIntegrations(cwd));
3934
+ const allPassed = checks.every((c) => c.status !== "fail");
3935
+ return { checks, allPassed };
3936
+ }
3937
+ function formatCheck(check) {
3938
+ const icons = {
3939
+ pass: chalk4.green("\u2713"),
3940
+ fail: chalk4.red("\u2717"),
3941
+ warn: chalk4.yellow("!"),
3942
+ info: chalk4.blue("\u2139")
3943
+ };
3944
+ const icon = icons[check.status];
3945
+ let line = ` ${icon} ${check.message}`;
3946
+ if ((check.status === "fail" || check.status === "warn") && check.fix) {
3947
+ line += `
3948
+ -> ${check.fix}`;
3949
+ }
3950
+ return line;
3951
+ }
3952
+ function createDoctorCommand() {
3953
+ return new Command35("doctor").description("Check environment health: Node version, slash commands, MCP configuration").action((_opts, cmd) => {
3954
+ const globalOpts = cmd.optsWithGlobals();
3955
+ const cwd = process.cwd();
3956
+ const useJson = globalOpts.json;
3957
+ const result = runDoctor(cwd);
3958
+ if (useJson) {
3959
+ console.log(JSON.stringify(result, null, 2));
3960
+ } else {
3961
+ console.log("");
3962
+ console.log(` ${chalk4.bold("harness doctor")}`);
3963
+ console.log("");
3964
+ for (const check of result.checks) {
3965
+ console.log(formatCheck(check));
3966
+ }
3967
+ console.log("");
3968
+ const passed = result.checks.filter((c) => c.status === "pass").length;
3969
+ const total = result.checks.length;
3970
+ console.log(` ${passed}/${total} checks passed`);
3971
+ console.log("");
3972
+ }
3973
+ process.exit(result.allPassed ? ExitCode.SUCCESS : ExitCode.VALIDATION_FAILED);
3974
+ });
3975
+ }
3976
+
3977
+ // src/commands/ci/index.ts
3978
+ import { Command as Command38 } from "commander";
3979
+
3980
+ // src/commands/ci/check.ts
3981
+ import { Command as Command36 } from "commander";
3982
+ var VALID_CHECKS = [
3983
+ "validate",
3984
+ "deps",
3985
+ "docs",
3986
+ "entropy",
3987
+ "security",
3988
+ "perf",
3989
+ "phase-gate",
3990
+ "arch"
3991
+ ];
3992
+ async function runCICheck(options) {
3993
+ const configResult = resolveConfig(options.configPath);
3994
+ if (!configResult.ok) {
3995
+ return configResult;
3996
+ }
3997
+ const input = {
3998
+ projectRoot: process.cwd(),
3999
+ config: configResult.value
4000
+ };
4001
+ if (options.skip) input.skip = options.skip;
4002
+ if (options.failOn) input.failOn = options.failOn;
4003
+ const result = await runCIChecks(input);
4004
+ if (!result.ok) {
4005
+ return {
4006
+ ok: false,
4007
+ error: new CLIError(result.error.message, ExitCode.ERROR)
4008
+ };
4009
+ }
4010
+ return { ok: true, value: result.value };
4011
+ }
4012
+ function parseSkip(skip) {
4013
+ if (!skip) return [];
4014
+ return skip.split(",").map((s) => s.trim()).filter((s) => VALID_CHECKS.includes(s));
4015
+ }
4016
+ function parseFailOn(failOn) {
4017
+ if (failOn === "warning") return "warning";
4018
+ return "error";
4019
+ }
4020
+ function createCheckCommand() {
4021
+ return new Command36("check").description("Run all harness checks for CI (validate, deps, docs, entropy, phase-gate, arch)").option("--skip <checks>", "Comma-separated checks to skip (e.g., entropy,docs)").option("--fail-on <severity>", "Fail on severity level: error (default) or warning", "error").action(async (opts, cmd) => {
4022
+ const globalOpts = cmd.optsWithGlobals();
4023
+ const mode = resolveOutputMode(globalOpts);
4024
+ const skip = parseSkip(opts.skip);
4025
+ const failOn = parseFailOn(opts.failOn);
4026
+ const result = await runCICheck({
4027
+ configPath: globalOpts.config,
4028
+ skip,
4029
+ failOn
3296
4030
  });
3297
4031
  if (!result.ok) {
3298
4032
  if (mode === OutputMode.JSON) {
@@ -3328,9 +4062,9 @@ function createCheckCommand() {
3328
4062
  }
3329
4063
 
3330
4064
  // src/commands/ci/init.ts
3331
- import { Command as Command35 } from "commander";
3332
- import * as fs16 from "fs";
3333
- import * as path28 from "path";
4065
+ import { Command as Command37 } from "commander";
4066
+ import * as fs21 from "fs";
4067
+ import * as path33 from "path";
3334
4068
  var ALL_CHECKS = [
3335
4069
  "validate",
3336
4070
  "deps",
@@ -3431,12 +4165,12 @@ function generateCIConfig(options) {
3431
4165
  });
3432
4166
  }
3433
4167
  function detectPlatform() {
3434
- if (fs16.existsSync(".github")) return "github";
3435
- if (fs16.existsSync(".gitlab-ci.yml")) return "gitlab";
4168
+ if (fs21.existsSync(".github")) return "github";
4169
+ if (fs21.existsSync(".gitlab-ci.yml")) return "gitlab";
3436
4170
  return null;
3437
4171
  }
3438
4172
  function createInitCommand2() {
3439
- return new Command35("init").description("Generate CI configuration for harness checks").option("--platform <platform>", "CI platform: github, gitlab, or generic").option("--checks <list>", "Comma-separated list of checks to include").action(async (opts, cmd) => {
4173
+ return new Command37("init").description("Generate CI configuration for harness checks").option("--platform <platform>", "CI platform: github, gitlab, or generic").option("--checks <list>", "Comma-separated list of checks to include").action(async (opts, cmd) => {
3440
4174
  const globalOpts = cmd.optsWithGlobals();
3441
4175
  const platform = opts.platform ?? detectPlatform() ?? "generic";
3442
4176
  const checks = opts.checks ? opts.checks.split(",").map((s) => s.trim()) : void 0;
@@ -3448,12 +4182,12 @@ function createInitCommand2() {
3448
4182
  process.exit(result.error.exitCode);
3449
4183
  }
3450
4184
  const { filename, content } = result.value;
3451
- const targetPath = path28.resolve(filename);
3452
- const dir = path28.dirname(targetPath);
3453
- fs16.mkdirSync(dir, { recursive: true });
3454
- fs16.writeFileSync(targetPath, content);
4185
+ const targetPath = path33.resolve(filename);
4186
+ const dir = path33.dirname(targetPath);
4187
+ fs21.mkdirSync(dir, { recursive: true });
4188
+ fs21.writeFileSync(targetPath, content);
3455
4189
  if (platform === "generic" && process.platform !== "win32") {
3456
- fs16.chmodSync(targetPath, "755");
4190
+ fs21.chmodSync(targetPath, "755");
3457
4191
  }
3458
4192
  if (globalOpts.json) {
3459
4193
  console.log(JSON.stringify({ file: filename, platform }));
@@ -3466,18 +4200,359 @@ function createInitCommand2() {
3466
4200
 
3467
4201
  // src/commands/ci/index.ts
3468
4202
  function createCICommand() {
3469
- const command = new Command36("ci").description("CI/CD integration commands");
4203
+ const command = new Command38("ci").description("CI/CD integration commands");
3470
4204
  command.addCommand(createCheckCommand());
3471
4205
  command.addCommand(createInitCommand2());
3472
4206
  return command;
3473
4207
  }
3474
4208
 
4209
+ // src/commands/hooks/index.ts
4210
+ import { Command as Command43 } from "commander";
4211
+
4212
+ // src/commands/hooks/init.ts
4213
+ import { Command as Command39 } from "commander";
4214
+ import * as fs22 from "fs";
4215
+ import * as path34 from "path";
4216
+ import { fileURLToPath } from "url";
4217
+
4218
+ // src/hooks/profiles.ts
4219
+ var HOOK_SCRIPTS = [
4220
+ { name: "block-no-verify", event: "PreToolUse", matcher: "Bash", minProfile: "minimal" },
4221
+ { name: "protect-config", event: "PreToolUse", matcher: "Write|Edit", minProfile: "standard" },
4222
+ { name: "quality-gate", event: "PostToolUse", matcher: "Edit|Write", minProfile: "standard" },
4223
+ { name: "pre-compact-state", event: "PreCompact", matcher: "*", minProfile: "standard" },
4224
+ { name: "cost-tracker", event: "Stop", matcher: "*", minProfile: "strict" },
4225
+ { name: "sentinel-pre", event: "PreToolUse", matcher: "*", minProfile: "strict" },
4226
+ { name: "sentinel-post", event: "PostToolUse", matcher: "*", minProfile: "strict" }
4227
+ ];
4228
+ var PROFILE_ORDER = ["minimal", "standard", "strict"];
4229
+ function hooksForProfile(profile) {
4230
+ const profileIndex = PROFILE_ORDER.indexOf(profile);
4231
+ return HOOK_SCRIPTS.filter((h) => PROFILE_ORDER.indexOf(h.minProfile) <= profileIndex).map(
4232
+ (h) => h.name
4233
+ );
4234
+ }
4235
+ var PROFILES = {
4236
+ minimal: hooksForProfile("minimal"),
4237
+ standard: hooksForProfile("standard"),
4238
+ strict: hooksForProfile("strict")
4239
+ };
4240
+
4241
+ // src/commands/hooks/init.ts
4242
+ var __filename = fileURLToPath(import.meta.url);
4243
+ var __dirname = path34.dirname(__filename);
4244
+ var VALID_PROFILES = ["minimal", "standard", "strict"];
4245
+ function resolveHookSourceDir() {
4246
+ const candidate = path34.resolve(__dirname, "..", "..", "hooks");
4247
+ if (fs22.existsSync(candidate)) {
4248
+ return candidate;
4249
+ }
4250
+ throw new Error(`Cannot locate hook scripts directory. Expected at: ${candidate}`);
4251
+ }
4252
+ function buildSettingsHooks(profile) {
4253
+ const activeHookNames = PROFILES[profile];
4254
+ const activeScripts = HOOK_SCRIPTS.filter((h) => activeHookNames.includes(h.name));
4255
+ const hooks = {};
4256
+ for (const script of activeScripts) {
4257
+ if (!hooks[script.event]) {
4258
+ hooks[script.event] = [];
4259
+ }
4260
+ hooks[script.event].push({
4261
+ matcher: script.matcher,
4262
+ hooks: [{ type: "command", command: `node .harness/hooks/${script.name}.js` }]
4263
+ });
4264
+ }
4265
+ return hooks;
4266
+ }
4267
+ function mergeSettings(existing, hooksConfig) {
4268
+ return {
4269
+ ...existing,
4270
+ hooks: hooksConfig
4271
+ };
4272
+ }
4273
+ function initHooks(options) {
4274
+ const { profile, projectDir } = options;
4275
+ const hooksDestDir = path34.join(projectDir, ".harness", "hooks");
4276
+ fs22.mkdirSync(hooksDestDir, { recursive: true });
4277
+ if (fs22.existsSync(hooksDestDir)) {
4278
+ for (const entry of fs22.readdirSync(hooksDestDir)) {
4279
+ if (entry.endsWith(".js")) {
4280
+ fs22.unlinkSync(path34.join(hooksDestDir, entry));
4281
+ }
4282
+ }
4283
+ }
4284
+ const sourceDir = resolveHookSourceDir();
4285
+ const copiedScripts = [];
4286
+ const activeNames = PROFILES[profile];
4287
+ const activeScripts = HOOK_SCRIPTS.filter((h) => activeNames.includes(h.name));
4288
+ for (const script of activeScripts) {
4289
+ const srcFile = path34.join(sourceDir, `${script.name}.js`);
4290
+ const destFile = path34.join(hooksDestDir, `${script.name}.js`);
4291
+ if (fs22.existsSync(srcFile)) {
4292
+ fs22.copyFileSync(srcFile, destFile);
4293
+ copiedScripts.push(script.name);
4294
+ }
4295
+ }
4296
+ const profilePath = path34.join(hooksDestDir, "profile.json");
4297
+ fs22.writeFileSync(profilePath, JSON.stringify({ profile }, null, 2) + "\n");
4298
+ const claudeDir = path34.join(projectDir, ".claude");
4299
+ fs22.mkdirSync(claudeDir, { recursive: true });
4300
+ const settingsPath = path34.join(claudeDir, "settings.json");
4301
+ let existing = {};
4302
+ if (fs22.existsSync(settingsPath)) {
4303
+ try {
4304
+ existing = JSON.parse(fs22.readFileSync(settingsPath, "utf-8"));
4305
+ } catch (e) {
4306
+ throw new Error(
4307
+ `Malformed .claude/settings.json \u2014 fix the JSON syntax before running hooks init. Parse error: ${e instanceof Error ? e.message : String(e)}`,
4308
+ { cause: e }
4309
+ );
4310
+ }
4311
+ }
4312
+ const hooksConfig = buildSettingsHooks(profile);
4313
+ const merged = mergeSettings(existing, hooksConfig);
4314
+ fs22.writeFileSync(settingsPath, JSON.stringify(merged, null, 2) + "\n");
4315
+ return { copiedScripts, settingsPath, profilePath };
4316
+ }
4317
+ function createInitCommand3() {
4318
+ return new Command39("init").description("Install Claude Code hook configurations into the current project").option("--profile <profile>", "Hook profile: minimal, standard, or strict", "standard").action(async (opts, cmd) => {
4319
+ const globalOpts = cmd.optsWithGlobals();
4320
+ const profile = opts.profile;
4321
+ if (!VALID_PROFILES.includes(profile)) {
4322
+ logger.error(`Invalid profile: ${profile}. Must be one of: ${VALID_PROFILES.join(", ")}`);
4323
+ process.exit(2);
4324
+ }
4325
+ const projectDir = process.cwd();
4326
+ try {
4327
+ const result = initHooks({ profile, projectDir });
4328
+ if (globalOpts.json) {
4329
+ console.log(
4330
+ JSON.stringify({
4331
+ profile,
4332
+ copiedScripts: result.copiedScripts,
4333
+ settingsPath: result.settingsPath,
4334
+ profilePath: result.profilePath
4335
+ })
4336
+ );
4337
+ } else {
4338
+ logger.success(
4339
+ `Installed ${result.copiedScripts.length} hook scripts to .harness/hooks/`
4340
+ );
4341
+ logger.info(`Profile: ${profile}`);
4342
+ logger.info(`Settings: ${path34.relative(projectDir, result.settingsPath)}`);
4343
+ logger.dim("Run 'harness hooks list' to see installed hooks");
4344
+ }
4345
+ } catch (err) {
4346
+ const message = err instanceof Error ? err.message : String(err);
4347
+ logger.error(`Failed to initialize hooks: ${message}`);
4348
+ process.exit(2);
4349
+ }
4350
+ });
4351
+ }
4352
+
4353
+ // src/commands/hooks/list.ts
4354
+ import { Command as Command40 } from "commander";
4355
+ import * as fs23 from "fs";
4356
+ import * as path35 from "path";
4357
+ function listHooks(projectDir) {
4358
+ const hooksDir = path35.join(projectDir, ".harness", "hooks");
4359
+ const profilePath = path35.join(hooksDir, "profile.json");
4360
+ if (!fs23.existsSync(profilePath)) {
4361
+ return { installed: false, profile: null, hooks: [] };
4362
+ }
4363
+ let profile = "standard";
4364
+ let warning;
4365
+ try {
4366
+ const data = JSON.parse(fs23.readFileSync(profilePath, "utf-8"));
4367
+ if (data.profile && ["minimal", "standard", "strict"].includes(data.profile)) {
4368
+ profile = data.profile;
4369
+ }
4370
+ } catch {
4371
+ warning = "Malformed profile.json \u2014 defaulting to standard profile";
4372
+ }
4373
+ const activeNames = PROFILES[profile];
4374
+ const hooks = HOOK_SCRIPTS.filter((h) => activeNames.includes(h.name)).map((h) => ({
4375
+ name: h.name,
4376
+ event: h.event,
4377
+ matcher: h.matcher,
4378
+ scriptPath: path35.join(".harness", "hooks", `${h.name}.js`)
4379
+ }));
4380
+ const result = { installed: true, profile, hooks };
4381
+ if (warning) {
4382
+ result.warning = warning;
4383
+ }
4384
+ return result;
4385
+ }
4386
+ function createListCommand3() {
4387
+ return new Command40("list").description("Show installed hooks and active profile").action(async (_opts, cmd) => {
4388
+ const globalOpts = cmd.optsWithGlobals();
4389
+ const projectDir = process.cwd();
4390
+ const result = listHooks(projectDir);
4391
+ if (globalOpts.json) {
4392
+ console.log(JSON.stringify(result, null, 2));
4393
+ return;
4394
+ }
4395
+ if (!result.installed) {
4396
+ logger.info("No harness hooks installed. Run 'harness hooks init' to set up hooks.");
4397
+ return;
4398
+ }
4399
+ logger.info(`Profile: ${result.profile}`);
4400
+ logger.info(`Hooks (${result.hooks.length}):`);
4401
+ for (const hook of result.hooks) {
4402
+ console.log(` ${hook.name} ${hook.event}:${hook.matcher} ${hook.scriptPath}`);
4403
+ }
4404
+ });
4405
+ }
4406
+
4407
+ // src/commands/hooks/remove.ts
4408
+ import { Command as Command41 } from "commander";
4409
+ import * as fs24 from "fs";
4410
+ import * as path36 from "path";
4411
+ function removeHooks(projectDir) {
4412
+ const hooksDir = path36.join(projectDir, ".harness", "hooks");
4413
+ const settingsPath = path36.join(projectDir, ".claude", "settings.json");
4414
+ let removed = false;
4415
+ let settingsCleaned = false;
4416
+ if (fs24.existsSync(hooksDir)) {
4417
+ fs24.rmSync(hooksDir, { recursive: true, force: true });
4418
+ removed = true;
4419
+ }
4420
+ if (fs24.existsSync(settingsPath)) {
4421
+ try {
4422
+ const settings = JSON.parse(fs24.readFileSync(settingsPath, "utf-8"));
4423
+ if (settings.hooks !== void 0) {
4424
+ delete settings.hooks;
4425
+ settingsCleaned = true;
4426
+ if (Object.keys(settings).length === 0) {
4427
+ fs24.unlinkSync(settingsPath);
4428
+ } else {
4429
+ fs24.writeFileSync(settingsPath, JSON.stringify(settings, null, 2) + "\n");
4430
+ }
4431
+ }
4432
+ } catch {
4433
+ }
4434
+ }
4435
+ return { removed, hooksDir, settingsCleaned };
4436
+ }
4437
+ function createRemoveCommand() {
4438
+ return new Command41("remove").description("Remove harness-managed hooks from the current project").action(async (_opts, cmd) => {
4439
+ const globalOpts = cmd.optsWithGlobals();
4440
+ const projectDir = process.cwd();
4441
+ const result = removeHooks(projectDir);
4442
+ if (globalOpts.json) {
4443
+ console.log(JSON.stringify(result));
4444
+ return;
4445
+ }
4446
+ if (!result.removed && !result.settingsCleaned) {
4447
+ logger.info("No harness hooks found to remove.");
4448
+ return;
4449
+ }
4450
+ if (result.removed) {
4451
+ logger.success("Removed .harness/hooks/ directory");
4452
+ }
4453
+ if (result.settingsCleaned) {
4454
+ logger.success("Cleaned hook entries from .claude/settings.json");
4455
+ }
4456
+ });
4457
+ }
4458
+
4459
+ // src/commands/hooks/add.ts
4460
+ import { Command as Command42 } from "commander";
4461
+ import * as fs25 from "fs";
4462
+ import * as path37 from "path";
4463
+ import { fileURLToPath as fileURLToPath2 } from "url";
4464
+ var __dirname2 = path37.dirname(fileURLToPath2(import.meta.url));
4465
+ var ALIASES = {
4466
+ sentinel: ["sentinel-pre", "sentinel-post"]
4467
+ };
4468
+ function hookSourceDir() {
4469
+ const d = path37.resolve(__dirname2, "..", "..", "hooks");
4470
+ if (fs25.existsSync(d)) return d;
4471
+ throw new Error(`Hook scripts not found: ${d}`);
4472
+ }
4473
+ function readJson(p) {
4474
+ return fs25.existsSync(p) ? JSON.parse(fs25.readFileSync(p, "utf-8")) : {};
4475
+ }
4476
+ function registerHook(s, ev, matcher, name) {
4477
+ if (!s.hooks[ev]) s.hooks[ev] = [];
4478
+ const cmd = `node .harness/hooks/${name}.js`;
4479
+ if (!s.hooks[ev].some((e) => e.hooks?.some((h) => h.command === cmd))) {
4480
+ s.hooks[ev].push({ matcher, hooks: [{ type: "command", command: cmd }] });
4481
+ }
4482
+ }
4483
+ function addHooks(hookName, projectDir) {
4484
+ const names = ALIASES[hookName] ?? [hookName];
4485
+ const result = { added: [], alreadyInstalled: [], notFound: [] };
4486
+ const srcDir = hookSourceDir();
4487
+ const destDir = path37.join(projectDir, ".harness", "hooks");
4488
+ fs25.mkdirSync(destDir, { recursive: true });
4489
+ const claudeDir = path37.join(projectDir, ".claude");
4490
+ fs25.mkdirSync(claudeDir, { recursive: true });
4491
+ const settingsPath = path37.join(claudeDir, "settings.json");
4492
+ const settings = readJson(settingsPath);
4493
+ if (!settings.hooks) settings.hooks = {};
4494
+ for (const name of names) {
4495
+ const def = HOOK_SCRIPTS.find((h) => h.name === name);
4496
+ if (!def) {
4497
+ result.notFound.push(name);
4498
+ continue;
4499
+ }
4500
+ const src = path37.join(srcDir, `${name}.js`);
4501
+ const dest = path37.join(destDir, `${name}.js`);
4502
+ if (fs25.existsSync(dest)) {
4503
+ result.alreadyInstalled.push(name);
4504
+ } else if (!fs25.existsSync(src)) {
4505
+ result.notFound.push(name);
4506
+ continue;
4507
+ } else {
4508
+ fs25.copyFileSync(src, dest);
4509
+ result.added.push(name);
4510
+ }
4511
+ registerHook(settings, def.event, def.matcher, name);
4512
+ }
4513
+ fs25.writeFileSync(settingsPath, JSON.stringify(settings, null, 2) + "\n");
4514
+ return result;
4515
+ }
4516
+ function createAddCommand2() {
4517
+ return new Command42("add").argument("<hook-name>", "Hook name or alias (e.g., sentinel)").description("Add a hook without changing the profile").action(async (hookName, _opts, cmd) => {
4518
+ const projectDir = process.cwd();
4519
+ try {
4520
+ const res = addHooks(hookName, projectDir);
4521
+ if (cmd.optsWithGlobals().json) {
4522
+ console.log(JSON.stringify(res));
4523
+ return;
4524
+ }
4525
+ if (res.notFound.length > 0) {
4526
+ logger.error(`Unknown hook(s): ${res.notFound.join(", ")}`);
4527
+ logger.info(`Available: ${HOOK_SCRIPTS.map((h) => h.name).join(", ")}`);
4528
+ logger.info(`Aliases: ${Object.keys(ALIASES).join(", ")}`);
4529
+ process.exit(2);
4530
+ }
4531
+ for (const n of res.added) logger.success(`Added hook: ${n}`);
4532
+ for (const n of res.alreadyInstalled) logger.info(`Already installed: ${n}`);
4533
+ } catch (err) {
4534
+ logger.error(`Failed to add hook: ${err instanceof Error ? err.message : String(err)}`);
4535
+ process.exit(2);
4536
+ }
4537
+ });
4538
+ }
4539
+
4540
+ // src/commands/hooks/index.ts
4541
+ function createHooksCommand() {
4542
+ const command = new Command43("hooks").description("Manage Claude Code hook configurations");
4543
+ command.addCommand(createInitCommand3());
4544
+ command.addCommand(createListCommand3());
4545
+ command.addCommand(createRemoveCommand());
4546
+ command.addCommand(createAddCommand2());
4547
+ return command;
4548
+ }
4549
+
3475
4550
  // src/commands/update.ts
3476
- import { Command as Command37 } from "commander";
4551
+ import { Command as Command44 } from "commander";
3477
4552
  import { execFileSync as execFileSync4 } from "child_process";
3478
4553
  import { realpathSync } from "fs";
3479
4554
  import readline2 from "readline";
3480
- import chalk3 from "chalk";
4555
+ import chalk5 from "chalk";
3481
4556
  function detectPackageManager() {
3482
4557
  try {
3483
4558
  const argv1 = process.argv[1];
@@ -3533,10 +4608,10 @@ function prompt(question) {
3533
4608
  input: process.stdin,
3534
4609
  output: process.stdout
3535
4610
  });
3536
- return new Promise((resolve29) => {
4611
+ return new Promise((resolve31) => {
3537
4612
  rl.question(question, (answer) => {
3538
4613
  rl.close();
3539
- resolve29(answer.trim().toLowerCase());
4614
+ resolve31(answer.trim().toLowerCase());
3540
4615
  });
3541
4616
  });
3542
4617
  }
@@ -3552,11 +4627,11 @@ async function offerRegeneration() {
3552
4627
  });
3553
4628
  } catch {
3554
4629
  logger.warn("Generation failed. Run manually:");
3555
- console.log(` ${chalk3.cyan(`harness generate${isGlobal ? " --global" : ""}`)}`);
4630
+ console.log(` ${chalk5.cyan(`harness generate${isGlobal ? " --global" : ""}`)}`);
3556
4631
  }
3557
4632
  }
3558
4633
  function createUpdateCommand() {
3559
- return new Command37("update").description("Update all @harness-engineering packages to the latest version").option("--version <semver>", "Pin @harness-engineering/cli to a specific version").action(async (opts, cmd) => {
4634
+ return new Command44("update").description("Update all @harness-engineering packages to the latest version").option("--version <semver>", "Pin @harness-engineering/cli to a specific version").action(async (opts, cmd) => {
3560
4635
  const globalOpts = cmd.optsWithGlobals();
3561
4636
  const pm = detectPackageManager();
3562
4637
  if (globalOpts.verbose) {
@@ -3578,8 +4653,8 @@ function createUpdateCommand() {
3578
4653
  }
3579
4654
  if (currentVersion) {
3580
4655
  console.log("");
3581
- logger.info(`Current CLI version: ${chalk3.dim(`v${currentVersion}`)}`);
3582
- logger.info(`Latest CLI version: ${chalk3.green(`v${latestCliVersion}`)}`);
4656
+ logger.info(`Current CLI version: ${chalk5.dim(`v${currentVersion}`)}`);
4657
+ logger.info(`Latest CLI version: ${chalk5.green(`v${latestCliVersion}`)}`);
3583
4658
  console.log("");
3584
4659
  }
3585
4660
  }
@@ -3605,7 +4680,7 @@ function createUpdateCommand() {
3605
4680
  } catch {
3606
4681
  console.log("");
3607
4682
  logger.error("Update failed. You can try manually:");
3608
- console.log(` ${chalk3.cyan(installCmd)}`);
4683
+ console.log(` ${chalk5.cyan(installCmd)}`);
3609
4684
  process.exit(ExitCode.ERROR);
3610
4685
  }
3611
4686
  await offerRegeneration();
@@ -3614,9 +4689,9 @@ function createUpdateCommand() {
3614
4689
  }
3615
4690
 
3616
4691
  // src/commands/generate.ts
3617
- import { Command as Command38 } from "commander";
4692
+ import { Command as Command45 } from "commander";
3618
4693
  function createGenerateCommand3() {
3619
- return new Command38("generate").description("Generate all platform integrations (slash commands + agent definitions)").option("--platforms <list>", "Target platforms (comma-separated)", "claude-code,gemini-cli").option("--global", "Write to global directories", false).option("--include-global", "Include built-in global skills", false).option("--output <dir>", "Custom output directory").option("--dry-run", "Show what would change without writing", false).option("--yes", "Skip deletion confirmation prompts", false).action(async (opts, cmd) => {
4694
+ return new Command45("generate").description("Generate all platform integrations (slash commands + agent definitions)").option("--platforms <list>", "Target platforms (comma-separated)", "claude-code,gemini-cli").option("--global", "Write to global directories", false).option("--include-global", "Include built-in global skills", false).option("--output <dir>", "Custom output directory").option("--dry-run", "Show what would change without writing", false).option("--yes", "Skip deletion confirmation prompts", false).action(async (opts, cmd) => {
3620
4695
  const globalOpts = cmd.optsWithGlobals();
3621
4696
  const platforms = opts.platforms.split(",").map((p) => p.trim());
3622
4697
  for (const p of platforms) {
@@ -3675,8 +4750,8 @@ function createGenerateCommand3() {
3675
4750
  }
3676
4751
 
3677
4752
  // src/commands/graph/scan.ts
3678
- import { Command as Command39 } from "commander";
3679
- import * as path29 from "path";
4753
+ import { Command as Command46 } from "commander";
4754
+ import * as path38 from "path";
3680
4755
  async function runScan(projectPath) {
3681
4756
  const { GraphStore, CodeIngestor, TopologicalLinker, KnowledgeIngestor, GitIngestor } = await import("./dist-B26DFXMP.js");
3682
4757
  const store = new GraphStore();
@@ -3689,13 +4764,13 @@ async function runScan(projectPath) {
3689
4764
  await new GitIngestor(store).ingest(projectPath);
3690
4765
  } catch {
3691
4766
  }
3692
- const graphDir = path29.join(projectPath, ".harness", "graph");
4767
+ const graphDir = path38.join(projectPath, ".harness", "graph");
3693
4768
  await store.save(graphDir);
3694
4769
  return { nodeCount: store.nodeCount, edgeCount: store.edgeCount, durationMs: Date.now() - start };
3695
4770
  }
3696
4771
  function createScanCommand() {
3697
- return new Command39("scan").description("Scan project and build knowledge graph").argument("[path]", "Project root path", ".").action(async (inputPath, _opts, cmd) => {
3698
- const projectPath = path29.resolve(inputPath);
4772
+ return new Command46("scan").description("Scan project and build knowledge graph").argument("[path]", "Project root path", ".").action(async (inputPath, _opts, cmd) => {
4773
+ const projectPath = path38.resolve(inputPath);
3699
4774
  const globalOpts = cmd.optsWithGlobals();
3700
4775
  try {
3701
4776
  const result = await runScan(projectPath);
@@ -3714,13 +4789,13 @@ function createScanCommand() {
3714
4789
  }
3715
4790
 
3716
4791
  // src/commands/graph/ingest.ts
3717
- import { Command as Command40 } from "commander";
3718
- import * as path30 from "path";
4792
+ import { Command as Command47 } from "commander";
4793
+ import * as path39 from "path";
3719
4794
  async function loadConnectorConfig(projectPath, source) {
3720
4795
  try {
3721
- const fs23 = await import("fs/promises");
3722
- const configPath = path30.join(projectPath, "harness.config.json");
3723
- const config = JSON.parse(await fs23.readFile(configPath, "utf-8"));
4796
+ const fs34 = await import("fs/promises");
4797
+ const configPath = path39.join(projectPath, "harness.config.json");
4798
+ const config = JSON.parse(await fs34.readFile(configPath, "utf-8"));
3724
4799
  const connector = config.graph?.connectors?.find(
3725
4800
  (c) => c.source === source
3726
4801
  );
@@ -3760,7 +4835,7 @@ async function runIngest(projectPath, source, opts) {
3760
4835
  JiraConnector,
3761
4836
  SlackConnector
3762
4837
  } = await import("./dist-B26DFXMP.js");
3763
- const graphDir = path30.join(projectPath, ".harness", "graph");
4838
+ const graphDir = path39.join(projectPath, ".harness", "graph");
3764
4839
  const store = new GraphStore();
3765
4840
  await store.load(graphDir);
3766
4841
  if (opts?.all) {
@@ -3821,13 +4896,13 @@ async function runIngest(projectPath, source, opts) {
3821
4896
  return result;
3822
4897
  }
3823
4898
  function createIngestCommand() {
3824
- return new Command40("ingest").description("Ingest data into the knowledge graph").option("--source <name>", "Source to ingest (code, knowledge, git, jira, slack)").option("--all", "Run all sources (code, knowledge, git, and configured connectors)").option("--full", "Force full re-ingestion").action(async (opts, cmd) => {
4899
+ return new Command47("ingest").description("Ingest data into the knowledge graph").option("--source <name>", "Source to ingest (code, knowledge, git, jira, slack)").option("--all", "Run all sources (code, knowledge, git, and configured connectors)").option("--full", "Force full re-ingestion").action(async (opts, cmd) => {
3825
4900
  if (!opts.source && !opts.all) {
3826
4901
  console.error("Error: --source or --all is required");
3827
4902
  process.exit(1);
3828
4903
  }
3829
4904
  const globalOpts = cmd.optsWithGlobals();
3830
- const projectPath = path30.resolve(globalOpts.config ? path30.dirname(globalOpts.config) : ".");
4905
+ const projectPath = path39.resolve(globalOpts.config ? path39.dirname(globalOpts.config) : ".");
3831
4906
  try {
3832
4907
  const result = await runIngest(projectPath, opts.source ?? "", {
3833
4908
  full: opts.full,
@@ -3849,12 +4924,12 @@ function createIngestCommand() {
3849
4924
  }
3850
4925
 
3851
4926
  // src/commands/graph/query.ts
3852
- import { Command as Command41 } from "commander";
3853
- import * as path31 from "path";
4927
+ import { Command as Command48 } from "commander";
4928
+ import * as path40 from "path";
3854
4929
  async function runQuery(projectPath, rootNodeId, opts) {
3855
4930
  const { GraphStore, ContextQL } = await import("./dist-B26DFXMP.js");
3856
4931
  const store = new GraphStore();
3857
- const graphDir = path31.join(projectPath, ".harness", "graph");
4932
+ const graphDir = path40.join(projectPath, ".harness", "graph");
3858
4933
  const loaded = await store.load(graphDir);
3859
4934
  if (!loaded) throw new Error("No graph found. Run `harness scan` first.");
3860
4935
  const params = {
@@ -3868,9 +4943,9 @@ async function runQuery(projectPath, rootNodeId, opts) {
3868
4943
  return cql.execute(params);
3869
4944
  }
3870
4945
  function createQueryCommand() {
3871
- return new Command41("query").description("Query the knowledge graph").argument("<rootNodeId>", "Starting node ID").option("--depth <n>", "Max traversal depth", "3").option("--types <types>", "Comma-separated node types to include").option("--edges <edges>", "Comma-separated edge types to include").option("--bidirectional", "Traverse both directions").action(async (rootNodeId, opts, cmd) => {
4946
+ return new Command48("query").description("Query the knowledge graph").argument("<rootNodeId>", "Starting node ID").option("--depth <n>", "Max traversal depth", "3").option("--types <types>", "Comma-separated node types to include").option("--edges <edges>", "Comma-separated edge types to include").option("--bidirectional", "Traverse both directions").action(async (rootNodeId, opts, cmd) => {
3872
4947
  const globalOpts = cmd.optsWithGlobals();
3873
- const projectPath = path31.resolve(globalOpts.config ? path31.dirname(globalOpts.config) : ".");
4948
+ const projectPath = path40.resolve(globalOpts.config ? path40.dirname(globalOpts.config) : ".");
3874
4949
  try {
3875
4950
  const result = await runQuery(projectPath, rootNodeId, {
3876
4951
  depth: parseInt(opts.depth),
@@ -3896,21 +4971,21 @@ function createQueryCommand() {
3896
4971
  }
3897
4972
 
3898
4973
  // src/commands/graph/index.ts
3899
- import { Command as Command42 } from "commander";
4974
+ import { Command as Command49 } from "commander";
3900
4975
 
3901
4976
  // src/commands/graph/status.ts
3902
- import * as path32 from "path";
4977
+ import * as path41 from "path";
3903
4978
  async function runGraphStatus(projectPath) {
3904
4979
  const { GraphStore } = await import("./dist-B26DFXMP.js");
3905
- const graphDir = path32.join(projectPath, ".harness", "graph");
4980
+ const graphDir = path41.join(projectPath, ".harness", "graph");
3906
4981
  const store = new GraphStore();
3907
4982
  const loaded = await store.load(graphDir);
3908
4983
  if (!loaded) return { status: "no_graph", message: "No graph found. Run `harness scan` first." };
3909
- const fs23 = await import("fs/promises");
3910
- const metaPath = path32.join(graphDir, "metadata.json");
4984
+ const fs34 = await import("fs/promises");
4985
+ const metaPath = path41.join(graphDir, "metadata.json");
3911
4986
  let lastScan = "unknown";
3912
4987
  try {
3913
- const meta = JSON.parse(await fs23.readFile(metaPath, "utf-8"));
4988
+ const meta = JSON.parse(await fs34.readFile(metaPath, "utf-8"));
3914
4989
  lastScan = meta.lastScanTimestamp;
3915
4990
  } catch {
3916
4991
  }
@@ -3921,8 +4996,8 @@ async function runGraphStatus(projectPath) {
3921
4996
  }
3922
4997
  let connectorSyncStatus = {};
3923
4998
  try {
3924
- const syncMetaPath = path32.join(graphDir, "sync-metadata.json");
3925
- const syncMeta = JSON.parse(await fs23.readFile(syncMetaPath, "utf-8"));
4999
+ const syncMetaPath = path41.join(graphDir, "sync-metadata.json");
5000
+ const syncMeta = JSON.parse(await fs34.readFile(syncMetaPath, "utf-8"));
3926
5001
  for (const [name, data] of Object.entries(syncMeta.connectors ?? {})) {
3927
5002
  connectorSyncStatus[name] = data.lastSyncTimestamp;
3928
5003
  }
@@ -3939,10 +5014,10 @@ async function runGraphStatus(projectPath) {
3939
5014
  }
3940
5015
 
3941
5016
  // src/commands/graph/export.ts
3942
- import * as path33 from "path";
5017
+ import * as path42 from "path";
3943
5018
  async function runGraphExport(projectPath, format) {
3944
5019
  const { GraphStore } = await import("./dist-B26DFXMP.js");
3945
- const graphDir = path33.join(projectPath, ".harness", "graph");
5020
+ const graphDir = path42.join(projectPath, ".harness", "graph");
3946
5021
  const store = new GraphStore();
3947
5022
  const loaded = await store.load(graphDir);
3948
5023
  if (!loaded) throw new Error("No graph found. Run `harness scan` first.");
@@ -3971,13 +5046,13 @@ async function runGraphExport(projectPath, format) {
3971
5046
  }
3972
5047
 
3973
5048
  // src/commands/graph/index.ts
3974
- import * as path34 from "path";
5049
+ import * as path43 from "path";
3975
5050
  function createGraphCommand() {
3976
- const graph = new Command42("graph").description("Knowledge graph management");
5051
+ const graph = new Command49("graph").description("Knowledge graph management");
3977
5052
  graph.command("status").description("Show graph statistics").action(async (_opts, cmd) => {
3978
5053
  try {
3979
5054
  const globalOpts = cmd.optsWithGlobals();
3980
- const projectPath = path34.resolve(globalOpts.config ? path34.dirname(globalOpts.config) : ".");
5055
+ const projectPath = path43.resolve(globalOpts.config ? path43.dirname(globalOpts.config) : ".");
3981
5056
  const result = await runGraphStatus(projectPath);
3982
5057
  if (globalOpts.json) {
3983
5058
  console.log(JSON.stringify(result, null, 2));
@@ -4004,7 +5079,7 @@ function createGraphCommand() {
4004
5079
  });
4005
5080
  graph.command("export").description("Export graph").requiredOption("--format <format>", "Output format (json, mermaid)").action(async (opts, cmd) => {
4006
5081
  const globalOpts = cmd.optsWithGlobals();
4007
- const projectPath = path34.resolve(globalOpts.config ? path34.dirname(globalOpts.config) : ".");
5082
+ const projectPath = path43.resolve(globalOpts.config ? path43.dirname(globalOpts.config) : ".");
4008
5083
  try {
4009
5084
  const output = await runGraphExport(projectPath, opts.format);
4010
5085
  console.log(output);
@@ -4017,19 +5092,19 @@ function createGraphCommand() {
4017
5092
  }
4018
5093
 
4019
5094
  // src/commands/mcp.ts
4020
- import { Command as Command43 } from "commander";
5095
+ import { Command as Command50 } from "commander";
4021
5096
  function createMcpCommand() {
4022
- return new Command43("mcp").description("Start the MCP (Model Context Protocol) server on stdio").action(async () => {
4023
- const { startServer: startServer2 } = await import("./mcp-362EZHF4.js");
4024
- await startServer2();
5097
+ return new Command50("mcp").description("Start the MCP (Model Context Protocol) server on stdio").option("--tools <tools...>", "Only register the specified tools (used by Cursor integration)").action(async (opts) => {
5098
+ const { startServer: startServer2 } = await import("./mcp-YENEPHBW.js");
5099
+ await startServer2(opts.tools);
4025
5100
  });
4026
5101
  }
4027
5102
 
4028
5103
  // src/commands/impact-preview.ts
4029
- import { Command as Command44 } from "commander";
5104
+ import { Command as Command51 } from "commander";
4030
5105
  import { execSync as execSync3 } from "child_process";
4031
- import * as path35 from "path";
4032
- import * as fs17 from "fs";
5106
+ import * as path44 from "path";
5107
+ import * as fs26 from "fs";
4033
5108
  function getStagedFiles(cwd) {
4034
5109
  try {
4035
5110
  const output = execSync3("git diff --cached --name-only", {
@@ -4043,7 +5118,7 @@ function getStagedFiles(cwd) {
4043
5118
  }
4044
5119
  function graphExists(projectPath) {
4045
5120
  try {
4046
- return fs17.existsSync(path35.join(projectPath, ".harness", "graph", "graph.json"));
5121
+ return fs26.existsSync(path44.join(projectPath, ".harness", "graph", "graph.json"));
4047
5122
  } catch {
4048
5123
  return false;
4049
5124
  }
@@ -4052,7 +5127,7 @@ function extractNodeName(id) {
4052
5127
  const parts = id.split(":");
4053
5128
  if (parts.length > 1) {
4054
5129
  const fullPath = parts.slice(1).join(":");
4055
- return path35.basename(fullPath);
5130
+ return path44.basename(fullPath);
4056
5131
  }
4057
5132
  return id;
4058
5133
  }
@@ -4175,7 +5250,7 @@ function formatPerFile(perFileResults) {
4175
5250
  return lines.join("\n");
4176
5251
  }
4177
5252
  async function runImpactPreview(options) {
4178
- const projectPath = path35.resolve(options.path ?? process.cwd());
5253
+ const projectPath = path44.resolve(options.path ?? process.cwd());
4179
5254
  const stagedFiles = getStagedFiles(projectPath);
4180
5255
  if (stagedFiles.length === 0) {
4181
5256
  return "Impact Preview: no staged changes";
@@ -4222,7 +5297,7 @@ async function runImpactPreview(options) {
4222
5297
  return formatCompact(stagedFiles.length, merged, aggregateCounts);
4223
5298
  }
4224
5299
  function createImpactPreviewCommand() {
4225
- const command = new Command44("impact-preview").description("Show blast radius of staged changes using the knowledge graph").option("--detailed", "Show all affected files instead of top items").option("--per-file", "Show impact per staged file instead of aggregate").option("--path <dir>", "Project root (default: cwd)").action(async (opts) => {
5300
+ const command = new Command51("impact-preview").description("Show blast radius of staged changes using the knowledge graph").option("--detailed", "Show all affected files instead of top items").option("--per-file", "Show impact per staged file instead of aggregate").option("--path <dir>", "Project root (default: cwd)").action(async (opts) => {
4226
5301
  const output = await runImpactPreview({
4227
5302
  detailed: opts.detailed,
4228
5303
  perFile: opts.perFile,
@@ -4235,7 +5310,7 @@ function createImpactPreviewCommand() {
4235
5310
  }
4236
5311
 
4237
5312
  // src/commands/check-arch.ts
4238
- import { Command as Command45 } from "commander";
5313
+ import { Command as Command52 } from "commander";
4239
5314
  import { execSync as execSync4 } from "child_process";
4240
5315
  function getCommitHash2(cwd) {
4241
5316
  try {
@@ -4330,7 +5405,7 @@ async function runCheckArch(options) {
4330
5405
  });
4331
5406
  }
4332
5407
  function createCheckArchCommand() {
4333
- const command = new Command45("check-arch").description("Check architecture assertions against baseline and thresholds").option("--update-baseline", "Capture current state as new baseline").option("--module <path>", "Check a single module").action(async (opts, cmd) => {
5408
+ const command = new Command52("check-arch").description("Check architecture assertions against baseline and thresholds").option("--update-baseline", "Capture current state as new baseline").option("--module <path>", "Check a single module").action(async (opts, cmd) => {
4334
5409
  const globalOpts = cmd.optsWithGlobals();
4335
5410
  const mode = globalOpts.json ? OutputMode.JSON : globalOpts.quiet ? OutputMode.QUIET : globalOpts.verbose ? OutputMode.VERBOSE : OutputMode.TEXT;
4336
5411
  const formatter = new OutputFormatter(mode);
@@ -4396,20 +5471,20 @@ function createCheckArchCommand() {
4396
5471
  }
4397
5472
 
4398
5473
  // src/commands/blueprint.ts
4399
- import { Command as Command46 } from "commander";
4400
- import * as path36 from "path";
5474
+ import { Command as Command53 } from "commander";
5475
+ import * as path45 from "path";
4401
5476
  function createBlueprintCommand() {
4402
- return new Command46("blueprint").description("Generate a self-contained, interactive blueprint of the codebase").argument("[path]", "Path to the project root", ".").option("-o, --output <dir>", "Output directory", "docs/blueprint").action(async (projectPath, options) => {
5477
+ return new Command53("blueprint").description("Generate a self-contained, interactive blueprint of the codebase").argument("[path]", "Path to the project root", ".").option("-o, --output <dir>", "Output directory", "docs/blueprint").action(async (projectPath, options) => {
4403
5478
  try {
4404
- const rootDir = path36.resolve(projectPath);
4405
- const outputDir = path36.resolve(options.output);
5479
+ const rootDir = path45.resolve(projectPath);
5480
+ const outputDir = path45.resolve(options.output);
4406
5481
  logger.info(`Scanning project at ${rootDir}...`);
4407
5482
  const scanner = new ProjectScanner(rootDir);
4408
5483
  const data = await scanner.scan();
4409
5484
  logger.info(`Generating blueprint to ${outputDir}...`);
4410
5485
  const generator = new BlueprintGenerator();
4411
5486
  await generator.generate(data, { outputDir });
4412
- logger.success(`Blueprint generated successfully at ${path36.join(outputDir, "index.html")}`);
5487
+ logger.success(`Blueprint generated successfully at ${path45.join(outputDir, "index.html")}`);
4413
5488
  } catch (error) {
4414
5489
  logger.error(
4415
5490
  `Failed to generate blueprint: ${error instanceof Error ? error.message : String(error)}`
@@ -4420,16 +5495,16 @@ function createBlueprintCommand() {
4420
5495
  }
4421
5496
 
4422
5497
  // src/commands/share.ts
4423
- import { Command as Command47 } from "commander";
4424
- import * as fs18 from "fs";
4425
- import * as path37 from "path";
5498
+ import { Command as Command54 } from "commander";
5499
+ import * as fs27 from "fs";
5500
+ import * as path46 from "path";
4426
5501
  import { parse as parseYaml } from "yaml";
4427
5502
  var MANIFEST_FILENAME = "constraints.yaml";
4428
5503
  function createShareCommand() {
4429
- return new Command47("share").description("Extract and publish a constraints bundle from constraints.yaml").argument("[path]", "Path to the project root", ".").option("-o, --output <dir>", "Output directory for the bundle", ".").action(async (projectPath, options) => {
4430
- const rootDir = path37.resolve(projectPath);
4431
- const manifestPath = path37.join(rootDir, MANIFEST_FILENAME);
4432
- if (!fs18.existsSync(manifestPath)) {
5504
+ return new Command54("share").description("Extract and publish a constraints bundle from constraints.yaml").argument("[path]", "Path to the project root", ".").option("-o, --output <dir>", "Output directory for the bundle", ".").action(async (projectPath, options) => {
5505
+ const rootDir = path46.resolve(projectPath);
5506
+ const manifestPath = path46.join(rootDir, MANIFEST_FILENAME);
5507
+ if (!fs27.existsSync(manifestPath)) {
4433
5508
  logger.error(
4434
5509
  `No ${MANIFEST_FILENAME} found at ${manifestPath}.
4435
5510
  Create a constraints.yaml in your project root to define what to share.`
@@ -4438,7 +5513,7 @@ Create a constraints.yaml in your project root to define what to share.`
4438
5513
  }
4439
5514
  let parsed;
4440
5515
  try {
4441
- const raw = fs18.readFileSync(manifestPath, "utf-8");
5516
+ const raw = fs27.readFileSync(manifestPath, "utf-8");
4442
5517
  parsed = parseYaml(raw);
4443
5518
  } catch (err) {
4444
5519
  logger.error(
@@ -4452,7 +5527,7 @@ Create a constraints.yaml in your project root to define what to share.`
4452
5527
  process.exit(1);
4453
5528
  }
4454
5529
  const manifest = manifestResult.value;
4455
- const configResult = resolveConfig(path37.join(rootDir, "harness.config.json"));
5530
+ const configResult = resolveConfig(path46.join(rootDir, "harness.config.json"));
4456
5531
  if (!configResult.ok) {
4457
5532
  logger.error(configResult.error.message);
4458
5533
  process.exit(1);
@@ -4470,8 +5545,8 @@ Create a constraints.yaml in your project root to define what to share.`
4470
5545
  );
4471
5546
  process.exit(1);
4472
5547
  }
4473
- const outputDir = path37.resolve(options.output);
4474
- const outputPath = path37.join(outputDir, `${manifest.name}.harness-constraints.json`);
5548
+ const outputDir = path46.resolve(options.output);
5549
+ const outputPath = path46.join(outputDir, `${manifest.name}.harness-constraints.json`);
4475
5550
  const writeResult = await writeConfig(outputPath, bundle);
4476
5551
  if (!writeResult.ok) {
4477
5552
  logger.error(`Failed to write bundle: ${writeResult.error.message}`);
@@ -4482,25 +5557,25 @@ Create a constraints.yaml in your project root to define what to share.`
4482
5557
  }
4483
5558
 
4484
5559
  // src/commands/install.ts
4485
- import * as fs20 from "fs";
4486
- import * as path39 from "path";
4487
- import { Command as Command48 } from "commander";
5560
+ import * as fs29 from "fs";
5561
+ import * as path48 from "path";
5562
+ import { Command as Command55 } from "commander";
4488
5563
  import { parse as yamlParse } from "yaml";
4489
5564
 
4490
5565
  // src/registry/tarball.ts
4491
- import * as fs19 from "fs";
4492
- import * as path38 from "path";
4493
- import * as os3 from "os";
5566
+ import * as fs28 from "fs";
5567
+ import * as path47 from "path";
5568
+ import * as os6 from "os";
4494
5569
  import { execFileSync as execFileSync5 } from "child_process";
4495
5570
  function extractTarball(tarballBuffer) {
4496
- const tmpDir = fs19.mkdtempSync(path38.join(os3.tmpdir(), "harness-skill-install-"));
4497
- const tarballPath = path38.join(tmpDir, "package.tgz");
5571
+ const tmpDir = fs28.mkdtempSync(path47.join(os6.tmpdir(), "harness-skill-install-"));
5572
+ const tarballPath = path47.join(tmpDir, "package.tgz");
4498
5573
  try {
4499
- fs19.writeFileSync(tarballPath, tarballBuffer);
5574
+ fs28.writeFileSync(tarballPath, tarballBuffer);
4500
5575
  execFileSync5("tar", ["-xzf", tarballPath, "-C", tmpDir], {
4501
5576
  timeout: 3e4
4502
5577
  });
4503
- fs19.unlinkSync(tarballPath);
5578
+ fs28.unlinkSync(tarballPath);
4504
5579
  } catch (err) {
4505
5580
  cleanupTempDir(tmpDir);
4506
5581
  throw new Error(
@@ -4511,43 +5586,43 @@ function extractTarball(tarballBuffer) {
4511
5586
  return tmpDir;
4512
5587
  }
4513
5588
  function placeSkillContent(extractedPkgDir, communityBaseDir, skillName, platforms) {
4514
- const files = fs19.readdirSync(extractedPkgDir);
5589
+ const files = fs28.readdirSync(extractedPkgDir);
4515
5590
  for (const platform of platforms) {
4516
- const targetDir = path38.join(communityBaseDir, platform, skillName);
4517
- if (fs19.existsSync(targetDir)) {
4518
- fs19.rmSync(targetDir, { recursive: true, force: true });
5591
+ const targetDir = path47.join(communityBaseDir, platform, skillName);
5592
+ if (fs28.existsSync(targetDir)) {
5593
+ fs28.rmSync(targetDir, { recursive: true, force: true });
4519
5594
  }
4520
- fs19.mkdirSync(targetDir, { recursive: true });
5595
+ fs28.mkdirSync(targetDir, { recursive: true });
4521
5596
  for (const file of files) {
4522
5597
  if (file === "package.json" || file === "node_modules") continue;
4523
- const srcPath = path38.join(extractedPkgDir, file);
4524
- const destPath = path38.join(targetDir, file);
4525
- const stat = fs19.statSync(srcPath);
5598
+ const srcPath = path47.join(extractedPkgDir, file);
5599
+ const destPath = path47.join(targetDir, file);
5600
+ const stat = fs28.statSync(srcPath);
4526
5601
  if (stat.isDirectory()) {
4527
- fs19.cpSync(srcPath, destPath, { recursive: true });
5602
+ fs28.cpSync(srcPath, destPath, { recursive: true });
4528
5603
  } else {
4529
- fs19.copyFileSync(srcPath, destPath);
5604
+ fs28.copyFileSync(srcPath, destPath);
4530
5605
  }
4531
5606
  }
4532
5607
  }
4533
5608
  }
4534
5609
  function removeSkillContent(communityBaseDir, skillName, platforms) {
4535
5610
  for (const platform of platforms) {
4536
- const targetDir = path38.join(communityBaseDir, platform, skillName);
4537
- if (fs19.existsSync(targetDir)) {
4538
- fs19.rmSync(targetDir, { recursive: true, force: true });
5611
+ const targetDir = path47.join(communityBaseDir, platform, skillName);
5612
+ if (fs28.existsSync(targetDir)) {
5613
+ fs28.rmSync(targetDir, { recursive: true, force: true });
4539
5614
  }
4540
5615
  }
4541
5616
  }
4542
5617
  function cleanupTempDir(dirPath) {
4543
5618
  try {
4544
- fs19.rmSync(dirPath, { recursive: true, force: true });
5619
+ fs28.rmSync(dirPath, { recursive: true, force: true });
4545
5620
  } catch {
4546
5621
  }
4547
5622
  }
4548
5623
 
4549
5624
  // src/registry/resolver.ts
4550
- import semver2 from "semver";
5625
+ import semver3 from "semver";
4551
5626
  function resolveVersion(metadata, versionRange) {
4552
5627
  const versions = Object.keys(metadata.versions);
4553
5628
  if (versions.length === 0) {
@@ -4559,13 +5634,13 @@ function resolveVersion(metadata, versionRange) {
4559
5634
  const latestInfo = metadata.versions[latestTag];
4560
5635
  if (latestInfo) return latestInfo;
4561
5636
  }
4562
- const highest = semver2.maxSatisfying(versions, "*");
5637
+ const highest = semver3.maxSatisfying(versions, "*");
4563
5638
  if (!highest || !metadata.versions[highest]) {
4564
5639
  throw new Error(`No versions available for ${metadata.name}.`);
4565
5640
  }
4566
5641
  return metadata.versions[highest];
4567
5642
  }
4568
- const matched = semver2.maxSatisfying(versions, versionRange);
5643
+ const matched = semver3.maxSatisfying(versions, versionRange);
4569
5644
  if (!matched || !metadata.versions[matched]) {
4570
5645
  throw new Error(
4571
5646
  `No version of ${metadata.name} matches range ${versionRange}. Available: ${versions.join(", ")}`
@@ -4597,35 +5672,35 @@ function validateSkillYaml(parsed) {
4597
5672
  };
4598
5673
  }
4599
5674
  async function runLocalInstall(fromPath, options) {
4600
- const resolvedPath = path39.resolve(fromPath);
4601
- if (!fs20.existsSync(resolvedPath)) {
5675
+ const resolvedPath = path48.resolve(fromPath);
5676
+ if (!fs29.existsSync(resolvedPath)) {
4602
5677
  throw new Error(`--from path does not exist: ${resolvedPath}`);
4603
5678
  }
4604
- const stat = fs20.statSync(resolvedPath);
5679
+ const stat = fs29.statSync(resolvedPath);
4605
5680
  let extractDir = null;
4606
5681
  let pkgDir;
4607
5682
  if (stat.isDirectory()) {
4608
5683
  pkgDir = resolvedPath;
4609
5684
  } else if (resolvedPath.endsWith(".tgz") || resolvedPath.endsWith(".tar.gz")) {
4610
- const tarballBuffer = fs20.readFileSync(resolvedPath);
5685
+ const tarballBuffer = fs29.readFileSync(resolvedPath);
4611
5686
  extractDir = extractTarball(tarballBuffer);
4612
- pkgDir = path39.join(extractDir, "package");
5687
+ pkgDir = path48.join(extractDir, "package");
4613
5688
  } else {
4614
5689
  throw new Error(`--from path must be a directory or .tgz file. Got: ${resolvedPath}`);
4615
5690
  }
4616
5691
  try {
4617
- const skillYamlPath = path39.join(pkgDir, "skill.yaml");
4618
- if (!fs20.existsSync(skillYamlPath)) {
5692
+ const skillYamlPath = path48.join(pkgDir, "skill.yaml");
5693
+ if (!fs29.existsSync(skillYamlPath)) {
4619
5694
  throw new Error(`No skill.yaml found at ${skillYamlPath}`);
4620
5695
  }
4621
- const rawYaml = fs20.readFileSync(skillYamlPath, "utf-8");
5696
+ const rawYaml = fs29.readFileSync(skillYamlPath, "utf-8");
4622
5697
  const parsed = yamlParse(rawYaml);
4623
5698
  const skillYaml = validateSkillYaml(parsed);
4624
5699
  const shortName = skillYaml.name;
4625
5700
  const globalDir = resolveGlobalSkillsDir();
4626
- const skillsDir = path39.dirname(globalDir);
4627
- const communityBase = path39.join(skillsDir, "community");
4628
- const lockfilePath = path39.join(communityBase, "skills-lock.json");
5701
+ const skillsDir = path48.dirname(globalDir);
5702
+ const communityBase = path48.join(skillsDir, "community");
5703
+ const lockfilePath = path48.join(communityBase, "skills-lock.json");
4629
5704
  const bundledNames = getBundledSkillNames(globalDir);
4630
5705
  if (bundledNames.has(shortName)) {
4631
5706
  throw new Error(
@@ -4666,9 +5741,9 @@ async function runInstall(skillName, options) {
4666
5741
  const packageName = resolvePackageName(skillName);
4667
5742
  const shortName = extractSkillName(packageName);
4668
5743
  const globalDir = resolveGlobalSkillsDir();
4669
- const skillsDir = path39.dirname(globalDir);
4670
- const communityBase = path39.join(skillsDir, "community");
4671
- const lockfilePath = path39.join(communityBase, "skills-lock.json");
5744
+ const skillsDir = path48.dirname(globalDir);
5745
+ const communityBase = path48.join(skillsDir, "community");
5746
+ const lockfilePath = path48.join(communityBase, "skills-lock.json");
4672
5747
  const bundledNames = getBundledSkillNames(globalDir);
4673
5748
  if (bundledNames.has(shortName)) {
4674
5749
  throw new Error(
@@ -4694,12 +5769,12 @@ async function runInstall(skillName, options) {
4694
5769
  const extractDir = extractTarball(tarballBuffer);
4695
5770
  let skillYaml;
4696
5771
  try {
4697
- const extractedPkgDir = path39.join(extractDir, "package");
4698
- const skillYamlPath = path39.join(extractedPkgDir, "skill.yaml");
4699
- if (!fs20.existsSync(skillYamlPath)) {
5772
+ const extractedPkgDir = path48.join(extractDir, "package");
5773
+ const skillYamlPath = path48.join(extractedPkgDir, "skill.yaml");
5774
+ if (!fs29.existsSync(skillYamlPath)) {
4700
5775
  throw new Error(`contains invalid skill.yaml: file not found in package`);
4701
5776
  }
4702
- const rawYaml = fs20.readFileSync(skillYamlPath, "utf-8");
5777
+ const rawYaml = fs29.readFileSync(skillYamlPath, "utf-8");
4703
5778
  const parsed = yamlParse(rawYaml);
4704
5779
  skillYaml = validateSkillYaml(parsed);
4705
5780
  placeSkillContent(extractedPkgDir, communityBase, shortName, skillYaml.platforms);
@@ -4738,7 +5813,7 @@ async function runInstall(skillName, options) {
4738
5813
  return result;
4739
5814
  }
4740
5815
  function createInstallCommand() {
4741
- const cmd = new Command48("install");
5816
+ const cmd = new Command55("install");
4742
5817
  cmd.description("Install a community skill from the @harness-skills registry").argument("<skill>", "Skill name or @harness-skills/scoped package name").option("--version <range>", "Semver range or exact version to install").option("--force", "Force reinstall even if same version is already installed").option("--from <path>", "Install from a local directory or .tgz file").option("--registry <url>", "Use a custom npm registry URL").action(async (skill, opts) => {
4743
5818
  try {
4744
5819
  const result = await runInstall(skill, opts);
@@ -4762,15 +5837,15 @@ function createInstallCommand() {
4762
5837
  }
4763
5838
 
4764
5839
  // src/commands/install-constraints.ts
4765
- import * as fs21 from "fs/promises";
4766
- import * as path40 from "path";
4767
- import { Command as Command49 } from "commander";
4768
- import semver3 from "semver";
5840
+ import * as fs30 from "fs/promises";
5841
+ import * as path49 from "path";
5842
+ import { Command as Command56 } from "commander";
5843
+ import semver4 from "semver";
4769
5844
  async function runInstallConstraints(options) {
4770
5845
  const { source, configPath, lockfilePath } = options;
4771
5846
  let rawBundle;
4772
5847
  try {
4773
- rawBundle = await fs21.readFile(source, "utf-8");
5848
+ rawBundle = await fs30.readFile(source, "utf-8");
4774
5849
  } catch (err) {
4775
5850
  if (isNodeError(err) && err.code === "ENOENT") {
4776
5851
  return { ok: false, error: `Bundle file not found: ${source}` };
@@ -4793,9 +5868,9 @@ async function runInstallConstraints(options) {
4793
5868
  }
4794
5869
  const bundle = bundleResult.data;
4795
5870
  if (bundle.minHarnessVersion) {
4796
- const installed = semver3.valid(semver3.coerce(CLI_VERSION));
4797
- const required = semver3.valid(semver3.coerce(bundle.minHarnessVersion));
4798
- if (installed && required && semver3.lt(installed, required)) {
5871
+ const installed = semver4.valid(semver4.coerce(CLI_VERSION));
5872
+ const required = semver4.valid(semver4.coerce(bundle.minHarnessVersion));
5873
+ if (installed && required && semver4.lt(installed, required)) {
4799
5874
  return {
4800
5875
  ok: false,
4801
5876
  error: `Bundle requires harness version >= ${bundle.minHarnessVersion}, but installed version is ${CLI_VERSION}. Please upgrade.`
@@ -4813,7 +5888,7 @@ async function runInstallConstraints(options) {
4813
5888
  }
4814
5889
  let localConfig;
4815
5890
  try {
4816
- const raw = await fs21.readFile(configPath, "utf-8");
5891
+ const raw = await fs30.readFile(configPath, "utf-8");
4817
5892
  localConfig = JSON.parse(raw);
4818
5893
  } catch (err) {
4819
5894
  return {
@@ -4961,7 +6036,7 @@ function isNodeError(err) {
4961
6036
  return err instanceof Error && "code" in err;
4962
6037
  }
4963
6038
  function resolveConfigPath(opts) {
4964
- if (opts.config) return path40.resolve(opts.config);
6039
+ if (opts.config) return path49.resolve(opts.config);
4965
6040
  const found = findConfigFile();
4966
6041
  if (!found.ok) {
4967
6042
  logger.error(found.error.message);
@@ -4996,9 +6071,9 @@ function logInstallResult(val, opts) {
4996
6071
  }
4997
6072
  async function handleInstallConstraints(source, opts) {
4998
6073
  const configPath = resolveConfigPath(opts);
4999
- const projectRoot = path40.dirname(configPath);
5000
- const lockfilePath = path40.join(projectRoot, ".harness", "constraints.lock.json");
5001
- const resolvedSource = path40.resolve(source);
6074
+ const projectRoot = path49.dirname(configPath);
6075
+ const lockfilePath = path49.join(projectRoot, ".harness", "constraints.lock.json");
6076
+ const resolvedSource = path49.resolve(source);
5002
6077
  if (opts.forceLocal && opts.forcePackage) {
5003
6078
  logger.error("Cannot use both --force-local and --force-package.");
5004
6079
  process.exit(1);
@@ -5018,15 +6093,15 @@ async function handleInstallConstraints(source, opts) {
5018
6093
  logInstallResult(result.value, opts);
5019
6094
  }
5020
6095
  function createInstallConstraintsCommand() {
5021
- const cmd = new Command49("install-constraints");
6096
+ const cmd = new Command56("install-constraints");
5022
6097
  cmd.description("Install a constraints bundle into the local harness config").argument("<source>", "Path to a .harness-constraints.json bundle file").option("--force-local", "Resolve all conflicts by keeping local values").option("--force-package", "Resolve all conflicts by using package values").option("--dry-run", "Show what would change without writing files").option("-c, --config <path>", "Path to harness.config.json").action(handleInstallConstraints);
5023
6098
  return cmd;
5024
6099
  }
5025
6100
 
5026
6101
  // src/commands/uninstall-constraints.ts
5027
- import * as fs22 from "fs/promises";
5028
- import * as path41 from "path";
5029
- import { Command as Command50 } from "commander";
6102
+ import * as fs31 from "fs/promises";
6103
+ import * as path50 from "path";
6104
+ import { Command as Command57 } from "commander";
5030
6105
  async function runUninstallConstraints(options) {
5031
6106
  const { packageName, configPath, lockfilePath } = options;
5032
6107
  const lockfileResult = await readLockfile(lockfilePath);
@@ -5046,7 +6121,7 @@ async function runUninstallConstraints(options) {
5046
6121
  }
5047
6122
  let localConfig;
5048
6123
  try {
5049
- const raw = await fs22.readFile(configPath, "utf-8");
6124
+ const raw = await fs31.readFile(configPath, "utf-8");
5050
6125
  localConfig = JSON.parse(raw);
5051
6126
  } catch (err) {
5052
6127
  return {
@@ -5083,11 +6158,11 @@ async function runUninstallConstraints(options) {
5083
6158
  };
5084
6159
  }
5085
6160
  function createUninstallConstraintsCommand() {
5086
- const cmd = new Command50("uninstall-constraints");
6161
+ const cmd = new Command57("uninstall-constraints");
5087
6162
  cmd.description("Remove a previously installed constraints package").argument("<name>", "Name of the constraint package to uninstall").option("-c, --config <path>", "Path to harness.config.json").action(async (name, opts) => {
5088
6163
  let configPath;
5089
6164
  if (opts.config) {
5090
- configPath = path41.resolve(opts.config);
6165
+ configPath = path50.resolve(opts.config);
5091
6166
  } else {
5092
6167
  const found = findConfigFile();
5093
6168
  if (!found.ok) {
@@ -5096,8 +6171,8 @@ function createUninstallConstraintsCommand() {
5096
6171
  }
5097
6172
  configPath = found.value;
5098
6173
  }
5099
- const projectRoot = path41.dirname(configPath);
5100
- const lockfilePath = path41.join(projectRoot, ".harness", "constraints.lock.json");
6174
+ const projectRoot = path50.dirname(configPath);
6175
+ const lockfilePath = path50.join(projectRoot, ".harness", "constraints.lock.json");
5101
6176
  const result = await runUninstallConstraints({
5102
6177
  packageName: name,
5103
6178
  configPath,
@@ -5122,15 +6197,15 @@ function createUninstallConstraintsCommand() {
5122
6197
  }
5123
6198
 
5124
6199
  // src/commands/uninstall.ts
5125
- import * as path42 from "path";
5126
- import { Command as Command51 } from "commander";
6200
+ import * as path51 from "path";
6201
+ import { Command as Command58 } from "commander";
5127
6202
  async function runUninstall(skillName, options) {
5128
6203
  const packageName = resolvePackageName(skillName);
5129
6204
  const shortName = extractSkillName(packageName);
5130
6205
  const globalDir = resolveGlobalSkillsDir();
5131
- const skillsDir = path42.dirname(globalDir);
5132
- const communityBase = path42.join(skillsDir, "community");
5133
- const lockfilePath = path42.join(communityBase, "skills-lock.json");
6206
+ const skillsDir = path51.dirname(globalDir);
6207
+ const communityBase = path51.join(skillsDir, "community");
6208
+ const lockfilePath = path51.join(communityBase, "skills-lock.json");
5134
6209
  const lockfile = readLockfile2(lockfilePath);
5135
6210
  const entry = lockfile.skills[packageName];
5136
6211
  if (!entry) {
@@ -5160,7 +6235,7 @@ async function runUninstall(skillName, options) {
5160
6235
  return result;
5161
6236
  }
5162
6237
  function createUninstallCommand() {
5163
- const cmd = new Command51("uninstall");
6238
+ const cmd = new Command58("uninstall");
5164
6239
  cmd.description("Uninstall a community skill").argument("<skill>", "Skill name or @harness-skills/scoped package name").option("--force", "Remove even if other skills depend on this one").action(async (skill, opts) => {
5165
6240
  try {
5166
6241
  const result = await runUninstall(skill, opts);
@@ -5179,13 +6254,13 @@ function createUninstallCommand() {
5179
6254
  }
5180
6255
 
5181
6256
  // src/commands/orchestrator.ts
5182
- import { Command as Command52 } from "commander";
5183
- import * as path43 from "path";
6257
+ import { Command as Command59 } from "commander";
6258
+ import * as path52 from "path";
5184
6259
  import { Orchestrator, WorkflowLoader, launchTUI } from "@harness-engineering/orchestrator";
5185
6260
  function createOrchestratorCommand() {
5186
- const orchestrator = new Command52("orchestrator");
6261
+ const orchestrator = new Command59("orchestrator");
5187
6262
  orchestrator.command("run").description("Run the orchestrator daemon").option("-w, --workflow <path>", "Path to WORKFLOW.md", "WORKFLOW.md").action(async (opts) => {
5188
- const workflowPath = path43.resolve(process.cwd(), opts.workflow);
6263
+ const workflowPath = path52.resolve(process.cwd(), opts.workflow);
5189
6264
  const loader = new WorkflowLoader();
5190
6265
  const result = await loader.loadWorkflow(workflowPath);
5191
6266
  if (!result.ok) {
@@ -5209,13 +6284,13 @@ function createOrchestratorCommand() {
5209
6284
  }
5210
6285
 
5211
6286
  // src/commands/learnings/index.ts
5212
- import { Command as Command54 } from "commander";
6287
+ import { Command as Command61 } from "commander";
5213
6288
 
5214
6289
  // src/commands/learnings/prune.ts
5215
- import { Command as Command53 } from "commander";
5216
- import * as path44 from "path";
6290
+ import { Command as Command60 } from "commander";
6291
+ import * as path53 from "path";
5217
6292
  async function handlePrune(opts) {
5218
- const projectPath = path44.resolve(opts.path);
6293
+ const projectPath = path53.resolve(opts.path);
5219
6294
  const result = await pruneLearnings(projectPath, opts.stream);
5220
6295
  if (!result.ok) {
5221
6296
  logger.error(result.error.message);
@@ -5254,21 +6329,666 @@ function printPatternProposals(patterns) {
5254
6329
  );
5255
6330
  }
5256
6331
  function createPruneCommand() {
5257
- return new Command53("prune").description(
6332
+ return new Command60("prune").description(
5258
6333
  "Analyze global learnings for patterns, present improvement proposals, and archive old entries"
5259
6334
  ).option("--path <path>", "Project root path", ".").option("--stream <name>", "Target a specific stream").action(handlePrune);
5260
6335
  }
5261
6336
 
5262
6337
  // src/commands/learnings/index.ts
5263
6338
  function createLearningsCommand() {
5264
- const command = new Command54("learnings").description("Learnings management commands");
6339
+ const command = new Command61("learnings").description("Learnings management commands");
5265
6340
  command.addCommand(createPruneCommand());
5266
6341
  return command;
5267
6342
  }
5268
6343
 
6344
+ // src/commands/integrations/index.ts
6345
+ import { Command as Command66 } from "commander";
6346
+
6347
+ // src/commands/integrations/add.ts
6348
+ import { Command as Command62 } from "commander";
6349
+ import * as fs32 from "fs";
6350
+ import * as path54 from "path";
6351
+ import chalk6 from "chalk";
6352
+ function addIntegration(cwd, name) {
6353
+ const def = INTEGRATION_REGISTRY.find((i) => i.name === name);
6354
+ if (!def) {
6355
+ return Err(
6356
+ new CLIError(
6357
+ `Integration '${name}' not found in registry. Run 'harness integrations list' to see available integrations.`,
6358
+ ExitCode.ERROR
6359
+ )
6360
+ );
6361
+ }
6362
+ if (def.tier === 0) {
6363
+ return Err(
6364
+ new CLIError(
6365
+ `${def.displayName} is a Tier 0 integration, already configured by 'harness setup'. Run 'harness setup' if missing.`,
6366
+ ExitCode.ERROR
6367
+ )
6368
+ );
6369
+ }
6370
+ const mcpPath = path54.join(cwd, ".mcp.json");
6371
+ const mcpEntry = {
6372
+ command: def.mcpConfig.command
6373
+ };
6374
+ if (def.mcpConfig.args.length > 0) mcpEntry.args = def.mcpConfig.args;
6375
+ if (def.mcpConfig.env) mcpEntry.env = def.mcpConfig.env;
6376
+ writeMcpEntry(mcpPath, def.name, mcpEntry);
6377
+ const geminiDir = path54.join(cwd, ".gemini");
6378
+ if (fs32.existsSync(geminiDir)) {
6379
+ const geminiPath = path54.join(geminiDir, "settings.json");
6380
+ writeMcpEntry(geminiPath, def.name, mcpEntry);
6381
+ }
6382
+ const configPath = path54.join(cwd, "harness.config.json");
6383
+ const integConfig = readIntegrationsConfig(configPath);
6384
+ if (!integConfig.enabled.includes(def.name)) {
6385
+ integConfig.enabled.push(def.name);
6386
+ }
6387
+ integConfig.dismissed = integConfig.dismissed.filter((d) => d !== def.name);
6388
+ writeIntegrationsConfig(configPath, integConfig);
6389
+ const envVarMissing = !!def.envVar && !process.env[def.envVar];
6390
+ return Ok({
6391
+ name: def.name,
6392
+ displayName: def.displayName,
6393
+ envVarMissing,
6394
+ ...def.envVar !== void 0 && { envVar: def.envVar },
6395
+ ...def.installHint !== void 0 && { installHint: def.installHint }
6396
+ });
6397
+ }
6398
+ function createAddIntegrationCommand() {
6399
+ return new Command62("add").description("Enable an MCP integration").argument("<name>", "Integration name (e.g. perplexity, augment-code)").action(async (name, _opts, cmd) => {
6400
+ const globalOpts = cmd.optsWithGlobals();
6401
+ const cwd = process.cwd();
6402
+ const result = addIntegration(cwd, name);
6403
+ if (!result.ok) {
6404
+ if (!globalOpts.quiet) {
6405
+ logger.error(result.error.message);
6406
+ }
6407
+ process.exit(result.error.exitCode);
6408
+ return;
6409
+ }
6410
+ const { displayName, envVarMissing, envVar, installHint } = result.value;
6411
+ if (!globalOpts.quiet) {
6412
+ console.log("");
6413
+ logger.success(`${displayName} integration enabled.`);
6414
+ console.log("");
6415
+ if (envVarMissing && envVar) {
6416
+ logger.warn(`Set ${chalk6.bold(envVar)} in your environment to activate.`);
6417
+ if (installHint) {
6418
+ console.log(` ${chalk6.dim(installHint)}`);
6419
+ }
6420
+ console.log("");
6421
+ }
6422
+ }
6423
+ process.exit(ExitCode.SUCCESS);
6424
+ });
6425
+ }
6426
+
6427
+ // src/commands/integrations/list.ts
6428
+ import { Command as Command63 } from "commander";
6429
+ import * as path55 from "path";
6430
+ import chalk7 from "chalk";
6431
+ function createListIntegrationsCommand() {
6432
+ return new Command63("list").description("Show all MCP integrations with status").action(async (_opts, cmd) => {
6433
+ const globalOpts = cmd.optsWithGlobals();
6434
+ const cwd = process.cwd();
6435
+ const mcpPath = path55.join(cwd, ".mcp.json");
6436
+ const configPath = path55.join(cwd, "harness.config.json");
6437
+ const mcpConfig = readMcpConfig(mcpPath);
6438
+ const integConfig = readIntegrationsConfig(configPath);
6439
+ const mcpServers = mcpConfig.mcpServers ?? {};
6440
+ const tier0 = INTEGRATION_REGISTRY.filter((i) => i.tier === 0);
6441
+ const tier1 = INTEGRATION_REGISTRY.filter((i) => i.tier === 1);
6442
+ if (globalOpts.json) {
6443
+ const entries = INTEGRATION_REGISTRY.map((i) => ({
6444
+ name: i.name,
6445
+ tier: i.tier,
6446
+ configured: i.name in mcpServers,
6447
+ enabled: integConfig.enabled.includes(i.name),
6448
+ dismissed: integConfig.dismissed.includes(i.name),
6449
+ envVar: i.envVar ?? null,
6450
+ envVarSet: i.envVar ? !!process.env[i.envVar] : null
6451
+ }));
6452
+ console.log(JSON.stringify(entries, null, 2));
6453
+ process.exit(ExitCode.SUCCESS);
6454
+ return;
6455
+ }
6456
+ console.log("");
6457
+ console.log("MCP Integrations:");
6458
+ console.log("");
6459
+ console.log(" Tier 0 (zero-config):");
6460
+ for (const i of tier0) {
6461
+ const configured = i.name in mcpServers;
6462
+ const icon = configured ? chalk7.green("\u2713") : chalk7.dim("\u25CB");
6463
+ console.log(` ${icon} ${i.name.padEnd(22)} ${i.description}`);
6464
+ }
6465
+ console.log("");
6466
+ console.log(" Tier 1 (API key required):");
6467
+ for (const i of tier1) {
6468
+ const configured = i.name in mcpServers;
6469
+ const dismissed = integConfig.dismissed.includes(i.name);
6470
+ const icon = configured ? chalk7.green("\u2713") : chalk7.dim("\u25CB");
6471
+ let suffix = "";
6472
+ if (dismissed) {
6473
+ suffix = chalk7.dim("[dismissed]");
6474
+ } else if (i.envVar) {
6475
+ const envSet = !!process.env[i.envVar];
6476
+ suffix = `${i.envVar} ${envSet ? chalk7.green("\u2713") : chalk7.yellow("not set")}`;
6477
+ }
6478
+ console.log(` ${icon} ${i.name.padEnd(22)} ${i.description.padEnd(35)} ${suffix}`);
6479
+ }
6480
+ console.log("");
6481
+ console.log(
6482
+ ` Run '${chalk7.cyan("harness integrations add <name>")}' to enable a Tier 1 integration.`
6483
+ );
6484
+ console.log("");
6485
+ process.exit(ExitCode.SUCCESS);
6486
+ });
6487
+ }
6488
+
6489
+ // src/commands/integrations/remove.ts
6490
+ import { Command as Command64 } from "commander";
6491
+ import * as fs33 from "fs";
6492
+ import * as path56 from "path";
6493
+ function removeIntegration(cwd, name) {
6494
+ const def = INTEGRATION_REGISTRY.find((i) => i.name === name);
6495
+ if (!def) {
6496
+ return Err(
6497
+ new CLIError(
6498
+ `Integration '${name}' not found in registry. Run 'harness integrations list' to see available integrations.`,
6499
+ ExitCode.ERROR
6500
+ )
6501
+ );
6502
+ }
6503
+ const mcpPath = path56.join(cwd, ".mcp.json");
6504
+ removeMcpEntry(mcpPath, def.name);
6505
+ const geminiDir = path56.join(cwd, ".gemini");
6506
+ if (fs33.existsSync(geminiDir)) {
6507
+ const geminiPath = path56.join(geminiDir, "settings.json");
6508
+ removeMcpEntry(geminiPath, def.name);
6509
+ }
6510
+ const configPath = path56.join(cwd, "harness.config.json");
6511
+ const integConfig = readIntegrationsConfig(configPath);
6512
+ integConfig.enabled = integConfig.enabled.filter((e) => e !== def.name);
6513
+ writeIntegrationsConfig(configPath, integConfig);
6514
+ return Ok(def.displayName);
6515
+ }
6516
+ function createRemoveIntegrationCommand() {
6517
+ return new Command64("remove").description("Remove an MCP integration").argument("<name>", "Integration name (e.g. perplexity, augment-code)").action(async (name, _opts, cmd) => {
6518
+ const globalOpts = cmd.optsWithGlobals();
6519
+ const cwd = process.cwd();
6520
+ const result = removeIntegration(cwd, name);
6521
+ if (!result.ok) {
6522
+ if (!globalOpts.quiet) {
6523
+ logger.error(result.error.message);
6524
+ }
6525
+ process.exit(result.error.exitCode);
6526
+ return;
6527
+ }
6528
+ if (!globalOpts.quiet) {
6529
+ console.log("");
6530
+ logger.success(`${result.value} integration removed.`);
6531
+ console.log("");
6532
+ }
6533
+ process.exit(ExitCode.SUCCESS);
6534
+ });
6535
+ }
6536
+
6537
+ // src/commands/integrations/dismiss.ts
6538
+ import { Command as Command65 } from "commander";
6539
+ import * as path57 from "path";
6540
+ function dismissIntegration(cwd, name) {
6541
+ const def = INTEGRATION_REGISTRY.find((i) => i.name === name);
6542
+ if (!def) {
6543
+ return Err(
6544
+ new CLIError(
6545
+ `Integration '${name}' not found in registry. Run 'harness integrations list' to see available integrations.`,
6546
+ ExitCode.ERROR
6547
+ )
6548
+ );
6549
+ }
6550
+ const configPath = path57.join(cwd, "harness.config.json");
6551
+ const integConfig = readIntegrationsConfig(configPath);
6552
+ if (!integConfig.dismissed.includes(def.name)) {
6553
+ integConfig.dismissed.push(def.name);
6554
+ }
6555
+ integConfig.enabled = integConfig.enabled.filter((e) => e !== def.name);
6556
+ writeIntegrationsConfig(configPath, integConfig);
6557
+ return Ok(def.displayName);
6558
+ }
6559
+ function createDismissIntegrationCommand() {
6560
+ return new Command65("dismiss").description("Suppress doctor recommendations for an integration").argument("<name>", "Integration name (e.g. perplexity, augment-code)").action(async (name, _opts, cmd) => {
6561
+ const globalOpts = cmd.optsWithGlobals();
6562
+ const cwd = process.cwd();
6563
+ const result = dismissIntegration(cwd, name);
6564
+ if (!result.ok) {
6565
+ if (!globalOpts.quiet) {
6566
+ logger.error(result.error.message);
6567
+ }
6568
+ process.exit(result.error.exitCode);
6569
+ return;
6570
+ }
6571
+ if (!globalOpts.quiet) {
6572
+ console.log("");
6573
+ logger.info(
6574
+ `${result.value} dismissed. It will no longer appear in 'harness doctor' suggestions.`
6575
+ );
6576
+ console.log("");
6577
+ }
6578
+ process.exit(ExitCode.SUCCESS);
6579
+ });
6580
+ }
6581
+
6582
+ // src/commands/integrations/index.ts
6583
+ function createIntegrationsCommand() {
6584
+ const command = new Command66("integrations").description(
6585
+ "Manage MCP peer integrations (add, list, remove, dismiss)"
6586
+ );
6587
+ command.addCommand(createListIntegrationsCommand());
6588
+ command.addCommand(createAddIntegrationCommand());
6589
+ command.addCommand(createRemoveIntegrationCommand());
6590
+ command.addCommand(createDismissIntegrationCommand());
6591
+ return command;
6592
+ }
6593
+
6594
+ // src/commands/usage.ts
6595
+ import { Command as Command67 } from "commander";
6596
+ async function loadAndPriceRecords(cwd, includeClaudeSessions = false) {
6597
+ const { readCostRecords, loadPricingData, calculateCost, parseCCRecords } = await import("./dist-4LPXJYVZ.js");
6598
+ const records = readCostRecords(cwd);
6599
+ if (includeClaudeSessions) {
6600
+ const ccRecords = parseCCRecords();
6601
+ records.push(...ccRecords);
6602
+ }
6603
+ if (records.length === 0) return records;
6604
+ const pricingData = await loadPricingData(cwd);
6605
+ for (const record of records) {
6606
+ if (record.model && record.costMicroUSD == null) {
6607
+ const cost = calculateCost(record, pricingData);
6608
+ if (cost != null) record.costMicroUSD = cost;
6609
+ }
6610
+ }
6611
+ return records;
6612
+ }
6613
+ function formatMicroUSD(microUSD) {
6614
+ if (microUSD == null) return "N/A";
6615
+ return "$" + (microUSD / 1e6).toFixed(4);
6616
+ }
6617
+ function formatTokenCount(count) {
6618
+ if (count >= 1e6) return (count / 1e6).toFixed(1) + "M";
6619
+ if (count >= 1e3) return (count / 1e3).toFixed(1) + "K";
6620
+ return String(count);
6621
+ }
6622
+ function formatModels(models) {
6623
+ if (models.length === 0) return "unknown";
6624
+ if (models.length === 1) return models[0] ?? "unknown";
6625
+ return `${models[0] ?? "unknown"} and ${models.length - 1} other${models.length - 1 > 1 ? "s" : ""}`;
6626
+ }
6627
+ function registerDailyCommand(usage) {
6628
+ usage.command("daily").description("Show per-day token usage and cost").option("--days <n>", "Number of days to show (default: 7, max: 90)", "7").action(async (opts, cmd) => {
6629
+ const globalOpts = cmd.optsWithGlobals();
6630
+ const days = Math.min(Math.max(parseInt(opts.days, 10) || 7, 1), 90);
6631
+ const cwd = process.cwd();
6632
+ const records = await loadAndPriceRecords(cwd, globalOpts.includeClaudeSessions);
6633
+ if (records.length === 0) {
6634
+ if (globalOpts.json) {
6635
+ console.log(JSON.stringify([]));
6636
+ } else {
6637
+ logger.info("No usage data found. Run some harness sessions first.");
6638
+ }
6639
+ return;
6640
+ }
6641
+ const { aggregateByDay } = await import("./dist-4LPXJYVZ.js");
6642
+ const dailyData = aggregateByDay(records);
6643
+ const limited = dailyData.slice(0, days);
6644
+ if (globalOpts.json) {
6645
+ console.log(JSON.stringify(limited, null, 2));
6646
+ return;
6647
+ }
6648
+ const header = "Date | Sessions | Input | Output | Model(s) | Cost";
6649
+ const divider = "-------------|----------|-----------|-----------|------------------------------|--------";
6650
+ logger.info(header);
6651
+ logger.info(divider);
6652
+ for (const day of limited) {
6653
+ const date = day.date.padEnd(12);
6654
+ const sessions = String(day.sessionCount).padStart(8);
6655
+ const input = formatTokenCount(day.tokens.inputTokens).padStart(9);
6656
+ const output = formatTokenCount(day.tokens.outputTokens).padStart(9);
6657
+ const models = formatModels(day.models).padEnd(28);
6658
+ const cost = formatMicroUSD(day.costMicroUSD);
6659
+ logger.info(`${date} | ${sessions} | ${input} | ${output} | ${models} | ${cost}`);
6660
+ }
6661
+ });
6662
+ }
6663
+ function registerSessionsCommand(usage) {
6664
+ usage.command("sessions").description("List recent sessions with token usage and cost").option("--limit <n>", "Number of sessions to show (default: 10, max: 100)", "10").action(async (opts, cmd) => {
6665
+ const globalOpts = cmd.optsWithGlobals();
6666
+ const limit = Math.min(Math.max(parseInt(opts.limit, 10) || 10, 1), 100);
6667
+ const cwd = process.cwd();
6668
+ const records = await loadAndPriceRecords(cwd, globalOpts.includeClaudeSessions);
6669
+ if (records.length === 0) {
6670
+ if (globalOpts.json) {
6671
+ console.log(JSON.stringify([]));
6672
+ } else {
6673
+ logger.info("No usage data found. Run some harness sessions first.");
6674
+ }
6675
+ return;
6676
+ }
6677
+ const { aggregateBySession } = await import("./dist-4LPXJYVZ.js");
6678
+ const sessionData = aggregateBySession(records);
6679
+ const limited = sessionData.slice(0, limit);
6680
+ if (globalOpts.json) {
6681
+ console.log(JSON.stringify(limited, null, 2));
6682
+ return;
6683
+ }
6684
+ const header = "Session ID | Started | Duration | Tokens | Model | Cost";
6685
+ const divider = "---------------------|----------------------|-----------|-----------|----------------------|--------";
6686
+ logger.info(header);
6687
+ logger.info(divider);
6688
+ for (const s of limited) {
6689
+ const id = s.sessionId.slice(0, 20).padEnd(20);
6690
+ const started = s.firstTimestamp.slice(0, 19).padEnd(20);
6691
+ const durationMs = new Date(s.lastTimestamp).getTime() - new Date(s.firstTimestamp).getTime();
6692
+ const durationMin = Math.max(1, Math.round(durationMs / 6e4));
6693
+ const duration = `${durationMin}m`.padStart(9);
6694
+ const tokens = formatTokenCount(s.tokens.totalTokens).padStart(9);
6695
+ const model = (s.model ?? "unknown").slice(0, 20).padEnd(20);
6696
+ const cost = formatMicroUSD(s.costMicroUSD);
6697
+ logger.info(`${id} | ${started} | ${duration} | ${tokens} | ${model} | ${cost}`);
6698
+ }
6699
+ });
6700
+ }
6701
+ function registerSessionCommand(usage) {
6702
+ usage.command("session <id>").description("Show detailed token breakdown for a specific session").action(async (id, _opts, cmd) => {
6703
+ const globalOpts = cmd.optsWithGlobals();
6704
+ const cwd = process.cwd();
6705
+ const records = await loadAndPriceRecords(cwd, globalOpts.includeClaudeSessions);
6706
+ const { aggregateBySession } = await import("./dist-4LPXJYVZ.js");
6707
+ const sessionData = aggregateBySession(records);
6708
+ const match = sessionData.find((s) => s.sessionId === id);
6709
+ if (!match) {
6710
+ const fuzzy = sessionData.filter(
6711
+ (s) => s.sessionId.includes(id) || id.includes(s.sessionId.slice(0, 8))
6712
+ );
6713
+ const errMsg = `Session "${id}" not found.`;
6714
+ if (fuzzy.length > 0) {
6715
+ const suggestions = fuzzy.slice(0, 3).map((s) => s.sessionId);
6716
+ if (globalOpts.json) {
6717
+ console.log(JSON.stringify({ error: errMsg, suggestions }));
6718
+ } else {
6719
+ logger.error(errMsg);
6720
+ logger.info("Did you mean:");
6721
+ for (const s of suggestions) {
6722
+ logger.info(` ${s}`);
6723
+ }
6724
+ }
6725
+ } else {
6726
+ if (globalOpts.json) {
6727
+ console.log(JSON.stringify({ error: errMsg, suggestions: [] }));
6728
+ } else {
6729
+ logger.error(errMsg);
6730
+ }
6731
+ }
6732
+ process.exitCode = 1;
6733
+ return;
6734
+ }
6735
+ if (globalOpts.json) {
6736
+ console.log(JSON.stringify(match, null, 2));
6737
+ return;
6738
+ }
6739
+ logger.info(`Session: ${match.sessionId}`);
6740
+ logger.info(`Started: ${match.firstTimestamp}`);
6741
+ logger.info(`Ended: ${match.lastTimestamp}`);
6742
+ logger.info(`Model: ${match.model ?? "unknown"}`);
6743
+ logger.info(`Source: ${match.source}`);
6744
+ logger.info("");
6745
+ logger.info("Token Breakdown:");
6746
+ logger.info(` Input tokens: ${formatTokenCount(match.tokens.inputTokens)}`);
6747
+ logger.info(` Output tokens: ${formatTokenCount(match.tokens.outputTokens)}`);
6748
+ logger.info(` Total tokens: ${formatTokenCount(match.tokens.totalTokens)}`);
6749
+ if (match.cacheReadTokens != null) {
6750
+ logger.info(` Cache read tokens: ${formatTokenCount(match.cacheReadTokens)}`);
6751
+ }
6752
+ if (match.cacheCreationTokens != null) {
6753
+ logger.info(` Cache creation tokens: ${formatTokenCount(match.cacheCreationTokens)}`);
6754
+ }
6755
+ logger.info("");
6756
+ logger.info(`Cost: ${formatMicroUSD(match.costMicroUSD)}`);
6757
+ });
6758
+ }
6759
+ function registerLatestCommand(usage) {
6760
+ usage.command("latest").description("Show the most recently completed session cost summary").action(async (_opts, cmd) => {
6761
+ const globalOpts = cmd.optsWithGlobals();
6762
+ const cwd = process.cwd();
6763
+ const records = await loadAndPriceRecords(cwd, globalOpts.includeClaudeSessions);
6764
+ if (records.length === 0) {
6765
+ if (globalOpts.json) {
6766
+ console.log(JSON.stringify({ error: "No usage data found" }));
6767
+ } else {
6768
+ logger.info("No usage data found. Run some harness sessions first.");
6769
+ }
6770
+ return;
6771
+ }
6772
+ const { aggregateBySession } = await import("./dist-4LPXJYVZ.js");
6773
+ const sessionData = aggregateBySession(records);
6774
+ const latest = sessionData[0];
6775
+ if (!latest) {
6776
+ if (globalOpts.json) {
6777
+ console.log(JSON.stringify({ error: "No session data found" }));
6778
+ } else {
6779
+ logger.info("No session data found.");
6780
+ }
6781
+ return;
6782
+ }
6783
+ if (globalOpts.json) {
6784
+ console.log(JSON.stringify(latest, null, 2));
6785
+ return;
6786
+ }
6787
+ logger.info(`Session: ${latest.sessionId}`);
6788
+ logger.info(`Started: ${latest.firstTimestamp}`);
6789
+ logger.info(`Ended: ${latest.lastTimestamp}`);
6790
+ logger.info(`Model: ${latest.model ?? "unknown"}`);
6791
+ logger.info(
6792
+ `Tokens: ${formatTokenCount(latest.tokens.totalTokens)} (${formatTokenCount(latest.tokens.inputTokens)} in / ${formatTokenCount(latest.tokens.outputTokens)} out)`
6793
+ );
6794
+ logger.info(`Cost: ${formatMicroUSD(latest.costMicroUSD)}`);
6795
+ });
6796
+ }
6797
+ function createUsageCommand() {
6798
+ const usage = new Command67("usage").description("Token usage and cost tracking");
6799
+ usage.option(
6800
+ "--include-claude-sessions",
6801
+ "Include Claude Code session data from ~/.claude/projects/"
6802
+ );
6803
+ registerDailyCommand(usage);
6804
+ registerSessionsCommand(usage);
6805
+ registerSessionCommand(usage);
6806
+ registerLatestCommand(usage);
6807
+ return usage;
6808
+ }
6809
+
6810
+ // src/commands/taint.ts
6811
+ import { Command as Command68 } from "commander";
6812
+ function getProjectRoot() {
6813
+ return process.cwd();
6814
+ }
6815
+ function registerClearCommand(taint) {
6816
+ taint.command("clear [sessionId]").description(
6817
+ "Clear session taint \u2014 removes taint file(s) and re-enables destructive operations"
6818
+ ).action((sessionId) => {
6819
+ const projectRoot = getProjectRoot();
6820
+ const count = clearTaint(projectRoot, sessionId);
6821
+ if (count === 0) {
6822
+ if (sessionId) {
6823
+ logger.info(`No taint found for session "${sessionId}".`);
6824
+ } else {
6825
+ logger.info("No active taint files found.");
6826
+ }
6827
+ } else if (sessionId) {
6828
+ logger.info(
6829
+ `Sentinel: taint cleared for session "${sessionId}". Destructive operations re-enabled.`
6830
+ );
6831
+ } else {
6832
+ logger.info(
6833
+ `Sentinel: cleared ${count} taint file${count === 1 ? "" : "s"}. Destructive operations re-enabled.`
6834
+ );
6835
+ }
6836
+ });
6837
+ }
6838
+ function registerStatusCommand(taint) {
6839
+ taint.command("status [sessionId]").description("Show current taint status for a session or all sessions").action((sessionId) => {
6840
+ const projectRoot = getProjectRoot();
6841
+ if (sessionId) {
6842
+ const result = checkTaint(projectRoot, sessionId);
6843
+ if (result.expired) {
6844
+ logger.info(`Session "${sessionId}": taint expired (cleared).`);
6845
+ } else if (result.tainted && result.state) {
6846
+ const state = result.state;
6847
+ const expiresAt = new Date(state.expiresAt);
6848
+ const remaining = Math.max(0, Math.round((expiresAt.getTime() - Date.now()) / 1e3 / 60));
6849
+ logger.info(`Session "${sessionId}": TAINTED (${state.severity})`);
6850
+ logger.info(` Reason: ${state.reason}`);
6851
+ logger.info(` Expires in: ~${remaining} minute${remaining === 1 ? "" : "s"}`);
6852
+ logger.info(` Findings: ${state.findings.length}`);
6853
+ } else {
6854
+ logger.info(`Session "${sessionId}": clean (no taint).`);
6855
+ }
6856
+ } else {
6857
+ const sessions = listTaintedSessions(projectRoot);
6858
+ if (sessions.length === 0) {
6859
+ logger.info("No active taint sessions.");
6860
+ } else {
6861
+ logger.info(`Active taint sessions (${sessions.length}):`);
6862
+ for (const id of sessions) {
6863
+ const result = checkTaint(projectRoot, id);
6864
+ if (result.tainted && result.state) {
6865
+ const remaining = Math.max(
6866
+ 0,
6867
+ Math.round((new Date(result.state.expiresAt).getTime() - Date.now()) / 1e3 / 60)
6868
+ );
6869
+ logger.info(` ${id}: ${result.state.severity} \u2014 expires in ~${remaining}m`);
6870
+ }
6871
+ }
6872
+ }
6873
+ }
6874
+ });
6875
+ }
6876
+ function createTaintCommand() {
6877
+ const taint = new Command68("taint").description("Manage sentinel session taint state");
6878
+ registerClearCommand(taint);
6879
+ registerStatusCommand(taint);
6880
+ return taint;
6881
+ }
6882
+
6883
+ // src/commands/scan-config.ts
6884
+ import { Command as Command69 } from "commander";
6885
+ import { existsSync as existsSync30, readFileSync as readFileSync18, writeFileSync as writeFileSync15 } from "fs";
6886
+ import { join as join44, relative as relative2 } from "path";
6887
+ var CONFIG_FILES = ["CLAUDE.md", "AGENTS.md", ".gemini/settings.json", "skill.yaml"];
6888
+ function stripHighSeverityPatterns(content, injectionFindings) {
6889
+ const highLines = /* @__PURE__ */ new Set();
6890
+ for (const f of injectionFindings) {
6891
+ if (f.severity === "high" && f.line !== void 0) {
6892
+ highLines.add(f.line);
6893
+ }
6894
+ }
6895
+ if (highLines.size === 0) return { cleaned: content, linesStripped: 0 };
6896
+ const lines = content.split("\n");
6897
+ let linesStripped = 0;
6898
+ for (const lineNum of highLines) {
6899
+ const idx = lineNum - 1;
6900
+ if (idx >= 0 && idx < lines.length) {
6901
+ lines[idx] = "";
6902
+ linesStripped++;
6903
+ }
6904
+ }
6905
+ return { cleaned: lines.join("\n"), linesStripped };
6906
+ }
6907
+ function applyFix(filePath, targetDir, content, injectionFindings) {
6908
+ const hasHighSeverity = injectionFindings.some((f) => f.severity === "high");
6909
+ if (!hasHighSeverity) return;
6910
+ const { cleaned, linesStripped } = stripHighSeverityPatterns(content, injectionFindings);
6911
+ if (linesStripped > 0) {
6912
+ writeFileSync15(filePath, cleaned);
6913
+ logger.info(
6914
+ `scan-config --fix: stripped ${linesStripped} high-severity line(s) from ${relative2(targetDir, filePath).replaceAll("\\", "/")}`
6915
+ );
6916
+ }
6917
+ }
6918
+ function scanSingleFile(filePath, targetDir, scanner, options) {
6919
+ if (!existsSync30(filePath)) return null;
6920
+ let content;
6921
+ try {
6922
+ content = readFileSync18(filePath, "utf8");
6923
+ } catch {
6924
+ return null;
6925
+ }
6926
+ const injectionFindings = scanForInjection(content);
6927
+ const findings = mapInjectionFindings(injectionFindings);
6928
+ const secFindings = scanner.scanContent(content, filePath);
6929
+ findings.push(...mapSecurityFindings(secFindings, findings));
6930
+ if (options.fix) {
6931
+ applyFix(filePath, targetDir, content, injectionFindings);
6932
+ }
6933
+ return {
6934
+ file: relative2(targetDir, filePath).replaceAll("\\", "/"),
6935
+ findings,
6936
+ overallSeverity: computeOverallSeverity(findings)
6937
+ };
6938
+ }
6939
+ async function runScanConfig(targetDir, options) {
6940
+ const scanner = new SecurityScanner(parseSecurityConfig({}));
6941
+ const results = [];
6942
+ for (const configFile of CONFIG_FILES) {
6943
+ const result = scanSingleFile(join44(targetDir, configFile), targetDir, scanner, options);
6944
+ if (result) results.push(result);
6945
+ }
6946
+ return { exitCode: computeScanExitCode(results), results };
6947
+ }
6948
+ function formatTextOutput(result) {
6949
+ if (result.results.length === 0) {
6950
+ logger.info("scan-config: no config files found to scan.");
6951
+ return;
6952
+ }
6953
+ for (const fileResult of result.results) {
6954
+ if (fileResult.findings.length === 0) {
6955
+ logger.info(`${fileResult.file}: clean`);
6956
+ continue;
6957
+ }
6958
+ logger.info(
6959
+ `${fileResult.file}: ${fileResult.overallSeverity} (${fileResult.findings.length} finding(s))`
6960
+ );
6961
+ for (const f of fileResult.findings) {
6962
+ const lineInfo = f.line ? ` (line ${f.line})` : "";
6963
+ logger.info(` [${f.ruleId}] ${f.severity.toUpperCase()}: ${f.message}${lineInfo}`);
6964
+ }
6965
+ }
6966
+ if (result.exitCode === 2) {
6967
+ logger.error("scan-config: HIGH severity findings detected. Execution should be blocked.");
6968
+ } else if (result.exitCode === 1) {
6969
+ logger.warn("scan-config: MEDIUM severity findings detected. Session should be tainted.");
6970
+ }
6971
+ }
6972
+ function createScanConfigCommand() {
6973
+ const command = new Command69("scan-config").description(
6974
+ "Scan CLAUDE.md, AGENTS.md, .gemini/settings.json, and skill.yaml for prompt injection patterns"
6975
+ ).option("--path <dir>", "Target directory to scan", process.cwd()).option("--fix", "Strip high-severity patterns from files in-place").action(async (opts, cmd) => {
6976
+ const globalOpts = cmd.optsWithGlobals();
6977
+ const mode = globalOpts.json ? OutputMode.JSON : globalOpts.quiet ? OutputMode.QUIET : OutputMode.TEXT;
6978
+ const result = await runScanConfig(opts.path, { fix: opts.fix });
6979
+ if (mode === OutputMode.JSON) {
6980
+ console.log(JSON.stringify(result, null, 2));
6981
+ } else if (mode !== OutputMode.QUIET) {
6982
+ formatTextOutput(result);
6983
+ }
6984
+ process.exit(result.exitCode);
6985
+ });
6986
+ return command;
6987
+ }
6988
+
5269
6989
  // src/index.ts
5270
6990
  function createProgram() {
5271
- const program = new Command55();
6991
+ const program = new Command70();
5272
6992
  program.name("harness").description("CLI for Harness Engineering toolkit").version(CLI_VERSION).option("-c, --config <path>", "Path to config file").option("--json", "Output as JSON").option("--verbose", "Verbose output").option("--quiet", "Minimal output");
5273
6993
  program.addCommand(createValidateCommand());
5274
6994
  program.addCommand(createCheckDepsCommand());
@@ -5289,10 +7009,13 @@ function createProgram() {
5289
7009
  program.addCommand(createCheckPhaseGateCommand());
5290
7010
  program.addCommand(createCreateSkillCommand());
5291
7011
  program.addCommand(createSetupMcpCommand());
7012
+ program.addCommand(createSetupCommand());
7013
+ program.addCommand(createDoctorCommand());
5292
7014
  program.addCommand(createGenerateSlashCommandsCommand());
5293
7015
  program.addCommand(createGenerateAgentDefinitionsCommand());
5294
7016
  program.addCommand(createGenerateCommand3());
5295
7017
  program.addCommand(createCICommand());
7018
+ program.addCommand(createHooksCommand());
5296
7019
  program.addCommand(createUpdateCommand());
5297
7020
  program.addCommand(createScanCommand());
5298
7021
  program.addCommand(createIngestCommand());
@@ -5308,11 +7031,16 @@ function createProgram() {
5308
7031
  program.addCommand(createUninstallConstraintsCommand());
5309
7032
  program.addCommand(createUninstallCommand());
5310
7033
  program.addCommand(createOrchestratorCommand());
7034
+ program.addCommand(createIntegrationsCommand());
7035
+ program.addCommand(createUsageCommand());
7036
+ program.addCommand(createTaintCommand());
7037
+ program.addCommand(createScanConfigCommand());
5311
7038
  return program;
5312
7039
  }
5313
7040
 
5314
7041
  export {
5315
7042
  buildPreamble,
7043
+ printFirstRunWelcome,
5316
7044
  runScan,
5317
7045
  runIngest,
5318
7046
  runQuery,