@hunter-harness/workflow-harness 0.2.1 → 0.2.3

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 (274) hide show
  1. package/harness/bundles/general/claude-code/.harness-build.json +1 -1
  2. package/harness/bundles/general/claude-code/harness-archive/SKILL.md +1 -1
  3. package/harness/bundles/general/claude-code/harness-archive/reference.md +2 -8
  4. package/harness/bundles/general/claude-code/harness-codebase-map/SKILL.md +2 -1
  5. package/harness/bundles/general/claude-code/harness-knowledge-ingest/SKILL.md +1 -1
  6. package/harness/bundles/general/claude-code/harness-knowledge-ingest/scripts/harness_knowledge.py +474 -122
  7. package/harness/bundles/general/claude-code/harness-knowledge-query/SKILL.md +1 -1
  8. package/harness/bundles/general/claude-code/harness-plan/SKILL.md +2 -1
  9. package/harness/bundles/general/claude-code/harness-review/SKILL.md +5 -1
  10. package/harness/bundles/general/claude-code/harness-run/SKILL.md +1 -1
  11. package/harness/bundles/general/claude-code/harness-run/checklist.md +1 -1
  12. package/harness/bundles/general/claude-code/harness-submit/SKILL.md +2 -2
  13. package/harness/bundles/general/claude-code/harness-submit/checklist.md +30 -6
  14. package/harness/bundles/general/claude-code/harness-sync/SKILL.md +1 -1
  15. package/harness/bundles/general/claude-code/harness-test/SKILL.md +2 -2
  16. package/harness/bundles/general/claude-code/harness-test/checklist.md +1 -1
  17. package/harness/bundles/general/claude-code/harness-test/pitfalls.md +16 -0
  18. package/harness/bundles/general/claude-code/harness-test/scripts/runtime-helpers.mjs +216 -0
  19. package/harness/bundles/general/claude-code/protocols/archive-report-protocol.md +1 -1
  20. package/harness/bundles/general/claude-code/protocols/ledger-protocol.md +55 -2
  21. package/harness/bundles/general/claude-code/protocols/report-pipeline-protocol.md +1 -8
  22. package/harness/bundles/general/claude-code/protocols/sensitive-info-protocol.md +13 -0
  23. package/harness/bundles/general/claude-code/protocols/state-layout-protocol.md +24 -0
  24. package/harness/bundles/general/claude-code/scripts/harness_archive.py +31 -14
  25. package/harness/bundles/general/claude-code/scripts/harness_check_gate.py +111 -0
  26. package/harness/bundles/general/claude-code/scripts/harness_deploy.py +179 -4
  27. package/harness/bundles/general/claude-code/scripts/harness_ledger.py +269 -3
  28. package/harness/bundles/general/claude-code/scripts/harness_preflight.py +72 -382
  29. package/harness/bundles/general/claude-code/scripts/harness_profile.py +742 -0
  30. package/harness/bundles/general/claude-code/scripts/harness_service.py +99 -2
  31. package/harness/bundles/general/claude-code/scripts/harness_state.py +179 -0
  32. package/harness/bundles/general/codebuddy/.harness-build.json +1 -1
  33. package/harness/bundles/general/codebuddy/harness-archive/SKILL.md +1 -1
  34. package/harness/bundles/general/codebuddy/harness-archive/reference.md +2 -8
  35. package/harness/bundles/general/codebuddy/harness-codebase-map/SKILL.md +2 -1
  36. package/harness/bundles/general/codebuddy/harness-knowledge-ingest/SKILL.md +1 -1
  37. package/harness/bundles/general/codebuddy/harness-knowledge-ingest/scripts/harness_knowledge.py +474 -122
  38. package/harness/bundles/general/codebuddy/harness-knowledge-query/SKILL.md +1 -1
  39. package/harness/bundles/general/codebuddy/harness-plan/SKILL.md +2 -1
  40. package/harness/bundles/general/codebuddy/harness-review/SKILL.md +5 -1
  41. package/harness/bundles/general/codebuddy/harness-run/SKILL.md +1 -1
  42. package/harness/bundles/general/codebuddy/harness-run/checklist.md +1 -1
  43. package/harness/bundles/general/codebuddy/harness-submit/SKILL.md +2 -2
  44. package/harness/bundles/general/codebuddy/harness-submit/checklist.md +30 -6
  45. package/harness/bundles/general/codebuddy/harness-sync/SKILL.md +1 -1
  46. package/harness/bundles/general/codebuddy/harness-test/SKILL.md +2 -2
  47. package/harness/bundles/general/codebuddy/harness-test/checklist.md +1 -1
  48. package/harness/bundles/general/codebuddy/harness-test/pitfalls.md +16 -0
  49. package/harness/bundles/general/codebuddy/harness-test/scripts/runtime-helpers.mjs +216 -0
  50. package/harness/bundles/general/codebuddy/protocols/archive-report-protocol.md +1 -1
  51. package/harness/bundles/general/codebuddy/protocols/ledger-protocol.md +55 -2
  52. package/harness/bundles/general/codebuddy/protocols/report-pipeline-protocol.md +1 -8
  53. package/harness/bundles/general/codebuddy/protocols/sensitive-info-protocol.md +13 -0
  54. package/harness/bundles/general/codebuddy/protocols/state-layout-protocol.md +24 -0
  55. package/harness/bundles/general/codebuddy/scripts/harness_archive.py +31 -14
  56. package/harness/bundles/general/codebuddy/scripts/harness_check_gate.py +111 -0
  57. package/harness/bundles/general/codebuddy/scripts/harness_deploy.py +179 -4
  58. package/harness/bundles/general/codebuddy/scripts/harness_ledger.py +269 -3
  59. package/harness/bundles/general/codebuddy/scripts/harness_preflight.py +72 -382
  60. package/harness/bundles/general/codebuddy/scripts/harness_profile.py +742 -0
  61. package/harness/bundles/general/codebuddy/scripts/harness_service.py +99 -2
  62. package/harness/bundles/general/codebuddy/scripts/harness_state.py +179 -0
  63. package/harness/bundles/general/codex/.harness-build.json +1 -1
  64. package/harness/bundles/general/codex/harness-archive/SKILL.md +1 -1
  65. package/harness/bundles/general/codex/harness-archive/reference.md +2 -8
  66. package/harness/bundles/general/codex/harness-codebase-map/SKILL.md +2 -1
  67. package/harness/bundles/general/codex/harness-knowledge-ingest/SKILL.md +1 -1
  68. package/harness/bundles/general/codex/harness-knowledge-ingest/scripts/harness_knowledge.py +474 -122
  69. package/harness/bundles/general/codex/harness-knowledge-query/SKILL.md +1 -1
  70. package/harness/bundles/general/codex/harness-plan/SKILL.md +2 -1
  71. package/harness/bundles/general/codex/harness-review/SKILL.md +5 -1
  72. package/harness/bundles/general/codex/harness-run/SKILL.md +1 -1
  73. package/harness/bundles/general/codex/harness-run/checklist.md +1 -1
  74. package/harness/bundles/general/codex/harness-submit/SKILL.md +2 -2
  75. package/harness/bundles/general/codex/harness-submit/checklist.md +30 -6
  76. package/harness/bundles/general/codex/harness-sync/SKILL.md +1 -1
  77. package/harness/bundles/general/codex/harness-test/SKILL.md +2 -2
  78. package/harness/bundles/general/codex/harness-test/checklist.md +1 -1
  79. package/harness/bundles/general/codex/harness-test/pitfalls.md +16 -0
  80. package/harness/bundles/general/codex/harness-test/scripts/runtime-helpers.mjs +216 -0
  81. package/harness/bundles/general/codex/protocols/archive-report-protocol.md +1 -1
  82. package/harness/bundles/general/codex/protocols/ledger-protocol.md +55 -2
  83. package/harness/bundles/general/codex/protocols/report-pipeline-protocol.md +1 -8
  84. package/harness/bundles/general/codex/protocols/sensitive-info-protocol.md +13 -0
  85. package/harness/bundles/general/codex/protocols/state-layout-protocol.md +24 -0
  86. package/harness/bundles/general/codex/scripts/harness_archive.py +31 -14
  87. package/harness/bundles/general/codex/scripts/harness_check_gate.py +111 -0
  88. package/harness/bundles/general/codex/scripts/harness_deploy.py +179 -4
  89. package/harness/bundles/general/codex/scripts/harness_ledger.py +269 -3
  90. package/harness/bundles/general/codex/scripts/harness_preflight.py +72 -382
  91. package/harness/bundles/general/codex/scripts/harness_profile.py +742 -0
  92. package/harness/bundles/general/codex/scripts/harness_service.py +99 -2
  93. package/harness/bundles/general/codex/scripts/harness_state.py +179 -0
  94. package/harness/bundles/general/cursor/.harness-build.json +1 -1
  95. package/harness/bundles/general/cursor/harness-archive/SKILL.md +1 -1
  96. package/harness/bundles/general/cursor/harness-archive/reference.md +2 -8
  97. package/harness/bundles/general/cursor/harness-codebase-map/SKILL.md +2 -1
  98. package/harness/bundles/general/cursor/harness-knowledge-ingest/SKILL.md +1 -1
  99. package/harness/bundles/general/cursor/harness-knowledge-ingest/scripts/harness_knowledge.py +474 -122
  100. package/harness/bundles/general/cursor/harness-knowledge-query/SKILL.md +1 -1
  101. package/harness/bundles/general/cursor/harness-plan/SKILL.md +2 -1
  102. package/harness/bundles/general/cursor/harness-review/SKILL.md +5 -1
  103. package/harness/bundles/general/cursor/harness-run/SKILL.md +1 -1
  104. package/harness/bundles/general/cursor/harness-run/checklist.md +1 -1
  105. package/harness/bundles/general/cursor/harness-submit/SKILL.md +2 -2
  106. package/harness/bundles/general/cursor/harness-submit/checklist.md +30 -6
  107. package/harness/bundles/general/cursor/harness-sync/SKILL.md +1 -1
  108. package/harness/bundles/general/cursor/harness-test/SKILL.md +2 -2
  109. package/harness/bundles/general/cursor/harness-test/checklist.md +1 -1
  110. package/harness/bundles/general/cursor/harness-test/pitfalls.md +16 -0
  111. package/harness/bundles/general/cursor/harness-test/scripts/runtime-helpers.mjs +216 -0
  112. package/harness/bundles/general/cursor/protocols/archive-report-protocol.md +1 -1
  113. package/harness/bundles/general/cursor/protocols/ledger-protocol.md +55 -2
  114. package/harness/bundles/general/cursor/protocols/report-pipeline-protocol.md +1 -8
  115. package/harness/bundles/general/cursor/protocols/sensitive-info-protocol.md +13 -0
  116. package/harness/bundles/general/cursor/protocols/state-layout-protocol.md +24 -0
  117. package/harness/bundles/general/cursor/scripts/harness_archive.py +31 -14
  118. package/harness/bundles/general/cursor/scripts/harness_check_gate.py +111 -0
  119. package/harness/bundles/general/cursor/scripts/harness_deploy.py +179 -4
  120. package/harness/bundles/general/cursor/scripts/harness_ledger.py +269 -3
  121. package/harness/bundles/general/cursor/scripts/harness_preflight.py +72 -382
  122. package/harness/bundles/general/cursor/scripts/harness_profile.py +742 -0
  123. package/harness/bundles/general/cursor/scripts/harness_service.py +99 -2
  124. package/harness/bundles/general/cursor/scripts/harness_state.py +179 -0
  125. package/harness/bundles/java/claude-code/.harness-build.json +1 -1
  126. package/harness/bundles/java/claude-code/harness-apidoc/SKILL.md +1 -1
  127. package/harness/bundles/java/claude-code/harness-archive/SKILL.md +1 -1
  128. package/harness/bundles/java/claude-code/harness-archive/reference.md +2 -8
  129. package/harness/bundles/java/claude-code/harness-codebase-map/SKILL.md +2 -1
  130. package/harness/bundles/java/claude-code/harness-knowledge-ingest/SKILL.md +1 -1
  131. package/harness/bundles/java/claude-code/harness-knowledge-ingest/scripts/harness_knowledge.py +474 -122
  132. package/harness/bundles/java/claude-code/harness-knowledge-query/SKILL.md +1 -1
  133. package/harness/bundles/java/claude-code/harness-package/SKILL.md +3 -3
  134. package/harness/bundles/java/claude-code/harness-plan/SKILL.md +2 -1
  135. package/harness/bundles/java/claude-code/harness-review/SKILL.md +5 -1
  136. package/harness/bundles/java/claude-code/harness-run/SKILL.md +4 -4
  137. package/harness/bundles/java/claude-code/harness-run/checklist.md +3 -1
  138. package/harness/bundles/java/claude-code/harness-run/reference.md +6 -0
  139. package/harness/bundles/java/claude-code/harness-submit/SKILL.md +3 -3
  140. package/harness/bundles/java/claude-code/harness-submit/checklist.md +30 -6
  141. package/harness/bundles/java/claude-code/harness-sync/SKILL.md +1 -1
  142. package/harness/bundles/java/claude-code/harness-test/SKILL.md +5 -5
  143. package/harness/bundles/java/claude-code/harness-test/checklist.md +3 -1
  144. package/harness/bundles/java/claude-code/harness-test/pitfalls.md +16 -0
  145. package/harness/bundles/java/claude-code/harness-test/reference.md +2 -0
  146. package/harness/bundles/java/claude-code/harness-test/scripts/runtime-helpers.mjs +216 -0
  147. package/harness/bundles/java/claude-code/protocols/archive-report-protocol.md +1 -1
  148. package/harness/bundles/java/claude-code/protocols/ledger-protocol.md +55 -2
  149. package/harness/bundles/java/claude-code/protocols/report-pipeline-protocol.md +1 -8
  150. package/harness/bundles/java/claude-code/protocols/sensitive-info-protocol.md +13 -0
  151. package/harness/bundles/java/claude-code/protocols/state-layout-protocol.md +24 -0
  152. package/harness/bundles/java/claude-code/scripts/harness_archive.py +31 -14
  153. package/harness/bundles/java/claude-code/scripts/harness_check_gate.py +111 -0
  154. package/harness/bundles/java/claude-code/scripts/harness_deploy.py +179 -4
  155. package/harness/bundles/java/claude-code/scripts/harness_ledger.py +269 -3
  156. package/harness/bundles/java/claude-code/scripts/harness_preflight.py +72 -382
  157. package/harness/bundles/java/claude-code/scripts/harness_profile.py +742 -0
  158. package/harness/bundles/java/claude-code/scripts/harness_service.py +99 -2
  159. package/harness/bundles/java/claude-code/scripts/harness_state.py +179 -0
  160. package/harness/bundles/java/codebuddy/.harness-build.json +1 -1
  161. package/harness/bundles/java/codebuddy/harness-apidoc/SKILL.md +1 -1
  162. package/harness/bundles/java/codebuddy/harness-archive/SKILL.md +1 -1
  163. package/harness/bundles/java/codebuddy/harness-archive/reference.md +2 -8
  164. package/harness/bundles/java/codebuddy/harness-codebase-map/SKILL.md +2 -1
  165. package/harness/bundles/java/codebuddy/harness-knowledge-ingest/SKILL.md +1 -1
  166. package/harness/bundles/java/codebuddy/harness-knowledge-ingest/scripts/harness_knowledge.py +474 -122
  167. package/harness/bundles/java/codebuddy/harness-knowledge-query/SKILL.md +1 -1
  168. package/harness/bundles/java/codebuddy/harness-package/SKILL.md +3 -3
  169. package/harness/bundles/java/codebuddy/harness-plan/SKILL.md +2 -1
  170. package/harness/bundles/java/codebuddy/harness-review/SKILL.md +5 -1
  171. package/harness/bundles/java/codebuddy/harness-run/SKILL.md +4 -4
  172. package/harness/bundles/java/codebuddy/harness-run/checklist.md +3 -1
  173. package/harness/bundles/java/codebuddy/harness-run/reference.md +6 -0
  174. package/harness/bundles/java/codebuddy/harness-submit/SKILL.md +3 -3
  175. package/harness/bundles/java/codebuddy/harness-submit/checklist.md +30 -6
  176. package/harness/bundles/java/codebuddy/harness-sync/SKILL.md +1 -1
  177. package/harness/bundles/java/codebuddy/harness-test/SKILL.md +5 -5
  178. package/harness/bundles/java/codebuddy/harness-test/checklist.md +3 -1
  179. package/harness/bundles/java/codebuddy/harness-test/pitfalls.md +16 -0
  180. package/harness/bundles/java/codebuddy/harness-test/reference.md +2 -0
  181. package/harness/bundles/java/codebuddy/harness-test/scripts/runtime-helpers.mjs +216 -0
  182. package/harness/bundles/java/codebuddy/protocols/archive-report-protocol.md +1 -1
  183. package/harness/bundles/java/codebuddy/protocols/ledger-protocol.md +55 -2
  184. package/harness/bundles/java/codebuddy/protocols/report-pipeline-protocol.md +1 -8
  185. package/harness/bundles/java/codebuddy/protocols/sensitive-info-protocol.md +13 -0
  186. package/harness/bundles/java/codebuddy/protocols/state-layout-protocol.md +24 -0
  187. package/harness/bundles/java/codebuddy/scripts/harness_archive.py +31 -14
  188. package/harness/bundles/java/codebuddy/scripts/harness_check_gate.py +111 -0
  189. package/harness/bundles/java/codebuddy/scripts/harness_deploy.py +179 -4
  190. package/harness/bundles/java/codebuddy/scripts/harness_ledger.py +269 -3
  191. package/harness/bundles/java/codebuddy/scripts/harness_preflight.py +72 -382
  192. package/harness/bundles/java/codebuddy/scripts/harness_profile.py +742 -0
  193. package/harness/bundles/java/codebuddy/scripts/harness_service.py +99 -2
  194. package/harness/bundles/java/codebuddy/scripts/harness_state.py +179 -0
  195. package/harness/bundles/java/codex/.harness-build.json +1 -1
  196. package/harness/bundles/java/codex/harness-apidoc/SKILL.md +1 -1
  197. package/harness/bundles/java/codex/harness-archive/SKILL.md +1 -1
  198. package/harness/bundles/java/codex/harness-archive/reference.md +2 -8
  199. package/harness/bundles/java/codex/harness-codebase-map/SKILL.md +2 -1
  200. package/harness/bundles/java/codex/harness-knowledge-ingest/SKILL.md +1 -1
  201. package/harness/bundles/java/codex/harness-knowledge-ingest/scripts/harness_knowledge.py +474 -122
  202. package/harness/bundles/java/codex/harness-knowledge-query/SKILL.md +1 -1
  203. package/harness/bundles/java/codex/harness-package/SKILL.md +3 -3
  204. package/harness/bundles/java/codex/harness-plan/SKILL.md +2 -1
  205. package/harness/bundles/java/codex/harness-review/SKILL.md +5 -1
  206. package/harness/bundles/java/codex/harness-run/SKILL.md +4 -4
  207. package/harness/bundles/java/codex/harness-run/checklist.md +3 -1
  208. package/harness/bundles/java/codex/harness-run/reference.md +6 -0
  209. package/harness/bundles/java/codex/harness-submit/SKILL.md +3 -3
  210. package/harness/bundles/java/codex/harness-submit/checklist.md +30 -6
  211. package/harness/bundles/java/codex/harness-sync/SKILL.md +1 -1
  212. package/harness/bundles/java/codex/harness-test/SKILL.md +5 -5
  213. package/harness/bundles/java/codex/harness-test/checklist.md +3 -1
  214. package/harness/bundles/java/codex/harness-test/pitfalls.md +16 -0
  215. package/harness/bundles/java/codex/harness-test/reference.md +2 -0
  216. package/harness/bundles/java/codex/harness-test/scripts/runtime-helpers.mjs +216 -0
  217. package/harness/bundles/java/codex/protocols/archive-report-protocol.md +1 -1
  218. package/harness/bundles/java/codex/protocols/ledger-protocol.md +55 -2
  219. package/harness/bundles/java/codex/protocols/report-pipeline-protocol.md +1 -8
  220. package/harness/bundles/java/codex/protocols/sensitive-info-protocol.md +13 -0
  221. package/harness/bundles/java/codex/protocols/state-layout-protocol.md +24 -0
  222. package/harness/bundles/java/codex/scripts/harness_archive.py +31 -14
  223. package/harness/bundles/java/codex/scripts/harness_check_gate.py +111 -0
  224. package/harness/bundles/java/codex/scripts/harness_deploy.py +179 -4
  225. package/harness/bundles/java/codex/scripts/harness_ledger.py +269 -3
  226. package/harness/bundles/java/codex/scripts/harness_preflight.py +72 -382
  227. package/harness/bundles/java/codex/scripts/harness_profile.py +742 -0
  228. package/harness/bundles/java/codex/scripts/harness_service.py +99 -2
  229. package/harness/bundles/java/codex/scripts/harness_state.py +179 -0
  230. package/harness/bundles/java/cursor/.harness-build.json +1 -1
  231. package/harness/bundles/java/cursor/harness-apidoc/SKILL.md +1 -1
  232. package/harness/bundles/java/cursor/harness-archive/SKILL.md +1 -1
  233. package/harness/bundles/java/cursor/harness-archive/reference.md +2 -8
  234. package/harness/bundles/java/cursor/harness-codebase-map/SKILL.md +2 -1
  235. package/harness/bundles/java/cursor/harness-knowledge-ingest/SKILL.md +1 -1
  236. package/harness/bundles/java/cursor/harness-knowledge-ingest/scripts/harness_knowledge.py +474 -122
  237. package/harness/bundles/java/cursor/harness-knowledge-query/SKILL.md +1 -1
  238. package/harness/bundles/java/cursor/harness-package/SKILL.md +3 -3
  239. package/harness/bundles/java/cursor/harness-plan/SKILL.md +2 -1
  240. package/harness/bundles/java/cursor/harness-review/SKILL.md +5 -1
  241. package/harness/bundles/java/cursor/harness-run/SKILL.md +4 -4
  242. package/harness/bundles/java/cursor/harness-run/checklist.md +3 -1
  243. package/harness/bundles/java/cursor/harness-run/reference.md +6 -0
  244. package/harness/bundles/java/cursor/harness-submit/SKILL.md +3 -3
  245. package/harness/bundles/java/cursor/harness-submit/checklist.md +30 -6
  246. package/harness/bundles/java/cursor/harness-sync/SKILL.md +1 -1
  247. package/harness/bundles/java/cursor/harness-test/SKILL.md +5 -5
  248. package/harness/bundles/java/cursor/harness-test/checklist.md +3 -1
  249. package/harness/bundles/java/cursor/harness-test/pitfalls.md +16 -0
  250. package/harness/bundles/java/cursor/harness-test/reference.md +2 -0
  251. package/harness/bundles/java/cursor/harness-test/scripts/runtime-helpers.mjs +216 -0
  252. package/harness/bundles/java/cursor/protocols/archive-report-protocol.md +1 -1
  253. package/harness/bundles/java/cursor/protocols/ledger-protocol.md +55 -2
  254. package/harness/bundles/java/cursor/protocols/report-pipeline-protocol.md +1 -8
  255. package/harness/bundles/java/cursor/protocols/sensitive-info-protocol.md +13 -0
  256. package/harness/bundles/java/cursor/protocols/state-layout-protocol.md +24 -0
  257. package/harness/bundles/java/cursor/scripts/harness_archive.py +31 -14
  258. package/harness/bundles/java/cursor/scripts/harness_check_gate.py +111 -0
  259. package/harness/bundles/java/cursor/scripts/harness_deploy.py +179 -4
  260. package/harness/bundles/java/cursor/scripts/harness_ledger.py +269 -3
  261. package/harness/bundles/java/cursor/scripts/harness_preflight.py +72 -382
  262. package/harness/bundles/java/cursor/scripts/harness_profile.py +742 -0
  263. package/harness/bundles/java/cursor/scripts/harness_service.py +99 -2
  264. package/harness/bundles/java/cursor/scripts/harness_state.py +179 -0
  265. package/harness/manifests/general/claude-code.json +44 -28
  266. package/harness/manifests/general/codebuddy.json +44 -28
  267. package/harness/manifests/general/codex.json +44 -28
  268. package/harness/manifests/general/cursor.json +44 -28
  269. package/harness/manifests/java/claude-code.json +48 -32
  270. package/harness/manifests/java/codebuddy.json +48 -32
  271. package/harness/manifests/java/codex.json +48 -32
  272. package/harness/manifests/java/cursor.json +48 -32
  273. package/hunter-workflow-family.json +2 -2
  274. package/package.json +1 -1
@@ -1,6 +1,12 @@
1
1
  #!/usr/bin/env python3
2
2
  """Harness preflight: build-profile detect/check + quirk recording + agent precheck.
3
3
 
4
+ 变更簇 4:detect/check 委托 ``harness_profile``(profile v2 公共内核),不再保留
5
+ v1 重复探测逻辑与 ``buildCommands`` 扁平字符串。record-quirk 适配 v2 ``commands``
6
+ 结构:``fix-command`` 写 ``source=user`` override(spec §3.1 显式保留),跨 detect
7
+ 保留;``skip-not-block`` 仍写 ``knownPreexistingErrors``。check-agents 与 pitfalls
8
+ 附录为本 skill 独有,保留。
9
+
4
10
  Implements DESIGN.md D5 (build-profile) and D8 (subagent precheck).
5
11
  Python 3.10+ stdlib only. UTF-8 without BOM. Windows path friendly.
6
12
  """
@@ -9,12 +15,9 @@ from __future__ import annotations
9
15
 
10
16
  import argparse
11
17
  import datetime as dt
12
- import hashlib
13
18
  import json
14
- import os
15
19
  import re
16
- import shutil
17
- import subprocess
20
+ import shlex
18
21
  import sys
19
22
  from pathlib import Path
20
23
  from typing import Any
@@ -26,21 +29,16 @@ if hasattr(sys.stderr, "reconfigure"):
26
29
  sys.stderr.reconfigure(encoding="utf-8")
27
30
 
28
31
 
29
- SCHEMA_VERSION = 1
30
- PROFILE_REL = Path(".harness") / "config" / "build-profile.json"
32
+ import harness_profile as hprof # noqa: E402
33
+
34
+
31
35
  PITFALLS_REL = Path(".harness") / "pitfalls.md"
32
36
  PITFALLS_APPENDIX_HEADER = "## Preflight 附录(自动追加)"
33
37
 
34
- DEFAULT_BUILD_COMMANDS: dict[str, str] = {
35
- "compile": "",
36
- "unitTest": "",
37
- "unitTestFull": "",
38
- "install": "",
39
- "package": "",
40
- }
41
-
42
38
  VALID_QUIRK_ACTIONS = {"skip-not-block", "fix-command"}
43
39
 
40
+ _DETECT_HINT = "python harness_preflight.py detect --project <root> --json"
41
+
44
42
 
45
43
  def now_iso() -> str:
46
44
  return dt.datetime.now().astimezone().isoformat(timespec="seconds")
@@ -51,358 +49,30 @@ def emit_json(payload: dict[str, Any], *, ok: bool = True) -> int:
51
49
  return 0 if ok else 1
52
50
 
53
51
 
54
- def read_json(path: Path) -> Any:
55
- return json.loads(path.read_text(encoding="utf-8"))
56
-
57
-
58
- def write_json(path: Path, data: Any) -> None:
59
- path.parent.mkdir(parents=True, exist_ok=True)
60
- text = json.dumps(data, ensure_ascii=False, indent=2) + "\n"
61
- path.write_text(text, encoding="utf-8")
62
-
63
-
64
- def sha256_file(path: Path) -> str | None:
65
- if not path.is_file():
66
- return None
67
- h = hashlib.sha256()
68
- with path.open("rb") as fh:
69
- for chunk in iter(lambda: fh.read(65536), b""):
70
- h.update(chunk)
71
- return h.hexdigest()
72
-
73
-
74
- def find_root_pom(project: Path) -> Path | None:
75
- candidates = [project / "pom.xml", project / "pom.xml.example"]
76
- for c in candidates:
77
- if c.is_file():
78
- return c
79
- return None
80
-
81
-
82
- def which_tool(name: str) -> str | None:
83
- found = shutil.which(name)
84
- if found:
85
- return str(Path(found).resolve())
86
- # Windows: try .cmd / .bat / .exe explicitly
87
- if os.name == "nt":
88
- for ext in (".cmd", ".bat", ".exe"):
89
- found = shutil.which(name + ext)
90
- if found:
91
- return str(Path(found).resolve())
92
- return None
93
-
94
-
95
- def run_version(tool_path: str | None, args: list[str], timeout: float = 8.0) -> str:
96
- """Best-effort version probe. Empty string if unavailable."""
97
- if not tool_path:
98
- return ""
99
- try:
100
- completed = subprocess.run(
101
- [tool_path, *args],
102
- capture_output=True,
103
- text=True,
104
- encoding="utf-8",
105
- errors="replace",
106
- timeout=timeout,
107
- check=False,
108
- )
109
- except (OSError, subprocess.TimeoutExpired):
110
- return ""
111
- text = (completed.stdout or "") + "\n" + (completed.stderr or "")
112
- return _extract_version(text)
113
-
114
-
115
- def _extract_version(text: str) -> str:
116
- # node: v20.11.0 / Apache Maven 3.9.6
117
- m = re.search(r"\bv?(\d+\.\d+\.\d+(?:[-+][\w.]+)?)\b", text)
118
- if m:
119
- return m.group(1)
120
- m = re.search(r"version\s+([^\s,]+)", text, re.IGNORECASE)
121
- if m:
122
- return m.group(1).strip()
123
- line = next((ln.strip() for ln in text.splitlines() if ln.strip()), "")
124
- return line[:120]
125
-
126
-
127
- def is_executable_path(path_str: str | None) -> bool:
128
- if not path_str:
129
- return False
130
- p = Path(path_str)
131
- if not p.exists():
132
- return False
133
- if p.is_file():
134
- if os.name == "nt":
135
- return True
136
- return os.access(p, os.X_OK)
137
- # On Windows, shutil.which may return .cmd wrappers that exist
138
- return p.exists()
139
-
140
-
141
- def load_existing_profile(project: Path) -> dict[str, Any] | None:
142
- path = project / PROFILE_REL
143
- if not path.is_file():
144
- return None
145
- try:
146
- data = read_json(path)
147
- except (OSError, json.JSONDecodeError):
148
- return None
149
- return data if isinstance(data, dict) else None
150
-
151
-
152
- def parse_claude_hints(project: Path) -> dict[str, str]:
153
- """Extract optional build command hints from CLAUDE.md / AGENTS.md."""
154
- hints: dict[str, str] = {}
155
- for name in ("CLAUDE.md", "AGENTS.md", ".claude/CLAUDE.md"):
156
- path = project / name
157
- if not path.is_file():
158
- continue
159
- try:
160
- text = path.read_text(encoding="utf-8")
161
- except OSError:
162
- continue
163
- # Look for fenced or inline mvn/npm command examples
164
- for key, pattern in (
165
- ("compile", r"(?:compile|编译)[^\n`]*`([^`]+)`"),
166
- ("unitTest", r"(?:unit.?test|单元测试)[^\n`]*`([^`]+)`"),
167
- ("package", r"(?:package|打包)[^\n`]*`([^`]+)`"),
168
- ("install", r"(?:install|安装依赖)[^\n`]*`([^`]+)`"),
169
- ):
170
- m = re.search(pattern, text, re.IGNORECASE)
171
- if m and key not in hints:
172
- hints[key] = m.group(1).strip()
173
- # Direct mvn lines
174
- for m in re.finditer(r"`(mvn[^`]+)`", text):
175
- cmd = m.group(1).strip()
176
- if "compile" in cmd and "compile" not in hints:
177
- hints["compile"] = cmd
178
- elif re.search(r"\btest\b", cmd) and "unitTest" not in hints:
179
- hints["unitTest"] = cmd
180
- elif "package" in cmd and "package" not in hints:
181
- hints["package"] = cmd
182
- elif "install" in cmd and "install" not in hints:
183
- hints["install"] = cmd
184
- return hints
185
-
186
-
187
- def empty_profile_skeleton() -> dict[str, Any]:
188
- return {
189
- "schemaVersion": SCHEMA_VERSION,
190
- "detectedAt": "",
191
- "toolPaths": {"node": "", "mvn": ""},
192
- "buildCommands": dict(DEFAULT_BUILD_COMMANDS),
193
- "verificationInputs": {},
194
- "serviceStart": {
195
- "command": "",
196
- "healthUrl": "",
197
- "startTimeoutSec": 120,
198
- "inputFiles": [],
199
- "profile": "",
200
- "overlayPath": "",
201
- },
202
- "knownPreexistingErrors": [],
203
- "shellQuirks": [],
204
- "fingerprint": {"mvnVersion": "", "nodeVersion": "", "pomHash": ""},
205
- }
206
-
207
-
208
- def merge_preserve_quirks(
209
- base: dict[str, Any],
210
- existing: dict[str, Any] | None,
211
- ) -> dict[str, Any]:
212
- """Keep human-curated quirks/errors/commands when re-detecting."""
213
- if not existing:
214
- return base
215
- # Preserve knownPreexistingErrors / shellQuirks / filled buildCommands / serviceStart
216
- if isinstance(existing.get("knownPreexistingErrors"), list):
217
- base["knownPreexistingErrors"] = list(existing["knownPreexistingErrors"])
218
- if isinstance(existing.get("shellQuirks"), list):
219
- base["shellQuirks"] = list(existing["shellQuirks"])
220
- existing_cmds = existing.get("buildCommands")
221
- if isinstance(existing_cmds, dict):
222
- for k, v in existing_cmds.items():
223
- if isinstance(v, str) and v.strip():
224
- base["buildCommands"][k] = v
225
- existing_svc = existing.get("serviceStart")
226
- if isinstance(existing_svc, dict):
227
- merged_svc = dict(base.get("serviceStart") or {})
228
- for k, v in existing_svc.items():
229
- if v not in (None, ""):
230
- merged_svc[k] = v
231
- base["serviceStart"] = merged_svc
232
- # 保留用户已配置的 verificationInputs(可能含 module 专属 glob),不覆盖。
233
- if isinstance(existing.get("verificationInputs"), dict):
234
- base["verificationInputs"] = dict(existing["verificationInputs"])
235
- return base
236
-
237
-
238
- def build_fingerprint(project: Path, node_path: str | None, mvn_path: str | None) -> dict[str, str]:
239
- pom = find_root_pom(project)
240
- pom_hash = sha256_file(pom) if pom else ""
241
- return {
242
- "mvnVersion": run_version(mvn_path, ["--version"]) if mvn_path else "",
243
- "nodeVersion": run_version(node_path, ["--version"]) if node_path else "",
244
- "pomHash": pom_hash or "",
245
- }
246
-
247
-
248
- def current_pom_hash(project: Path) -> str:
249
- pom = find_root_pom(project)
250
- return (sha256_file(pom) if pom else "") or ""
251
-
52
+ # ---------------------------------------------------------------------------
53
+ # detect / check — 委托 harness_profile(profile v2 公共内核)
54
+ # ---------------------------------------------------------------------------
252
55
 
253
56
  def cmd_detect(project: Path) -> dict[str, Any]:
254
- project = project.resolve()
255
- existing = load_existing_profile(project)
256
- profile = empty_profile_skeleton()
257
-
258
- node_path = which_tool("node")
259
- mvn_path = which_tool("mvn")
260
- profile["toolPaths"] = {
261
- "node": node_path or "",
262
- "mvn": mvn_path or "",
263
- }
264
- profile["fingerprint"] = build_fingerprint(project, node_path, mvn_path)
265
- profile["detectedAt"] = now_iso()
266
-
267
- hints = parse_claude_hints(project)
268
- cmds = dict(DEFAULT_BUILD_COMMANDS)
269
- cmds.update({k: v for k, v in hints.items() if k in cmds})
270
- # Sensible Java placeholders when pom exists but no hints
271
- if find_root_pom(project) and not any(cmds.values()):
272
- cmds["compile"] = "mvn -f pom.xml compile -o -q"
273
- cmds["unitTest"] = "mvn -f pom.xml test -Dtest={testClasses} -o"
274
- cmds["unitTestFull"] = "mvn -f pom.xml test -o"
275
- cmds["install"] = "mvn install -pl {modules} -am -DskipTests -nsu"
276
- cmds["package"] = "mvn -f pom.xml package '-Dmaven.test.skip=true'"
277
- profile["buildCommands"] = cmds
278
-
279
- # Java 项目给 verificationInputs.unitTestFull 一个根级默认闭包
280
- # (多 module 项目用户可改为 module/pom.xml + module/src/**)。通用/无 pom
281
- # 项目保持空 {} —— can-reuse --profile-input unitTestFull 会返回
282
- # insufficient-evidence,执行全量测试但不允许缓存复用,直到 profile 配置好。
283
- if find_root_pom(project):
284
- # A reactor-level Maven test can run every module, so its reuse
285
- # fingerprint must include every module's pom and source roots.
286
- module_poms = sorted(
287
- pom.relative_to(project).as_posix()
288
- for pom in project.rglob("pom.xml")
289
- if pom.is_file() and ".harness" not in pom.parts and ".git" not in pom.parts
290
- )
291
- full_inputs: list[str] = []
292
- for pom in module_poms:
293
- full_inputs.append(pom)
294
- parent = Path(pom).parent
295
- prefix = "" if str(parent) == "." else f"{parent.as_posix()}/"
296
- full_inputs.extend([f"{prefix}src/main/**", f"{prefix}src/test/**"])
297
- profile["verificationInputs"] = {"unitTestFull": full_inputs}
298
-
299
- profile = merge_preserve_quirks(profile, existing)
300
-
301
- # Idempotent fingerprint/toolPaths overwrite from fresh detect;
302
- # detectedAt updates each run (tests compare ignoring it).
303
- out_path = project / PROFILE_REL
304
- write_json(out_path, profile)
305
-
306
- return {
307
- "ok": True,
308
- "action": "detect",
309
- "project": str(project),
310
- "profilePath": str(out_path),
311
- "profile": profile,
312
- "created": existing is None,
313
- "updated": True,
314
- }
57
+ """Full probe and write build-profile.json (v2). 委托 hprof.detect。"""
58
+ return hprof.detect(project)
315
59
 
316
60
 
317
61
  def cmd_check(project: Path) -> dict[str, Any]:
318
- """Second-run fast check: existence + executability + fingerprint compare.
62
+ """Fast stale check (missing/invalid/stale/ready). 委托 hprof.check。
319
63
 
320
- Does NOT run mvn/node full version probes (≤5s target).
64
+ 兼容:stale 时补 ``hint``(skill canonical hint 引导重新 detect)。
321
65
  """
322
- project = project.resolve()
323
- profile_path = project / PROFILE_REL
324
- issues: list[str] = []
325
- stale = False
326
-
327
- if not profile_path.is_file():
328
- return {
329
- "ok": False,
330
- "hardFailure": True,
331
- "action": "check",
332
- "project": str(project),
333
- "stale": True,
334
- "issues": ["build-profile.json missing; run detect"],
335
- "hint": "python harness_preflight.py detect --project <root> --json",
336
- }
337
-
338
- try:
339
- profile = read_json(profile_path)
340
- except (OSError, json.JSONDecodeError) as exc:
341
- return {
342
- "ok": False,
343
- "hardFailure": True,
344
- "action": "check",
345
- "project": str(project),
346
- "stale": True,
347
- "issues": [f"build-profile.json unreadable: {exc}"],
348
- "hint": "python harness_preflight.py detect --project <root> --json",
349
- }
350
-
351
- if not isinstance(profile, dict):
352
- return {
353
- "ok": False,
354
- "hardFailure": True,
355
- "action": "check",
356
- "project": str(project),
357
- "stale": True,
358
- "issues": ["build-profile.json is not an object"],
359
- "hint": "python harness_preflight.py detect --project <root> --json",
360
- }
361
-
362
- tool_paths = profile.get("toolPaths") or {}
363
- if not isinstance(tool_paths, dict):
364
- tool_paths = {}
365
-
366
- for tool_name in ("node", "mvn"):
367
- path_str = tool_paths.get(tool_name) or ""
368
- if not path_str:
369
- # Empty is allowed (tool not present at detect time)
370
- continue
371
- if not is_executable_path(path_str):
372
- stale = True
373
- issues.append(f"toolPaths.{tool_name} missing or not executable: {path_str}")
374
-
375
- fp = profile.get("fingerprint") or {}
376
- if not isinstance(fp, dict):
377
- fp = {}
378
- stored_pom = fp.get("pomHash") or ""
379
- current_pom = current_pom_hash(project)
380
- if stored_pom != current_pom:
381
- stale = True
382
- issues.append(
383
- f"fingerprint.pomHash changed: stored={stored_pom or '(empty)'} "
384
- f"current={current_pom or '(empty)'}"
385
- )
386
-
387
- # If profile recorded a tool version but path is now gone → already covered.
388
- # If pom appeared/disappeared relative to empty hash → covered above.
389
-
390
- result = {
391
- "ok": not stale,
392
- "action": "check",
393
- "project": str(project),
394
- "stale": stale,
395
- "issues": issues,
396
- "fingerprint": {
397
- "stored": {"pomHash": stored_pom, "mvnVersion": fp.get("mvnVersion", ""), "nodeVersion": fp.get("nodeVersion", "")},
398
- "current": {"pomHash": current_pom},
399
- },
400
- }
401
- if stale:
402
- result["hint"] = "python harness_preflight.py detect --project <root> --json"
66
+ result = hprof.check(project)
67
+ if result.get("stale") and "hint" not in result:
68
+ result["hint"] = _DETECT_HINT
403
69
  return result
404
70
 
405
71
 
72
+ # ---------------------------------------------------------------------------
73
+ # record-quirk — 适配 v2 commands(source=user override)
74
+ # ---------------------------------------------------------------------------
75
+
406
76
  def ensure_pitfalls_appendix(project: Path) -> Path:
407
77
  path = project / PITFALLS_REL
408
78
  path.parent.mkdir(parents=True, exist_ok=True)
@@ -428,12 +98,26 @@ def append_pitfalls_line(project: Path, line: str) -> Path:
428
98
  text = path.read_text(encoding="utf-8")
429
99
  if not text.endswith("\n"):
430
100
  text += "\n"
431
- # Append after appendix header block (end of file is fine for append-only)
432
101
  text += line.rstrip() + "\n"
433
102
  path.write_text(text, encoding="utf-8")
434
103
  return path
435
104
 
436
105
 
106
+ def _load_or_skeleton(project: Path) -> tuple[dict[str, Any], Path]:
107
+ """加载 v2 profile;缺失时返回空 skeleton(不自动 detect,避免副作用)。"""
108
+ profile_path = project / hprof.PROFILE_REL
109
+ if profile_path.is_file():
110
+ try:
111
+ profile = hprof.read_json(profile_path)
112
+ if isinstance(profile, dict):
113
+ return profile, profile_path
114
+ except (OSError, json.JSONDecodeError):
115
+ pass
116
+ profile = hprof.empty_profile_skeleton(hprof.DEFAULT_EXCLUDED_ROOTS)
117
+ profile["detectedAt"] = now_iso()
118
+ return profile, profile_path
119
+
120
+
437
121
  def cmd_record_quirk(
438
122
  project: Path,
439
123
  pattern: str,
@@ -449,28 +133,17 @@ def cmd_record_quirk(
449
133
  "issues": [f"invalid action: {action}; expected one of {sorted(VALID_QUIRK_ACTIONS)}"],
450
134
  }
451
135
 
452
- profile_path = project / PROFILE_REL
453
- if profile_path.is_file():
454
- try:
455
- profile = read_json(profile_path)
456
- if not isinstance(profile, dict):
457
- profile = empty_profile_skeleton()
458
- except (OSError, json.JSONDecodeError):
459
- profile = empty_profile_skeleton()
460
- else:
461
- profile = empty_profile_skeleton()
462
- profile["detectedAt"] = now_iso()
136
+ profile, profile_path = _load_or_skeleton(project)
463
137
 
464
138
  profile.setdefault("knownPreexistingErrors", [])
465
139
  profile.setdefault("shellQuirks", [])
466
- profile.setdefault("buildCommands", dict(DEFAULT_BUILD_COMMANDS))
467
-
140
+ profile.setdefault("commands", {})
468
141
  if not isinstance(profile["knownPreexistingErrors"], list):
469
142
  profile["knownPreexistingErrors"] = []
470
143
  if not isinstance(profile["shellQuirks"], list):
471
144
  profile["shellQuirks"] = []
472
- if not isinstance(profile["buildCommands"], dict):
473
- profile["buildCommands"] = dict(DEFAULT_BUILD_COMMANDS)
145
+ if not isinstance(profile["commands"], dict):
146
+ profile["commands"] = {}
474
147
 
475
148
  changed: list[str] = []
476
149
 
@@ -494,16 +167,29 @@ def cmd_record_quirk(
494
167
  else:
495
168
  changed.append("shellQuirks(already-present)")
496
169
  if fixed_command:
497
- # Known buildCommands key update it; otherwise store under a
498
- # namespaced custom key to avoid polluting the standard key space.
499
- if pattern in DEFAULT_BUILD_COMMANDS:
170
+ # v2:写 commands.<key> source=user override(spec §3.1 显式保留)。
171
+ # 已知 verification key 覆写其 command;否则存 namespaced custom key
172
+ if pattern in hprof.VERIFICATION_KEYS:
500
173
  key = pattern
501
174
  else:
502
175
  key = f"custom:{pattern}"
503
- profile["buildCommands"][key] = fixed_command
504
- changed.append(f"buildCommands.{key}")
505
-
506
- write_json(profile_path, profile)
176
+ existing_cmd = profile["commands"].get(key, {})
177
+ if not isinstance(existing_cmd, dict):
178
+ existing_cmd = {}
179
+ new_cmd = dict(existing_cmd)
180
+ new_cmd["command"] = fixed_command
181
+ try:
182
+ new_cmd["argvTemplate"] = shlex.split(fixed_command)
183
+ except ValueError:
184
+ # 不平衡引号回退到空格切分(best-effort;record-quirk 是人工逃逸口)
185
+ new_cmd["argvTemplate"] = fixed_command.split()
186
+ new_cmd["source"] = "user"
187
+ profile["commands"][key] = new_cmd
188
+ changed.append(f"commands.{key}")
189
+ # 重派 verificationInputs 兼容字段,保持与 commands 一致
190
+ hprof._derive_verification_inputs(profile)
191
+
192
+ hprof.write_json(profile_path, profile)
507
193
 
508
194
  date_str = dt.date.today().isoformat()
509
195
  pitfalls_line = f"- {date_str}: `{pattern}` — {reason} (action={action}"
@@ -528,6 +214,10 @@ def cmd_record_quirk(
528
214
  }
529
215
 
530
216
 
217
+ # ---------------------------------------------------------------------------
218
+ # check-agents — agent 定义可用性校验(本 skill 独有,不涉及 profile)
219
+ # ---------------------------------------------------------------------------
220
+
531
221
  def parse_frontmatter(text: str) -> tuple[dict[str, Any] | None, str | None]:
532
222
  """Parse YAML-ish frontmatter between leading --- fences.
533
223
 
@@ -756,9 +446,9 @@ def main(argv: list[str] | None = None) -> int:
756
446
  return emit_json(result, ok=bool(result.get("ok", True)))
757
447
  if args.command == "check":
758
448
  result = cmd_check(args.project)
759
- # stale=true with a readable profile still exits 0 (callers branch on JSON);
760
- # hard failures (profile missing / unreadable / not an object) exit 1.
761
- return emit_json(result, ok=not result.get("hardFailure", False))
449
+ # missing/invalid = hard failure (exit 1); stale/ready exit 0 (callers branch on JSON)
450
+ hard = result.get("status") in ("missing", "invalid")
451
+ return emit_json(result, ok=not hard)
762
452
  if args.command == "record-quirk":
763
453
  result = cmd_record_quirk(
764
454
  args.project,