hunter-harness 0.2.0 → 0.2.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 (564) hide show
  1. package/dist/bin.js +659 -230
  2. package/package.json +9 -7
  3. package/resources/harness/bundles/general/claude-code/.harness-build.json +0 -6
  4. package/resources/harness/bundles/general/claude-code/CONTEXT.md +0 -65
  5. package/resources/harness/bundles/general/claude-code/README.md +0 -478
  6. package/resources/harness/bundles/general/claude-code/agents/harness-evaluator.md +0 -96
  7. package/resources/harness/bundles/general/claude-code/agents/harness-explorer.md +0 -72
  8. package/resources/harness/bundles/general/claude-code/agents/harness-reviewer.md +0 -69
  9. package/resources/harness/bundles/general/claude-code/harness-archive/SKILL.md +0 -215
  10. package/resources/harness/bundles/general/claude-code/harness-archive/checklist.md +0 -52
  11. package/resources/harness/bundles/general/claude-code/harness-archive/reference.md +0 -103
  12. package/resources/harness/bundles/general/claude-code/harness-archive/scripts/gen-manifest.ps1 +0 -31
  13. package/resources/harness/bundles/general/claude-code/harness-archive/templates/render-summary.mjs +0 -171
  14. package/resources/harness/bundles/general/claude-code/harness-archive/templates/summary-data-template.json +0 -128
  15. package/resources/harness/bundles/general/claude-code/harness-codebase-map/SKILL.md +0 -112
  16. package/resources/harness/bundles/general/claude-code/harness-codebase-map/checklist.md +0 -126
  17. package/resources/harness/bundles/general/claude-code/harness-codebase-map/reference.md +0 -364
  18. package/resources/harness/bundles/general/claude-code/harness-codebase-map/templates/ARCHITECTURE.md +0 -57
  19. package/resources/harness/bundles/general/claude-code/harness-codebase-map/templates/CONCERNS.md +0 -49
  20. package/resources/harness/bundles/general/claude-code/harness-codebase-map/templates/CONVENTIONS.md +0 -57
  21. package/resources/harness/bundles/general/claude-code/harness-codebase-map/templates/INTEGRATIONS.md +0 -52
  22. package/resources/harness/bundles/general/claude-code/harness-codebase-map/templates/STACK.md +0 -55
  23. package/resources/harness/bundles/general/claude-code/harness-codebase-map/templates/STRUCTURE.md +0 -69
  24. package/resources/harness/bundles/general/claude-code/harness-codebase-map/templates/TESTING.md +0 -64
  25. package/resources/harness/bundles/general/claude-code/harness-codebase-map/templates/map-manifest.schema.json +0 -73
  26. package/resources/harness/bundles/general/claude-code/harness-codebase-map/templates/map-summary.md +0 -64
  27. package/resources/harness/bundles/general/claude-code/harness-knowledge-ingest/SKILL.md +0 -246
  28. package/resources/harness/bundles/general/claude-code/harness-knowledge-ingest/design.md +0 -842
  29. package/resources/harness/bundles/general/claude-code/harness-knowledge-ingest/evaluations/harness_knowledge_evaluation.xml +0 -42
  30. package/resources/harness/bundles/general/claude-code/harness-knowledge-ingest/mcp-config.example.json +0 -10
  31. package/resources/harness/bundles/general/claude-code/harness-knowledge-ingest/reference.md +0 -309
  32. package/resources/harness/bundles/general/claude-code/harness-knowledge-ingest/scripts/harness_knowledge.py +0 -4082
  33. package/resources/harness/bundles/general/claude-code/harness-knowledge-ingest/scripts/harness_knowledge_mcp.py +0 -273
  34. package/resources/harness/bundles/general/claude-code/harness-knowledge-query/SKILL.md +0 -164
  35. package/resources/harness/bundles/general/claude-code/harness-plan/SKILL.md +0 -127
  36. package/resources/harness/bundles/general/claude-code/harness-plan/checklist.md +0 -243
  37. package/resources/harness/bundles/general/claude-code/harness-plan/protocols.md +0 -124
  38. package/resources/harness/bundles/general/claude-code/harness-plan/reference.md +0 -376
  39. package/resources/harness/bundles/general/claude-code/harness-review/SKILL.md +0 -160
  40. package/resources/harness/bundles/general/claude-code/harness-review/checklist.md +0 -124
  41. package/resources/harness/bundles/general/claude-code/harness-review/protocols.md +0 -68
  42. package/resources/harness/bundles/general/claude-code/harness-review/reference.md +0 -86
  43. package/resources/harness/bundles/general/claude-code/harness-run/SKILL.md +0 -132
  44. package/resources/harness/bundles/general/claude-code/harness-run/checklist.md +0 -259
  45. package/resources/harness/bundles/general/claude-code/harness-run/protocols.md +0 -78
  46. package/resources/harness/bundles/general/claude-code/harness-run/reference.md +0 -834
  47. package/resources/harness/bundles/general/claude-code/harness-submit/SKILL.md +0 -159
  48. package/resources/harness/bundles/general/claude-code/harness-submit/checklist.md +0 -407
  49. package/resources/harness/bundles/general/claude-code/harness-submit/reference.md +0 -152
  50. package/resources/harness/bundles/general/claude-code/harness-sync/SKILL.md +0 -82
  51. package/resources/harness/bundles/general/claude-code/harness-sync/reference.md +0 -153
  52. package/resources/harness/bundles/general/claude-code/harness-test/SKILL.md +0 -180
  53. package/resources/harness/bundles/general/claude-code/harness-test/checklist.md +0 -319
  54. package/resources/harness/bundles/general/claude-code/harness-test/pitfalls.md +0 -260
  55. package/resources/harness/bundles/general/claude-code/harness-test/reference.md +0 -791
  56. package/resources/harness/bundles/general/claude-code/protocols/archive-report-protocol.md +0 -175
  57. package/resources/harness/bundles/general/claude-code/protocols/evidence-based-reporting-protocol.md +0 -134
  58. package/resources/harness/bundles/general/claude-code/protocols/ledger-protocol.md +0 -270
  59. package/resources/harness/bundles/general/claude-code/protocols/powershell-protocol.md +0 -181
  60. package/resources/harness/bundles/general/claude-code/protocols/report-pipeline-protocol.md +0 -150
  61. package/resources/harness/bundles/general/claude-code/protocols/sensitive-info-protocol.md +0 -92
  62. package/resources/harness/bundles/general/claude-code/protocols/state-layout-protocol.md +0 -131
  63. package/resources/harness/bundles/general/claude-code/protocols/submit-protocol.md +0 -78
  64. package/resources/harness/bundles/general/claude-code/scripts/harness_archive.py +0 -2319
  65. package/resources/harness/bundles/general/claude-code/scripts/harness_deploy.py +0 -674
  66. package/resources/harness/bundles/general/claude-code/scripts/harness_events.py +0 -680
  67. package/resources/harness/bundles/general/claude-code/scripts/harness_ledger.py +0 -671
  68. package/resources/harness/bundles/general/claude-code/scripts/harness_preflight.py +0 -780
  69. package/resources/harness/bundles/general/claude-code/scripts/harness_service.py +0 -1331
  70. package/resources/harness/bundles/general/codebuddy/.harness-build.json +0 -6
  71. package/resources/harness/bundles/general/codebuddy/CONTEXT.md +0 -65
  72. package/resources/harness/bundles/general/codebuddy/README.md +0 -478
  73. package/resources/harness/bundles/general/codebuddy/agents/harness-evaluator.md +0 -94
  74. package/resources/harness/bundles/general/codebuddy/agents/harness-explorer.md +0 -53
  75. package/resources/harness/bundles/general/codebuddy/agents/harness-reviewer.md +0 -52
  76. package/resources/harness/bundles/general/codebuddy/harness-archive/SKILL.md +0 -198
  77. package/resources/harness/bundles/general/codebuddy/harness-archive/checklist.md +0 -52
  78. package/resources/harness/bundles/general/codebuddy/harness-archive/reference.md +0 -103
  79. package/resources/harness/bundles/general/codebuddy/harness-archive/scripts/gen-manifest.ps1 +0 -31
  80. package/resources/harness/bundles/general/codebuddy/harness-archive/templates/render-summary.mjs +0 -171
  81. package/resources/harness/bundles/general/codebuddy/harness-archive/templates/summary-data-template.json +0 -128
  82. package/resources/harness/bundles/general/codebuddy/harness-codebase-map/SKILL.md +0 -95
  83. package/resources/harness/bundles/general/codebuddy/harness-codebase-map/checklist.md +0 -126
  84. package/resources/harness/bundles/general/codebuddy/harness-codebase-map/reference.md +0 -364
  85. package/resources/harness/bundles/general/codebuddy/harness-codebase-map/templates/ARCHITECTURE.md +0 -57
  86. package/resources/harness/bundles/general/codebuddy/harness-codebase-map/templates/CONCERNS.md +0 -49
  87. package/resources/harness/bundles/general/codebuddy/harness-codebase-map/templates/CONVENTIONS.md +0 -57
  88. package/resources/harness/bundles/general/codebuddy/harness-codebase-map/templates/INTEGRATIONS.md +0 -52
  89. package/resources/harness/bundles/general/codebuddy/harness-codebase-map/templates/STACK.md +0 -55
  90. package/resources/harness/bundles/general/codebuddy/harness-codebase-map/templates/STRUCTURE.md +0 -69
  91. package/resources/harness/bundles/general/codebuddy/harness-codebase-map/templates/TESTING.md +0 -64
  92. package/resources/harness/bundles/general/codebuddy/harness-codebase-map/templates/map-manifest.schema.json +0 -73
  93. package/resources/harness/bundles/general/codebuddy/harness-codebase-map/templates/map-summary.md +0 -64
  94. package/resources/harness/bundles/general/codebuddy/harness-knowledge-ingest/SKILL.md +0 -229
  95. package/resources/harness/bundles/general/codebuddy/harness-knowledge-ingest/design.md +0 -842
  96. package/resources/harness/bundles/general/codebuddy/harness-knowledge-ingest/evaluations/harness_knowledge_evaluation.xml +0 -42
  97. package/resources/harness/bundles/general/codebuddy/harness-knowledge-ingest/mcp-config.example.json +0 -10
  98. package/resources/harness/bundles/general/codebuddy/harness-knowledge-ingest/reference.md +0 -309
  99. package/resources/harness/bundles/general/codebuddy/harness-knowledge-ingest/scripts/harness_knowledge.py +0 -4082
  100. package/resources/harness/bundles/general/codebuddy/harness-knowledge-ingest/scripts/harness_knowledge_mcp.py +0 -273
  101. package/resources/harness/bundles/general/codebuddy/harness-knowledge-query/SKILL.md +0 -147
  102. package/resources/harness/bundles/general/codebuddy/harness-plan/SKILL.md +0 -109
  103. package/resources/harness/bundles/general/codebuddy/harness-plan/checklist.md +0 -243
  104. package/resources/harness/bundles/general/codebuddy/harness-plan/protocols.md +0 -124
  105. package/resources/harness/bundles/general/codebuddy/harness-plan/reference.md +0 -376
  106. package/resources/harness/bundles/general/codebuddy/harness-review/SKILL.md +0 -142
  107. package/resources/harness/bundles/general/codebuddy/harness-review/checklist.md +0 -124
  108. package/resources/harness/bundles/general/codebuddy/harness-review/protocols.md +0 -68
  109. package/resources/harness/bundles/general/codebuddy/harness-review/reference.md +0 -86
  110. package/resources/harness/bundles/general/codebuddy/harness-run/SKILL.md +0 -113
  111. package/resources/harness/bundles/general/codebuddy/harness-run/checklist.md +0 -259
  112. package/resources/harness/bundles/general/codebuddy/harness-run/protocols.md +0 -78
  113. package/resources/harness/bundles/general/codebuddy/harness-run/reference.md +0 -834
  114. package/resources/harness/bundles/general/codebuddy/harness-submit/SKILL.md +0 -142
  115. package/resources/harness/bundles/general/codebuddy/harness-submit/checklist.md +0 -407
  116. package/resources/harness/bundles/general/codebuddy/harness-submit/reference.md +0 -152
  117. package/resources/harness/bundles/general/codebuddy/harness-sync/SKILL.md +0 -65
  118. package/resources/harness/bundles/general/codebuddy/harness-sync/reference.md +0 -153
  119. package/resources/harness/bundles/general/codebuddy/harness-test/SKILL.md +0 -160
  120. package/resources/harness/bundles/general/codebuddy/harness-test/checklist.md +0 -319
  121. package/resources/harness/bundles/general/codebuddy/harness-test/pitfalls.md +0 -260
  122. package/resources/harness/bundles/general/codebuddy/harness-test/reference.md +0 -791
  123. package/resources/harness/bundles/general/codebuddy/protocols/archive-report-protocol.md +0 -175
  124. package/resources/harness/bundles/general/codebuddy/protocols/evidence-based-reporting-protocol.md +0 -134
  125. package/resources/harness/bundles/general/codebuddy/protocols/ledger-protocol.md +0 -270
  126. package/resources/harness/bundles/general/codebuddy/protocols/powershell-protocol.md +0 -181
  127. package/resources/harness/bundles/general/codebuddy/protocols/report-pipeline-protocol.md +0 -150
  128. package/resources/harness/bundles/general/codebuddy/protocols/sensitive-info-protocol.md +0 -92
  129. package/resources/harness/bundles/general/codebuddy/protocols/state-layout-protocol.md +0 -131
  130. package/resources/harness/bundles/general/codebuddy/protocols/submit-protocol.md +0 -78
  131. package/resources/harness/bundles/general/codebuddy/scripts/harness_archive.py +0 -2319
  132. package/resources/harness/bundles/general/codebuddy/scripts/harness_deploy.py +0 -674
  133. package/resources/harness/bundles/general/codebuddy/scripts/harness_events.py +0 -680
  134. package/resources/harness/bundles/general/codebuddy/scripts/harness_ledger.py +0 -671
  135. package/resources/harness/bundles/general/codebuddy/scripts/harness_preflight.py +0 -780
  136. package/resources/harness/bundles/general/codebuddy/scripts/harness_service.py +0 -1331
  137. package/resources/harness/bundles/general/codex/.harness-build.json +0 -6
  138. package/resources/harness/bundles/general/codex/CONTEXT.md +0 -65
  139. package/resources/harness/bundles/general/codex/README.md +0 -478
  140. package/resources/harness/bundles/general/codex/harness-archive/SKILL.md +0 -198
  141. package/resources/harness/bundles/general/codex/harness-archive/checklist.md +0 -52
  142. package/resources/harness/bundles/general/codex/harness-archive/reference.md +0 -103
  143. package/resources/harness/bundles/general/codex/harness-archive/scripts/gen-manifest.ps1 +0 -31
  144. package/resources/harness/bundles/general/codex/harness-archive/templates/render-summary.mjs +0 -171
  145. package/resources/harness/bundles/general/codex/harness-archive/templates/summary-data-template.json +0 -128
  146. package/resources/harness/bundles/general/codex/harness-codebase-map/SKILL.md +0 -95
  147. package/resources/harness/bundles/general/codex/harness-codebase-map/checklist.md +0 -126
  148. package/resources/harness/bundles/general/codex/harness-codebase-map/reference.md +0 -364
  149. package/resources/harness/bundles/general/codex/harness-codebase-map/templates/ARCHITECTURE.md +0 -57
  150. package/resources/harness/bundles/general/codex/harness-codebase-map/templates/CONCERNS.md +0 -49
  151. package/resources/harness/bundles/general/codex/harness-codebase-map/templates/CONVENTIONS.md +0 -57
  152. package/resources/harness/bundles/general/codex/harness-codebase-map/templates/INTEGRATIONS.md +0 -52
  153. package/resources/harness/bundles/general/codex/harness-codebase-map/templates/STACK.md +0 -55
  154. package/resources/harness/bundles/general/codex/harness-codebase-map/templates/STRUCTURE.md +0 -69
  155. package/resources/harness/bundles/general/codex/harness-codebase-map/templates/TESTING.md +0 -64
  156. package/resources/harness/bundles/general/codex/harness-codebase-map/templates/map-manifest.schema.json +0 -73
  157. package/resources/harness/bundles/general/codex/harness-codebase-map/templates/map-summary.md +0 -64
  158. package/resources/harness/bundles/general/codex/harness-knowledge-ingest/SKILL.md +0 -229
  159. package/resources/harness/bundles/general/codex/harness-knowledge-ingest/design.md +0 -842
  160. package/resources/harness/bundles/general/codex/harness-knowledge-ingest/evaluations/harness_knowledge_evaluation.xml +0 -42
  161. package/resources/harness/bundles/general/codex/harness-knowledge-ingest/mcp-config.example.json +0 -10
  162. package/resources/harness/bundles/general/codex/harness-knowledge-ingest/reference.md +0 -309
  163. package/resources/harness/bundles/general/codex/harness-knowledge-ingest/scripts/harness_knowledge.py +0 -4082
  164. package/resources/harness/bundles/general/codex/harness-knowledge-ingest/scripts/harness_knowledge_mcp.py +0 -273
  165. package/resources/harness/bundles/general/codex/harness-knowledge-query/SKILL.md +0 -147
  166. package/resources/harness/bundles/general/codex/harness-plan/SKILL.md +0 -109
  167. package/resources/harness/bundles/general/codex/harness-plan/checklist.md +0 -243
  168. package/resources/harness/bundles/general/codex/harness-plan/protocols.md +0 -124
  169. package/resources/harness/bundles/general/codex/harness-plan/reference.md +0 -376
  170. package/resources/harness/bundles/general/codex/harness-review/SKILL.md +0 -137
  171. package/resources/harness/bundles/general/codex/harness-review/checklist.md +0 -124
  172. package/resources/harness/bundles/general/codex/harness-review/protocols.md +0 -68
  173. package/resources/harness/bundles/general/codex/harness-review/reference.md +0 -86
  174. package/resources/harness/bundles/general/codex/harness-run/SKILL.md +0 -113
  175. package/resources/harness/bundles/general/codex/harness-run/checklist.md +0 -259
  176. package/resources/harness/bundles/general/codex/harness-run/protocols.md +0 -78
  177. package/resources/harness/bundles/general/codex/harness-run/reference.md +0 -834
  178. package/resources/harness/bundles/general/codex/harness-submit/SKILL.md +0 -142
  179. package/resources/harness/bundles/general/codex/harness-submit/checklist.md +0 -407
  180. package/resources/harness/bundles/general/codex/harness-submit/reference.md +0 -152
  181. package/resources/harness/bundles/general/codex/harness-sync/SKILL.md +0 -65
  182. package/resources/harness/bundles/general/codex/harness-sync/reference.md +0 -153
  183. package/resources/harness/bundles/general/codex/harness-test/SKILL.md +0 -160
  184. package/resources/harness/bundles/general/codex/harness-test/checklist.md +0 -319
  185. package/resources/harness/bundles/general/codex/harness-test/pitfalls.md +0 -260
  186. package/resources/harness/bundles/general/codex/harness-test/reference.md +0 -791
  187. package/resources/harness/bundles/general/codex/protocols/archive-report-protocol.md +0 -175
  188. package/resources/harness/bundles/general/codex/protocols/evidence-based-reporting-protocol.md +0 -134
  189. package/resources/harness/bundles/general/codex/protocols/ledger-protocol.md +0 -270
  190. package/resources/harness/bundles/general/codex/protocols/powershell-protocol.md +0 -181
  191. package/resources/harness/bundles/general/codex/protocols/report-pipeline-protocol.md +0 -150
  192. package/resources/harness/bundles/general/codex/protocols/sensitive-info-protocol.md +0 -92
  193. package/resources/harness/bundles/general/codex/protocols/state-layout-protocol.md +0 -131
  194. package/resources/harness/bundles/general/codex/protocols/submit-protocol.md +0 -78
  195. package/resources/harness/bundles/general/codex/scripts/harness_archive.py +0 -2319
  196. package/resources/harness/bundles/general/codex/scripts/harness_deploy.py +0 -674
  197. package/resources/harness/bundles/general/codex/scripts/harness_events.py +0 -680
  198. package/resources/harness/bundles/general/codex/scripts/harness_ledger.py +0 -671
  199. package/resources/harness/bundles/general/codex/scripts/harness_preflight.py +0 -780
  200. package/resources/harness/bundles/general/codex/scripts/harness_service.py +0 -1331
  201. package/resources/harness/bundles/general/cursor/.harness-build.json +0 -6
  202. package/resources/harness/bundles/general/cursor/CONTEXT.md +0 -65
  203. package/resources/harness/bundles/general/cursor/README.md +0 -478
  204. package/resources/harness/bundles/general/cursor/harness-archive/SKILL.md +0 -198
  205. package/resources/harness/bundles/general/cursor/harness-archive/checklist.md +0 -52
  206. package/resources/harness/bundles/general/cursor/harness-archive/reference.md +0 -103
  207. package/resources/harness/bundles/general/cursor/harness-archive/scripts/gen-manifest.ps1 +0 -31
  208. package/resources/harness/bundles/general/cursor/harness-archive/templates/render-summary.mjs +0 -171
  209. package/resources/harness/bundles/general/cursor/harness-archive/templates/summary-data-template.json +0 -128
  210. package/resources/harness/bundles/general/cursor/harness-codebase-map/SKILL.md +0 -95
  211. package/resources/harness/bundles/general/cursor/harness-codebase-map/checklist.md +0 -126
  212. package/resources/harness/bundles/general/cursor/harness-codebase-map/reference.md +0 -364
  213. package/resources/harness/bundles/general/cursor/harness-codebase-map/templates/ARCHITECTURE.md +0 -57
  214. package/resources/harness/bundles/general/cursor/harness-codebase-map/templates/CONCERNS.md +0 -49
  215. package/resources/harness/bundles/general/cursor/harness-codebase-map/templates/CONVENTIONS.md +0 -57
  216. package/resources/harness/bundles/general/cursor/harness-codebase-map/templates/INTEGRATIONS.md +0 -52
  217. package/resources/harness/bundles/general/cursor/harness-codebase-map/templates/STACK.md +0 -55
  218. package/resources/harness/bundles/general/cursor/harness-codebase-map/templates/STRUCTURE.md +0 -69
  219. package/resources/harness/bundles/general/cursor/harness-codebase-map/templates/TESTING.md +0 -64
  220. package/resources/harness/bundles/general/cursor/harness-codebase-map/templates/map-manifest.schema.json +0 -73
  221. package/resources/harness/bundles/general/cursor/harness-codebase-map/templates/map-summary.md +0 -64
  222. package/resources/harness/bundles/general/cursor/harness-knowledge-ingest/SKILL.md +0 -229
  223. package/resources/harness/bundles/general/cursor/harness-knowledge-ingest/design.md +0 -842
  224. package/resources/harness/bundles/general/cursor/harness-knowledge-ingest/evaluations/harness_knowledge_evaluation.xml +0 -42
  225. package/resources/harness/bundles/general/cursor/harness-knowledge-ingest/mcp-config.example.json +0 -10
  226. package/resources/harness/bundles/general/cursor/harness-knowledge-ingest/reference.md +0 -309
  227. package/resources/harness/bundles/general/cursor/harness-knowledge-ingest/scripts/harness_knowledge.py +0 -4082
  228. package/resources/harness/bundles/general/cursor/harness-knowledge-ingest/scripts/harness_knowledge_mcp.py +0 -273
  229. package/resources/harness/bundles/general/cursor/harness-knowledge-query/SKILL.md +0 -147
  230. package/resources/harness/bundles/general/cursor/harness-plan/SKILL.md +0 -109
  231. package/resources/harness/bundles/general/cursor/harness-plan/checklist.md +0 -243
  232. package/resources/harness/bundles/general/cursor/harness-plan/protocols.md +0 -124
  233. package/resources/harness/bundles/general/cursor/harness-plan/reference.md +0 -376
  234. package/resources/harness/bundles/general/cursor/harness-review/SKILL.md +0 -137
  235. package/resources/harness/bundles/general/cursor/harness-review/checklist.md +0 -124
  236. package/resources/harness/bundles/general/cursor/harness-review/protocols.md +0 -68
  237. package/resources/harness/bundles/general/cursor/harness-review/reference.md +0 -86
  238. package/resources/harness/bundles/general/cursor/harness-run/SKILL.md +0 -113
  239. package/resources/harness/bundles/general/cursor/harness-run/checklist.md +0 -259
  240. package/resources/harness/bundles/general/cursor/harness-run/protocols.md +0 -78
  241. package/resources/harness/bundles/general/cursor/harness-run/reference.md +0 -834
  242. package/resources/harness/bundles/general/cursor/harness-submit/SKILL.md +0 -142
  243. package/resources/harness/bundles/general/cursor/harness-submit/checklist.md +0 -407
  244. package/resources/harness/bundles/general/cursor/harness-submit/reference.md +0 -152
  245. package/resources/harness/bundles/general/cursor/harness-sync/SKILL.md +0 -65
  246. package/resources/harness/bundles/general/cursor/harness-sync/reference.md +0 -153
  247. package/resources/harness/bundles/general/cursor/harness-test/SKILL.md +0 -160
  248. package/resources/harness/bundles/general/cursor/harness-test/checklist.md +0 -319
  249. package/resources/harness/bundles/general/cursor/harness-test/pitfalls.md +0 -260
  250. package/resources/harness/bundles/general/cursor/harness-test/reference.md +0 -791
  251. package/resources/harness/bundles/general/cursor/protocols/archive-report-protocol.md +0 -175
  252. package/resources/harness/bundles/general/cursor/protocols/evidence-based-reporting-protocol.md +0 -134
  253. package/resources/harness/bundles/general/cursor/protocols/ledger-protocol.md +0 -270
  254. package/resources/harness/bundles/general/cursor/protocols/powershell-protocol.md +0 -181
  255. package/resources/harness/bundles/general/cursor/protocols/report-pipeline-protocol.md +0 -150
  256. package/resources/harness/bundles/general/cursor/protocols/sensitive-info-protocol.md +0 -92
  257. package/resources/harness/bundles/general/cursor/protocols/state-layout-protocol.md +0 -131
  258. package/resources/harness/bundles/general/cursor/protocols/submit-protocol.md +0 -78
  259. package/resources/harness/bundles/general/cursor/scripts/harness_archive.py +0 -2319
  260. package/resources/harness/bundles/general/cursor/scripts/harness_deploy.py +0 -674
  261. package/resources/harness/bundles/general/cursor/scripts/harness_events.py +0 -680
  262. package/resources/harness/bundles/general/cursor/scripts/harness_ledger.py +0 -671
  263. package/resources/harness/bundles/general/cursor/scripts/harness_preflight.py +0 -780
  264. package/resources/harness/bundles/general/cursor/scripts/harness_service.py +0 -1331
  265. package/resources/harness/bundles/java/claude-code/.harness-build.json +0 -6
  266. package/resources/harness/bundles/java/claude-code/CONTEXT.md +0 -65
  267. package/resources/harness/bundles/java/claude-code/README.md +0 -478
  268. package/resources/harness/bundles/java/claude-code/agents/harness-evaluator.md +0 -96
  269. package/resources/harness/bundles/java/claude-code/agents/harness-explorer.md +0 -72
  270. package/resources/harness/bundles/java/claude-code/agents/harness-reviewer.md +0 -69
  271. package/resources/harness/bundles/java/claude-code/harness-apidoc/SKILL.md +0 -86
  272. package/resources/harness/bundles/java/claude-code/harness-apidoc/checklist.md +0 -142
  273. package/resources/harness/bundles/java/claude-code/harness-apidoc/reference.md +0 -233
  274. package/resources/harness/bundles/java/claude-code/harness-archive/SKILL.md +0 -215
  275. package/resources/harness/bundles/java/claude-code/harness-archive/checklist.md +0 -52
  276. package/resources/harness/bundles/java/claude-code/harness-archive/reference.md +0 -103
  277. package/resources/harness/bundles/java/claude-code/harness-archive/scripts/gen-manifest.ps1 +0 -31
  278. package/resources/harness/bundles/java/claude-code/harness-archive/templates/render-summary.mjs +0 -171
  279. package/resources/harness/bundles/java/claude-code/harness-archive/templates/summary-data-template.json +0 -128
  280. package/resources/harness/bundles/java/claude-code/harness-codebase-map/SKILL.md +0 -112
  281. package/resources/harness/bundles/java/claude-code/harness-codebase-map/checklist.md +0 -126
  282. package/resources/harness/bundles/java/claude-code/harness-codebase-map/reference.md +0 -364
  283. package/resources/harness/bundles/java/claude-code/harness-codebase-map/templates/ARCHITECTURE.md +0 -57
  284. package/resources/harness/bundles/java/claude-code/harness-codebase-map/templates/CONCERNS.md +0 -49
  285. package/resources/harness/bundles/java/claude-code/harness-codebase-map/templates/CONVENTIONS.md +0 -57
  286. package/resources/harness/bundles/java/claude-code/harness-codebase-map/templates/INTEGRATIONS.md +0 -52
  287. package/resources/harness/bundles/java/claude-code/harness-codebase-map/templates/STACK.md +0 -55
  288. package/resources/harness/bundles/java/claude-code/harness-codebase-map/templates/STRUCTURE.md +0 -69
  289. package/resources/harness/bundles/java/claude-code/harness-codebase-map/templates/TESTING.md +0 -64
  290. package/resources/harness/bundles/java/claude-code/harness-codebase-map/templates/map-manifest.schema.json +0 -73
  291. package/resources/harness/bundles/java/claude-code/harness-codebase-map/templates/map-summary.md +0 -64
  292. package/resources/harness/bundles/java/claude-code/harness-knowledge-ingest/SKILL.md +0 -246
  293. package/resources/harness/bundles/java/claude-code/harness-knowledge-ingest/design.md +0 -842
  294. package/resources/harness/bundles/java/claude-code/harness-knowledge-ingest/evaluations/harness_knowledge_evaluation.xml +0 -42
  295. package/resources/harness/bundles/java/claude-code/harness-knowledge-ingest/mcp-config.example.json +0 -10
  296. package/resources/harness/bundles/java/claude-code/harness-knowledge-ingest/reference.md +0 -309
  297. package/resources/harness/bundles/java/claude-code/harness-knowledge-ingest/scripts/harness_knowledge.py +0 -4082
  298. package/resources/harness/bundles/java/claude-code/harness-knowledge-ingest/scripts/harness_knowledge_mcp.py +0 -273
  299. package/resources/harness/bundles/java/claude-code/harness-knowledge-query/SKILL.md +0 -164
  300. package/resources/harness/bundles/java/claude-code/harness-package/SKILL.md +0 -87
  301. package/resources/harness/bundles/java/claude-code/harness-package/checklist.md +0 -322
  302. package/resources/harness/bundles/java/claude-code/harness-package/reference.md +0 -210
  303. package/resources/harness/bundles/java/claude-code/harness-plan/SKILL.md +0 -127
  304. package/resources/harness/bundles/java/claude-code/harness-plan/checklist.md +0 -243
  305. package/resources/harness/bundles/java/claude-code/harness-plan/protocols.md +0 -124
  306. package/resources/harness/bundles/java/claude-code/harness-plan/reference.md +0 -376
  307. package/resources/harness/bundles/java/claude-code/harness-review/SKILL.md +0 -160
  308. package/resources/harness/bundles/java/claude-code/harness-review/checklist.md +0 -124
  309. package/resources/harness/bundles/java/claude-code/harness-review/protocols.md +0 -68
  310. package/resources/harness/bundles/java/claude-code/harness-review/reference.md +0 -86
  311. package/resources/harness/bundles/java/claude-code/harness-run/SKILL.md +0 -148
  312. package/resources/harness/bundles/java/claude-code/harness-run/checklist.md +0 -250
  313. package/resources/harness/bundles/java/claude-code/harness-run/protocols.md +0 -78
  314. package/resources/harness/bundles/java/claude-code/harness-run/reference.md +0 -814
  315. package/resources/harness/bundles/java/claude-code/harness-submit/SKILL.md +0 -166
  316. package/resources/harness/bundles/java/claude-code/harness-submit/checklist.md +0 -407
  317. package/resources/harness/bundles/java/claude-code/harness-submit/reference.md +0 -152
  318. package/resources/harness/bundles/java/claude-code/harness-sync/SKILL.md +0 -82
  319. package/resources/harness/bundles/java/claude-code/harness-sync/reference.md +0 -153
  320. package/resources/harness/bundles/java/claude-code/harness-test/SKILL.md +0 -192
  321. package/resources/harness/bundles/java/claude-code/harness-test/checklist.md +0 -317
  322. package/resources/harness/bundles/java/claude-code/harness-test/pitfalls-java.md +0 -16
  323. package/resources/harness/bundles/java/claude-code/harness-test/pitfalls.md +0 -260
  324. package/resources/harness/bundles/java/claude-code/harness-test/reference.md +0 -788
  325. package/resources/harness/bundles/java/claude-code/protocols/archive-report-protocol.md +0 -175
  326. package/resources/harness/bundles/java/claude-code/protocols/evidence-based-reporting-protocol.md +0 -134
  327. package/resources/harness/bundles/java/claude-code/protocols/ledger-protocol.md +0 -270
  328. package/resources/harness/bundles/java/claude-code/protocols/powershell-protocol.md +0 -181
  329. package/resources/harness/bundles/java/claude-code/protocols/report-pipeline-protocol.md +0 -150
  330. package/resources/harness/bundles/java/claude-code/protocols/sensitive-info-protocol.md +0 -92
  331. package/resources/harness/bundles/java/claude-code/protocols/state-layout-protocol.md +0 -131
  332. package/resources/harness/bundles/java/claude-code/protocols/submit-protocol.md +0 -78
  333. package/resources/harness/bundles/java/claude-code/scripts/harness_archive.py +0 -2319
  334. package/resources/harness/bundles/java/claude-code/scripts/harness_deploy.py +0 -674
  335. package/resources/harness/bundles/java/claude-code/scripts/harness_events.py +0 -680
  336. package/resources/harness/bundles/java/claude-code/scripts/harness_ledger.py +0 -671
  337. package/resources/harness/bundles/java/claude-code/scripts/harness_preflight.py +0 -780
  338. package/resources/harness/bundles/java/claude-code/scripts/harness_service.py +0 -1331
  339. package/resources/harness/bundles/java/codebuddy/.harness-build.json +0 -6
  340. package/resources/harness/bundles/java/codebuddy/CONTEXT.md +0 -65
  341. package/resources/harness/bundles/java/codebuddy/README.md +0 -478
  342. package/resources/harness/bundles/java/codebuddy/agents/harness-evaluator.md +0 -94
  343. package/resources/harness/bundles/java/codebuddy/agents/harness-explorer.md +0 -53
  344. package/resources/harness/bundles/java/codebuddy/agents/harness-reviewer.md +0 -52
  345. package/resources/harness/bundles/java/codebuddy/harness-apidoc/SKILL.md +0 -68
  346. package/resources/harness/bundles/java/codebuddy/harness-apidoc/checklist.md +0 -142
  347. package/resources/harness/bundles/java/codebuddy/harness-apidoc/reference.md +0 -233
  348. package/resources/harness/bundles/java/codebuddy/harness-archive/SKILL.md +0 -198
  349. package/resources/harness/bundles/java/codebuddy/harness-archive/checklist.md +0 -52
  350. package/resources/harness/bundles/java/codebuddy/harness-archive/reference.md +0 -103
  351. package/resources/harness/bundles/java/codebuddy/harness-archive/scripts/gen-manifest.ps1 +0 -31
  352. package/resources/harness/bundles/java/codebuddy/harness-archive/templates/render-summary.mjs +0 -171
  353. package/resources/harness/bundles/java/codebuddy/harness-archive/templates/summary-data-template.json +0 -128
  354. package/resources/harness/bundles/java/codebuddy/harness-codebase-map/SKILL.md +0 -95
  355. package/resources/harness/bundles/java/codebuddy/harness-codebase-map/checklist.md +0 -126
  356. package/resources/harness/bundles/java/codebuddy/harness-codebase-map/reference.md +0 -364
  357. package/resources/harness/bundles/java/codebuddy/harness-codebase-map/templates/ARCHITECTURE.md +0 -57
  358. package/resources/harness/bundles/java/codebuddy/harness-codebase-map/templates/CONCERNS.md +0 -49
  359. package/resources/harness/bundles/java/codebuddy/harness-codebase-map/templates/CONVENTIONS.md +0 -57
  360. package/resources/harness/bundles/java/codebuddy/harness-codebase-map/templates/INTEGRATIONS.md +0 -52
  361. package/resources/harness/bundles/java/codebuddy/harness-codebase-map/templates/STACK.md +0 -55
  362. package/resources/harness/bundles/java/codebuddy/harness-codebase-map/templates/STRUCTURE.md +0 -69
  363. package/resources/harness/bundles/java/codebuddy/harness-codebase-map/templates/TESTING.md +0 -64
  364. package/resources/harness/bundles/java/codebuddy/harness-codebase-map/templates/map-manifest.schema.json +0 -73
  365. package/resources/harness/bundles/java/codebuddy/harness-codebase-map/templates/map-summary.md +0 -64
  366. package/resources/harness/bundles/java/codebuddy/harness-knowledge-ingest/SKILL.md +0 -229
  367. package/resources/harness/bundles/java/codebuddy/harness-knowledge-ingest/design.md +0 -842
  368. package/resources/harness/bundles/java/codebuddy/harness-knowledge-ingest/evaluations/harness_knowledge_evaluation.xml +0 -42
  369. package/resources/harness/bundles/java/codebuddy/harness-knowledge-ingest/mcp-config.example.json +0 -10
  370. package/resources/harness/bundles/java/codebuddy/harness-knowledge-ingest/reference.md +0 -309
  371. package/resources/harness/bundles/java/codebuddy/harness-knowledge-ingest/scripts/harness_knowledge.py +0 -4082
  372. package/resources/harness/bundles/java/codebuddy/harness-knowledge-ingest/scripts/harness_knowledge_mcp.py +0 -273
  373. package/resources/harness/bundles/java/codebuddy/harness-knowledge-query/SKILL.md +0 -147
  374. package/resources/harness/bundles/java/codebuddy/harness-package/SKILL.md +0 -69
  375. package/resources/harness/bundles/java/codebuddy/harness-package/checklist.md +0 -322
  376. package/resources/harness/bundles/java/codebuddy/harness-package/reference.md +0 -210
  377. package/resources/harness/bundles/java/codebuddy/harness-plan/SKILL.md +0 -109
  378. package/resources/harness/bundles/java/codebuddy/harness-plan/checklist.md +0 -243
  379. package/resources/harness/bundles/java/codebuddy/harness-plan/protocols.md +0 -124
  380. package/resources/harness/bundles/java/codebuddy/harness-plan/reference.md +0 -376
  381. package/resources/harness/bundles/java/codebuddy/harness-review/SKILL.md +0 -142
  382. package/resources/harness/bundles/java/codebuddy/harness-review/checklist.md +0 -124
  383. package/resources/harness/bundles/java/codebuddy/harness-review/protocols.md +0 -68
  384. package/resources/harness/bundles/java/codebuddy/harness-review/reference.md +0 -86
  385. package/resources/harness/bundles/java/codebuddy/harness-run/SKILL.md +0 -129
  386. package/resources/harness/bundles/java/codebuddy/harness-run/checklist.md +0 -250
  387. package/resources/harness/bundles/java/codebuddy/harness-run/protocols.md +0 -78
  388. package/resources/harness/bundles/java/codebuddy/harness-run/reference.md +0 -814
  389. package/resources/harness/bundles/java/codebuddy/harness-submit/SKILL.md +0 -149
  390. package/resources/harness/bundles/java/codebuddy/harness-submit/checklist.md +0 -407
  391. package/resources/harness/bundles/java/codebuddy/harness-submit/reference.md +0 -152
  392. package/resources/harness/bundles/java/codebuddy/harness-sync/SKILL.md +0 -65
  393. package/resources/harness/bundles/java/codebuddy/harness-sync/reference.md +0 -153
  394. package/resources/harness/bundles/java/codebuddy/harness-test/SKILL.md +0 -172
  395. package/resources/harness/bundles/java/codebuddy/harness-test/checklist.md +0 -317
  396. package/resources/harness/bundles/java/codebuddy/harness-test/pitfalls-java.md +0 -16
  397. package/resources/harness/bundles/java/codebuddy/harness-test/pitfalls.md +0 -260
  398. package/resources/harness/bundles/java/codebuddy/harness-test/reference.md +0 -788
  399. package/resources/harness/bundles/java/codebuddy/protocols/archive-report-protocol.md +0 -175
  400. package/resources/harness/bundles/java/codebuddy/protocols/evidence-based-reporting-protocol.md +0 -134
  401. package/resources/harness/bundles/java/codebuddy/protocols/ledger-protocol.md +0 -270
  402. package/resources/harness/bundles/java/codebuddy/protocols/powershell-protocol.md +0 -181
  403. package/resources/harness/bundles/java/codebuddy/protocols/report-pipeline-protocol.md +0 -150
  404. package/resources/harness/bundles/java/codebuddy/protocols/sensitive-info-protocol.md +0 -92
  405. package/resources/harness/bundles/java/codebuddy/protocols/state-layout-protocol.md +0 -131
  406. package/resources/harness/bundles/java/codebuddy/protocols/submit-protocol.md +0 -78
  407. package/resources/harness/bundles/java/codebuddy/scripts/harness_archive.py +0 -2319
  408. package/resources/harness/bundles/java/codebuddy/scripts/harness_deploy.py +0 -674
  409. package/resources/harness/bundles/java/codebuddy/scripts/harness_events.py +0 -680
  410. package/resources/harness/bundles/java/codebuddy/scripts/harness_ledger.py +0 -671
  411. package/resources/harness/bundles/java/codebuddy/scripts/harness_preflight.py +0 -780
  412. package/resources/harness/bundles/java/codebuddy/scripts/harness_service.py +0 -1331
  413. package/resources/harness/bundles/java/codex/.harness-build.json +0 -6
  414. package/resources/harness/bundles/java/codex/CONTEXT.md +0 -65
  415. package/resources/harness/bundles/java/codex/README.md +0 -478
  416. package/resources/harness/bundles/java/codex/harness-apidoc/SKILL.md +0 -68
  417. package/resources/harness/bundles/java/codex/harness-apidoc/checklist.md +0 -142
  418. package/resources/harness/bundles/java/codex/harness-apidoc/reference.md +0 -233
  419. package/resources/harness/bundles/java/codex/harness-archive/SKILL.md +0 -198
  420. package/resources/harness/bundles/java/codex/harness-archive/checklist.md +0 -52
  421. package/resources/harness/bundles/java/codex/harness-archive/reference.md +0 -103
  422. package/resources/harness/bundles/java/codex/harness-archive/scripts/gen-manifest.ps1 +0 -31
  423. package/resources/harness/bundles/java/codex/harness-archive/templates/render-summary.mjs +0 -171
  424. package/resources/harness/bundles/java/codex/harness-archive/templates/summary-data-template.json +0 -128
  425. package/resources/harness/bundles/java/codex/harness-codebase-map/SKILL.md +0 -95
  426. package/resources/harness/bundles/java/codex/harness-codebase-map/checklist.md +0 -126
  427. package/resources/harness/bundles/java/codex/harness-codebase-map/reference.md +0 -364
  428. package/resources/harness/bundles/java/codex/harness-codebase-map/templates/ARCHITECTURE.md +0 -57
  429. package/resources/harness/bundles/java/codex/harness-codebase-map/templates/CONCERNS.md +0 -49
  430. package/resources/harness/bundles/java/codex/harness-codebase-map/templates/CONVENTIONS.md +0 -57
  431. package/resources/harness/bundles/java/codex/harness-codebase-map/templates/INTEGRATIONS.md +0 -52
  432. package/resources/harness/bundles/java/codex/harness-codebase-map/templates/STACK.md +0 -55
  433. package/resources/harness/bundles/java/codex/harness-codebase-map/templates/STRUCTURE.md +0 -69
  434. package/resources/harness/bundles/java/codex/harness-codebase-map/templates/TESTING.md +0 -64
  435. package/resources/harness/bundles/java/codex/harness-codebase-map/templates/map-manifest.schema.json +0 -73
  436. package/resources/harness/bundles/java/codex/harness-codebase-map/templates/map-summary.md +0 -64
  437. package/resources/harness/bundles/java/codex/harness-knowledge-ingest/SKILL.md +0 -229
  438. package/resources/harness/bundles/java/codex/harness-knowledge-ingest/design.md +0 -842
  439. package/resources/harness/bundles/java/codex/harness-knowledge-ingest/evaluations/harness_knowledge_evaluation.xml +0 -42
  440. package/resources/harness/bundles/java/codex/harness-knowledge-ingest/mcp-config.example.json +0 -10
  441. package/resources/harness/bundles/java/codex/harness-knowledge-ingest/reference.md +0 -309
  442. package/resources/harness/bundles/java/codex/harness-knowledge-ingest/scripts/harness_knowledge.py +0 -4082
  443. package/resources/harness/bundles/java/codex/harness-knowledge-ingest/scripts/harness_knowledge_mcp.py +0 -273
  444. package/resources/harness/bundles/java/codex/harness-knowledge-query/SKILL.md +0 -147
  445. package/resources/harness/bundles/java/codex/harness-package/SKILL.md +0 -69
  446. package/resources/harness/bundles/java/codex/harness-package/checklist.md +0 -322
  447. package/resources/harness/bundles/java/codex/harness-package/reference.md +0 -210
  448. package/resources/harness/bundles/java/codex/harness-plan/SKILL.md +0 -109
  449. package/resources/harness/bundles/java/codex/harness-plan/checklist.md +0 -243
  450. package/resources/harness/bundles/java/codex/harness-plan/protocols.md +0 -124
  451. package/resources/harness/bundles/java/codex/harness-plan/reference.md +0 -376
  452. package/resources/harness/bundles/java/codex/harness-review/SKILL.md +0 -137
  453. package/resources/harness/bundles/java/codex/harness-review/checklist.md +0 -124
  454. package/resources/harness/bundles/java/codex/harness-review/protocols.md +0 -68
  455. package/resources/harness/bundles/java/codex/harness-review/reference.md +0 -86
  456. package/resources/harness/bundles/java/codex/harness-run/SKILL.md +0 -129
  457. package/resources/harness/bundles/java/codex/harness-run/checklist.md +0 -250
  458. package/resources/harness/bundles/java/codex/harness-run/protocols.md +0 -78
  459. package/resources/harness/bundles/java/codex/harness-run/reference.md +0 -814
  460. package/resources/harness/bundles/java/codex/harness-submit/SKILL.md +0 -149
  461. package/resources/harness/bundles/java/codex/harness-submit/checklist.md +0 -407
  462. package/resources/harness/bundles/java/codex/harness-submit/reference.md +0 -152
  463. package/resources/harness/bundles/java/codex/harness-sync/SKILL.md +0 -65
  464. package/resources/harness/bundles/java/codex/harness-sync/reference.md +0 -153
  465. package/resources/harness/bundles/java/codex/harness-test/SKILL.md +0 -172
  466. package/resources/harness/bundles/java/codex/harness-test/checklist.md +0 -317
  467. package/resources/harness/bundles/java/codex/harness-test/pitfalls-java.md +0 -16
  468. package/resources/harness/bundles/java/codex/harness-test/pitfalls.md +0 -260
  469. package/resources/harness/bundles/java/codex/harness-test/reference.md +0 -788
  470. package/resources/harness/bundles/java/codex/protocols/archive-report-protocol.md +0 -175
  471. package/resources/harness/bundles/java/codex/protocols/evidence-based-reporting-protocol.md +0 -134
  472. package/resources/harness/bundles/java/codex/protocols/ledger-protocol.md +0 -270
  473. package/resources/harness/bundles/java/codex/protocols/powershell-protocol.md +0 -181
  474. package/resources/harness/bundles/java/codex/protocols/report-pipeline-protocol.md +0 -150
  475. package/resources/harness/bundles/java/codex/protocols/sensitive-info-protocol.md +0 -92
  476. package/resources/harness/bundles/java/codex/protocols/state-layout-protocol.md +0 -131
  477. package/resources/harness/bundles/java/codex/protocols/submit-protocol.md +0 -78
  478. package/resources/harness/bundles/java/codex/scripts/harness_archive.py +0 -2319
  479. package/resources/harness/bundles/java/codex/scripts/harness_deploy.py +0 -674
  480. package/resources/harness/bundles/java/codex/scripts/harness_events.py +0 -680
  481. package/resources/harness/bundles/java/codex/scripts/harness_ledger.py +0 -671
  482. package/resources/harness/bundles/java/codex/scripts/harness_preflight.py +0 -780
  483. package/resources/harness/bundles/java/codex/scripts/harness_service.py +0 -1331
  484. package/resources/harness/bundles/java/cursor/.harness-build.json +0 -6
  485. package/resources/harness/bundles/java/cursor/CONTEXT.md +0 -65
  486. package/resources/harness/bundles/java/cursor/README.md +0 -478
  487. package/resources/harness/bundles/java/cursor/harness-apidoc/SKILL.md +0 -68
  488. package/resources/harness/bundles/java/cursor/harness-apidoc/checklist.md +0 -142
  489. package/resources/harness/bundles/java/cursor/harness-apidoc/reference.md +0 -233
  490. package/resources/harness/bundles/java/cursor/harness-archive/SKILL.md +0 -198
  491. package/resources/harness/bundles/java/cursor/harness-archive/checklist.md +0 -52
  492. package/resources/harness/bundles/java/cursor/harness-archive/reference.md +0 -103
  493. package/resources/harness/bundles/java/cursor/harness-archive/scripts/gen-manifest.ps1 +0 -31
  494. package/resources/harness/bundles/java/cursor/harness-archive/templates/render-summary.mjs +0 -171
  495. package/resources/harness/bundles/java/cursor/harness-archive/templates/summary-data-template.json +0 -128
  496. package/resources/harness/bundles/java/cursor/harness-codebase-map/SKILL.md +0 -95
  497. package/resources/harness/bundles/java/cursor/harness-codebase-map/checklist.md +0 -126
  498. package/resources/harness/bundles/java/cursor/harness-codebase-map/reference.md +0 -364
  499. package/resources/harness/bundles/java/cursor/harness-codebase-map/templates/ARCHITECTURE.md +0 -57
  500. package/resources/harness/bundles/java/cursor/harness-codebase-map/templates/CONCERNS.md +0 -49
  501. package/resources/harness/bundles/java/cursor/harness-codebase-map/templates/CONVENTIONS.md +0 -57
  502. package/resources/harness/bundles/java/cursor/harness-codebase-map/templates/INTEGRATIONS.md +0 -52
  503. package/resources/harness/bundles/java/cursor/harness-codebase-map/templates/STACK.md +0 -55
  504. package/resources/harness/bundles/java/cursor/harness-codebase-map/templates/STRUCTURE.md +0 -69
  505. package/resources/harness/bundles/java/cursor/harness-codebase-map/templates/TESTING.md +0 -64
  506. package/resources/harness/bundles/java/cursor/harness-codebase-map/templates/map-manifest.schema.json +0 -73
  507. package/resources/harness/bundles/java/cursor/harness-codebase-map/templates/map-summary.md +0 -64
  508. package/resources/harness/bundles/java/cursor/harness-knowledge-ingest/SKILL.md +0 -229
  509. package/resources/harness/bundles/java/cursor/harness-knowledge-ingest/design.md +0 -842
  510. package/resources/harness/bundles/java/cursor/harness-knowledge-ingest/evaluations/harness_knowledge_evaluation.xml +0 -42
  511. package/resources/harness/bundles/java/cursor/harness-knowledge-ingest/mcp-config.example.json +0 -10
  512. package/resources/harness/bundles/java/cursor/harness-knowledge-ingest/reference.md +0 -309
  513. package/resources/harness/bundles/java/cursor/harness-knowledge-ingest/scripts/harness_knowledge.py +0 -4082
  514. package/resources/harness/bundles/java/cursor/harness-knowledge-ingest/scripts/harness_knowledge_mcp.py +0 -273
  515. package/resources/harness/bundles/java/cursor/harness-knowledge-query/SKILL.md +0 -147
  516. package/resources/harness/bundles/java/cursor/harness-package/SKILL.md +0 -69
  517. package/resources/harness/bundles/java/cursor/harness-package/checklist.md +0 -322
  518. package/resources/harness/bundles/java/cursor/harness-package/reference.md +0 -210
  519. package/resources/harness/bundles/java/cursor/harness-plan/SKILL.md +0 -109
  520. package/resources/harness/bundles/java/cursor/harness-plan/checklist.md +0 -243
  521. package/resources/harness/bundles/java/cursor/harness-plan/protocols.md +0 -124
  522. package/resources/harness/bundles/java/cursor/harness-plan/reference.md +0 -376
  523. package/resources/harness/bundles/java/cursor/harness-review/SKILL.md +0 -137
  524. package/resources/harness/bundles/java/cursor/harness-review/checklist.md +0 -124
  525. package/resources/harness/bundles/java/cursor/harness-review/protocols.md +0 -68
  526. package/resources/harness/bundles/java/cursor/harness-review/reference.md +0 -86
  527. package/resources/harness/bundles/java/cursor/harness-run/SKILL.md +0 -129
  528. package/resources/harness/bundles/java/cursor/harness-run/checklist.md +0 -250
  529. package/resources/harness/bundles/java/cursor/harness-run/protocols.md +0 -78
  530. package/resources/harness/bundles/java/cursor/harness-run/reference.md +0 -814
  531. package/resources/harness/bundles/java/cursor/harness-submit/SKILL.md +0 -149
  532. package/resources/harness/bundles/java/cursor/harness-submit/checklist.md +0 -407
  533. package/resources/harness/bundles/java/cursor/harness-submit/reference.md +0 -152
  534. package/resources/harness/bundles/java/cursor/harness-sync/SKILL.md +0 -65
  535. package/resources/harness/bundles/java/cursor/harness-sync/reference.md +0 -153
  536. package/resources/harness/bundles/java/cursor/harness-test/SKILL.md +0 -172
  537. package/resources/harness/bundles/java/cursor/harness-test/checklist.md +0 -317
  538. package/resources/harness/bundles/java/cursor/harness-test/pitfalls-java.md +0 -16
  539. package/resources/harness/bundles/java/cursor/harness-test/pitfalls.md +0 -260
  540. package/resources/harness/bundles/java/cursor/harness-test/reference.md +0 -788
  541. package/resources/harness/bundles/java/cursor/protocols/archive-report-protocol.md +0 -175
  542. package/resources/harness/bundles/java/cursor/protocols/evidence-based-reporting-protocol.md +0 -134
  543. package/resources/harness/bundles/java/cursor/protocols/ledger-protocol.md +0 -270
  544. package/resources/harness/bundles/java/cursor/protocols/powershell-protocol.md +0 -181
  545. package/resources/harness/bundles/java/cursor/protocols/report-pipeline-protocol.md +0 -150
  546. package/resources/harness/bundles/java/cursor/protocols/sensitive-info-protocol.md +0 -92
  547. package/resources/harness/bundles/java/cursor/protocols/state-layout-protocol.md +0 -131
  548. package/resources/harness/bundles/java/cursor/protocols/submit-protocol.md +0 -78
  549. package/resources/harness/bundles/java/cursor/scripts/harness_archive.py +0 -2319
  550. package/resources/harness/bundles/java/cursor/scripts/harness_deploy.py +0 -674
  551. package/resources/harness/bundles/java/cursor/scripts/harness_events.py +0 -680
  552. package/resources/harness/bundles/java/cursor/scripts/harness_ledger.py +0 -671
  553. package/resources/harness/bundles/java/cursor/scripts/harness_preflight.py +0 -780
  554. package/resources/harness/bundles/java/cursor/scripts/harness_service.py +0 -1331
  555. package/resources/harness/manifests/general/claude-code.json +0 -277
  556. package/resources/harness/manifests/general/codebuddy.json +0 -277
  557. package/resources/harness/manifests/general/codex.json +0 -265
  558. package/resources/harness/manifests/general/cursor.json +0 -265
  559. package/resources/harness/manifests/java/claude-code.json +0 -305
  560. package/resources/harness/manifests/java/codebuddy.json +0 -305
  561. package/resources/harness/manifests/java/codex.json +0 -293
  562. package/resources/harness/manifests/java/cursor.json +0 -293
  563. package/resources/harness/migrations/0.1.1/general.json +0 -358
  564. package/resources/harness/migrations/0.1.1/java.json +0 -398
@@ -1,1331 +0,0 @@
1
- #!/usr/bin/env python3
2
- """Harness service-session manager (D7).
3
-
4
- Subcommands:
5
- ensure — reuse / restart / start / needs-user-decision
6
- status — session + liveness + fingerprint match
7
- stop — stop AI-managed service and clear session
8
-
9
- Python 3.10+, stdlib only. UTF-8 without BOM. Windows path safe.
10
-
11
- Safety: never kill a process that cannot be verified as AI-started.
12
- Missing or corrupt session → treat as user process → needs-user-decision.
13
- """
14
-
15
- from __future__ import annotations
16
-
17
- import argparse
18
- import datetime as dt
19
- import hashlib
20
- import json
21
- import os
22
- import re
23
- import signal
24
- import socket
25
- import subprocess
26
- import sys
27
- import time
28
- import urllib.error
29
- import urllib.request
30
- from pathlib import Path
31
- from typing import Any
32
- from urllib.parse import urlparse
33
-
34
-
35
- SCRIPTS_DIR = Path(__file__).resolve().parent
36
- if str(SCRIPTS_DIR) not in sys.path:
37
- sys.path.insert(0, str(SCRIPTS_DIR))
38
-
39
- from harness_ledger import compute_inputs_hash # noqa: E402
40
-
41
-
42
- if hasattr(sys.stdout, "reconfigure"):
43
- sys.stdout.reconfigure(encoding="utf-8")
44
- if hasattr(sys.stderr, "reconfigure"):
45
- sys.stderr.reconfigure(encoding="utf-8")
46
-
47
-
48
- PROFILE_REL = Path(".harness") / "config" / "build-profile.json"
49
- SESSION_REL = Path("runtime") / "service-session.json"
50
- LOG_REL = Path("logs") / "service-start.log"
51
-
52
- FATAL_KEYWORDS = (
53
- "BindException",
54
- "Could not resolve placeholder",
55
- "BeanCreationException",
56
- "BUILD FAILURE",
57
- )
58
-
59
- # Process create-time vs session.startedAt tolerance (seconds).
60
- IDENTITY_TOLERANCE_SEC = 5.0
61
-
62
- # Windows process flags
63
- _DETACHED_PROCESS = 0x00000008
64
- _CREATE_NEW_PROCESS_GROUP = 0x00000200
65
- _CREATE_NO_WINDOW = 0x08000000
66
- _CREATE_BREAKAWAY_FROM_JOB = 0x01000000
67
- _STILL_ACTIVE = 259
68
-
69
-
70
- def now_iso() -> str:
71
- return dt.datetime.now().astimezone().isoformat(timespec="milliseconds")
72
-
73
-
74
- def emit_json(payload: dict[str, Any], *, as_json: bool) -> None:
75
- text = json.dumps(payload, ensure_ascii=False, indent=2) + "\n"
76
- if as_json:
77
- sys.stdout.write(text)
78
- else:
79
- action = payload.get("action") or payload.get("status")
80
- ok = payload.get("ok", True)
81
- sys.stdout.write(f"ok={ok} action={action}\n")
82
-
83
-
84
- def emit_error(message: str, *, as_json: bool, code: int = 1, **extra: Any) -> int:
85
- payload: dict[str, Any] = {"ok": False, "error": message}
86
- payload.update(extra)
87
- if as_json:
88
- sys.stderr.write(json.dumps(payload, ensure_ascii=False) + "\n")
89
- else:
90
- sys.stderr.write(f"error: {message}\n")
91
- return code
92
-
93
-
94
- def resolve_path(raw: str | Path) -> Path:
95
- return Path(raw).expanduser().resolve()
96
-
97
-
98
- def parse_files_arg(raw: str | None) -> list[str]:
99
- if raw is None or not str(raw).strip():
100
- return []
101
- parts = [p.strip() for p in str(raw).split(",")]
102
- return [p for p in parts if p]
103
-
104
-
105
- def sha256_text(text: str) -> str:
106
- return "sha256:" + hashlib.sha256(text.encode("utf-8")).hexdigest()
107
-
108
-
109
- def session_path(change_dir: Path) -> Path:
110
- return change_dir / SESSION_REL
111
-
112
-
113
- def log_path(change_dir: Path) -> Path:
114
- return change_dir / LOG_REL
115
-
116
-
117
- def profile_path(project: Path) -> Path:
118
- return project / PROFILE_REL
119
-
120
-
121
- def read_json(path: Path) -> Any:
122
- return json.loads(path.read_text(encoding="utf-8-sig"))
123
-
124
-
125
- def write_json(path: Path, data: Any) -> None:
126
- path.parent.mkdir(parents=True, exist_ok=True)
127
- text = json.dumps(data, ensure_ascii=False, indent=2) + "\n"
128
- path.write_text(text, encoding="utf-8", newline="\n")
129
-
130
-
131
- def load_build_profile(project: Path) -> dict[str, Any]:
132
- path = profile_path(project)
133
- if not path.is_file():
134
- raise FileNotFoundError(
135
- f"build-profile.json missing: {path}; run harness_preflight.py detect first"
136
- )
137
- data = read_json(path)
138
- if not isinstance(data, dict):
139
- raise ValueError(f"build-profile.json must be an object: {path}")
140
- return data
141
-
142
-
143
- def get_service_start(profile: dict[str, Any]) -> dict[str, Any]:
144
- svc = profile.get("serviceStart")
145
- if not isinstance(svc, dict):
146
- raise ValueError("build-profile.json missing serviceStart object")
147
- command = svc.get("command")
148
- if not isinstance(command, str) or not command.strip():
149
- raise ValueError(
150
- "build-profile.json serviceStart.command is empty; "
151
- "configure the service start command explicitly (will not guess)"
152
- )
153
- return svc
154
-
155
-
156
- def resolve_service_input_files(
157
- project: Path,
158
- service_start: dict[str, Any],
159
- cli_files: list[str],
160
- ) -> list[str]:
161
- """Union of CLI ``--files`` and ``serviceStart.inputFiles`` globs.
162
-
163
- Globs expand relative to project; only files inside project are kept
164
- (deduped, path-sorted). Empty result raises ValueError -- never produce a
165
- reusable empty fingerprint (§5.1/§5.2). Never globs outside project.
166
- """
167
- base = project.resolve()
168
- seen: set[str] = set()
169
-
170
- for raw in cli_files:
171
- p = Path(raw).expanduser()
172
- if not p.is_absolute():
173
- p = base / p
174
- try:
175
- p = p.resolve()
176
- except OSError:
177
- continue
178
- if not p.is_file():
179
- continue
180
- try:
181
- p.relative_to(base)
182
- except ValueError:
183
- continue # reject project-external path
184
- seen.add(p.as_posix())
185
-
186
- input_files = service_start.get("inputFiles")
187
- if isinstance(input_files, list):
188
- for pat in input_files:
189
- if not isinstance(pat, str) or not pat.strip():
190
- continue
191
- for match in base.glob(pat):
192
- if not match.is_file():
193
- continue
194
- resolved = match.resolve()
195
- try:
196
- resolved.relative_to(base)
197
- except ValueError:
198
- continue # reject project-external glob escape
199
- seen.add(resolved.as_posix())
200
-
201
- result = sorted(seen)
202
- if not result:
203
- raise ValueError(
204
- "service inputs are empty; configure serviceStart.inputFiles "
205
- "(or pass --files) so the service fingerprint covers real source"
206
- )
207
- return result
208
-
209
-
210
- # ---------------------------------------------------------------------------
211
- # Process liveness / identity (stdlib-first; ctypes best-effort on Windows)
212
- # ---------------------------------------------------------------------------
213
-
214
-
215
- def is_pid_alive(pid: int) -> bool:
216
- if not isinstance(pid, int) or pid <= 0:
217
- return False
218
- if os.name == "nt":
219
- return _windows_pid_alive(pid)
220
- try:
221
- os.kill(pid, 0)
222
- return True
223
- except ProcessLookupError:
224
- return False
225
- except PermissionError:
226
- return True
227
- except OSError:
228
- return False
229
-
230
-
231
- def _windows_pid_alive(pid: int) -> bool:
232
- try:
233
- import ctypes
234
- from ctypes import wintypes
235
-
236
- kernel32 = ctypes.windll.kernel32
237
- PROCESS_QUERY_LIMITED_INFORMATION = 0x1000
238
- handle = kernel32.OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, False, pid)
239
- if not handle:
240
- handle = kernel32.OpenProcess(0x0400, False, pid) # PROCESS_QUERY_INFORMATION
241
- if not handle:
242
- return False
243
- try:
244
- exit_code = wintypes.DWORD()
245
- if not kernel32.GetExitCodeProcess(handle, ctypes.byref(exit_code)):
246
- return False
247
- return int(exit_code.value) == _STILL_ACTIVE
248
- finally:
249
- kernel32.CloseHandle(handle)
250
- except Exception:
251
- return False
252
-
253
-
254
- def get_process_create_time(pid: int) -> dt.datetime | None:
255
- """Best-effort process create time (timezone-aware). None if unavailable."""
256
- if os.name == "nt":
257
- return _windows_process_create_time(pid)
258
- return _posix_process_create_time(pid)
259
-
260
-
261
- def _windows_process_create_time(pid: int) -> dt.datetime | None:
262
- try:
263
- import ctypes
264
- from ctypes import wintypes
265
-
266
- kernel32 = ctypes.windll.kernel32
267
- handle = kernel32.OpenProcess(0x1000, False, pid)
268
- if not handle:
269
- handle = kernel32.OpenProcess(0x0400, False, pid)
270
- if not handle:
271
- return None
272
- try:
273
- creation = wintypes.FILETIME()
274
- exit_time = wintypes.FILETIME()
275
- kernel_time = wintypes.FILETIME()
276
- user_time = wintypes.FILETIME()
277
- ok = kernel32.GetProcessTimes(
278
- handle,
279
- ctypes.byref(creation),
280
- ctypes.byref(exit_time),
281
- ctypes.byref(kernel_time),
282
- ctypes.byref(user_time),
283
- )
284
- if not ok:
285
- return None
286
- val = (creation.dwHighDateTime << 32) | creation.dwLowDateTime
287
- # FILETIME: 100-ns since 1601-01-01 UTC
288
- unix_sec = (val - 116444736000000000) / 10_000_000
289
- return dt.datetime.fromtimestamp(unix_sec, tz=dt.timezone.utc)
290
- finally:
291
- kernel32.CloseHandle(handle)
292
- except Exception:
293
- return None
294
-
295
-
296
- def _posix_process_create_time(pid: int) -> dt.datetime | None:
297
- try:
298
- stat_path = Path(f"/proc/{pid}/stat")
299
- if not stat_path.is_file():
300
- # macOS / other: no reliable stdlib create-time
301
- return None
302
- text = stat_path.read_text(encoding="utf-8", errors="replace")
303
- # comm may contain spaces/parens — split after last ')'
304
- rparen = text.rfind(")")
305
- if rparen < 0:
306
- return None
307
- fields = text[rparen + 2 :].split()
308
- # field index 20 in remaining = starttime (clock ticks since boot)
309
- start_ticks = int(fields[19])
310
- ticks = os.sysconf(os.sysconf_names.get("SC_CLK_TCK", "SC_CLK_TCK"))
311
- if not ticks:
312
- ticks = 100
313
- boot = _linux_boot_time()
314
- if boot is None:
315
- return None
316
- return dt.datetime.fromtimestamp(boot + start_ticks / ticks, tz=dt.timezone.utc)
317
- except Exception:
318
- return None
319
-
320
-
321
- def _linux_boot_time() -> float | None:
322
- try:
323
- for line in Path("/proc/stat").read_text(encoding="utf-8").splitlines():
324
- if line.startswith("btime "):
325
- return float(line.split()[1])
326
- except Exception:
327
- return None
328
- return None
329
-
330
-
331
- def parse_iso(value: Any) -> dt.datetime | None:
332
- if not isinstance(value, str) or not value.strip():
333
- return None
334
- text = value.strip()
335
- try:
336
- # Support "...Z" and space separator
337
- if text.endswith("Z"):
338
- text = text[:-1] + "+00:00"
339
- parsed = dt.datetime.fromisoformat(text)
340
- if parsed.tzinfo is None:
341
- parsed = parsed.astimezone()
342
- return parsed
343
- except ValueError:
344
- return None
345
-
346
-
347
- def verify_process_identity(session: dict[str, Any]) -> bool | None:
348
- """True=same process, False=definitely different/dead, None=cannot verify.
349
-
350
- Requires pid alive AND create-time within tolerance of session.startedAt.
351
- If create-time unavailable → None (conservative → needs-user-decision).
352
- """
353
- pid = session.get("pid")
354
- if not isinstance(pid, int) or pid <= 0:
355
- return False
356
- if not is_pid_alive(pid):
357
- return False
358
-
359
- started_at = parse_iso(session.get("startedAt"))
360
- if started_at is None:
361
- return None
362
-
363
- create_time = get_process_create_time(pid)
364
- if create_time is None:
365
- return None
366
-
367
- # Compare in UTC
368
- started_utc = started_at.astimezone(dt.timezone.utc)
369
- create_utc = create_time.astimezone(dt.timezone.utc)
370
- delta = abs((create_utc - started_utc).total_seconds())
371
- return delta <= IDENTITY_TOLERANCE_SEC
372
-
373
-
374
- def terminate_process_tree(pid: int) -> None:
375
- """Stop process (and children on Windows via taskkill /T). Never raises for missing pid."""
376
- if not isinstance(pid, int) or pid <= 0:
377
- return
378
- if not is_pid_alive(pid):
379
- return
380
- if os.name == "nt":
381
- try:
382
- subprocess.run(
383
- ["taskkill", "/PID", str(pid), "/T", "/F"],
384
- capture_output=True,
385
- text=True,
386
- encoding="utf-8",
387
- errors="replace",
388
- timeout=30,
389
- check=False,
390
- )
391
- except (OSError, subprocess.TimeoutExpired):
392
- pass
393
- return
394
- try:
395
- os.killpg(pid, signal.SIGTERM)
396
- except OSError:
397
- try:
398
- os.kill(pid, signal.SIGTERM)
399
- except OSError:
400
- pass
401
- # Brief wait then SIGKILL
402
- deadline = time.monotonic() + 3.0
403
- while time.monotonic() < deadline and is_pid_alive(pid):
404
- time.sleep(0.1)
405
- if is_pid_alive(pid):
406
- try:
407
- os.killpg(pid, signal.SIGKILL)
408
- except OSError:
409
- try:
410
- os.kill(pid, signal.SIGKILL)
411
- except OSError:
412
- pass
413
-
414
-
415
- # ---------------------------------------------------------------------------
416
- # Port / health probing
417
- # ---------------------------------------------------------------------------
418
-
419
-
420
- def extract_port(service_start: dict[str, Any]) -> int | None:
421
- for key in ("port", "listenPort"):
422
- val = service_start.get(key)
423
- if isinstance(val, int) and 0 < val < 65536:
424
- return val
425
- if isinstance(val, str) and val.strip().isdigit():
426
- p = int(val.strip())
427
- if 0 < p < 65536:
428
- return p
429
-
430
- health = service_start.get("healthUrl") or service_start.get("healthFile") or ""
431
- if not isinstance(health, str) or not health.strip():
432
- return None
433
- return port_from_health_spec(health.strip())
434
-
435
-
436
- def port_from_health_spec(spec: str) -> int | None:
437
- lower = spec.lower()
438
- if lower.startswith("file:") or lower.startswith("path:"):
439
- return None
440
- # bare path (Windows drive or relative) — not a URL
441
- if re.match(r"^[A-Za-z]:[\\/]", spec) or (os.sep in spec and "://" not in spec):
442
- return None
443
- if lower.startswith("tcp://") or lower.startswith("socket://"):
444
- rest = spec.split("://", 1)[1]
445
- host_port = rest.split("/", 1)[0]
446
- if ":" in host_port:
447
- try:
448
- return int(host_port.rsplit(":", 1)[1])
449
- except ValueError:
450
- return None
451
- return None
452
- try:
453
- parsed = urlparse(spec if "://" in spec else f"http://{spec}")
454
- if parsed.port:
455
- return int(parsed.port)
456
- except ValueError:
457
- return None
458
- return None
459
-
460
-
461
- def is_port_in_use(port: int, host: str = "127.0.0.1") -> bool:
462
- """True if something is accepting connections on host:port."""
463
- try:
464
- with socket.create_connection((host, port), timeout=0.5):
465
- return True
466
- except OSError:
467
- return False
468
-
469
-
470
- def resolve_health_file(spec: str) -> Path | None:
471
- lower = spec.lower()
472
- if lower.startswith("file:"):
473
- raw = spec[5:]
474
- # file:///C:/path or file:C:/path or file:/path
475
- if raw.startswith("///"):
476
- raw = raw[3:]
477
- elif raw.startswith("//"):
478
- raw = raw[2:]
479
- return Path(raw)
480
- if lower.startswith("path:"):
481
- return Path(spec[5:])
482
- if re.match(r"^[A-Za-z]:[\\/]", spec) or (spec.startswith(".") and "://" not in spec):
483
- return Path(spec)
484
- return None
485
-
486
-
487
- def probe_health(service_start: dict[str, Any]) -> bool:
488
- """Return True if service appears healthy per serviceStart health config."""
489
- # Prefer explicit healthFile
490
- health_file = service_start.get("healthFile")
491
- if isinstance(health_file, str) and health_file.strip():
492
- return Path(health_file.strip()).is_file()
493
-
494
- spec = service_start.get("healthUrl")
495
- if not isinstance(spec, str) or not spec.strip():
496
- # No health probe configured → treat as healthy once process is up
497
- # (caller should still have started the process). For wait loop, require
498
- # at least that we have a running pid — handled by caller.
499
- return True
500
-
501
- spec = spec.strip()
502
- file_path = resolve_health_file(spec)
503
- if file_path is not None:
504
- return file_path.is_file()
505
-
506
- lower = spec.lower()
507
- if lower.startswith("tcp://") or lower.startswith("socket://"):
508
- rest = spec.split("://", 1)[1]
509
- host_port = rest.split("/", 1)[0]
510
- if ":" not in host_port:
511
- return False
512
- host, port_s = host_port.rsplit(":", 1)
513
- try:
514
- port = int(port_s)
515
- except ValueError:
516
- return False
517
- return is_port_in_use(port, host or "127.0.0.1")
518
-
519
- # HTTP(S)
520
- url = spec if "://" in spec else f"http://{spec}"
521
- try:
522
- req = urllib.request.Request(url, method="GET")
523
- with urllib.request.urlopen(req, timeout=2.0) as resp:
524
- return 200 <= int(getattr(resp, "status", 200)) < 300
525
- except (urllib.error.URLError, urllib.error.HTTPError, TimeoutError, OSError):
526
- return False
527
-
528
-
529
- def log_has_fatal(path: Path) -> str | None:
530
- if not path.is_file():
531
- return None
532
- try:
533
- text = path.read_text(encoding="utf-8", errors="replace")
534
- except OSError:
535
- return None
536
- # Check last ~200 lines for fatal keywords
537
- lines = text.splitlines()
538
- tail = "\n".join(lines[-200:])
539
- for kw in FATAL_KEYWORDS:
540
- if kw in tail:
541
- return kw
542
- return None
543
-
544
-
545
- class ServiceStartError(Exception):
546
- def __init__(self, message: str, *, fatal_keyword: str | None = None) -> None:
547
- super().__init__(message)
548
- self.fatal_keyword = fatal_keyword
549
-
550
-
551
- def wait_for_healthy(
552
- service_start: dict[str, Any],
553
- log_file: Path,
554
- *,
555
- pid: int | None = None,
556
- ) -> None:
557
- """Startup wait state machine: 0–30s /2s, 30–120s /5s; fatal keywords abort."""
558
- timeout_sec = service_start.get("startTimeoutSec", 120)
559
- try:
560
- timeout_sec = float(timeout_sec)
561
- except (TypeError, ValueError):
562
- timeout_sec = 120.0
563
- if timeout_sec <= 0:
564
- timeout_sec = 120.0
565
-
566
- start = time.monotonic()
567
- while True:
568
- elapsed = time.monotonic() - start
569
- fatal = log_has_fatal(log_file)
570
- if fatal:
571
- raise ServiceStartError(
572
- f"service start aborted: fatal keyword in log: {fatal}",
573
- fatal_keyword=fatal,
574
- )
575
- if pid is not None and not is_pid_alive(pid):
576
- raise ServiceStartError(f"service process exited early (pid={pid})")
577
- if probe_health(service_start):
578
- return
579
- if elapsed >= timeout_sec:
580
- raise ServiceStartError(
581
- f"service start timed out after {timeout_sec:.0f}s "
582
- f"(health probe not ready; see {log_file})"
583
- )
584
- # 0–30s every 2s; 30–120s every 5s
585
- if elapsed < 30.0:
586
- time.sleep(2.0)
587
- else:
588
- time.sleep(5.0)
589
-
590
-
591
- # ---------------------------------------------------------------------------
592
- # Session I/O
593
- # ---------------------------------------------------------------------------
594
-
595
-
596
- class SessionCorrupt(Exception):
597
- pass
598
-
599
-
600
- def load_session(change_dir: Path) -> dict[str, Any] | None:
601
- """Return session dict, None if missing, raise SessionCorrupt if damaged."""
602
- path = session_path(change_dir)
603
- if not path.is_file():
604
- return None
605
- try:
606
- text = path.read_text(encoding="utf-8-sig")
607
- except OSError as exc:
608
- raise SessionCorrupt(f"cannot read session: {exc}") from exc
609
- if not text.strip():
610
- raise SessionCorrupt("session file is empty")
611
- try:
612
- data = json.loads(text)
613
- except json.JSONDecodeError as exc:
614
- raise SessionCorrupt(f"session JSON corrupt: {exc}") from exc
615
- if not isinstance(data, dict):
616
- raise SessionCorrupt("session must be a JSON object")
617
- # Minimal required fields for a usable AI session
618
- pid = data.get("pid")
619
- if not isinstance(pid, int):
620
- raise SessionCorrupt("session.pid missing or not an int")
621
- if "startedBy" not in data:
622
- raise SessionCorrupt("session.startedBy missing")
623
- if "startedAt" not in data:
624
- raise SessionCorrupt("session.startedAt missing")
625
- return data
626
-
627
-
628
- def clear_session(change_dir: Path) -> None:
629
- path = session_path(change_dir)
630
- if path.is_file():
631
- try:
632
- path.unlink()
633
- except OSError:
634
- pass
635
-
636
-
637
- def write_session(change_dir: Path, session: dict[str, Any]) -> Path:
638
- path = session_path(change_dir)
639
- write_json(path, session)
640
- return path
641
-
642
-
643
- # ---------------------------------------------------------------------------
644
- # Start / stop helpers
645
- # ---------------------------------------------------------------------------
646
-
647
- _WIN_LAUNCHER_SOURCE = """\
648
- #!/usr/bin/env python3
649
- \"\"\"Harness Windows service launcher (internal).\"\"\"
650
- from __future__ import annotations
651
-
652
- import subprocess
653
- import sys
654
- from pathlib import Path
655
-
656
- _CREATE_NEW_PROCESS_GROUP = 0x00000200
657
- _CREATE_NO_WINDOW = 0x08000000
658
- _CREATE_BREAKAWAY_FROM_JOB = 0x01000000
659
-
660
-
661
- def main() -> int:
662
- log_path = Path(sys.argv[1])
663
- command_path = Path(sys.argv[2])
664
- pid_path = Path(sys.argv[3])
665
- command = command_path.read_text(encoding="utf-8").strip()
666
- if not command:
667
- raise SystemExit("empty service command")
668
-
669
- log_path.parent.mkdir(parents=True, exist_ok=True)
670
- log_handle = log_path.open("w", encoding="utf-8", errors="replace")
671
- try:
672
- proc = subprocess.Popen(
673
- command,
674
- shell=True,
675
- stdout=log_handle,
676
- stderr=subprocess.STDOUT,
677
- stdin=subprocess.DEVNULL,
678
- creationflags=(
679
- _CREATE_NEW_PROCESS_GROUP
680
- | _CREATE_NO_WINDOW
681
- | _CREATE_BREAKAWAY_FROM_JOB
682
- ),
683
- close_fds=False,
684
- )
685
- finally:
686
- log_handle.close()
687
-
688
- pid_path.write_text(str(proc.pid), encoding="utf-8")
689
- # Exit immediately: the detached service (shell) continues on its own.
690
- # Staying alive to wait() would keep the launcher process running and
691
- # trigger ResourceWarning when the harness_service Popen is GC'd.
692
- return 0
693
-
694
-
695
- if __name__ == "__main__":
696
- raise SystemExit(main())
697
- """
698
-
699
-
700
- def _runtime_dir(change_dir: Path) -> Path:
701
- path = change_dir / "runtime"
702
- path.mkdir(parents=True, exist_ok=True)
703
- return path
704
-
705
-
706
- def _launcher_pid_path(change_dir: Path) -> Path:
707
- return _runtime_dir(change_dir) / "_harness_service.launcher.pid"
708
-
709
-
710
- def _cleanup_windows_launcher(change_dir: Path) -> None:
711
- if os.name != "nt":
712
- return
713
- path = _launcher_pid_path(change_dir)
714
- if not path.is_file():
715
- return
716
- text = path.read_text(encoding="utf-8").strip()
717
- try:
718
- path.unlink()
719
- except OSError:
720
- pass
721
- if text.isdigit():
722
- pid = int(text)
723
- if is_pid_alive(pid):
724
- terminate_process_tree(pid)
725
-
726
-
727
- def _write_windows_launcher(change_dir: Path) -> Path:
728
- launcher = _runtime_dir(change_dir) / "_harness_service_launcher.py"
729
- launcher.write_text(_WIN_LAUNCHER_SOURCE, encoding="utf-8", newline="\n")
730
- return launcher
731
-
732
-
733
- def _wait_for_child_pid(pid_path: Path, *, timeout_sec: float = 15.0) -> int:
734
- deadline = time.monotonic() + timeout_sec
735
- while time.monotonic() < deadline:
736
- if pid_path.is_file():
737
- text = pid_path.read_text(encoding="utf-8").strip()
738
- if text.isdigit():
739
- return int(text)
740
- time.sleep(0.05)
741
- raise TimeoutError(f"service child pid not recorded within {timeout_sec:.0f}s ({pid_path})")
742
-
743
-
744
- def _start_detached_service_windows(
745
- command: str,
746
- *,
747
- change_dir: Path,
748
- cwd: Path,
749
- log_file: Path,
750
- ) -> int:
751
- runtime = _runtime_dir(change_dir)
752
- launcher = _write_windows_launcher(change_dir)
753
- command_path = runtime / "_harness_service.command.txt"
754
- pid_path = runtime / "_harness_service.child.pid"
755
- command_path.write_text(command, encoding="utf-8", newline="\n")
756
- if pid_path.exists():
757
- pid_path.unlink()
758
-
759
- launcher_args = [
760
- sys.executable,
761
- str(launcher),
762
- str(log_file),
763
- str(command_path),
764
- str(pid_path),
765
- ]
766
- win_flags = (
767
- _DETACHED_PROCESS
768
- | _CREATE_NEW_PROCESS_GROUP
769
- | _CREATE_NO_WINDOW
770
- | _CREATE_BREAKAWAY_FROM_JOB
771
- )
772
- launcher_proc = subprocess.Popen(
773
- launcher_args,
774
- cwd=str(cwd),
775
- stdin=subprocess.DEVNULL,
776
- stdout=subprocess.DEVNULL,
777
- stderr=subprocess.DEVNULL,
778
- creationflags=win_flags,
779
- close_fds=False,
780
- )
781
- _launcher_pid_path(change_dir).write_text(str(launcher_proc.pid), encoding="utf-8")
782
- # Reap the short-lived launcher (it exits right after recording the child
783
- # pid) so its Popen does not ResourceWarning at GC.
784
- try:
785
- launcher_proc.wait(timeout=5.0)
786
- except subprocess.TimeoutExpired:
787
- pass
788
- return _wait_for_child_pid(pid_path)
789
-
790
-
791
- def start_detached_service(
792
- command: str,
793
- *,
794
- change_dir: Path,
795
- cwd: Path,
796
- ) -> int:
797
- """Start service detached from this script; log to logs/service-start.log."""
798
- log_file = log_path(change_dir)
799
- log_file.parent.mkdir(parents=True, exist_ok=True)
800
- if log_file.is_file():
801
- log_file.unlink()
802
-
803
- if os.name == "nt":
804
- return _start_detached_service_windows(
805
- command,
806
- change_dir=change_dir,
807
- cwd=cwd,
808
- log_file=log_file,
809
- )
810
-
811
- log_handle = log_file.open("w", encoding="utf-8", errors="replace")
812
- popen_kwargs: dict[str, Any] = {
813
- "args": command,
814
- "shell": True,
815
- "stdout": log_handle,
816
- "stderr": subprocess.STDOUT,
817
- "cwd": str(cwd),
818
- "stdin": subprocess.DEVNULL,
819
- "start_new_session": True,
820
- "close_fds": True,
821
- }
822
- try:
823
- proc = subprocess.Popen(**popen_kwargs)
824
- finally:
825
- try:
826
- log_handle.close()
827
- except OSError:
828
- pass
829
-
830
- return int(proc.pid)
831
-
832
-
833
- def build_session(
834
- *,
835
- pid: int,
836
- module_inputs_hash: str,
837
- module_inputs_files: list[str],
838
- command: str,
839
- service_start: dict[str, Any],
840
- started_at: str | None = None,
841
- ) -> dict[str, Any]:
842
- profile_name = service_start.get("profile") or "local-dev"
843
- overlay = service_start.get("overlayPath") or ""
844
- return {
845
- "pid": pid,
846
- "startedBy": "AI",
847
- "moduleInputsHash": module_inputs_hash,
848
- "moduleInputsFiles": module_inputs_files,
849
- "profile": profile_name,
850
- "startCommandHash": sha256_text(command),
851
- "overlayPath": overlay,
852
- "startedAt": started_at or now_iso(),
853
- "command": command,
854
- }
855
-
856
-
857
- def compute_module_hash(
858
- files: list[str],
859
- session: dict[str, Any] | None = None,
860
- ) -> tuple[str, list[str]]:
861
- """Compute inputsHash from --files, else session.moduleInputsFiles, else empty."""
862
- use_files = list(files)
863
- if not use_files and session is not None:
864
- stored = session.get("moduleInputsFiles")
865
- if isinstance(stored, list):
866
- use_files = [str(x) for x in stored if str(x).strip()]
867
- if not use_files:
868
- # Empty set → stable empty hash (order-independent)
869
- return compute_inputs_hash([])
870
- return compute_inputs_hash(use_files)
871
-
872
-
873
- def needs_user_decision(
874
- *,
875
- reason: str,
876
- as_json: bool,
877
- **extra: Any,
878
- ) -> int:
879
- payload: dict[str, Any] = {
880
- "ok": True,
881
- "action": "needs-user-decision",
882
- "reason": reason,
883
- }
884
- payload.update(extra)
885
- emit_json(payload, as_json=as_json)
886
- return 0
887
-
888
-
889
- def stop_ai_session(
890
- change_dir: Path,
891
- session: dict[str, Any],
892
- *,
893
- require_identity: bool = True,
894
- ) -> dict[str, Any]:
895
- """Stop verified AI session process and clear session file."""
896
- pid = session.get("pid")
897
- if require_identity:
898
- identity = verify_process_identity(session)
899
- if identity is not True:
900
- return {
901
- "ok": True,
902
- "action": "needs-user-decision",
903
- "reason": (
904
- "cannot-verify-process-identity"
905
- if identity is None
906
- else "process-identity-mismatch"
907
- ),
908
- "pid": pid,
909
- "killed": False,
910
- }
911
- if isinstance(pid, int) and is_pid_alive(pid):
912
- terminate_process_tree(pid)
913
- _cleanup_windows_launcher(change_dir)
914
- clear_session(change_dir)
915
- return {
916
- "ok": True,
917
- "action": "stopped",
918
- "pid": pid,
919
- "killed": True,
920
- "sessionCleared": True,
921
- }
922
-
923
-
924
- # ---------------------------------------------------------------------------
925
- # Subcommands
926
- # ---------------------------------------------------------------------------
927
-
928
-
929
- def cmd_ensure(args: argparse.Namespace) -> int:
930
- as_json = bool(args.json)
931
- change_dir = resolve_path(args.change_dir)
932
- project = resolve_path(args.project)
933
- files = parse_files_arg(getattr(args, "files", None))
934
-
935
- try:
936
- profile = load_build_profile(project)
937
- service_start = get_service_start(profile)
938
- except (OSError, ValueError, FileNotFoundError, json.JSONDecodeError) as exc:
939
- return emit_error(str(exc), as_json=as_json)
940
-
941
- command = str(service_start["command"]).strip()
942
- port = extract_port(service_start)
943
-
944
- # Resolve service input file set (CLI --files ∪ serviceStart.inputFiles).
945
- # Empty result is deferred: _start_and_record rejects it before generating a
946
- # reusable empty fingerprint; the port-occupied / reuse paths still proceed.
947
- try:
948
- files = resolve_service_input_files(project, service_start, files)
949
- except ValueError:
950
- files = []
951
-
952
- try:
953
- session = load_session(change_dir)
954
- except SessionCorrupt as exc:
955
- return needs_user_decision(
956
- reason=f"session-corrupt: {exc}",
957
- as_json=as_json,
958
- detail="missing or corrupt session is treated as a user process; will not kill",
959
- )
960
-
961
- # --- Branch 1: existing AI session with live verified process ---
962
- if session is not None:
963
- pid = session["pid"]
964
- alive = is_pid_alive(pid)
965
- if alive:
966
- identity = verify_process_identity(session)
967
- if identity is not True:
968
- return needs_user_decision(
969
- reason=(
970
- "cannot-verify-process-identity"
971
- if identity is None
972
- else "process-identity-mismatch"
973
- ),
974
- as_json=as_json,
975
- pid=pid,
976
- sessionPath=str(session_path(change_dir)),
977
- detail=(
978
- "pid is alive but create-time/cmdline identity could not be "
979
- "confirmed against session; refusing to reuse or kill"
980
- ),
981
- )
982
-
983
- try:
984
- current_hash, current_files = compute_module_hash(files, session)
985
- except (OSError, FileNotFoundError) as exc:
986
- return emit_error(f"inputsHash failed: {exc}", as_json=as_json)
987
-
988
- stored_hash = session.get("moduleInputsHash")
989
- # §5.3: reuse must compare inputsHash + startCommandHash + profile
990
- # + overlayPath (process identity already verified above). Any
991
- # change -> restart; never reuse on a partial match.
992
- current_cmd_hash = sha256_text(command)
993
- current_profile = service_start.get("profile") or "local-dev"
994
- current_overlay = service_start.get("overlayPath") or ""
995
- fingerprint_match = (
996
- stored_hash == current_hash
997
- and session.get("startCommandHash") == current_cmd_hash
998
- and session.get("profile") == current_profile
999
- and session.get("overlayPath") == current_overlay
1000
- )
1001
- if fingerprint_match:
1002
- payload = {
1003
- "ok": True,
1004
- "action": "reused",
1005
- "pid": pid,
1006
- "moduleInputsHash": current_hash,
1007
- "moduleInputsFiles": current_files,
1008
- "sessionPath": str(session_path(change_dir)),
1009
- }
1010
- emit_json(payload, as_json=as_json)
1011
- return 0
1012
-
1013
- # Fingerprint mismatch → stop old, start new
1014
- stop_result = stop_ai_session(change_dir, session, require_identity=True)
1015
- if stop_result.get("action") == "needs-user-decision":
1016
- emit_json(stop_result, as_json=as_json)
1017
- return 0
1018
-
1019
- return _start_and_record(
1020
- change_dir=change_dir,
1021
- project=project,
1022
- service_start=service_start,
1023
- command=command,
1024
- files=files if files else current_files,
1025
- as_json=as_json,
1026
- action="restarted",
1027
- previousPid=pid,
1028
- )
1029
-
1030
- # pid dead → stale session; clear and fall through
1031
- clear_session(change_dir)
1032
-
1033
- # --- Branch 2: no usable session; port occupied → user decision ---
1034
- if port is not None and is_port_in_use(port):
1035
- return needs_user_decision(
1036
- reason="port-occupied-without-ai-session",
1037
- as_json=as_json,
1038
- port=port,
1039
- detail=(
1040
- "port is in use but no verified AI service-session exists; "
1041
- "treated as user process — will not kill"
1042
- ),
1043
- )
1044
-
1045
- # --- Branch 3: start fresh ---
1046
- return _start_and_record(
1047
- change_dir=change_dir,
1048
- project=project,
1049
- service_start=service_start,
1050
- command=command,
1051
- files=files,
1052
- as_json=as_json,
1053
- action="started",
1054
- )
1055
-
1056
-
1057
- def _start_and_record(
1058
- *,
1059
- change_dir: Path,
1060
- project: Path,
1061
- service_start: dict[str, Any],
1062
- command: str,
1063
- files: list[str],
1064
- as_json: bool,
1065
- action: str,
1066
- **extra: Any,
1067
- ) -> int:
1068
- if not files:
1069
- # §5.1/§5.2: never generate a reusable empty service fingerprint.
1070
- return emit_error(
1071
- "service inputs are empty; configure serviceStart.inputFiles "
1072
- "(or pass --files) so the service fingerprint covers real source",
1073
- as_json=as_json,
1074
- )
1075
- try:
1076
- module_hash, module_files = compute_module_hash(files, None)
1077
- except (OSError, FileNotFoundError) as exc:
1078
- return emit_error(f"inputsHash failed: {exc}", as_json=as_json)
1079
-
1080
- # Clear stale file-based health markers so wait_for_healthy cannot
1081
- # succeed on a leftover marker from a previous process.
1082
- _clear_file_health_markers(service_start)
1083
-
1084
- started_at = now_iso()
1085
- try:
1086
- pid = start_detached_service(command, change_dir=change_dir, cwd=project)
1087
- except (OSError, TimeoutError) as exc:
1088
- _cleanup_windows_launcher(change_dir)
1089
- return emit_error(f"failed to start service: {exc}", as_json=as_json)
1090
-
1091
- # Give the OS a moment to register the process before identity/create-time reads
1092
- time.sleep(0.15)
1093
-
1094
- try:
1095
- wait_for_healthy(service_start, log_path(change_dir), pid=pid)
1096
- except ServiceStartError as exc:
1097
- # Best-effort cleanup of the failed start
1098
- if is_pid_alive(pid):
1099
- terminate_process_tree(pid)
1100
- _cleanup_windows_launcher(change_dir)
1101
- clear_session(change_dir)
1102
- return emit_error(
1103
- str(exc),
1104
- as_json=as_json,
1105
- action="start-failed",
1106
- pid=pid,
1107
- fatalKeyword=exc.fatal_keyword,
1108
- )
1109
-
1110
- session = build_session(
1111
- pid=pid,
1112
- module_inputs_hash=module_hash,
1113
- module_inputs_files=module_files,
1114
- command=command,
1115
- service_start=service_start,
1116
- started_at=started_at,
1117
- )
1118
- write_session(change_dir, session)
1119
-
1120
- payload: dict[str, Any] = {
1121
- "ok": True,
1122
- "action": action,
1123
- "pid": pid,
1124
- "moduleInputsHash": module_hash,
1125
- "moduleInputsFiles": module_files,
1126
- "sessionPath": str(session_path(change_dir)),
1127
- "logPath": str(log_path(change_dir)),
1128
- "startedAt": started_at,
1129
- }
1130
- payload.update(extra)
1131
- emit_json(payload, as_json=as_json)
1132
- return 0
1133
-
1134
-
1135
- def _clear_file_health_markers(service_start: dict[str, Any]) -> None:
1136
- candidates: list[Path] = []
1137
- hf = service_start.get("healthFile")
1138
- if isinstance(hf, str) and hf.strip():
1139
- candidates.append(Path(hf.strip()))
1140
- spec = service_start.get("healthUrl")
1141
- if isinstance(spec, str) and spec.strip():
1142
- resolved = resolve_health_file(spec.strip())
1143
- if resolved is not None:
1144
- candidates.append(resolved)
1145
- for path in candidates:
1146
- try:
1147
- if path.is_file():
1148
- path.unlink()
1149
- except OSError:
1150
- pass
1151
-
1152
-
1153
- def cmd_status(args: argparse.Namespace) -> int:
1154
- as_json = bool(args.json)
1155
- change_dir = resolve_path(args.change_dir)
1156
- files = parse_files_arg(getattr(args, "files", None))
1157
-
1158
- try:
1159
- session = load_session(change_dir)
1160
- except SessionCorrupt as exc:
1161
- payload = {
1162
- "ok": True,
1163
- "action": "status",
1164
- "sessionPresent": True,
1165
- "sessionCorrupt": True,
1166
- "reason": str(exc),
1167
- "alive": False,
1168
- "identityVerified": False,
1169
- "fingerprintMatch": None,
1170
- "treatAsUserProcess": True,
1171
- }
1172
- emit_json(payload, as_json=as_json)
1173
- return 0
1174
-
1175
- if session is None:
1176
- payload = {
1177
- "ok": True,
1178
- "action": "status",
1179
- "sessionPresent": False,
1180
- "alive": False,
1181
- "identityVerified": False,
1182
- "fingerprintMatch": None,
1183
- }
1184
- emit_json(payload, as_json=as_json)
1185
- return 0
1186
-
1187
- pid = session.get("pid")
1188
- alive = isinstance(pid, int) and is_pid_alive(pid)
1189
- identity = verify_process_identity(session) if alive else False
1190
-
1191
- fingerprint_match: bool | None = None
1192
- current_hash: str | None = None
1193
- try:
1194
- current_hash, _ = compute_module_hash(files, session)
1195
- stored = session.get("moduleInputsHash")
1196
- if isinstance(stored, str) and stored:
1197
- fingerprint_match = stored == current_hash
1198
- except (OSError, FileNotFoundError):
1199
- fingerprint_match = None
1200
-
1201
- payload = {
1202
- "ok": True,
1203
- "action": "status",
1204
- "sessionPresent": True,
1205
- "sessionCorrupt": False,
1206
- "session": session,
1207
- "pid": pid,
1208
- "alive": alive,
1209
- "identityVerified": identity is True,
1210
- "identityStatus": (
1211
- "verified" if identity is True else ("unknown" if identity is None else "mismatch")
1212
- ),
1213
- "fingerprintMatch": fingerprint_match,
1214
- "currentModuleInputsHash": current_hash,
1215
- "startedBy": session.get("startedBy"),
1216
- }
1217
- emit_json(payload, as_json=as_json)
1218
- return 0
1219
-
1220
-
1221
- def cmd_stop(args: argparse.Namespace) -> int:
1222
- as_json = bool(args.json)
1223
- change_dir = resolve_path(args.change_dir)
1224
- if_started_by_ai = bool(getattr(args, "if_started_by_ai", False))
1225
-
1226
- try:
1227
- session = load_session(change_dir)
1228
- except SessionCorrupt as exc:
1229
- return needs_user_decision(
1230
- reason=f"session-corrupt: {exc}",
1231
- as_json=as_json,
1232
- detail="corrupt session treated as user process; will not kill",
1233
- killed=False,
1234
- )
1235
-
1236
- if session is None:
1237
- payload = {
1238
- "ok": True,
1239
- "action": "already-stopped",
1240
- "killed": False,
1241
- "sessionCleared": False,
1242
- "detail": "no service-session.json",
1243
- }
1244
- emit_json(payload, as_json=as_json)
1245
- return 0
1246
-
1247
- started_by = session.get("startedBy")
1248
- if if_started_by_ai and started_by != "AI":
1249
- payload = {
1250
- "ok": True,
1251
- "action": "skipped",
1252
- "reason": "not-started-by-ai",
1253
- "startedBy": started_by,
1254
- "killed": False,
1255
- "sessionCleared": False,
1256
- }
1257
- emit_json(payload, as_json=as_json)
1258
- return 0
1259
-
1260
- # Default stop also refuses to kill non-AI / unverified processes
1261
- if started_by != "AI":
1262
- return needs_user_decision(
1263
- reason="not-started-by-ai",
1264
- as_json=as_json,
1265
- startedBy=started_by,
1266
- killed=False,
1267
- detail="session not marked startedBy=AI; will not kill",
1268
- )
1269
-
1270
- result = stop_ai_session(change_dir, session, require_identity=True)
1271
- emit_json(result, as_json=as_json)
1272
- return 0
1273
-
1274
-
1275
- def build_parser() -> argparse.ArgumentParser:
1276
- parser = argparse.ArgumentParser(
1277
- prog="harness_service.py",
1278
- description="Manage AI service-session lifecycle (ensure/status/stop)",
1279
- )
1280
- parser.add_argument(
1281
- "--json",
1282
- action="store_true",
1283
- help="emit machine-readable JSON on stdout",
1284
- )
1285
- sub = parser.add_subparsers(dest="command_name", required=True)
1286
-
1287
- p_ensure = sub.add_parser("ensure", help="reuse / restart / start service")
1288
- p_ensure.add_argument("--change-dir", required=True)
1289
- p_ensure.add_argument("--project", required=True)
1290
- p_ensure.add_argument(
1291
- "--files",
1292
- default=None,
1293
- help="comma-separated service module source files for inputsHash",
1294
- )
1295
- p_ensure.add_argument("--json", action="store_true")
1296
- p_ensure.set_defaults(func=cmd_ensure)
1297
-
1298
- p_status = sub.add_parser("status", help="show session + liveness + fingerprint")
1299
- p_status.add_argument("--change-dir", required=True)
1300
- p_status.add_argument(
1301
- "--files",
1302
- default=None,
1303
- help="optional files for current fingerprint comparison",
1304
- )
1305
- p_status.add_argument("--json", action="store_true")
1306
- p_status.set_defaults(func=cmd_status)
1307
-
1308
- p_stop = sub.add_parser("stop", help="stop service and clear session")
1309
- p_stop.add_argument("--change-dir", required=True)
1310
- p_stop.add_argument(
1311
- "--if-started-by-ai",
1312
- action="store_true",
1313
- help="only stop when session.startedBy == AI (archive cleanup)",
1314
- )
1315
- p_stop.add_argument("--json", action="store_true")
1316
- p_stop.set_defaults(func=cmd_stop)
1317
-
1318
- return parser
1319
-
1320
-
1321
- def main(argv: list[str] | None = None) -> int:
1322
- parser = build_parser()
1323
- args = parser.parse_args(argv)
1324
- # Allow top-level --json as well as subcommand --json
1325
- if getattr(args, "json", False) is False and "--json" in (argv or sys.argv[1:]):
1326
- args.json = True
1327
- return int(args.func(args))
1328
-
1329
-
1330
- if __name__ == "__main__":
1331
- raise SystemExit(main())