@hunter-harness/workflow-harness 0.3.1 → 0.4.1

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 (402) 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 +30 -1
  4. package/harness/bundles/general/claude-code/harness-archive/templates/summary-data-template.json +1 -0
  5. package/harness/bundles/general/claude-code/harness-codebase-map/SKILL.md +1 -1
  6. package/harness/bundles/general/claude-code/harness-execute/SKILL.md +1 -1
  7. package/harness/bundles/general/claude-code/harness-knowledge-ingest/SKILL.md +1 -1
  8. package/harness/bundles/general/claude-code/harness-knowledge-query/SKILL.md +1 -1
  9. package/harness/bundles/general/claude-code/harness-plan/SKILL.md +1 -1
  10. package/harness/bundles/general/claude-code/harness-pull/SKILL.md +1 -1
  11. package/harness/bundles/general/claude-code/harness-push/SKILL.md +1 -1
  12. package/harness/bundles/general/claude-code/harness-review/SKILL.md +1 -1
  13. package/harness/bundles/general/claude-code/harness-run/SKILL.md +1 -1
  14. package/harness/bundles/general/claude-code/harness-submit/SKILL.md +1 -1
  15. package/harness/bundles/general/claude-code/harness-sync/SKILL.md +1 -1
  16. package/harness/bundles/general/claude-code/harness-test/SKILL.md +1 -1
  17. package/harness/bundles/general/claude-code/scripts/harness_archive.py +146 -8
  18. package/harness/bundles/general/claude-code/scripts/harness_deploy.py +1 -1
  19. package/harness/bundles/general/claude-code/scripts/harness_knowledge_candidates.py +538 -4
  20. package/harness/bundles/general/codebuddy/.harness-build.json +1 -1
  21. package/harness/bundles/general/codebuddy/harness-archive/SKILL.md +1 -1
  22. package/harness/bundles/general/codebuddy/harness-archive/reference.md +30 -1
  23. package/harness/bundles/general/codebuddy/harness-archive/templates/summary-data-template.json +1 -0
  24. package/harness/bundles/general/codebuddy/harness-codebase-map/SKILL.md +1 -1
  25. package/harness/bundles/general/codebuddy/harness-execute/SKILL.md +1 -1
  26. package/harness/bundles/general/codebuddy/harness-knowledge-ingest/SKILL.md +1 -1
  27. package/harness/bundles/general/codebuddy/harness-knowledge-query/SKILL.md +1 -1
  28. package/harness/bundles/general/codebuddy/harness-plan/SKILL.md +1 -1
  29. package/harness/bundles/general/codebuddy/harness-pull/SKILL.md +1 -1
  30. package/harness/bundles/general/codebuddy/harness-push/SKILL.md +1 -1
  31. package/harness/bundles/general/codebuddy/harness-review/SKILL.md +1 -1
  32. package/harness/bundles/general/codebuddy/harness-run/SKILL.md +1 -1
  33. package/harness/bundles/general/codebuddy/harness-submit/SKILL.md +1 -1
  34. package/harness/bundles/general/codebuddy/harness-sync/SKILL.md +1 -1
  35. package/harness/bundles/general/codebuddy/harness-test/SKILL.md +1 -1
  36. package/harness/bundles/general/codebuddy/scripts/harness_archive.py +146 -8
  37. package/harness/bundles/general/codebuddy/scripts/harness_deploy.py +1 -1
  38. package/harness/bundles/general/codebuddy/scripts/harness_knowledge_candidates.py +538 -4
  39. package/harness/bundles/general/codex/.harness-build.json +1 -1
  40. package/harness/bundles/general/codex/harness-archive/SKILL.md +1 -1
  41. package/harness/bundles/general/codex/harness-archive/reference.md +30 -1
  42. package/harness/bundles/general/codex/harness-archive/templates/summary-data-template.json +1 -0
  43. package/harness/bundles/general/codex/harness-codebase-map/SKILL.md +1 -1
  44. package/harness/bundles/general/codex/harness-execute/SKILL.md +1 -1
  45. package/harness/bundles/general/codex/harness-knowledge-ingest/SKILL.md +1 -1
  46. package/harness/bundles/general/codex/harness-knowledge-query/SKILL.md +1 -1
  47. package/harness/bundles/general/codex/harness-plan/SKILL.md +1 -1
  48. package/harness/bundles/general/codex/harness-pull/SKILL.md +1 -1
  49. package/harness/bundles/general/codex/harness-push/SKILL.md +1 -1
  50. package/harness/bundles/general/codex/harness-review/SKILL.md +1 -1
  51. package/harness/bundles/general/codex/harness-run/SKILL.md +1 -1
  52. package/harness/bundles/general/codex/harness-submit/SKILL.md +1 -1
  53. package/harness/bundles/general/codex/harness-sync/SKILL.md +1 -1
  54. package/harness/bundles/general/codex/harness-test/SKILL.md +1 -1
  55. package/harness/bundles/general/codex/scripts/harness_archive.py +146 -8
  56. package/harness/bundles/general/codex/scripts/harness_deploy.py +1 -1
  57. package/harness/bundles/general/codex/scripts/harness_knowledge_candidates.py +538 -4
  58. package/harness/bundles/general/cursor/.harness-build.json +1 -1
  59. package/harness/bundles/general/cursor/harness-archive/SKILL.md +1 -1
  60. package/harness/bundles/general/cursor/harness-archive/reference.md +30 -1
  61. package/harness/bundles/general/cursor/harness-archive/templates/summary-data-template.json +1 -0
  62. package/harness/bundles/general/cursor/harness-codebase-map/SKILL.md +1 -1
  63. package/harness/bundles/general/cursor/harness-execute/SKILL.md +1 -1
  64. package/harness/bundles/general/cursor/harness-knowledge-ingest/SKILL.md +1 -1
  65. package/harness/bundles/general/cursor/harness-knowledge-query/SKILL.md +1 -1
  66. package/harness/bundles/general/cursor/harness-plan/SKILL.md +1 -1
  67. package/harness/bundles/general/cursor/harness-pull/SKILL.md +1 -1
  68. package/harness/bundles/general/cursor/harness-push/SKILL.md +1 -1
  69. package/harness/bundles/general/cursor/harness-review/SKILL.md +1 -1
  70. package/harness/bundles/general/cursor/harness-run/SKILL.md +1 -1
  71. package/harness/bundles/general/cursor/harness-submit/SKILL.md +1 -1
  72. package/harness/bundles/general/cursor/harness-sync/SKILL.md +1 -1
  73. package/harness/bundles/general/cursor/harness-test/SKILL.md +1 -1
  74. package/harness/bundles/general/cursor/scripts/harness_archive.py +146 -8
  75. package/harness/bundles/general/cursor/scripts/harness_deploy.py +1 -1
  76. package/harness/bundles/general/cursor/scripts/harness_knowledge_candidates.py +538 -4
  77. package/harness/bundles/general/pi/.harness-build.json +6 -0
  78. package/harness/bundles/general/pi/CONTEXT.md +98 -0
  79. package/harness/bundles/general/pi/README.md +478 -0
  80. package/harness/bundles/general/pi/contracts/build-profile-v3.schema.json +302 -0
  81. package/harness/bundles/general/pi/contracts/ci-metrics.schema.json +36 -0
  82. package/harness/bundles/general/pi/contracts/doctor-capability.schema.json +43 -0
  83. package/harness/bundles/general/pi/contracts/external-platform-observation.schema.json +62 -0
  84. package/harness/bundles/general/pi/contracts/fixtures/managed-execution.json +341 -0
  85. package/harness/bundles/general/pi/contracts/process-identity.schema.json +132 -0
  86. package/harness/bundles/general/pi/contracts/run-session.schema.json +142 -0
  87. package/harness/bundles/general/pi/contracts/service-retirement-receipt.schema.json +85 -0
  88. package/harness/bundles/general/pi/contracts/service-session.schema.json +147 -0
  89. package/harness/bundles/general/pi/contracts/workflow-policy.json +574 -0
  90. package/harness/bundles/general/pi/harness-archive/SKILL.md +322 -0
  91. package/harness/bundles/general/pi/harness-archive/checklist.md +71 -0
  92. package/harness/bundles/general/pi/harness-archive/reference.md +150 -0
  93. package/harness/bundles/general/pi/harness-archive/scripts/gen-manifest.ps1 +31 -0
  94. package/harness/bundles/general/pi/harness-archive/templates/summary-data-template.json +218 -0
  95. package/harness/bundles/general/pi/harness-codebase-map/SKILL.md +116 -0
  96. package/harness/bundles/general/pi/harness-codebase-map/checklist.md +126 -0
  97. package/harness/bundles/general/pi/harness-codebase-map/reference.md +364 -0
  98. package/harness/bundles/general/pi/harness-codebase-map/templates/ARCHITECTURE.md +57 -0
  99. package/harness/bundles/general/pi/harness-codebase-map/templates/CONCERNS.md +49 -0
  100. package/harness/bundles/general/pi/harness-codebase-map/templates/CONVENTIONS.md +57 -0
  101. package/harness/bundles/general/pi/harness-codebase-map/templates/INTEGRATIONS.md +52 -0
  102. package/harness/bundles/general/pi/harness-codebase-map/templates/STACK.md +55 -0
  103. package/harness/bundles/general/pi/harness-codebase-map/templates/STRUCTURE.md +69 -0
  104. package/harness/bundles/general/pi/harness-codebase-map/templates/TESTING.md +64 -0
  105. package/harness/bundles/general/pi/harness-codebase-map/templates/map-manifest.schema.json +73 -0
  106. package/harness/bundles/general/pi/harness-codebase-map/templates/map-summary.md +64 -0
  107. package/harness/bundles/general/pi/harness-execute/SKILL.md +170 -0
  108. package/harness/bundles/general/pi/harness-knowledge-ingest/SKILL.md +103 -0
  109. package/harness/bundles/general/pi/harness-knowledge-query/SKILL.md +97 -0
  110. package/harness/bundles/general/pi/harness-plan/SKILL.md +158 -0
  111. package/harness/bundles/general/pi/harness-plan/checklist.md +243 -0
  112. package/harness/bundles/general/pi/harness-plan/protocols.md +133 -0
  113. package/harness/bundles/general/pi/harness-plan/reference.md +468 -0
  114. package/harness/bundles/general/pi/harness-pull/SKILL.md +55 -0
  115. package/harness/bundles/general/pi/harness-push/SKILL.md +83 -0
  116. package/harness/bundles/general/pi/harness-review/SKILL.md +175 -0
  117. package/harness/bundles/general/pi/harness-review/checklist.md +124 -0
  118. package/harness/bundles/general/pi/harness-review/protocols.md +69 -0
  119. package/harness/bundles/general/pi/harness-review/reference.md +114 -0
  120. package/harness/bundles/general/pi/harness-run/SKILL.md +188 -0
  121. package/harness/bundles/general/pi/harness-run/checklist.md +279 -0
  122. package/harness/bundles/general/pi/harness-run/protocols.md +141 -0
  123. package/harness/bundles/general/pi/harness-run/reference.md +886 -0
  124. package/harness/bundles/general/pi/harness-submit/SKILL.md +182 -0
  125. package/harness/bundles/general/pi/harness-submit/checklist.md +452 -0
  126. package/harness/bundles/general/pi/harness-submit/reference.md +152 -0
  127. package/harness/bundles/general/pi/harness-sync/SKILL.md +72 -0
  128. package/harness/bundles/general/pi/harness-sync/reference.md +176 -0
  129. package/harness/bundles/general/pi/harness-test/SKILL.md +250 -0
  130. package/harness/bundles/general/pi/harness-test/checklist.md +359 -0
  131. package/harness/bundles/general/pi/harness-test/pitfalls-java.md +14 -0
  132. package/harness/bundles/general/pi/harness-test/pitfalls.md +307 -0
  133. package/harness/bundles/general/pi/harness-test/reference.md +880 -0
  134. package/harness/bundles/general/pi/harness-test/scripts/runtime-helpers.mjs +216 -0
  135. package/harness/bundles/general/pi/protocols/archive-report-protocol.md +196 -0
  136. package/harness/bundles/general/pi/protocols/ci-layering-protocol.md +22 -0
  137. package/harness/bundles/general/pi/protocols/evidence-based-reporting-protocol.md +134 -0
  138. package/harness/bundles/general/pi/protocols/execution-session-protocol.md +52 -0
  139. package/harness/bundles/general/pi/protocols/external-platform-protocol.md +27 -0
  140. package/harness/bundles/general/pi/protocols/ledger-protocol.md +365 -0
  141. package/harness/bundles/general/pi/protocols/memory-closeout-protocol.md +21 -0
  142. package/harness/bundles/general/pi/protocols/model-routing-protocol.md +22 -0
  143. package/harness/bundles/general/pi/protocols/powershell-protocol.md +238 -0
  144. package/harness/bundles/general/pi/protocols/registry-governance-protocol.md +31 -0
  145. package/harness/bundles/general/pi/protocols/report-pipeline-protocol.md +172 -0
  146. package/harness/bundles/general/pi/protocols/sensitive-info-protocol.md +110 -0
  147. package/harness/bundles/general/pi/protocols/state-layout-protocol.md +209 -0
  148. package/harness/bundles/general/pi/protocols/submit-protocol.md +78 -0
  149. package/harness/bundles/general/pi/protocols/verification-graph-protocol.md +32 -0
  150. package/harness/bundles/general/pi/scripts/harness_adoption_metrics.py +391 -0
  151. package/harness/bundles/general/pi/scripts/harness_apidoc.py +53 -0
  152. package/harness/bundles/general/pi/scripts/harness_archive.py +11345 -0
  153. package/harness/bundles/general/pi/scripts/harness_change.py +1626 -0
  154. package/harness/bundles/general/pi/scripts/harness_check_gate.py +113 -0
  155. package/harness/bundles/general/pi/scripts/harness_context.py +1774 -0
  156. package/harness/bundles/general/pi/scripts/harness_deploy.py +968 -0
  157. package/harness/bundles/general/pi/scripts/harness_efficiency.py +443 -0
  158. package/harness/bundles/general/pi/scripts/harness_environment.py +1690 -0
  159. package/harness/bundles/general/pi/scripts/harness_events.py +2234 -0
  160. package/harness/bundles/general/pi/scripts/harness_events_sync.py +1425 -0
  161. package/harness/bundles/general/pi/scripts/harness_execution_contracts.py +596 -0
  162. package/harness/bundles/general/pi/scripts/harness_fixback.py +1975 -0
  163. package/harness/bundles/general/pi/scripts/harness_gate.py +3816 -0
  164. package/harness/bundles/general/pi/scripts/harness_headless.py +37 -0
  165. package/harness/bundles/general/pi/scripts/harness_integration.py +2564 -0
  166. package/harness/bundles/general/pi/scripts/harness_knowledge_candidates.py +796 -0
  167. package/harness/bundles/general/pi/scripts/harness_ledger.py +3556 -0
  168. package/harness/bundles/general/pi/scripts/harness_migration_head.py +220 -0
  169. package/harness/bundles/general/pi/scripts/harness_orchestration.py +344 -0
  170. package/harness/bundles/general/pi/scripts/harness_paths.py +676 -0
  171. package/harness/bundles/general/pi/scripts/harness_phase.py +1726 -0
  172. package/harness/bundles/general/pi/scripts/harness_plan_aggregate.py +249 -0
  173. package/harness/bundles/general/pi/scripts/harness_plan_finalize.py +1016 -0
  174. package/harness/bundles/general/pi/scripts/harness_preflight.py +650 -0
  175. package/harness/bundles/general/pi/scripts/harness_process.py +1065 -0
  176. package/harness/bundles/general/pi/scripts/harness_profile.py +1817 -0
  177. package/harness/bundles/general/pi/scripts/harness_report_model.py +442 -0
  178. package/harness/bundles/general/pi/scripts/harness_retry.py +175 -0
  179. package/harness/bundles/general/pi/scripts/harness_review.py +631 -0
  180. package/harness/bundles/general/pi/scripts/harness_runtime.py +2243 -0
  181. package/harness/bundles/general/pi/scripts/harness_service.py +3355 -0
  182. package/harness/bundles/general/pi/scripts/harness_state.py +365 -0
  183. package/harness/bundles/general/pi/scripts/harness_sync.py +407 -0
  184. package/harness/bundles/general/pi/scripts/harness_test_cleanup.py +175 -0
  185. package/harness/bundles/general/pi/scripts/harness_test_guard.py +1899 -0
  186. package/harness/bundles/general/pi/scripts/harness_test_runner.py +1586 -0
  187. package/harness/bundles/general/pi/scripts/harness_verification.py +593 -0
  188. package/harness/bundles/general/pi/scripts/harness_workflow_policy.py +266 -0
  189. package/harness/bundles/java/claude-code/.harness-build.json +1 -1
  190. package/harness/bundles/java/claude-code/harness-apidoc/SKILL.md +1 -1
  191. package/harness/bundles/java/claude-code/harness-archive/SKILL.md +1 -1
  192. package/harness/bundles/java/claude-code/harness-archive/reference.md +30 -1
  193. package/harness/bundles/java/claude-code/harness-archive/templates/summary-data-template.json +1 -0
  194. package/harness/bundles/java/claude-code/harness-codebase-map/SKILL.md +1 -1
  195. package/harness/bundles/java/claude-code/harness-execute/SKILL.md +1 -1
  196. package/harness/bundles/java/claude-code/harness-knowledge-ingest/SKILL.md +1 -1
  197. package/harness/bundles/java/claude-code/harness-knowledge-query/SKILL.md +1 -1
  198. package/harness/bundles/java/claude-code/harness-package/SKILL.md +1 -1
  199. package/harness/bundles/java/claude-code/harness-plan/SKILL.md +1 -1
  200. package/harness/bundles/java/claude-code/harness-pull/SKILL.md +1 -1
  201. package/harness/bundles/java/claude-code/harness-push/SKILL.md +1 -1
  202. package/harness/bundles/java/claude-code/harness-review/SKILL.md +1 -1
  203. package/harness/bundles/java/claude-code/harness-run/SKILL.md +1 -1
  204. package/harness/bundles/java/claude-code/harness-submit/SKILL.md +1 -1
  205. package/harness/bundles/java/claude-code/harness-sync/SKILL.md +1 -1
  206. package/harness/bundles/java/claude-code/harness-test/SKILL.md +1 -1
  207. package/harness/bundles/java/claude-code/scripts/harness_archive.py +146 -8
  208. package/harness/bundles/java/claude-code/scripts/harness_deploy.py +1 -1
  209. package/harness/bundles/java/claude-code/scripts/harness_knowledge_candidates.py +538 -4
  210. package/harness/bundles/java/codebuddy/.harness-build.json +1 -1
  211. package/harness/bundles/java/codebuddy/harness-apidoc/SKILL.md +1 -1
  212. package/harness/bundles/java/codebuddy/harness-archive/SKILL.md +1 -1
  213. package/harness/bundles/java/codebuddy/harness-archive/reference.md +30 -1
  214. package/harness/bundles/java/codebuddy/harness-archive/templates/summary-data-template.json +1 -0
  215. package/harness/bundles/java/codebuddy/harness-codebase-map/SKILL.md +1 -1
  216. package/harness/bundles/java/codebuddy/harness-execute/SKILL.md +1 -1
  217. package/harness/bundles/java/codebuddy/harness-knowledge-ingest/SKILL.md +1 -1
  218. package/harness/bundles/java/codebuddy/harness-knowledge-query/SKILL.md +1 -1
  219. package/harness/bundles/java/codebuddy/harness-package/SKILL.md +1 -1
  220. package/harness/bundles/java/codebuddy/harness-plan/SKILL.md +1 -1
  221. package/harness/bundles/java/codebuddy/harness-pull/SKILL.md +1 -1
  222. package/harness/bundles/java/codebuddy/harness-push/SKILL.md +1 -1
  223. package/harness/bundles/java/codebuddy/harness-review/SKILL.md +1 -1
  224. package/harness/bundles/java/codebuddy/harness-run/SKILL.md +1 -1
  225. package/harness/bundles/java/codebuddy/harness-submit/SKILL.md +1 -1
  226. package/harness/bundles/java/codebuddy/harness-sync/SKILL.md +1 -1
  227. package/harness/bundles/java/codebuddy/harness-test/SKILL.md +1 -1
  228. package/harness/bundles/java/codebuddy/scripts/harness_archive.py +146 -8
  229. package/harness/bundles/java/codebuddy/scripts/harness_deploy.py +1 -1
  230. package/harness/bundles/java/codebuddy/scripts/harness_knowledge_candidates.py +538 -4
  231. package/harness/bundles/java/codex/.harness-build.json +1 -1
  232. package/harness/bundles/java/codex/harness-apidoc/SKILL.md +1 -1
  233. package/harness/bundles/java/codex/harness-archive/SKILL.md +1 -1
  234. package/harness/bundles/java/codex/harness-archive/reference.md +30 -1
  235. package/harness/bundles/java/codex/harness-archive/templates/summary-data-template.json +1 -0
  236. package/harness/bundles/java/codex/harness-codebase-map/SKILL.md +1 -1
  237. package/harness/bundles/java/codex/harness-execute/SKILL.md +1 -1
  238. package/harness/bundles/java/codex/harness-knowledge-ingest/SKILL.md +1 -1
  239. package/harness/bundles/java/codex/harness-knowledge-query/SKILL.md +1 -1
  240. package/harness/bundles/java/codex/harness-package/SKILL.md +1 -1
  241. package/harness/bundles/java/codex/harness-plan/SKILL.md +1 -1
  242. package/harness/bundles/java/codex/harness-pull/SKILL.md +1 -1
  243. package/harness/bundles/java/codex/harness-push/SKILL.md +1 -1
  244. package/harness/bundles/java/codex/harness-review/SKILL.md +1 -1
  245. package/harness/bundles/java/codex/harness-run/SKILL.md +1 -1
  246. package/harness/bundles/java/codex/harness-submit/SKILL.md +1 -1
  247. package/harness/bundles/java/codex/harness-sync/SKILL.md +1 -1
  248. package/harness/bundles/java/codex/harness-test/SKILL.md +1 -1
  249. package/harness/bundles/java/codex/scripts/harness_archive.py +146 -8
  250. package/harness/bundles/java/codex/scripts/harness_deploy.py +1 -1
  251. package/harness/bundles/java/codex/scripts/harness_knowledge_candidates.py +538 -4
  252. package/harness/bundles/java/cursor/.harness-build.json +1 -1
  253. package/harness/bundles/java/cursor/harness-apidoc/SKILL.md +1 -1
  254. package/harness/bundles/java/cursor/harness-archive/SKILL.md +1 -1
  255. package/harness/bundles/java/cursor/harness-archive/reference.md +30 -1
  256. package/harness/bundles/java/cursor/harness-archive/templates/summary-data-template.json +1 -0
  257. package/harness/bundles/java/cursor/harness-codebase-map/SKILL.md +1 -1
  258. package/harness/bundles/java/cursor/harness-execute/SKILL.md +1 -1
  259. package/harness/bundles/java/cursor/harness-knowledge-ingest/SKILL.md +1 -1
  260. package/harness/bundles/java/cursor/harness-knowledge-query/SKILL.md +1 -1
  261. package/harness/bundles/java/cursor/harness-package/SKILL.md +1 -1
  262. package/harness/bundles/java/cursor/harness-plan/SKILL.md +1 -1
  263. package/harness/bundles/java/cursor/harness-pull/SKILL.md +1 -1
  264. package/harness/bundles/java/cursor/harness-push/SKILL.md +1 -1
  265. package/harness/bundles/java/cursor/harness-review/SKILL.md +1 -1
  266. package/harness/bundles/java/cursor/harness-run/SKILL.md +1 -1
  267. package/harness/bundles/java/cursor/harness-submit/SKILL.md +1 -1
  268. package/harness/bundles/java/cursor/harness-sync/SKILL.md +1 -1
  269. package/harness/bundles/java/cursor/harness-test/SKILL.md +1 -1
  270. package/harness/bundles/java/cursor/scripts/harness_archive.py +146 -8
  271. package/harness/bundles/java/cursor/scripts/harness_deploy.py +1 -1
  272. package/harness/bundles/java/cursor/scripts/harness_knowledge_candidates.py +538 -4
  273. package/harness/bundles/java/pi/.harness-build.json +6 -0
  274. package/harness/bundles/java/pi/CONTEXT.md +98 -0
  275. package/harness/bundles/java/pi/README.md +478 -0
  276. package/harness/bundles/java/pi/contracts/build-profile-v3.schema.json +302 -0
  277. package/harness/bundles/java/pi/contracts/ci-metrics.schema.json +36 -0
  278. package/harness/bundles/java/pi/contracts/doctor-capability.schema.json +43 -0
  279. package/harness/bundles/java/pi/contracts/external-platform-observation.schema.json +62 -0
  280. package/harness/bundles/java/pi/contracts/fixtures/managed-execution.json +341 -0
  281. package/harness/bundles/java/pi/contracts/process-identity.schema.json +132 -0
  282. package/harness/bundles/java/pi/contracts/run-session.schema.json +142 -0
  283. package/harness/bundles/java/pi/contracts/service-retirement-receipt.schema.json +85 -0
  284. package/harness/bundles/java/pi/contracts/service-session.schema.json +147 -0
  285. package/harness/bundles/java/pi/contracts/workflow-policy.json +574 -0
  286. package/harness/bundles/java/pi/harness-apidoc/SKILL.md +97 -0
  287. package/harness/bundles/java/pi/harness-apidoc/checklist.md +142 -0
  288. package/harness/bundles/java/pi/harness-apidoc/reference.md +233 -0
  289. package/harness/bundles/java/pi/harness-archive/SKILL.md +322 -0
  290. package/harness/bundles/java/pi/harness-archive/checklist.md +71 -0
  291. package/harness/bundles/java/pi/harness-archive/reference.md +150 -0
  292. package/harness/bundles/java/pi/harness-archive/scripts/gen-manifest.ps1 +31 -0
  293. package/harness/bundles/java/pi/harness-archive/templates/summary-data-template.json +218 -0
  294. package/harness/bundles/java/pi/harness-codebase-map/SKILL.md +116 -0
  295. package/harness/bundles/java/pi/harness-codebase-map/checklist.md +126 -0
  296. package/harness/bundles/java/pi/harness-codebase-map/reference.md +364 -0
  297. package/harness/bundles/java/pi/harness-codebase-map/templates/ARCHITECTURE.md +57 -0
  298. package/harness/bundles/java/pi/harness-codebase-map/templates/CONCERNS.md +49 -0
  299. package/harness/bundles/java/pi/harness-codebase-map/templates/CONVENTIONS.md +57 -0
  300. package/harness/bundles/java/pi/harness-codebase-map/templates/INTEGRATIONS.md +52 -0
  301. package/harness/bundles/java/pi/harness-codebase-map/templates/STACK.md +55 -0
  302. package/harness/bundles/java/pi/harness-codebase-map/templates/STRUCTURE.md +69 -0
  303. package/harness/bundles/java/pi/harness-codebase-map/templates/TESTING.md +64 -0
  304. package/harness/bundles/java/pi/harness-codebase-map/templates/map-manifest.schema.json +73 -0
  305. package/harness/bundles/java/pi/harness-codebase-map/templates/map-summary.md +64 -0
  306. package/harness/bundles/java/pi/harness-execute/SKILL.md +170 -0
  307. package/harness/bundles/java/pi/harness-knowledge-ingest/SKILL.md +103 -0
  308. package/harness/bundles/java/pi/harness-knowledge-query/SKILL.md +97 -0
  309. package/harness/bundles/java/pi/harness-package/SKILL.md +94 -0
  310. package/harness/bundles/java/pi/harness-package/checklist.md +322 -0
  311. package/harness/bundles/java/pi/harness-package/reference.md +210 -0
  312. package/harness/bundles/java/pi/harness-plan/SKILL.md +158 -0
  313. package/harness/bundles/java/pi/harness-plan/checklist.md +243 -0
  314. package/harness/bundles/java/pi/harness-plan/protocols.md +133 -0
  315. package/harness/bundles/java/pi/harness-plan/reference.md +468 -0
  316. package/harness/bundles/java/pi/harness-pull/SKILL.md +55 -0
  317. package/harness/bundles/java/pi/harness-push/SKILL.md +83 -0
  318. package/harness/bundles/java/pi/harness-review/SKILL.md +175 -0
  319. package/harness/bundles/java/pi/harness-review/checklist.md +124 -0
  320. package/harness/bundles/java/pi/harness-review/protocols.md +69 -0
  321. package/harness/bundles/java/pi/harness-review/reference.md +114 -0
  322. package/harness/bundles/java/pi/harness-run/SKILL.md +206 -0
  323. package/harness/bundles/java/pi/harness-run/checklist.md +252 -0
  324. package/harness/bundles/java/pi/harness-run/protocols.md +141 -0
  325. package/harness/bundles/java/pi/harness-run/reference.md +820 -0
  326. package/harness/bundles/java/pi/harness-submit/SKILL.md +189 -0
  327. package/harness/bundles/java/pi/harness-submit/checklist.md +452 -0
  328. package/harness/bundles/java/pi/harness-submit/reference.md +152 -0
  329. package/harness/bundles/java/pi/harness-sync/SKILL.md +72 -0
  330. package/harness/bundles/java/pi/harness-sync/reference.md +176 -0
  331. package/harness/bundles/java/pi/harness-test/SKILL.md +264 -0
  332. package/harness/bundles/java/pi/harness-test/checklist.md +320 -0
  333. package/harness/bundles/java/pi/harness-test/pitfalls-java.md +16 -0
  334. package/harness/bundles/java/pi/harness-test/pitfalls.md +307 -0
  335. package/harness/bundles/java/pi/harness-test/reference.md +792 -0
  336. package/harness/bundles/java/pi/harness-test/scripts/runtime-helpers.mjs +216 -0
  337. package/harness/bundles/java/pi/protocols/archive-report-protocol.md +196 -0
  338. package/harness/bundles/java/pi/protocols/ci-layering-protocol.md +22 -0
  339. package/harness/bundles/java/pi/protocols/evidence-based-reporting-protocol.md +134 -0
  340. package/harness/bundles/java/pi/protocols/execution-session-protocol.md +52 -0
  341. package/harness/bundles/java/pi/protocols/external-platform-protocol.md +27 -0
  342. package/harness/bundles/java/pi/protocols/ledger-protocol.md +365 -0
  343. package/harness/bundles/java/pi/protocols/memory-closeout-protocol.md +21 -0
  344. package/harness/bundles/java/pi/protocols/model-routing-protocol.md +22 -0
  345. package/harness/bundles/java/pi/protocols/powershell-protocol.md +238 -0
  346. package/harness/bundles/java/pi/protocols/registry-governance-protocol.md +31 -0
  347. package/harness/bundles/java/pi/protocols/report-pipeline-protocol.md +172 -0
  348. package/harness/bundles/java/pi/protocols/sensitive-info-protocol.md +110 -0
  349. package/harness/bundles/java/pi/protocols/state-layout-protocol.md +209 -0
  350. package/harness/bundles/java/pi/protocols/submit-protocol.md +78 -0
  351. package/harness/bundles/java/pi/protocols/verification-graph-protocol.md +32 -0
  352. package/harness/bundles/java/pi/scripts/harness_adoption_metrics.py +391 -0
  353. package/harness/bundles/java/pi/scripts/harness_apidoc.py +53 -0
  354. package/harness/bundles/java/pi/scripts/harness_archive.py +11345 -0
  355. package/harness/bundles/java/pi/scripts/harness_change.py +1626 -0
  356. package/harness/bundles/java/pi/scripts/harness_check_gate.py +113 -0
  357. package/harness/bundles/java/pi/scripts/harness_context.py +1774 -0
  358. package/harness/bundles/java/pi/scripts/harness_deploy.py +968 -0
  359. package/harness/bundles/java/pi/scripts/harness_efficiency.py +443 -0
  360. package/harness/bundles/java/pi/scripts/harness_environment.py +1690 -0
  361. package/harness/bundles/java/pi/scripts/harness_events.py +2234 -0
  362. package/harness/bundles/java/pi/scripts/harness_events_sync.py +1425 -0
  363. package/harness/bundles/java/pi/scripts/harness_execution_contracts.py +596 -0
  364. package/harness/bundles/java/pi/scripts/harness_fixback.py +1975 -0
  365. package/harness/bundles/java/pi/scripts/harness_gate.py +3816 -0
  366. package/harness/bundles/java/pi/scripts/harness_headless.py +37 -0
  367. package/harness/bundles/java/pi/scripts/harness_integration.py +2564 -0
  368. package/harness/bundles/java/pi/scripts/harness_knowledge_candidates.py +796 -0
  369. package/harness/bundles/java/pi/scripts/harness_ledger.py +3556 -0
  370. package/harness/bundles/java/pi/scripts/harness_migration_head.py +220 -0
  371. package/harness/bundles/java/pi/scripts/harness_orchestration.py +344 -0
  372. package/harness/bundles/java/pi/scripts/harness_paths.py +676 -0
  373. package/harness/bundles/java/pi/scripts/harness_phase.py +1726 -0
  374. package/harness/bundles/java/pi/scripts/harness_plan_aggregate.py +249 -0
  375. package/harness/bundles/java/pi/scripts/harness_plan_finalize.py +1016 -0
  376. package/harness/bundles/java/pi/scripts/harness_preflight.py +650 -0
  377. package/harness/bundles/java/pi/scripts/harness_process.py +1065 -0
  378. package/harness/bundles/java/pi/scripts/harness_profile.py +1817 -0
  379. package/harness/bundles/java/pi/scripts/harness_report_model.py +442 -0
  380. package/harness/bundles/java/pi/scripts/harness_retry.py +175 -0
  381. package/harness/bundles/java/pi/scripts/harness_review.py +631 -0
  382. package/harness/bundles/java/pi/scripts/harness_runtime.py +2243 -0
  383. package/harness/bundles/java/pi/scripts/harness_service.py +3355 -0
  384. package/harness/bundles/java/pi/scripts/harness_state.py +365 -0
  385. package/harness/bundles/java/pi/scripts/harness_sync.py +407 -0
  386. package/harness/bundles/java/pi/scripts/harness_test_cleanup.py +175 -0
  387. package/harness/bundles/java/pi/scripts/harness_test_guard.py +1899 -0
  388. package/harness/bundles/java/pi/scripts/harness_test_runner.py +1586 -0
  389. package/harness/bundles/java/pi/scripts/harness_verification.py +593 -0
  390. package/harness/bundles/java/pi/scripts/harness_workflow_policy.py +266 -0
  391. package/harness/manifests/general/claude-code.json +19 -19
  392. package/harness/manifests/general/codebuddy.json +19 -19
  393. package/harness/manifests/general/codex.json +19 -19
  394. package/harness/manifests/general/cursor.json +19 -19
  395. package/harness/manifests/general/pi.json +475 -0
  396. package/harness/manifests/java/claude-code.json +21 -21
  397. package/harness/manifests/java/codebuddy.json +21 -21
  398. package/harness/manifests/java/codex.json +21 -21
  399. package/harness/manifests/java/cursor.json +21 -21
  400. package/harness/manifests/java/pi.json +499 -0
  401. package/hunter-workflow-family.json +2 -2
  402. package/package.json +1 -1
@@ -0,0 +1,650 @@
1
+ #!/usr/bin/env python3
2
+ """Harness preflight: build-profile detect/check + quirk recording + agent precheck.
3
+
4
+ 变更簇 4:detect/check 委托 ``harness_profile``(Build Profile v3 公共内核),不再保留
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
+
10
+ Implements DESIGN.md D5 (build-profile) and D8 (subagent precheck).
11
+ Python 3.10+ stdlib only. UTF-8 without BOM. Windows path friendly.
12
+ """
13
+
14
+ from __future__ import annotations
15
+
16
+ import argparse
17
+ import datetime as dt
18
+ import json
19
+ import re
20
+ import shlex
21
+ import sys
22
+ from pathlib import Path
23
+ from typing import Any
24
+
25
+
26
+ if hasattr(sys.stdout, "reconfigure"):
27
+ sys.stdout.reconfigure(encoding="utf-8")
28
+ if hasattr(sys.stderr, "reconfigure"):
29
+ sys.stderr.reconfigure(encoding="utf-8")
30
+
31
+
32
+ import harness_change as hc # noqa: E402
33
+ import harness_profile as hprof # noqa: E402
34
+
35
+
36
+ PITFALLS_REL = Path(".harness") / "pitfalls.md"
37
+ PITFALLS_APPENDIX_HEADER = "## Preflight 附录(自动追加)"
38
+
39
+ VALID_QUIRK_ACTIONS = {"skip-not-block", "fix-command"}
40
+
41
+ _DETECT_HINT = "python harness_preflight.py detect --project <root> --json"
42
+
43
+
44
+ def now_iso() -> str:
45
+ return dt.datetime.now().astimezone().isoformat(timespec="seconds")
46
+
47
+
48
+ def emit_json(payload: dict[str, Any], *, ok: bool = True) -> int:
49
+ print(json.dumps(payload, ensure_ascii=False, indent=2))
50
+ return 0 if ok else 1
51
+
52
+
53
+ # ---------------------------------------------------------------------------
54
+ # detect / check — 委托 harness_profile(Build Profile v3 公共内核)
55
+ # ---------------------------------------------------------------------------
56
+
57
+ def cmd_detect(project: Path) -> dict[str, Any]:
58
+ """Full probe and write build-profile.json (v2). 委托 hprof.detect。"""
59
+ return hprof.detect(project)
60
+
61
+
62
+ def cmd_check(project: Path) -> dict[str, Any]:
63
+ """Fast stale check (missing/invalid/stale/ready). 委托 hprof.check。
64
+
65
+ 兼容:stale 时补 ``hint``(skill canonical 读 hint 引导重新 detect)。
66
+ """
67
+ result = hprof.check(project)
68
+ if result.get("stale") and "hint" not in result:
69
+ result["hint"] = _DETECT_HINT
70
+ return result
71
+
72
+
73
+ def check_concurrency(project: Path) -> dict[str, Any]:
74
+ """Report the configured concurrency mode and active Change landscape.
75
+
76
+ Retro §5.2: preflight must surface concurrencyMode, activeChanges, and
77
+ allowedParallelLevels so agents don't have to guess whether parallel
78
+ Changes are supported.
79
+ """
80
+ mode = hc.read_concurrency_mode(project)
81
+ active = hc.list_active_changes(project)
82
+ shared_conflicts: list[dict[str, Any]] = []
83
+ # In isolated-multi-active, surface any shared-state conflicts (e.g. same
84
+ # worktree path) so callers know isolation is incomplete.
85
+ if mode == "isolated-multi-active" and len(active) > 1:
86
+ seen_worktrees: dict[str, str] = {}
87
+ for entry in active:
88
+ change_dir = Path(entry["path"])
89
+ worktree_meta = change_dir / "meta" / "worktree.json"
90
+ if not worktree_meta.is_file():
91
+ continue
92
+ try:
93
+ meta = json.loads(worktree_meta.read_text(encoding="utf-8"))
94
+ except (OSError, json.JSONDecodeError):
95
+ continue
96
+ wt = meta.get("path") if isinstance(meta, dict) else None
97
+ if isinstance(wt, str) and wt:
98
+ if wt in seen_worktrees:
99
+ shared_conflicts.append({
100
+ "kind": "worktree",
101
+ "path": wt,
102
+ "changes": [seen_worktrees[wt], entry["changeId"]],
103
+ })
104
+ else:
105
+ seen_worktrees[wt] = entry["changeId"]
106
+ levels = ["change-internal"] if mode == "single-active" else [
107
+ "change-internal",
108
+ "multi-change",
109
+ ]
110
+ return {
111
+ "ok": True,
112
+ "concurrencyMode": mode,
113
+ "activeChanges": active,
114
+ "sharedStateConflicts": shared_conflicts,
115
+ "allowedParallelLevels": levels,
116
+ }
117
+
118
+
119
+ # ---------------------------------------------------------------------------
120
+ # record-quirk — 适配 v2 commands(source=user override)
121
+ # ---------------------------------------------------------------------------
122
+
123
+ def ensure_pitfalls_appendix(project: Path) -> Path:
124
+ path = project / PITFALLS_REL
125
+ path.parent.mkdir(parents=True, exist_ok=True)
126
+ if not path.exists():
127
+ content = (
128
+ "# 项目避坑记录\n\n"
129
+ "> 由 harness_preflight.py record-quirk 自动维护附录。\n\n"
130
+ f"{PITFALLS_APPENDIX_HEADER}\n\n"
131
+ )
132
+ path.write_text(content, encoding="utf-8")
133
+ return path
134
+ text = path.read_text(encoding="utf-8")
135
+ if PITFALLS_APPENDIX_HEADER not in text:
136
+ if not text.endswith("\n"):
137
+ text += "\n"
138
+ text += f"\n{PITFALLS_APPENDIX_HEADER}\n\n"
139
+ path.write_text(text, encoding="utf-8")
140
+ return path
141
+
142
+
143
+ def append_pitfalls_line(project: Path, line: str) -> Path:
144
+ path = ensure_pitfalls_appendix(project)
145
+ text = path.read_text(encoding="utf-8")
146
+ if not text.endswith("\n"):
147
+ text += "\n"
148
+ text += line.rstrip() + "\n"
149
+ path.write_text(text, encoding="utf-8")
150
+ return path
151
+
152
+
153
+ def _load_or_skeleton(project: Path) -> tuple[dict[str, Any], Path]:
154
+ """加载 v2 profile;缺失时返回空 skeleton(不自动 detect,避免副作用)。"""
155
+ profile_path = project / hprof.PROFILE_REL
156
+ if profile_path.is_file():
157
+ try:
158
+ profile = hprof.read_json(profile_path)
159
+ if isinstance(profile, dict):
160
+ return profile, profile_path
161
+ except (OSError, json.JSONDecodeError):
162
+ pass
163
+ profile = hprof.empty_profile_skeleton(hprof.DEFAULT_EXCLUDED_ROOTS)
164
+ profile["detectedAt"] = now_iso()
165
+ return profile, profile_path
166
+
167
+
168
+ def cmd_record_quirk(
169
+ project: Path,
170
+ pattern: str,
171
+ reason: str,
172
+ action: str,
173
+ fixed_command: str | None = None,
174
+ ) -> dict[str, Any]:
175
+ project = project.resolve()
176
+ if action not in VALID_QUIRK_ACTIONS:
177
+ return {
178
+ "ok": False,
179
+ "action": "record-quirk",
180
+ "issues": [f"invalid action: {action}; expected one of {sorted(VALID_QUIRK_ACTIONS)}"],
181
+ }
182
+
183
+ profile, profile_path = _load_or_skeleton(project)
184
+
185
+ profile.setdefault("knownPreexistingErrors", [])
186
+ profile.setdefault("shellQuirks", [])
187
+ profile.setdefault("commands", {})
188
+ if not isinstance(profile["knownPreexistingErrors"], list):
189
+ profile["knownPreexistingErrors"] = []
190
+ if not isinstance(profile["shellQuirks"], list):
191
+ profile["shellQuirks"] = []
192
+ if not isinstance(profile["commands"], dict):
193
+ profile["commands"] = {}
194
+
195
+ changed: list[str] = []
196
+
197
+ if action == "skip-not-block":
198
+ entry = {"pattern": pattern, "reason": reason, "action": "skip-not-block"}
199
+ existing_patterns = {
200
+ e.get("pattern")
201
+ for e in profile["knownPreexistingErrors"]
202
+ if isinstance(e, dict)
203
+ }
204
+ if pattern not in existing_patterns:
205
+ profile["knownPreexistingErrors"].append(entry)
206
+ changed.append("knownPreexistingErrors")
207
+ else:
208
+ # Append-only: do not overwrite existing entry; still sync pitfalls
209
+ changed.append("knownPreexistingErrors(already-present)")
210
+ else: # fix-command
211
+ if pattern not in profile["shellQuirks"]:
212
+ profile["shellQuirks"].append(pattern)
213
+ changed.append("shellQuirks")
214
+ else:
215
+ changed.append("shellQuirks(already-present)")
216
+ if fixed_command:
217
+ # v2:写 commands.<key> 为 source=user override(spec §3.1 显式保留)。
218
+ # 已知 verification key 覆写其 command;否则存 namespaced custom key。
219
+ if pattern in hprof.VERIFICATION_KEYS:
220
+ key = pattern
221
+ else:
222
+ key = f"custom:{pattern}"
223
+ existing_cmd = profile["commands"].get(key, {})
224
+ if not isinstance(existing_cmd, dict):
225
+ existing_cmd = {}
226
+ new_cmd = dict(existing_cmd)
227
+ new_cmd["command"] = fixed_command
228
+ try:
229
+ new_cmd["argvTemplate"] = shlex.split(fixed_command)
230
+ except ValueError:
231
+ # 不平衡引号回退到空格切分(best-effort;record-quirk 是人工逃逸口)
232
+ new_cmd["argvTemplate"] = fixed_command.split()
233
+ new_cmd["source"] = "user"
234
+ profile["commands"][key] = new_cmd
235
+ changed.append(f"commands.{key}")
236
+ # 重派 verificationInputs 兼容字段,保持与 commands 一致
237
+ hprof._derive_verification_inputs(profile)
238
+
239
+ hprof.write_json(profile_path, profile)
240
+
241
+ date_str = dt.date.today().isoformat()
242
+ pitfalls_line = f"- {date_str}: `{pattern}` — {reason} (action={action}"
243
+ if fixed_command:
244
+ pitfalls_line += f"; fixed-command=`{fixed_command}`"
245
+ pitfalls_line += ")"
246
+ pitfalls_path = append_pitfalls_line(project, pitfalls_line)
247
+
248
+ return {
249
+ "ok": True,
250
+ "action": "record-quirk",
251
+ "project": str(project),
252
+ "pattern": pattern,
253
+ "reason": reason,
254
+ "quirkAction": action,
255
+ "fixedCommand": fixed_command,
256
+ "changed": changed,
257
+ "profilePath": str(profile_path),
258
+ "pitfallsPath": str(pitfalls_path),
259
+ "pitfallsLine": pitfalls_line,
260
+ "profile": profile,
261
+ }
262
+
263
+
264
+ # ---------------------------------------------------------------------------
265
+ # check-agents — agent 定义可用性校验(本 skill 独有,不涉及 profile)
266
+ # ---------------------------------------------------------------------------
267
+
268
+ def parse_frontmatter(text: str) -> tuple[dict[str, Any] | None, str | None]:
269
+ """Parse YAML-ish frontmatter between leading --- fences.
270
+
271
+ Returns (meta, error_reason). Supports simple scalars, lists, and
272
+ nested list items used by harness agent definitions.
273
+ """
274
+ if not text.startswith("---"):
275
+ return None, "missing frontmatter start ---"
276
+ lines = text.splitlines()
277
+ if not lines or lines[0].strip() != "---":
278
+ return None, "missing frontmatter start ---"
279
+ end_idx = None
280
+ for i in range(1, len(lines)):
281
+ if lines[i].strip() == "---":
282
+ end_idx = i
283
+ break
284
+ if end_idx is None:
285
+ return None, "missing frontmatter end ---"
286
+
287
+ body = "\n".join(lines[1:end_idx])
288
+ meta: dict[str, Any] = {}
289
+ current_list_key: str | None = None
290
+
291
+ for raw in body.splitlines():
292
+ if not raw.strip():
293
+ continue
294
+ # list item under previous key
295
+ list_item = re.match(r"^-\s+(.*)$", raw)
296
+ if list_item and current_list_key:
297
+ meta.setdefault(current_list_key, [])
298
+ if not isinstance(meta[current_list_key], list):
299
+ meta[current_list_key] = []
300
+ meta[current_list_key].append(_parse_scalar(list_item.group(1).strip()))
301
+ continue
302
+
303
+ m = re.match(r"^([A-Za-z0-9_]+):\s*(.*)$", raw)
304
+ if not m:
305
+ current_list_key = None
306
+ continue
307
+ key, val = m.group(1), m.group(2).strip()
308
+ if val == "":
309
+ current_list_key = key
310
+ meta[key] = []
311
+ continue
312
+ current_list_key = None
313
+ if val.startswith("[") and val.endswith("]"):
314
+ inner = val[1:-1].strip()
315
+ if not inner:
316
+ meta[key] = []
317
+ else:
318
+ parts = _split_flow_list(inner)
319
+ meta[key] = [_parse_scalar(p.strip()) for p in parts]
320
+ else:
321
+ meta[key] = _parse_scalar(val)
322
+ return meta, None
323
+
324
+
325
+ def _split_flow_list(inner: str) -> list[str]:
326
+ """Split YAML flow list respecting nested brackets like Bash(powershell.exe:*)."""
327
+ parts: list[str] = []
328
+ buf: list[str] = []
329
+ depth = 0
330
+ for ch in inner:
331
+ if ch == "[":
332
+ depth += 1
333
+ buf.append(ch)
334
+ elif ch == "]":
335
+ depth = max(0, depth - 1)
336
+ buf.append(ch)
337
+ elif ch == "(":
338
+ depth += 1
339
+ buf.append(ch)
340
+ elif ch == ")":
341
+ depth = max(0, depth - 1)
342
+ buf.append(ch)
343
+ elif ch == "," and depth == 0:
344
+ parts.append("".join(buf))
345
+ buf = []
346
+ else:
347
+ buf.append(ch)
348
+ if buf:
349
+ parts.append("".join(buf))
350
+ return parts
351
+
352
+
353
+ def _parse_scalar(val: str) -> Any:
354
+ if (val.startswith('"') and val.endswith('"')) or (val.startswith("'") and val.endswith("'")):
355
+ return val[1:-1]
356
+ if val.lower() in ("true", "false"):
357
+ return val.lower() == "true"
358
+ if re.fullmatch(r"-?\d+", val):
359
+ return int(val)
360
+ return val
361
+
362
+
363
+ def _resolve_agents_root(skills_root: Path, agents_root: Path | None) -> tuple[Path | None, str | None]:
364
+ """Resolve agent definitions without confusing a skills root with its sibling."""
365
+ if agents_root is not None:
366
+ return agents_root.resolve(), None
367
+ if skills_root.name == "skills" and skills_root.parent.name in (".claude", ".codebuddy"):
368
+ return (skills_root.parent / "agents").resolve(), None
369
+ if skills_root.name == "skills" and skills_root.parent.name in (".agents", ".cursor"):
370
+ # These adapters (Codex/Cursor) may provide agent roles via host
371
+ # capability manifest rather than local .md files. Return None without
372
+ # a hard error; the caller checks runtime.json for host capabilities.
373
+ return None, None
374
+ return (skills_root / "agents").resolve(), None
375
+
376
+
377
+ def _read_host_capabilities(skills_root: Path) -> tuple[set[str], bool]:
378
+ """Read agent capabilities declared by the host adapter (retro §5.3).
379
+
380
+ Adapter installs may declare available agent roles in
381
+ `meta/runtime.json` under `agentCapabilities` (list of role names).
382
+ Returns ``(capabilities, manifest_present)``. ``manifest_present`` is true
383
+ only when a readable capability list exists; an unrelated runtime.json
384
+ must not turn an unknown host into a hard "agent missing" failure.
385
+ """
386
+ # runtime.json lives in the change's meta/ dir, but agent capabilities are
387
+ # project-level. Check the adapter's runtime.json at the project root.
388
+ candidates = [
389
+ skills_root.parent / "runtime.json",
390
+ skills_root / "runtime.json",
391
+ ]
392
+ for path in candidates:
393
+ if not path.is_file():
394
+ continue
395
+ try:
396
+ data = json.loads(path.read_text(encoding="utf-8-sig"))
397
+ except (OSError, json.JSONDecodeError):
398
+ continue
399
+ if not isinstance(data, dict):
400
+ continue
401
+ caps = data.get("agentCapabilities")
402
+ if isinstance(caps, list):
403
+ return {str(c) for c in caps if isinstance(c, str)}, True
404
+ return set(), False
405
+
406
+
407
+ def cmd_check_agents(
408
+ skills_root: Path,
409
+ agent: str,
410
+ *,
411
+ agents_root: Path | None = None,
412
+ ) -> dict[str, Any]:
413
+ skills_root = skills_root.resolve()
414
+ agent_name = agent.strip()
415
+ if not agent_name:
416
+ return {
417
+ "ok": False,
418
+ "action": "check-agents",
419
+ "agent": agent,
420
+ "usable": False,
421
+ "reason": "agent name is empty",
422
+ }
423
+
424
+ resolved_agents_root, _ = _resolve_agents_root(skills_root, agents_root)
425
+ host_capabilities, capability_manifest_present = _read_host_capabilities(skills_root)
426
+ host_callable = agent_name in host_capabilities
427
+
428
+ # Three independent fields (retro §5.3):
429
+ # - definitionPresent: local .md file exists
430
+ # - hostCallable: host adapter declares this agent role
431
+ # - toolContractValid: tools declaration is valid (non-empty list)
432
+ definition_present = False
433
+ tool_contract_valid = False
434
+ agent_path: Path | None = None
435
+ meta: dict[str, Any] | None = None
436
+
437
+ if resolved_agents_root is not None:
438
+ filename = agent_name if agent_name.endswith(".md") else f"{agent_name}.md"
439
+ agent_path = resolved_agents_root / filename
440
+ definition_present = agent_path.is_file()
441
+
442
+ # Codex/Cursor bundles intentionally do not install fixed harness-* agent
443
+ # definitions. Missing host capabilities therefore select the normal
444
+ # inline path instead of reporting UNKNOWN/"subagent unavailable".
445
+ if not definition_present and not host_callable:
446
+ adapter_name = skills_root.parent.name
447
+ if adapter_name in (".agents", ".cursor"):
448
+ reason_code = (
449
+ "HOST_CAPABILITY_NOT_DECLARED"
450
+ if capability_manifest_present
451
+ else "INLINE_BY_ADAPTER"
452
+ )
453
+ return {
454
+ "ok": True,
455
+ "action": "check-agents",
456
+ "agent": agent_name,
457
+ "usable": False,
458
+ "executionMode": "inline",
459
+ "fallbackPolicy": "inline-no-retry",
460
+ "definitionPresent": False,
461
+ "hostCallable": False,
462
+ "toolContractValid": False,
463
+ "capabilityManifestPresent": capability_manifest_present,
464
+ "reasonCode": reason_code,
465
+ "reason": (
466
+ "host capability manifest does not declare this fixed agent; "
467
+ "use the normal inline path"
468
+ if capability_manifest_present
469
+ else "adapter uses inline execution unless the host explicitly "
470
+ "declares a callable agent capability"
471
+ ),
472
+ }
473
+ return {
474
+ "ok": False,
475
+ "action": "check-agents",
476
+ "agent": agent_name,
477
+ "path": str(agent_path) if agent_path else None,
478
+ "agentsRoot": str(resolved_agents_root) if resolved_agents_root else None,
479
+ "usable": False,
480
+ "executionMode": "unavailable",
481
+ "fallbackPolicy": "inline-no-retry",
482
+ "definitionPresent": False,
483
+ "hostCallable": False,
484
+ "toolContractValid": False,
485
+ "capabilityManifestPresent": capability_manifest_present,
486
+ "reasonCode": "AGENT_DEFINITION_NOT_FOUND",
487
+ "reason": f"agent file not found and host does not declare role: {agent_name}",
488
+ }
489
+
490
+ # If definition present, validate frontmatter and tools
491
+ if definition_present and agent_path is not None:
492
+ try:
493
+ text = agent_path.read_text(encoding="utf-8")
494
+ except OSError as exc:
495
+ return {
496
+ "ok": False,
497
+ "action": "check-agents",
498
+ "agent": agent_name,
499
+ "path": str(agent_path),
500
+ "usable": False,
501
+ "executionMode": "unavailable",
502
+ "fallbackPolicy": "inline-no-retry",
503
+ "definitionPresent": True,
504
+ "hostCallable": host_callable,
505
+ "toolContractValid": False,
506
+ "capabilityManifestPresent": capability_manifest_present,
507
+ "reasonCode": "AGENT_DEFINITION_UNREADABLE",
508
+ "reason": f"cannot read agent file: {exc}",
509
+ }
510
+
511
+ meta, err = parse_frontmatter(text)
512
+ if err or meta is None:
513
+ return {
514
+ "ok": False,
515
+ "action": "check-agents",
516
+ "agent": agent_name,
517
+ "path": str(agent_path),
518
+ "usable": False,
519
+ "executionMode": "unavailable",
520
+ "fallbackPolicy": "inline-no-retry",
521
+ "definitionPresent": True,
522
+ "hostCallable": host_callable,
523
+ "toolContractValid": False,
524
+ "capabilityManifestPresent": capability_manifest_present,
525
+ "reasonCode": "AGENT_DEFINITION_INVALID",
526
+ "reason": f"frontmatter parse failed: {err or 'unknown'}",
527
+ }
528
+
529
+ tools = meta.get("tools")
530
+ if tools is None:
531
+ tool_contract_valid = False
532
+ elif isinstance(tools, list) and len(tools) > 0:
533
+ tool_contract_valid = True
534
+ else:
535
+ tool_contract_valid = False
536
+
537
+ # usable = hostCallable (host provides the agent role, tools validated by host)
538
+ # OR definitionPresent AND toolContractValid (definition-based adapters)
539
+ usable = host_callable or (
540
+ definition_present and tool_contract_valid
541
+ )
542
+
543
+ name_field = meta.get("name") if meta else None
544
+ tools_field = meta.get("tools") if meta else None
545
+
546
+ reason_code = "READY" if usable else "TOOL_CONTRACT_INVALID"
547
+ if not definition_present and host_callable:
548
+ reason_code = "DEFINITION_NOT_FOUND_HOST_CAPABLE"
549
+
550
+ return {
551
+ "ok": True,
552
+ "action": "check-agents",
553
+ "agent": agent_name,
554
+ "path": str(agent_path) if agent_path else None,
555
+ "agentsRoot": str(resolved_agents_root) if resolved_agents_root else None,
556
+ "usable": usable,
557
+ "executionMode": "delegated" if usable else "unavailable",
558
+ "fallbackPolicy": "inline-no-retry",
559
+ "definitionPresent": definition_present,
560
+ "hostCallable": host_callable,
561
+ "toolContractValid": tool_contract_valid,
562
+ "capabilityManifestPresent": capability_manifest_present,
563
+ "reasonCode": reason_code,
564
+ "reason": (
565
+ "agent available; "
566
+ f"definition={'present' if definition_present else 'absent'}, "
567
+ f"hostCallable={host_callable}, "
568
+ f"tools={'valid' if tool_contract_valid else 'invalid'}"
569
+ ),
570
+ "name": name_field,
571
+ "tools": tools_field,
572
+ "frontmatterKeys": sorted(meta.keys()) if meta else [],
573
+ }
574
+
575
+
576
+ def build_parser() -> argparse.ArgumentParser:
577
+ parser = argparse.ArgumentParser(
578
+ description="Harness preflight: build-profile + agent availability checks.",
579
+ )
580
+ parser.add_argument(
581
+ "--json",
582
+ action="store_true",
583
+ help="Emit machine-readable JSON (always on for subcommands; kept for contract).",
584
+ )
585
+ sub = parser.add_subparsers(dest="command", required=True)
586
+
587
+ p_detect = sub.add_parser("detect", help="Full probe and write build-profile.json")
588
+ p_detect.add_argument("--project", required=True, type=Path)
589
+ p_detect.add_argument("--json", action="store_true")
590
+
591
+ p_check = sub.add_parser("check", help="Fast stale check of build-profile")
592
+ p_check.add_argument("--project", required=True, type=Path)
593
+ p_check.add_argument("--json", action="store_true")
594
+
595
+ p_quirk = sub.add_parser("record-quirk", help="Append quirk without overwriting peers")
596
+ p_quirk.add_argument("--project", required=True, type=Path)
597
+ p_quirk.add_argument("--pattern", required=True)
598
+ p_quirk.add_argument("--reason", required=True)
599
+ p_quirk.add_argument(
600
+ "--action",
601
+ required=True,
602
+ choices=sorted(VALID_QUIRK_ACTIONS),
603
+ )
604
+ p_quirk.add_argument("--fixed-command", default=None)
605
+ p_quirk.add_argument("--json", action="store_true")
606
+
607
+ p_agents = sub.add_parser("check-agents", help="Validate agent definition usability")
608
+ p_agents.add_argument("--skills-root", required=True, type=Path)
609
+ p_agents.add_argument("--agents-root", type=Path)
610
+ p_agents.add_argument("--agent", required=True)
611
+ p_agents.add_argument("--json", action="store_true")
612
+
613
+ return parser
614
+
615
+
616
+ def main(argv: list[str] | None = None) -> int:
617
+ parser = build_parser()
618
+ args = parser.parse_args(argv)
619
+
620
+ if args.command == "detect":
621
+ result = cmd_detect(args.project)
622
+ return emit_json(result, ok=bool(result.get("ok", True)))
623
+ if args.command == "check":
624
+ result = cmd_check(args.project)
625
+ # missing/invalid = hard failure (exit 1); stale/ready exit 0 (callers branch on JSON)
626
+ hard = result.get("status") in ("missing", "invalid")
627
+ return emit_json(result, ok=not hard)
628
+ if args.command == "record-quirk":
629
+ result = cmd_record_quirk(
630
+ args.project,
631
+ pattern=args.pattern,
632
+ reason=args.reason,
633
+ action=args.action,
634
+ fixed_command=args.fixed_command,
635
+ )
636
+ return emit_json(result, ok=bool(result.get("ok", False)))
637
+ if args.command == "check-agents":
638
+ result = cmd_check_agents(
639
+ args.skills_root,
640
+ args.agent,
641
+ agents_root=args.agents_root,
642
+ )
643
+ return emit_json(result, ok=True)
644
+
645
+ parser.error(f"unknown command: {args.command}")
646
+ return 2
647
+
648
+
649
+ if __name__ == "__main__":
650
+ raise SystemExit(main())