@lannguyensi/harness 0.64.0 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (710) hide show
  1. package/CHANGELOG.md +64 -0
  2. package/README.md +46 -42
  3. package/dist/cli/add/index.js +17 -21
  4. package/dist/cli/add/index.js.map +1 -1
  5. package/dist/cli/adopt/derive.d.ts +2 -2
  6. package/dist/cli/adopt/derive.js +2 -19
  7. package/dist/cli/adopt/derive.js.map +1 -1
  8. package/dist/cli/adopt/index.d.ts +1 -1
  9. package/dist/cli/adopt/index.js +1 -12
  10. package/dist/cli/adopt/index.js.map +1 -1
  11. package/dist/cli/apply/apply.d.ts +20 -35
  12. package/dist/cli/apply/apply.js +61 -136
  13. package/dist/cli/apply/apply.js.map +1 -1
  14. package/dist/cli/apply/generate-codex-config.js +10 -58
  15. package/dist/cli/apply/generate-codex-config.js.map +1 -1
  16. package/dist/cli/apply/generate-memory-index.js +1 -2
  17. package/dist/cli/apply/generate-memory-index.js.map +1 -1
  18. package/dist/cli/apply/generate-opencode-config.d.ts +2 -10
  19. package/dist/cli/apply/generate-opencode-config.js +74 -113
  20. package/dist/cli/apply/generate-opencode-config.js.map +1 -1
  21. package/dist/cli/apply/generate-settings.d.ts +11 -64
  22. package/dist/cli/apply/generate-settings.js +27 -132
  23. package/dist/cli/apply/generate-settings.js.map +1 -1
  24. package/dist/cli/apply/index.d.ts +1 -1
  25. package/dist/cli/apply/index.js +1 -1
  26. package/dist/cli/apply/index.js.map +1 -1
  27. package/dist/cli/apply/install-codex-config.d.ts +153 -1
  28. package/dist/cli/apply/install-codex-config.js +445 -70
  29. package/dist/cli/apply/install-codex-config.js.map +1 -1
  30. package/dist/cli/apply/next-steps.d.ts +7 -0
  31. package/dist/cli/apply/next-steps.js +13 -1
  32. package/dist/cli/apply/next-steps.js.map +1 -1
  33. package/dist/cli/bounded-stdin.d.ts +0 -23
  34. package/dist/cli/bounded-stdin.js +2 -49
  35. package/dist/cli/bounded-stdin.js.map +1 -1
  36. package/dist/cli/describe.d.ts +1 -1
  37. package/dist/cli/describe.js +0 -3
  38. package/dist/cli/describe.js.map +1 -1
  39. package/dist/cli/diff/engine.d.ts +0 -11
  40. package/dist/cli/diff/engine.js +1 -17
  41. package/dist/cli/diff/engine.js.map +1 -1
  42. package/dist/cli/diff/index.js +14 -25
  43. package/dist/cli/diff/index.js.map +1 -1
  44. package/dist/cli/doctor/claude-mcp.d.ts +4 -19
  45. package/dist/cli/doctor/claude-mcp.js +11 -22
  46. package/dist/cli/doctor/claude-mcp.js.map +1 -1
  47. package/dist/cli/doctor/codex.d.ts +12 -14
  48. package/dist/cli/doctor/codex.js +31 -144
  49. package/dist/cli/doctor/codex.js.map +1 -1
  50. package/dist/cli/doctor/format.js +23 -345
  51. package/dist/cli/doctor/format.js.map +1 -1
  52. package/dist/cli/doctor/hook-liveness.d.ts +56 -0
  53. package/dist/cli/doctor/hook-liveness.js +455 -0
  54. package/dist/cli/doctor/hook-liveness.js.map +1 -0
  55. package/dist/cli/doctor/index.d.ts +13 -87
  56. package/dist/cli/doctor/index.js +57 -713
  57. package/dist/cli/doctor/index.js.map +1 -1
  58. package/dist/cli/doctor/opencode.d.ts +2 -1
  59. package/dist/cli/doctor/opencode.js.map +1 -1
  60. package/dist/cli/doctor/types.d.ts +21 -387
  61. package/dist/cli/doctor/types.js.map +1 -1
  62. package/dist/cli/drain-stdio.d.ts +31 -0
  63. package/dist/cli/drain-stdio.js +76 -0
  64. package/dist/cli/drain-stdio.js.map +1 -0
  65. package/dist/cli/export.d.ts +3 -1
  66. package/dist/cli/export.js +7 -16
  67. package/dist/cli/export.js.map +1 -1
  68. package/dist/cli/gate/codex-disable.d.ts +29 -0
  69. package/dist/cli/gate/codex-disable.js +195 -0
  70. package/dist/cli/gate/codex-disable.js.map +1 -0
  71. package/dist/cli/gate/codex-enable.d.ts +41 -0
  72. package/dist/cli/gate/codex-enable.js +127 -0
  73. package/dist/cli/gate/codex-enable.js.map +1 -0
  74. package/dist/cli/gate/codex-snapshot.d.ts +208 -0
  75. package/dist/cli/gate/codex-snapshot.js +402 -0
  76. package/dist/cli/gate/codex-snapshot.js.map +1 -0
  77. package/dist/cli/gate/disable.d.ts +9 -0
  78. package/dist/cli/gate/disable.js +263 -28
  79. package/dist/cli/gate/disable.js.map +1 -1
  80. package/dist/cli/gate/enable.d.ts +26 -6
  81. package/dist/cli/gate/enable.js +152 -80
  82. package/dist/cli/gate/enable.js.map +1 -1
  83. package/dist/cli/gate/link-chain.d.ts +53 -0
  84. package/dist/cli/gate/link-chain.js +122 -0
  85. package/dist/cli/gate/link-chain.js.map +1 -0
  86. package/dist/cli/gate/snapshot.d.ts +289 -12
  87. package/dist/cli/gate/snapshot.js +481 -22
  88. package/dist/cli/gate/snapshot.js.map +1 -1
  89. package/dist/cli/index.d.ts +0 -9
  90. package/dist/cli/index.js +9 -2131
  91. package/dist/cli/index.js.map +1 -1
  92. package/dist/cli/init/composer.d.ts +3 -6
  93. package/dist/cli/init/composer.js +6 -370
  94. package/dist/cli/init/composer.js.map +1 -1
  95. package/dist/cli/init/dependencies.d.ts +1 -2
  96. package/dist/cli/init/dependencies.js +4 -80
  97. package/dist/cli/init/dependencies.js.map +1 -1
  98. package/dist/cli/init/detect.js +5 -4
  99. package/dist/cli/init/detect.js.map +1 -1
  100. package/dist/cli/init/interactive.d.ts +1 -23
  101. package/dist/cli/init/interactive.js +33 -247
  102. package/dist/cli/init/interactive.js.map +1 -1
  103. package/dist/cli/init/profiles.d.ts +2 -2
  104. package/dist/cli/init/profiles.js +51 -245
  105. package/dist/cli/init/profiles.js.map +1 -1
  106. package/dist/cli/init/templates.d.ts +2 -37
  107. package/dist/cli/init/templates.js +25 -1237
  108. package/dist/cli/init/templates.js.map +1 -1
  109. package/dist/cli/list.d.ts +1 -1
  110. package/dist/cli/list.js +1 -38
  111. package/dist/cli/list.js.map +1 -1
  112. package/dist/cli/loader.d.ts +15 -1
  113. package/dist/cli/loader.js +56 -39
  114. package/dist/cli/loader.js.map +1 -1
  115. package/dist/cli/main.js +7 -2
  116. package/dist/cli/main.js.map +1 -1
  117. package/dist/cli/migrate-home/index.js +2 -2
  118. package/dist/cli/migrate-home/index.js.map +1 -1
  119. package/dist/cli/pack/add.js +1 -1
  120. package/dist/cli/pack/add.js.map +1 -1
  121. package/dist/cli/pack/hook-bootstrap.d.ts +5 -164
  122. package/dist/cli/pack/hook-bootstrap.js +15 -291
  123. package/dist/cli/pack/hook-bootstrap.js.map +1 -1
  124. package/dist/cli/pack/hook-branch-protection.d.ts +28 -21
  125. package/dist/cli/pack/hook-branch-protection.js +365 -340
  126. package/dist/cli/pack/hook-branch-protection.js.map +1 -1
  127. package/dist/cli/pack/index.d.ts +0 -1
  128. package/dist/cli/pack/index.js +0 -1
  129. package/dist/cli/pack/index.js.map +1 -1
  130. package/dist/cli/pack/list.js +1 -6
  131. package/dist/cli/pack/list.js.map +1 -1
  132. package/dist/cli/pack/mutate.d.ts +7 -9
  133. package/dist/cli/pack/mutate.js +6 -9
  134. package/dist/cli/pack/mutate.js.map +1 -1
  135. package/dist/cli/pack/reseed.d.ts +2 -2
  136. package/dist/cli/pack/reseed.js +16 -22
  137. package/dist/cli/pack/reseed.js.map +1 -1
  138. package/dist/cli/{delegate/register.d.ts → register-gate-group.d.ts} +1 -1
  139. package/dist/cli/register-gate-group.js +348 -0
  140. package/dist/cli/register-gate-group.js.map +1 -0
  141. package/dist/cli/register-inspect-group.d.ts +6 -0
  142. package/dist/cli/register-inspect-group.js +189 -0
  143. package/dist/cli/register-inspect-group.js.map +1 -0
  144. package/dist/cli/register-operator-lifecycle.d.ts +1 -1
  145. package/dist/cli/register-operator-lifecycle.js +3 -100
  146. package/dist/cli/register-operator-lifecycle.js.map +1 -1
  147. package/dist/cli/register-pack-group.d.ts +5 -0
  148. package/dist/cli/register-pack-group.js +134 -0
  149. package/dist/cli/register-pack-group.js.map +1 -0
  150. package/dist/cli/{register-audit-group.d.ts → register-setup-group.d.ts} +1 -1
  151. package/dist/cli/register-setup-group.js +495 -0
  152. package/dist/cli/register-setup-group.js.map +1 -0
  153. package/dist/cli/remove/index.d.ts +0 -14
  154. package/dist/cli/remove/index.js +2 -115
  155. package/dist/cli/remove/index.js.map +1 -1
  156. package/dist/cli/remove/mutate.d.ts +0 -2
  157. package/dist/cli/remove/mutate.js +1 -19
  158. package/dist/cli/remove/mutate.js.map +1 -1
  159. package/dist/cli/remove/register.js +2 -19
  160. package/dist/cli/remove/register.js.map +1 -1
  161. package/dist/cli/shell-quote.d.ts +7 -0
  162. package/dist/cli/shell-quote.js +17 -0
  163. package/dist/cli/shell-quote.js.map +1 -0
  164. package/dist/cli/uninstall/index.d.ts +4 -2
  165. package/dist/cli/uninstall/index.js +15 -7
  166. package/dist/cli/uninstall/index.js.map +1 -1
  167. package/dist/cli/uninstall/register.js +6 -4
  168. package/dist/cli/uninstall/register.js.map +1 -1
  169. package/dist/cli/uninstall/snapshot.d.ts +15 -0
  170. package/dist/cli/uninstall/snapshot.js +38 -0
  171. package/dist/cli/uninstall/snapshot.js.map +1 -1
  172. package/dist/cli/validate/checks.d.ts +0 -77
  173. package/dist/cli/validate/checks.js +3 -1049
  174. package/dist/cli/validate/checks.js.map +1 -1
  175. package/dist/cli/validate/index.js +19 -15
  176. package/dist/cli/validate/index.js.map +1 -1
  177. package/dist/index.d.ts +0 -3
  178. package/dist/index.js +0 -3
  179. package/dist/index.js.map +1 -1
  180. package/dist/io/claude-mcp.d.ts +1 -1
  181. package/dist/io/claude-mcp.js +27 -14
  182. package/dist/io/claude-mcp.js.map +1 -1
  183. package/dist/io/harness-lock.js +2 -2
  184. package/dist/io/harness-lock.js.map +1 -1
  185. package/dist/io/lock.d.ts +0 -26
  186. package/dist/io/lock.js +10 -27
  187. package/dist/io/lock.js.map +1 -1
  188. package/dist/io/merge-settings.js +6 -4
  189. package/dist/io/merge-settings.js.map +1 -1
  190. package/dist/io/project-name.d.ts +22 -39
  191. package/dist/io/project-name.js +25 -42
  192. package/dist/io/project-name.js.map +1 -1
  193. package/dist/io/read-regular-file.d.ts +103 -40
  194. package/dist/io/read-regular-file.js +196 -35
  195. package/dist/io/read-regular-file.js.map +1 -1
  196. package/dist/io/restart-hints.js +3 -6
  197. package/dist/io/restart-hints.js.map +1 -1
  198. package/dist/io/version-compare.d.ts +1 -3
  199. package/dist/io/version-compare.js +1 -3
  200. package/dist/io/version-compare.js.map +1 -1
  201. package/dist/io/write-regular-file.d.ts +30 -0
  202. package/dist/io/write-regular-file.js +85 -0
  203. package/dist/io/write-regular-file.js.map +1 -0
  204. package/dist/overrides/index.d.ts +1 -0
  205. package/dist/overrides/index.js +1 -0
  206. package/dist/overrides/index.js.map +1 -1
  207. package/dist/overrides/merge-layers.d.ts +43 -0
  208. package/dist/overrides/merge-layers.js +76 -0
  209. package/dist/overrides/merge-layers.js.map +1 -0
  210. package/dist/overrides/merge.d.ts +16 -0
  211. package/dist/overrides/merge.js +21 -8
  212. package/dist/overrides/merge.js.map +1 -1
  213. package/dist/policy-packs/builtin/branch-protection-runtime.d.ts +4 -69
  214. package/dist/policy-packs/builtin/branch-protection-runtime.js +12 -84
  215. package/dist/policy-packs/builtin/branch-protection-runtime.js.map +1 -1
  216. package/dist/policy-packs/builtin/branch-protection.d.ts +7 -30
  217. package/dist/policy-packs/builtin/branch-protection.js +56 -89
  218. package/dist/policy-packs/builtin/branch-protection.js.map +1 -1
  219. package/dist/policy-packs/config-check.d.ts +7 -5
  220. package/dist/policy-packs/config-check.js +2 -2
  221. package/dist/policy-packs/config-check.js.map +1 -1
  222. package/dist/policy-packs/expand.d.ts +1 -3
  223. package/dist/policy-packs/expand.js +5 -42
  224. package/dist/policy-packs/expand.js.map +1 -1
  225. package/dist/policy-packs/index.d.ts +3 -3
  226. package/dist/policy-packs/index.js +2 -2
  227. package/dist/policy-packs/index.js.map +1 -1
  228. package/dist/policy-packs/registry.d.ts +9 -38
  229. package/dist/policy-packs/registry.js +5 -65
  230. package/dist/policy-packs/registry.js.map +1 -1
  231. package/dist/policy-packs/runtime.d.ts +0 -4
  232. package/dist/policy-packs/runtime.js +9 -22
  233. package/dist/policy-packs/runtime.js.map +1 -1
  234. package/dist/policy-packs/types.d.ts +0 -19
  235. package/dist/policy-packs/ux-compare.d.ts +1 -11
  236. package/dist/policy-packs/ux-compare.js +6 -42
  237. package/dist/policy-packs/ux-compare.js.map +1 -1
  238. package/dist/policy-packs/ux-drift-check.d.ts +5 -5
  239. package/dist/policy-packs/ux-drift-check.js +17 -22
  240. package/dist/policy-packs/ux-drift-check.js.map +1 -1
  241. package/dist/policy-packs/version-check.d.ts +5 -26
  242. package/dist/policy-packs/version-check.js +19 -74
  243. package/dist/policy-packs/version-check.js.map +1 -1
  244. package/dist/probes/memory.d.ts +1 -1
  245. package/dist/probes/memory.js +1 -1
  246. package/dist/probes/memory.js.map +1 -1
  247. package/dist/runtime/agent-facing.d.ts +9 -0
  248. package/dist/runtime/agent-facing.js +28 -14
  249. package/dist/runtime/agent-facing.js.map +1 -1
  250. package/dist/runtime/bounded-text.d.ts +15 -0
  251. package/dist/runtime/bounded-text.js +27 -0
  252. package/dist/runtime/bounded-text.js.map +1 -0
  253. package/dist/runtime/git-branch.d.ts +125 -0
  254. package/dist/runtime/git-branch.js +381 -0
  255. package/dist/runtime/git-branch.js.map +1 -0
  256. package/dist/runtime/hermetic-spawn-guard.d.ts +2 -2
  257. package/dist/runtime/hermetic-spawn-guard.js +24 -34
  258. package/dist/runtime/hermetic-spawn-guard.js.map +1 -1
  259. package/dist/runtime/home-dir.js +3 -2
  260. package/dist/runtime/home-dir.js.map +1 -1
  261. package/dist/runtime/tool-name-aliases.d.ts +0 -6
  262. package/dist/runtime/tool-name-aliases.js +5 -18
  263. package/dist/runtime/tool-name-aliases.js.map +1 -1
  264. package/dist/schema/grounding.d.ts +7 -54
  265. package/dist/schema/grounding.js +10 -12
  266. package/dist/schema/grounding.js.map +1 -1
  267. package/dist/schema/hooks.d.ts +39 -136
  268. package/dist/schema/hooks.js +3 -6
  269. package/dist/schema/hooks.js.map +1 -1
  270. package/dist/schema/index.d.ts +114 -3828
  271. package/dist/schema/index.js +41 -80
  272. package/dist/schema/index.js.map +1 -1
  273. package/dist/schema/memory.d.ts +54 -131
  274. package/dist/schema/memory.js +2 -2
  275. package/dist/schema/memory.js.map +1 -1
  276. package/dist/schema/policy-packs.d.ts +3 -45
  277. package/dist/schema/policy-packs.js +7 -13
  278. package/dist/schema/policy-packs.js.map +1 -1
  279. package/dist/schema/policy-ux.d.ts +7 -0
  280. package/dist/schema/policy-ux.js +18 -0
  281. package/dist/schema/policy-ux.js.map +1 -0
  282. package/dist/schema/removed-keys.d.ts +185 -0
  283. package/dist/schema/removed-keys.js +531 -0
  284. package/dist/schema/removed-keys.js.map +1 -0
  285. package/dist/schema/tools.d.ts +30 -268
  286. package/dist/schema/tools.js +4 -4
  287. package/dist/schema/tools.js.map +1 -1
  288. package/package.json +5 -16
  289. package/dist/cli/approve/branch-protection.d.ts +0 -69
  290. package/dist/cli/approve/branch-protection.js +0 -144
  291. package/dist/cli/approve/branch-protection.js.map +0 -1
  292. package/dist/cli/approve/risk.d.ts +0 -112
  293. package/dist/cli/approve/risk.js +0 -197
  294. package/dist/cli/approve/risk.js.map +0 -1
  295. package/dist/cli/approve/stdin-report.d.ts +0 -57
  296. package/dist/cli/approve/stdin-report.js +0 -145
  297. package/dist/cli/approve/stdin-report.js.map +0 -1
  298. package/dist/cli/approve/understanding.d.ts +0 -410
  299. package/dist/cli/approve/understanding.js +0 -996
  300. package/dist/cli/approve/understanding.js.map +0 -1
  301. package/dist/cli/audit.d.ts +0 -80
  302. package/dist/cli/audit.js +0 -252
  303. package/dist/cli/audit.js.map +0 -1
  304. package/dist/cli/delegate/index.d.ts +0 -76
  305. package/dist/cli/delegate/index.js +0 -444
  306. package/dist/cli/delegate/index.js.map +0 -1
  307. package/dist/cli/delegate/register.js +0 -90
  308. package/dist/cli/delegate/register.js.map +0 -1
  309. package/dist/cli/doctor/auto-approve-mode.d.ts +0 -37
  310. package/dist/cli/doctor/auto-approve-mode.js +0 -80
  311. package/dist/cli/doctor/auto-approve-mode.js.map +0 -1
  312. package/dist/cli/doctor/bypass-without-auto-approve.d.ts +0 -38
  313. package/dist/cli/doctor/bypass-without-auto-approve.js +0 -95
  314. package/dist/cli/doctor/bypass-without-auto-approve.js.map +0 -1
  315. package/dist/cli/doctor/codex-config-drift.d.ts +0 -28
  316. package/dist/cli/doctor/codex-config-drift.js +0 -240
  317. package/dist/cli/doctor/codex-config-drift.js.map +0 -1
  318. package/dist/cli/doctor/expire-on-tool-match.d.ts +0 -15
  319. package/dist/cli/doctor/expire-on-tool-match.js +0 -58
  320. package/dist/cli/doctor/expire-on-tool-match.js.map +0 -1
  321. package/dist/cli/doctor/rogue-ledger.d.ts +0 -53
  322. package/dist/cli/doctor/rogue-ledger.js +0 -153
  323. package/dist/cli/doctor/rogue-ledger.js.map +0 -1
  324. package/dist/cli/doctor/session-start-preflight-setup-version.d.ts +0 -83
  325. package/dist/cli/doctor/session-start-preflight-setup-version.js +0 -114
  326. package/dist/cli/doctor/session-start-preflight-setup-version.js.map +0 -1
  327. package/dist/cli/doctor/settings-drift.d.ts +0 -25
  328. package/dist/cli/doctor/settings-drift.js +0 -213
  329. package/dist/cli/doctor/settings-drift.js.map +0 -1
  330. package/dist/cli/doctor/toolchain-parity.d.ts +0 -63
  331. package/dist/cli/doctor/toolchain-parity.js +0 -154
  332. package/dist/cli/doctor/toolchain-parity.js.map +0 -1
  333. package/dist/cli/doctor/ug-auto-approvals.d.ts +0 -40
  334. package/dist/cli/doctor/ug-auto-approvals.js +0 -91
  335. package/dist/cli/doctor/ug-auto-approvals.js.map +0 -1
  336. package/dist/cli/doctor/ug-delegations.d.ts +0 -26
  337. package/dist/cli/doctor/ug-delegations.js +0 -121
  338. package/dist/cli/doctor/ug-delegations.js.map +0 -1
  339. package/dist/cli/doctor/ug-inflight.d.ts +0 -35
  340. package/dist/cli/doctor/ug-inflight.js +0 -57
  341. package/dist/cli/doctor/ug-inflight.js.map +0 -1
  342. package/dist/cli/doctor/understanding-mode-env.d.ts +0 -51
  343. package/dist/cli/doctor/understanding-mode-env.js +0 -98
  344. package/dist/cli/doctor/understanding-mode-env.js.map +0 -1
  345. package/dist/cli/dry-run.d.ts +0 -58
  346. package/dist/cli/dry-run.js +0 -283
  347. package/dist/cli/dry-run.js.map +0 -1
  348. package/dist/cli/enriched-event.d.ts +0 -35
  349. package/dist/cli/enriched-event.js +0 -60
  350. package/dist/cli/enriched-event.js.map +0 -1
  351. package/dist/cli/event-input.d.ts +0 -28
  352. package/dist/cli/event-input.js +0 -73
  353. package/dist/cli/event-input.js.map +0 -1
  354. package/dist/cli/explain-action.d.ts +0 -25
  355. package/dist/cli/explain-action.js +0 -57
  356. package/dist/cli/explain-action.js.map +0 -1
  357. package/dist/cli/explain-policy.d.ts +0 -147
  358. package/dist/cli/explain-policy.js +0 -248
  359. package/dist/cli/explain-policy.js.map +0 -1
  360. package/dist/cli/explain.d.ts +0 -31
  361. package/dist/cli/explain.js +0 -159
  362. package/dist/cli/explain.js.map +0 -1
  363. package/dist/cli/gc/index.d.ts +0 -63
  364. package/dist/cli/gc/index.js +0 -566
  365. package/dist/cli/gc/index.js.map +0 -1
  366. package/dist/cli/pack/approve-escape.d.ts +0 -19
  367. package/dist/cli/pack/approve-escape.js +0 -190
  368. package/dist/cli/pack/approve-escape.js.map +0 -1
  369. package/dist/cli/pack/auto-approve-path.d.ts +0 -146
  370. package/dist/cli/pack/auto-approve-path.js +0 -462
  371. package/dist/cli/pack/auto-approve-path.js.map +0 -1
  372. package/dist/cli/pack/hook-codex-post-tool-use.d.ts +0 -25
  373. package/dist/cli/pack/hook-codex-post-tool-use.js +0 -160
  374. package/dist/cli/pack/hook-codex-post-tool-use.js.map +0 -1
  375. package/dist/cli/pack/hook-codex-pre-tool-use.d.ts +0 -48
  376. package/dist/cli/pack/hook-codex-pre-tool-use.js +0 -474
  377. package/dist/cli/pack/hook-codex-pre-tool-use.js.map +0 -1
  378. package/dist/cli/pack/hook-codex-stop.d.ts +0 -35
  379. package/dist/cli/pack/hook-codex-stop.js +0 -329
  380. package/dist/cli/pack/hook-codex-stop.js.map +0 -1
  381. package/dist/cli/pack/hook-codex-user-prompt-submit.d.ts +0 -24
  382. package/dist/cli/pack/hook-codex-user-prompt-submit.js +0 -93
  383. package/dist/cli/pack/hook-codex-user-prompt-submit.js.map +0 -1
  384. package/dist/cli/pack/hook-post-merge-gate-record.d.ts +0 -37
  385. package/dist/cli/pack/hook-post-merge-gate-record.js +0 -190
  386. package/dist/cli/pack/hook-post-merge-gate-record.js.map +0 -1
  387. package/dist/cli/pack/hook-post-merge-gate.d.ts +0 -34
  388. package/dist/cli/pack/hook-post-merge-gate.js +0 -277
  389. package/dist/cli/pack/hook-post-merge-gate.js.map +0 -1
  390. package/dist/cli/pack/hook-post-tool-use.d.ts +0 -45
  391. package/dist/cli/pack/hook-post-tool-use.js +0 -137
  392. package/dist/cli/pack/hook-post-tool-use.js.map +0 -1
  393. package/dist/cli/pack/hook-pre-tool-use.d.ts +0 -92
  394. package/dist/cli/pack/hook-pre-tool-use.js +0 -1328
  395. package/dist/cli/pack/hook-pre-tool-use.js.map +0 -1
  396. package/dist/cli/pack/hook-runtime-reality.d.ts +0 -63
  397. package/dist/cli/pack/hook-runtime-reality.js +0 -210
  398. package/dist/cli/pack/hook-runtime-reality.js.map +0 -1
  399. package/dist/cli/pack/hook-solution-acceptance-writeguard.d.ts +0 -32
  400. package/dist/cli/pack/hook-solution-acceptance-writeguard.js +0 -438
  401. package/dist/cli/pack/hook-solution-acceptance-writeguard.js.map +0 -1
  402. package/dist/cli/pack/hook-solution-acceptance.d.ts +0 -157
  403. package/dist/cli/pack/hook-solution-acceptance.js +0 -530
  404. package/dist/cli/pack/hook-solution-acceptance.js.map +0 -1
  405. package/dist/cli/pack/hook-stay-in-scope.d.ts +0 -37
  406. package/dist/cli/pack/hook-stay-in-scope.js +0 -128
  407. package/dist/cli/pack/hook-stay-in-scope.js.map +0 -1
  408. package/dist/cli/pack/hook-subagent-start.d.ts +0 -23
  409. package/dist/cli/pack/hook-subagent-start.js +0 -88
  410. package/dist/cli/pack/hook-subagent-start.js.map +0 -1
  411. package/dist/cli/pack/hook-subagent-stop.d.ts +0 -19
  412. package/dist/cli/pack/hook-subagent-stop.js +0 -41
  413. package/dist/cli/pack/hook-subagent-stop.js.map +0 -1
  414. package/dist/cli/pack/hook-track-active-claim.d.ts +0 -27
  415. package/dist/cli/pack/hook-track-active-claim.js +0 -275
  416. package/dist/cli/pack/hook-track-active-claim.js.map +0 -1
  417. package/dist/cli/pack/transcript-report-scan.d.ts +0 -71
  418. package/dist/cli/pack/transcript-report-scan.js +0 -359
  419. package/dist/cli/pack/transcript-report-scan.js.map +0 -1
  420. package/dist/cli/pack/understanding-report-schema-hint.d.ts +0 -26
  421. package/dist/cli/pack/understanding-report-schema-hint.js +0 -120
  422. package/dist/cli/pack/understanding-report-schema-hint.js.map +0 -1
  423. package/dist/cli/pack/upgrade.d.ts +0 -32
  424. package/dist/cli/pack/upgrade.js +0 -273
  425. package/dist/cli/pack/upgrade.js.map +0 -1
  426. package/dist/cli/pause/index.d.ts +0 -113
  427. package/dist/cli/pause/index.js +0 -251
  428. package/dist/cli/pause/index.js.map +0 -1
  429. package/dist/cli/pause-check.d.ts +0 -22
  430. package/dist/cli/pause-check.js +0 -54
  431. package/dist/cli/pause-check.js.map +0 -1
  432. package/dist/cli/policy/intercept.d.ts +0 -233
  433. package/dist/cli/policy/intercept.js +0 -1022
  434. package/dist/cli/policy/intercept.js.map +0 -1
  435. package/dist/cli/policy/risk-envelope-enrichment.d.ts +0 -40
  436. package/dist/cli/policy/risk-envelope-enrichment.js +0 -110
  437. package/dist/cli/policy/risk-envelope-enrichment.js.map +0 -1
  438. package/dist/cli/record/index.d.ts +0 -81
  439. package/dist/cli/record/index.js +0 -348
  440. package/dist/cli/record/index.js.map +0 -1
  441. package/dist/cli/register-audit-group.js +0 -91
  442. package/dist/cli/register-audit-group.js.map +0 -1
  443. package/dist/cli/resolve-env.d.ts +0 -32
  444. package/dist/cli/resolve-env.js +0 -46
  445. package/dist/cli/resolve-env.js.map +0 -1
  446. package/dist/cli/session-export/index.d.ts +0 -46
  447. package/dist/cli/session-export/index.js +0 -169
  448. package/dist/cli/session-export/index.js.map +0 -1
  449. package/dist/cli/session-export/redact.d.ts +0 -22
  450. package/dist/cli/session-export/redact.js +0 -47
  451. package/dist/cli/session-export/redact.js.map +0 -1
  452. package/dist/cli/session-export/transcript.d.ts +0 -24
  453. package/dist/cli/session-export/transcript.js +0 -164
  454. package/dist/cli/session-export/transcript.js.map +0 -1
  455. package/dist/cli/session-start/branch-check.d.ts +0 -18
  456. package/dist/cli/session-start/branch-check.js +0 -140
  457. package/dist/cli/session-start/branch-check.js.map +0 -1
  458. package/dist/cli/session-start/index.d.ts +0 -121
  459. package/dist/cli/session-start/index.js +0 -591
  460. package/dist/cli/session-start/index.js.map +0 -1
  461. package/dist/cli/session-start/shared-options.d.ts +0 -103
  462. package/dist/cli/session-start/shared-options.js +0 -107
  463. package/dist/cli/session-start/shared-options.js.map +0 -1
  464. package/dist/cli/session-start/stale-base-check.d.ts +0 -46
  465. package/dist/cli/session-start/stale-base-check.js +0 -352
  466. package/dist/cli/session-start/stale-base-check.js.map +0 -1
  467. package/dist/cli/session-start/toolchain-parity.d.ts +0 -267
  468. package/dist/cli/session-start/toolchain-parity.js +0 -797
  469. package/dist/cli/session-start/toolchain-parity.js.map +0 -1
  470. package/dist/cli/smoke/assertions.d.ts +0 -46
  471. package/dist/cli/smoke/assertions.js +0 -170
  472. package/dist/cli/smoke/assertions.js.map +0 -1
  473. package/dist/cli/smoke/index.d.ts +0 -76
  474. package/dist/cli/smoke/index.js +0 -245
  475. package/dist/cli/smoke/index.js.map +0 -1
  476. package/dist/cli/smoke/runner.d.ts +0 -55
  477. package/dist/cli/smoke/runner.js +0 -134
  478. package/dist/cli/smoke/runner.js.map +0 -1
  479. package/dist/cli/smoke/stream-parser.d.ts +0 -65
  480. package/dist/cli/smoke/stream-parser.js +0 -115
  481. package/dist/cli/smoke/stream-parser.js.map +0 -1
  482. package/dist/cli/test-risk.d.ts +0 -27
  483. package/dist/cli/test-risk.js +0 -38
  484. package/dist/cli/test-risk.js.map +0 -1
  485. package/dist/io/display-path.d.ts +0 -11
  486. package/dist/io/display-path.js +0 -29
  487. package/dist/io/display-path.js.map +0 -1
  488. package/dist/io/duration.d.ts +0 -5
  489. package/dist/io/duration.js +0 -50
  490. package/dist/io/duration.js.map +0 -1
  491. package/dist/io/extract.d.ts +0 -79
  492. package/dist/io/extract.js +0 -226
  493. package/dist/io/extract.js.map +0 -1
  494. package/dist/io/ledger-record.d.ts +0 -83
  495. package/dist/io/ledger-record.js +0 -301
  496. package/dist/io/ledger-record.js.map +0 -1
  497. package/dist/io/read-json-dir-entries.d.ts +0 -36
  498. package/dist/io/read-json-dir-entries.js +0 -48
  499. package/dist/io/read-json-dir-entries.js.map +0 -1
  500. package/dist/io/safe-json-parse.d.ts +0 -5
  501. package/dist/io/safe-json-parse.js +0 -21
  502. package/dist/io/safe-json-parse.js.map +0 -1
  503. package/dist/policies/index.d.ts +0 -5
  504. package/dist/policies/index.js +0 -6
  505. package/dist/policies/index.js.map +0 -1
  506. package/dist/policies/ledger-client.d.ts +0 -113
  507. package/dist/policies/ledger-client.js +0 -500
  508. package/dist/policies/ledger-client.js.map +0 -1
  509. package/dist/policies/producers.d.ts +0 -12
  510. package/dist/policies/producers.js +0 -61
  511. package/dist/policies/producers.js.map +0 -1
  512. package/dist/policies/requires.d.ts +0 -75
  513. package/dist/policies/requires.js +0 -240
  514. package/dist/policies/requires.js.map +0 -1
  515. package/dist/policies/timestamp.d.ts +0 -14
  516. package/dist/policies/timestamp.js +0 -36
  517. package/dist/policies/timestamp.js.map +0 -1
  518. package/dist/policy-packs/builtin/permission-profiles.d.ts +0 -11
  519. package/dist/policy-packs/builtin/permission-profiles.js +0 -74
  520. package/dist/policy-packs/builtin/permission-profiles.js.map +0 -1
  521. package/dist/policy-packs/builtin/post-merge-gate-runtime.d.ts +0 -286
  522. package/dist/policy-packs/builtin/post-merge-gate-runtime.js +0 -397
  523. package/dist/policy-packs/builtin/post-merge-gate-runtime.js.map +0 -1
  524. package/dist/policy-packs/builtin/post-merge-gate.d.ts +0 -56
  525. package/dist/policy-packs/builtin/post-merge-gate.js +0 -347
  526. package/dist/policy-packs/builtin/post-merge-gate.js.map +0 -1
  527. package/dist/policy-packs/builtin/solution-acceptance-reconnect.d.ts +0 -50
  528. package/dist/policy-packs/builtin/solution-acceptance-reconnect.js +0 -151
  529. package/dist/policy-packs/builtin/solution-acceptance-reconnect.js.map +0 -1
  530. package/dist/policy-packs/builtin/solution-acceptance-runtime.d.ts +0 -323
  531. package/dist/policy-packs/builtin/solution-acceptance-runtime.js +0 -672
  532. package/dist/policy-packs/builtin/solution-acceptance-runtime.js.map +0 -1
  533. package/dist/policy-packs/builtin/solution-acceptance.d.ts +0 -45
  534. package/dist/policy-packs/builtin/solution-acceptance.js +0 -226
  535. package/dist/policy-packs/builtin/solution-acceptance.js.map +0 -1
  536. package/dist/policy-packs/builtin/understanding-before-execution/active-claim.d.ts +0 -25
  537. package/dist/policy-packs/builtin/understanding-before-execution/active-claim.js +0 -94
  538. package/dist/policy-packs/builtin/understanding-before-execution/active-claim.js.map +0 -1
  539. package/dist/policy-packs/builtin/understanding-before-execution/auto-approve-default.d.ts +0 -35
  540. package/dist/policy-packs/builtin/understanding-before-execution/auto-approve-default.js +0 -86
  541. package/dist/policy-packs/builtin/understanding-before-execution/auto-approve-default.js.map +0 -1
  542. package/dist/policy-packs/builtin/understanding-before-execution/auto-approve.d.ts +0 -210
  543. package/dist/policy-packs/builtin/understanding-before-execution/auto-approve.js +0 -361
  544. package/dist/policy-packs/builtin/understanding-before-execution/auto-approve.js.map +0 -1
  545. package/dist/policy-packs/builtin/understanding-before-execution/delegation-markers.d.ts +0 -304
  546. package/dist/policy-packs/builtin/understanding-before-execution/delegation-markers.js +0 -734
  547. package/dist/policy-packs/builtin/understanding-before-execution/delegation-markers.js.map +0 -1
  548. package/dist/policy-packs/builtin/understanding-before-execution/expiry-reason.d.ts +0 -36
  549. package/dist/policy-packs/builtin/understanding-before-execution/expiry-reason.js +0 -73
  550. package/dist/policy-packs/builtin/understanding-before-execution/expiry-reason.js.map +0 -1
  551. package/dist/policy-packs/builtin/understanding-before-execution/index.d.ts +0 -19
  552. package/dist/policy-packs/builtin/understanding-before-execution/index.js +0 -83
  553. package/dist/policy-packs/builtin/understanding-before-execution/index.js.map +0 -1
  554. package/dist/policy-packs/builtin/understanding-before-execution/inflight-records.d.ts +0 -135
  555. package/dist/policy-packs/builtin/understanding-before-execution/inflight-records.js +0 -643
  556. package/dist/policy-packs/builtin/understanding-before-execution/inflight-records.js.map +0 -1
  557. package/dist/policy-packs/builtin/understanding-before-execution/ledger.d.ts +0 -25
  558. package/dist/policy-packs/builtin/understanding-before-execution/ledger.js +0 -56
  559. package/dist/policy-packs/builtin/understanding-before-execution/ledger.js.map +0 -1
  560. package/dist/policy-packs/builtin/understanding-before-execution/lifecycle.d.ts +0 -20
  561. package/dist/policy-packs/builtin/understanding-before-execution/lifecycle.js +0 -106
  562. package/dist/policy-packs/builtin/understanding-before-execution/lifecycle.js.map +0 -1
  563. package/dist/policy-packs/builtin/understanding-before-execution/markers.d.ts +0 -126
  564. package/dist/policy-packs/builtin/understanding-before-execution/markers.js +0 -245
  565. package/dist/policy-packs/builtin/understanding-before-execution/markers.js.map +0 -1
  566. package/dist/policy-packs/builtin/understanding-before-execution/measured-permission-modes.d.ts +0 -29
  567. package/dist/policy-packs/builtin/understanding-before-execution/measured-permission-modes.js +0 -82
  568. package/dist/policy-packs/builtin/understanding-before-execution/measured-permission-modes.js.map +0 -1
  569. package/dist/policy-packs/builtin/understanding-before-execution/permission-mode-observations.d.ts +0 -71
  570. package/dist/policy-packs/builtin/understanding-before-execution/permission-mode-observations.js +0 -175
  571. package/dist/policy-packs/builtin/understanding-before-execution/permission-mode-observations.js.map +0 -1
  572. package/dist/policy-packs/builtin/understanding-before-execution/persisted-reports.d.ts +0 -625
  573. package/dist/policy-packs/builtin/understanding-before-execution/persisted-reports.js +0 -1076
  574. package/dist/policy-packs/builtin/understanding-before-execution/persisted-reports.js.map +0 -1
  575. package/dist/policy-packs/builtin/understanding-before-execution/post-tool-use-boundary.d.ts +0 -128
  576. package/dist/policy-packs/builtin/understanding-before-execution/post-tool-use-boundary.js +0 -213
  577. package/dist/policy-packs/builtin/understanding-before-execution/post-tool-use-boundary.js.map +0 -1
  578. package/dist/policy-packs/builtin/understanding-before-execution/stay-in-scope-config.d.ts +0 -129
  579. package/dist/policy-packs/builtin/understanding-before-execution/stay-in-scope-config.js +0 -166
  580. package/dist/policy-packs/builtin/understanding-before-execution/stay-in-scope-config.js.map +0 -1
  581. package/dist/policy-packs/builtin/understanding-before-execution/task-markers.d.ts +0 -164
  582. package/dist/policy-packs/builtin/understanding-before-execution/task-markers.js +0 -275
  583. package/dist/policy-packs/builtin/understanding-before-execution/task-markers.js.map +0 -1
  584. package/dist/policy-packs/builtin/understanding-before-execution-runtime.d.ts +0 -1
  585. package/dist/policy-packs/builtin/understanding-before-execution-runtime.js +0 -10
  586. package/dist/policy-packs/builtin/understanding-before-execution-runtime.js.map +0 -1
  587. package/dist/policy-packs/builtin/understanding-before-execution.d.ts +0 -526
  588. package/dist/policy-packs/builtin/understanding-before-execution.js +0 -1078
  589. package/dist/policy-packs/builtin/understanding-before-execution.js.map +0 -1
  590. package/dist/policy-packs/permission-translator.d.ts +0 -9
  591. package/dist/policy-packs/permission-translator.js +0 -76
  592. package/dist/policy-packs/permission-translator.js.map +0 -1
  593. package/dist/runtime/action-envelope.d.ts +0 -64
  594. package/dist/runtime/action-envelope.js +0 -46
  595. package/dist/runtime/action-envelope.js.map +0 -1
  596. package/dist/runtime/approval-signing.d.ts +0 -111
  597. package/dist/runtime/approval-signing.js +0 -384
  598. package/dist/runtime/approval-signing.js.map +0 -1
  599. package/dist/runtime/bash-match-facts.d.ts +0 -60
  600. package/dist/runtime/bash-match-facts.js +0 -196
  601. package/dist/runtime/bash-match-facts.js.map +0 -1
  602. package/dist/runtime/bash-match-registry.d.ts +0 -112
  603. package/dist/runtime/bash-match-registry.js +0 -406
  604. package/dist/runtime/bash-match-registry.js.map +0 -1
  605. package/dist/runtime/bash-prefix-parse.d.ts +0 -31
  606. package/dist/runtime/bash-prefix-parse.js +0 -576
  607. package/dist/runtime/bash-prefix-parse.js.map +0 -1
  608. package/dist/runtime/command-normalize.d.ts +0 -658
  609. package/dist/runtime/command-normalize.js +0 -2410
  610. package/dist/runtime/command-normalize.js.map +0 -1
  611. package/dist/runtime/deletion-target-resolve.d.ts +0 -28
  612. package/dist/runtime/deletion-target-resolve.js +0 -1078
  613. package/dist/runtime/deletion-target-resolve.js.map +0 -1
  614. package/dist/runtime/destructive-shell-floor.d.ts +0 -19
  615. package/dist/runtime/destructive-shell-floor.js +0 -611
  616. package/dist/runtime/destructive-shell-floor.js.map +0 -1
  617. package/dist/runtime/environment-resolver.d.ts +0 -36
  618. package/dist/runtime/environment-resolver.js +0 -138
  619. package/dist/runtime/environment-resolver.js.map +0 -1
  620. package/dist/runtime/git-context.d.ts +0 -201
  621. package/dist/runtime/git-context.js +0 -422
  622. package/dist/runtime/git-context.js.map +0 -1
  623. package/dist/runtime/index.d.ts +0 -12
  624. package/dist/runtime/index.js +0 -13
  625. package/dist/runtime/index.js.map +0 -1
  626. package/dist/runtime/intercept.d.ts +0 -623
  627. package/dist/runtime/intercept.js +0 -1384
  628. package/dist/runtime/intercept.js.map +0 -1
  629. package/dist/runtime/kube-context.d.ts +0 -16
  630. package/dist/runtime/kube-context.js +0 -63
  631. package/dist/runtime/kube-context.js.map +0 -1
  632. package/dist/runtime/kubectl-target-parse.d.ts +0 -31
  633. package/dist/runtime/kubectl-target-parse.js +0 -249
  634. package/dist/runtime/kubectl-target-parse.js.map +0 -1
  635. package/dist/runtime/ledger-add.d.ts +0 -16
  636. package/dist/runtime/ledger-add.js +0 -150
  637. package/dist/runtime/ledger-add.js.map +0 -1
  638. package/dist/runtime/ledger-writer.d.ts +0 -27
  639. package/dist/runtime/ledger-writer.js +0 -46
  640. package/dist/runtime/ledger-writer.js.map +0 -1
  641. package/dist/runtime/pause-sentinel.d.ts +0 -60
  642. package/dist/runtime/pause-sentinel.js +0 -156
  643. package/dist/runtime/pause-sentinel.js.map +0 -1
  644. package/dist/runtime/pending-approval.d.ts +0 -23
  645. package/dist/runtime/pending-approval.js +0 -67
  646. package/dist/runtime/pending-approval.js.map +0 -1
  647. package/dist/runtime/read-only-bash.d.ts +0 -141
  648. package/dist/runtime/read-only-bash.js +0 -2204
  649. package/dist/runtime/read-only-bash.js.map +0 -1
  650. package/dist/runtime/recovery-git-commit.d.ts +0 -22
  651. package/dist/runtime/recovery-git-commit.js +0 -284
  652. package/dist/runtime/recovery-git-commit.js.map +0 -1
  653. package/dist/runtime/reject-malformed-session-id.d.ts +0 -8
  654. package/dist/runtime/reject-malformed-session-id.js +0 -16
  655. package/dist/runtime/reject-malformed-session-id.js.map +0 -1
  656. package/dist/runtime/risk-classifier.d.ts +0 -38
  657. package/dist/runtime/risk-classifier.js +0 -311
  658. package/dist/runtime/risk-classifier.js.map +0 -1
  659. package/dist/runtime/session-id.d.ts +0 -113
  660. package/dist/runtime/session-id.js +0 -193
  661. package/dist/runtime/session-id.js.map +0 -1
  662. package/dist/runtime/shell-word.d.ts +0 -62
  663. package/dist/runtime/shell-word.js +0 -410
  664. package/dist/runtime/shell-word.js.map +0 -1
  665. package/dist/runtime/task-providers/agent-tasks.d.ts +0 -105
  666. package/dist/runtime/task-providers/agent-tasks.js +0 -247
  667. package/dist/runtime/task-providers/agent-tasks.js.map +0 -1
  668. package/dist/runtime/when-eval.d.ts +0 -62
  669. package/dist/runtime/when-eval.js +0 -212
  670. package/dist/runtime/when-eval.js.map +0 -1
  671. package/dist/runtime/workflow-policies.d.ts +0 -207
  672. package/dist/runtime/workflow-policies.js +0 -596
  673. package/dist/runtime/workflow-policies.js.map +0 -1
  674. package/dist/schema/audit.d.ts +0 -71
  675. package/dist/schema/audit.js +0 -32
  676. package/dist/schema/audit.js.map +0 -1
  677. package/dist/schema/doctor.d.ts +0 -25
  678. package/dist/schema/doctor.js +0 -23
  679. package/dist/schema/doctor.js.map +0 -1
  680. package/dist/schema/environments.d.ts +0 -215
  681. package/dist/schema/environments.js +0 -101
  682. package/dist/schema/environments.js.map +0 -1
  683. package/dist/schema/extract.d.ts +0 -9
  684. package/dist/schema/extract.js +0 -86
  685. package/dist/schema/extract.js.map +0 -1
  686. package/dist/schema/permission-profiles.d.ts +0 -2292
  687. package/dist/schema/permission-profiles.js +0 -60
  688. package/dist/schema/permission-profiles.js.map +0 -1
  689. package/dist/schema/policies.d.ts +0 -974
  690. package/dist/schema/policies.js +0 -298
  691. package/dist/schema/policies.js.map +0 -1
  692. package/dist/schema/requires.d.ts +0 -131
  693. package/dist/schema/requires.js +0 -88
  694. package/dist/schema/requires.js.map +0 -1
  695. package/dist/schema/risk.d.ts +0 -144
  696. package/dist/schema/risk.js +0 -194
  697. package/dist/schema/risk.js.map +0 -1
  698. package/dist/schema/session-start-preflight.d.ts +0 -10
  699. package/dist/schema/session-start-preflight.js +0 -106
  700. package/dist/schema/session-start-preflight.js.map +0 -1
  701. package/dist/schema/stale-base-check.d.ts +0 -18
  702. package/dist/schema/stale-base-check.js +0 -37
  703. package/dist/schema/stale-base-check.js.map +0 -1
  704. package/dist/schema/toolchain-parity.d.ts +0 -21
  705. package/dist/schema/toolchain-parity.js +0 -48
  706. package/dist/schema/toolchain-parity.js.map +0 -1
  707. package/dist/schema/workflows.d.ts +0 -519
  708. package/dist/schema/workflows.js +0 -81
  709. package/dist/schema/workflows.js.map +0 -1
  710. package/scripts/runtime-reality-docker-probe.mjs +0 -71
@@ -1,399 +1,424 @@
1
- // `harness pack hook branch-protection` — PreToolUse blocker for the
2
- // `branch-protection` policy pack.
1
+ // `harness pack hook branch-protection`: PreToolUse blocker for the
2
+ // `branch-protection` policy pack (task a4d8adc5).
3
3
  //
4
- // Receives Claude Code's PreToolUse event JSON on stdin and emits a
5
- // `{ decision: "block" }` envelope when the agent is about to mutate
6
- // source on a protected branch without a satisfying ledger tag.
4
+ // Receives the runtime's PreToolUse event JSON on stdin and refuses the tool
5
+ // call when a directory it writes into belongs to a repository whose
6
+ // checked-out branch is protected. The branch is git's own answer
7
+ // (`git -C <dir> symbolic-ref -q HEAD`, src/runtime/git-branch.ts); this hook
8
+ // never reads git's files itself.
7
9
  //
8
- // Two paths satisfy the gate:
10
+ // Every event is judged twice, and the hook refuses when either judgment
11
+ // refuses or cannot answer; it allows only when both allow. The as-written
12
+ // judgment runs first.
9
13
  //
10
- // 1. **Producer path** — a `branch:non-protected` tag exists in the
11
- // ledger from within the last 5 minutes (set by
12
- // `harness session-start branch-check` when the session opened on
13
- // a non-protected branch).
14
+ // 1. As written: each path made absolute against the event cwd with `.` and
15
+ // `..` resolved on the text (`path.resolve`), symlinks left in the path;
16
+ // the presence walk runs on that text and git runs in that directory.
17
+ // Write, Edit, MultiEdit, NotebookEdit: the nearest existing directory
18
+ // holding the target path. Codex `apply_patch`: the same for every path
19
+ // named by an `*** Add File:`, `*** Update File:`, `*** Delete File:` or
20
+ // `*** Move to:` header line of the patch text in tool_input.patch,
21
+ // tool_input.input or a string tool_input, relative to the event cwd.
22
+ // Anything else, or a patch without a header there: the event cwd.
23
+ // 2. Physical, as the operating system resolves the path (symlinks
24
+ // followed, `..` taken from the directory reached so far), which is the
25
+ // directory `git -C` changes into. Write, Edit, MultiEdit, NotebookEdit:
26
+ // the nearest existing directory of the target path (a Write may create
27
+ // the directories in between), and, when the target is a symlink, the
28
+ // directory it leads to as well. Codex `apply_patch`: the same for every
29
+ // path named by a header line found in any string of the event (any
30
+ // field or array of tool_input, raw_input or input, and JSON text inside
31
+ // a string: the field Codex carries the patch in is not pinned). A
32
+ // relative path resolves against the event cwd and, when the tool input
33
+ // names a per-call `workdir` or `cwd`, against that as well. Anything
34
+ // else, or a patch without a header: the event cwd (and that per-call
35
+ // directory).
14
36
  //
15
- // 2. **Override path** — an operator-only approval marker file exists
16
- // at `harness.generated/.approvals/branch-protection-<sessionId>`,
17
- // written by `harness approve branch-protection` from outside the
18
- // gated shell to bless a deliberate protected-branch edit (version
19
- // bumps, CI workflow patches, hotfixes). The legacy
20
- // `branch-protection-ack:` LEDGER tag is NO LONGER trusted as an
21
- // override (audit finding #39): the agent has direct
22
- // `mcp__grounding-mcp__ledger_add` access and could self-write the
23
- // tag to bless its own edit. The marker lives under
24
- // `harness.generated/`, which Edit / Write / Bash are all gated from
25
- // writing, so only a process the operator launched can produce it.
26
- // The ack ledger row is still recorded for audit and surfaced in the
27
- // diagnostics, but its presence alone never satisfies the gate.
37
+ // Decision, per directory: git names a protected branch (compared
38
+ // case-insensitively) -> refuse; git could not answer (any error, a timeout,
39
+ // git missing, an unexpected answer) -> refuse with one fixed sentence naming
40
+ // git's first stderr line; a detached HEAD, or no `.git` entry anywhere above
41
+ // the directory -> allow. A manifest that does not load refuses every call.
42
+ // Resolving the paths and every git call are bounded, together, from the
43
+ // hook's start and below the pack's hook budget (a hook the runtime kills at
44
+ // its budget is read as an allow): past the bound the hook refuses.
28
45
  //
29
- // Failure mode: any error in load / parse / ledger query resolves to
30
- // BLOCK. This is the inverse of understanding-before-execution's
31
- // fail-open contract: branch-protection's whole job is to prevent
32
- // edit-on-master incidents, so a bug in the blocker that silently
33
- // allowed Writes through would defeat the purpose. The block envelope
34
- // always names a recovery path so the operator is never wedged.
46
+ // Block contract per runtime: Claude Code reads a JSON deny envelope on
47
+ // stdout (exit 0); Codex reads exit 2 with the reason on stderr
48
+ // (`--runtime codex`). The agent-facing text names `git checkout -b` as the
49
+ // way forward and nothing else. A Claude Code block whose envelope cannot be
50
+ // written (the reader has gone, or the stream is closed) fails closed too:
51
+ // exit 2 with the reason on stderr, since exit 0 without an envelope is read
52
+ // as an allow.
35
53
  import * as path from "node:path";
36
- import { queryLedgerByTag, } from "../../policies/index.js";
37
- import { ACK_TAG_PREFIX, DEFAULT_PROTECTED_BRANCHES, NON_PROTECTED_TAG_PREFIX, PACK_NAME, PRODUCER_FRESHNESS_MS, checkBranchProtectionMarker, resolveProtectedBranches, } from "../../policy-packs/builtin/branch-protection-runtime.js";
38
- import { resolveGeneratedDir } from "../../io/generated-dir.js";
39
- import { resolveGitContext } from "../../runtime/git-context.js";
40
- import { POLICY_DECISION_TYPE } from "../../io/ledger-record.js";
54
+ import { PACK_NAME, isProtectedBranch, resolveProtectedBranches, } from "../../policy-packs/builtin/branch-protection-runtime.js";
55
+ import { GIT_BRANCH_TIMEOUT_MS, PathBoundError, absolutePath, nearestExistingDirectory, nearestExistingDirectoryAsWritten, readBranchAt, resolveDirectory, writeTargetDirectories, } from "../../runtime/git-branch.js";
41
56
  import { renderAgentFacing } from "../../runtime/agent-facing.js";
42
- import { checkHookPause, loadManifestOrInjected, parseConfigUx, readStdin, runGateWithStdinRefusal, stdoutBlockRefusal, } from "./hook-bootstrap.js";
57
+ import { boundUtf8 } from "../../runtime/bounded-text.js";
58
+ import { STDIO_DRAIN_TIMEOUT_MS, tolerateClosedStdio } from "../drain-stdio.js";
59
+ import { loadManifestOrInjected, parseConfigUx, pickString, readStdinChecked, } from "./hook-bootstrap.js";
43
60
  /**
44
- * Pull the destination file path out of a PreToolUse event's `tool_input`
45
- * payload for the tools that mutate a single file. Returns null for tools
46
- * that don't have a single resolvable target (Bash, search tools, etc.) —
47
- * those keep cwd-based protection.
48
- *
49
- * Path-aware tools today: Write, Edit, MultiEdit, NotebookEdit.
61
+ * Bound on resolving the paths and on all git calls of one event together,
62
+ * in ms, counted from the moment the hook starts (the stdin read and the
63
+ * manifest load included), so neither a slow stdin nor a large event can
64
+ * push the hook past its budget.
50
65
  */
51
- function extractTargetPath(toolName, toolInput) {
66
+ export const GIT_READ_DEADLINE_MS = 3000;
67
+ /** The runtimes whose block contract this hook speaks. */
68
+ export const BRANCH_PROTECTION_RUNTIMES = ["claude-code", "codex"];
69
+ const CODEX_EXIT_BLOCK = 2;
70
+ /** Target path of the Claude Code tools that write a single file. */
71
+ function singleTargetPath(toolName, toolInput) {
52
72
  if (typeof toolInput !== "object" || toolInput === null)
53
73
  return null;
54
74
  const input = toolInput;
55
75
  switch (toolName) {
56
76
  case "Write":
57
77
  case "Edit":
58
- case "MultiEdit": {
59
- const fp = input["file_path"];
60
- return typeof fp === "string" && fp.length > 0 ? fp : null;
61
- }
62
- case "NotebookEdit": {
63
- const np = input["notebook_path"];
64
- return typeof np === "string" && np.length > 0 ? np : null;
65
- }
78
+ case "MultiEdit":
79
+ return pickString(input["file_path"]) ?? null;
80
+ case "NotebookEdit":
81
+ return pickString(input["notebook_path"]) ?? null;
66
82
  default:
67
83
  return null;
68
84
  }
69
85
  }
70
- function findGroundingMcp(manifest) {
71
- return manifest.tools.mcp.find((m) => m.name === "grounding-mcp") ?? null;
72
- }
73
- function evaluateEntries(entries, now) {
74
- const cutoff = now.getTime() - PRODUCER_FRESHNESS_MS;
75
- let hasFreshProducer = false;
76
- let hasAck = false;
77
- let freshProducerContent = null;
78
- let ackContent = null;
79
- for (const e of entries) {
80
- // Skip policy_decision audit rows: their serialized payload
81
- // incidentally contains the tag they're about (e.g. a denied
82
- // decision the engine recorded for THIS pack would carry the
83
- // literal "branch:non-protected" or "branch-protection-ack" in
84
- // its JSON, falsely satisfying the gate). Two-tier filter
85
- // mirrors `src/policies/requires.ts:75-83`: by-type for current
86
- // ledger rows, by-content-prefix as a backstop for legacy rows
87
- // a pre-Phase-5-#4 ledger may still carry.
88
- if (e.type === POLICY_DECISION_TYPE)
89
- continue;
90
- if (e.content.startsWith(`${POLICY_DECISION_TYPE}:`))
91
- continue;
92
- if (e.content.includes(ACK_TAG_PREFIX)) {
93
- hasAck = true;
94
- if (ackContent === null)
95
- ackContent = e.content;
96
- continue;
86
+ /**
87
+ * Every string in `value`, in document order: objects and arrays are walked,
88
+ * and a string holding JSON text is parsed and walked too.
89
+ */
90
+ function stringsIn(value) {
91
+ const out = [];
92
+ const stack = [value];
93
+ while (stack.length > 0) {
94
+ const v = stack.pop();
95
+ if (typeof v === "string") {
96
+ out.push(v);
97
+ const t = v.trim();
98
+ if (t.startsWith("{") || t.startsWith("[")) {
99
+ try {
100
+ stack.push(JSON.parse(t));
101
+ }
102
+ catch {
103
+ /* not JSON text */
104
+ }
105
+ }
97
106
  }
98
- if (!e.content.includes(NON_PROTECTED_TAG_PREFIX))
99
- continue;
100
- const ts = e.createdAt instanceof Date ? e.createdAt : new Date(e.createdAt);
101
- if (Number.isNaN(ts.getTime()))
102
- continue;
103
- if (ts.getTime() >= cutoff) {
104
- hasFreshProducer = true;
105
- if (freshProducerContent === null)
106
- freshProducerContent = e.content;
107
+ else if (Array.isArray(v)) {
108
+ for (let i = v.length - 1; i >= 0; i -= 1)
109
+ stack.push(v[i]);
110
+ }
111
+ else if (typeof v === "object" && v !== null) {
112
+ const children = Object.values(v);
113
+ for (let i = children.length - 1; i >= 0; i -= 1)
114
+ stack.push(children[i]);
107
115
  }
108
116
  }
109
- return {
110
- hasFreshProducer,
111
- hasAck,
112
- freshProducerContent,
113
- ackContent,
114
- totalEntries: entries.length,
115
- degraded: null,
116
- };
117
+ return out;
117
118
  }
118
- async function probeLedger(manifest, sessionId, opts) {
119
- if (opts.ledgerQuery) {
120
- const r = await opts.ledgerQuery(sessionId);
121
- if ("degraded" in r) {
122
- return {
123
- hasFreshProducer: false,
124
- hasAck: false,
125
- freshProducerContent: null,
126
- ackContent: null,
127
- totalEntries: 0,
128
- degraded: r.degraded,
129
- };
130
- }
131
- return evaluateEntries(r, opts.now ?? new Date());
119
+ const PATCH_HEADER = /^\*\*\*\s*(?:Add File|Update File|Delete File|Move to):\s*(.+)$/;
120
+ /** The paths named by the file header lines of one text. */
121
+ function headerPaths(text) {
122
+ const out = [];
123
+ for (const raw of text.split("\n")) {
124
+ const m = PATCH_HEADER.exec(raw.trim());
125
+ const target = m?.[1]?.trim() ?? "";
126
+ if (target.length > 0)
127
+ out.push(target);
132
128
  }
133
- if (!manifest) {
134
- return {
135
- hasFreshProducer: false,
136
- hasAck: false,
137
- freshProducerContent: null,
138
- ackContent: null,
139
- totalEntries: 0,
140
- degraded: "manifest unavailable",
141
- };
129
+ return out;
130
+ }
131
+ /**
132
+ * Every path an `apply_patch` call names in a file header line, read from
133
+ * every string of `value` (the whole event, or any part of it), each once.
134
+ */
135
+ export function patchTargetPaths(value) {
136
+ return [...new Set(stringsIn(value).flatMap(headerPaths))];
137
+ }
138
+ /** The patch text the as-written judgment reads: tool_input.patch, tool_input.input or a string tool_input. */
139
+ function asWrittenPatchText(toolInput) {
140
+ if (typeof toolInput === "string")
141
+ return toolInput;
142
+ if (typeof toolInput !== "object" || toolInput === null)
143
+ return "";
144
+ const input = toolInput;
145
+ return pickString(input["patch"], input["input"]) ?? "";
146
+ }
147
+ /**
148
+ * The directories an `apply_patch` call's relative paths resolve against:
149
+ * the event cwd, plus a per-call `workdir` or `cwd` named in tool_input,
150
+ * raw_input or input.
151
+ */
152
+ function patchBaseDirectories(event, cwd) {
153
+ const bases = [cwd];
154
+ for (const holder of [event.tool_input, event.raw_input, event.input]) {
155
+ if (typeof holder !== "object" || holder === null || Array.isArray(holder))
156
+ continue;
157
+ const fields = holder;
158
+ for (const key of ["workdir", "cwd"]) {
159
+ const value = pickString(fields[key]);
160
+ if (value !== undefined)
161
+ bases.push(absolutePath(value, cwd));
162
+ }
142
163
  }
143
- const server = findGroundingMcp(manifest);
144
- if (!server) {
145
- return {
146
- hasFreshProducer: false,
147
- hasAck: false,
148
- freshProducerContent: null,
149
- ackContent: null,
150
- totalEntries: 0,
151
- degraded: "grounding-mcp not declared in manifest",
164
+ return [...new Set(bases)];
165
+ }
166
+ /**
167
+ * The directories of the as-written judgment: each path made absolute
168
+ * against the event cwd with `.` and `..` resolved on the text, then its
169
+ * nearest existing directory with symlinks left in place.
170
+ */
171
+ function asWrittenTargets(toolName, toolInput, cwd, res) {
172
+ const single = singleTargetPath(toolName, toolInput);
173
+ const paths = single !== null ? [single] : toolName === "apply_patch" ? [...new Set(headerPaths(asWrittenPatchText(toolInput)))] : [];
174
+ if (paths.length === 0)
175
+ return { source: "cwd", dirs: [nearestExistingDirectoryAsWritten(cwd, res)] };
176
+ const dirs = paths.map((p) => nearestExistingDirectoryAsWritten(path.dirname(path.resolve(cwd, p)), res));
177
+ return { source: single !== null ? "target" : "patch", dirs: [...new Set(dirs)] };
178
+ }
179
+ /** The directories of the physical judgment: where the operating system resolves each path. */
180
+ function checkTargets(toolName, event, cwd, res) {
181
+ const single = singleTargetPath(toolName, event.tool_input);
182
+ if (single !== null)
183
+ return { source: "target", dirs: writeTargetDirectories(single, cwd, res) };
184
+ if (toolName !== "apply_patch")
185
+ return { source: "cwd", dirs: [nearestExistingDirectory(cwd, res)] };
186
+ const bases = patchBaseDirectories(event, cwd);
187
+ const paths = patchTargetPaths(event);
188
+ if (paths.length === 0)
189
+ return { source: "cwd", dirs: [...new Set(bases.map((b) => nearestExistingDirectory(b, res)))] };
190
+ const dirs = paths.flatMap((p) => (path.isAbsolute(p) ? [cwd] : bases).flatMap((b) => writeTargetDirectories(p, b, res)));
191
+ return { source: "patch", dirs: [...new Set(dirs)] };
192
+ }
193
+ /**
194
+ * Write `text` to `stream` and wait for the write to complete, for at most
195
+ * `timeoutMs`. The write counts as failed when the stream is already closed,
196
+ * when the completion callback carries an error, when the stream emits
197
+ * 'error' during the wait, or when it has closed by the time the wait ends.
198
+ * A wait that ends with the stream still open is a slow reader, not a failed
199
+ * write: the entry point's drain gives the rest of the text its own bounded
200
+ * wait.
201
+ */
202
+ function writeAndAwait(stream, text, timeoutMs) {
203
+ const closedReason = () => {
204
+ const s = stream;
205
+ return s.destroyed === true || s.writable === false ? "stdout is closed" : undefined;
206
+ };
207
+ return new Promise((resolve) => {
208
+ const before = closedReason();
209
+ if (before !== undefined) {
210
+ resolve({ delivered: false, why: before });
211
+ return;
212
+ }
213
+ let timer;
214
+ const onError = (err) => settle({ delivered: false, why: err.message });
215
+ const settle = (result) => {
216
+ clearTimeout(timer);
217
+ stream.removeListener("error", onError);
218
+ resolve(result);
152
219
  };
153
- }
154
- const command = Array.isArray(server.command)
155
- ? server.command
156
- : server.command.trim().split(/\s+/);
157
- const env = server.env ?? undefined;
158
- const timeoutMs = opts.ledgerTimeoutMs ?? server.health?.timeout_ms ?? 5_000;
159
- const result = await queryLedgerByTag({
160
- mcpCommand: command,
161
- ...(env && { mcpEnv: env }),
162
- sessionId,
163
- timeoutMs,
220
+ stream.on("error", onError);
221
+ timer = setTimeout(() => {
222
+ const why = closedReason();
223
+ settle(why === undefined ? { delivered: true } : { delivered: false, why });
224
+ }, timeoutMs);
225
+ try {
226
+ stream.write(text, (err) => {
227
+ settle(err ? { delivered: false, why: err.message } : { delivered: true });
228
+ });
229
+ }
230
+ catch (err) {
231
+ settle({ delivered: false, why: err instanceof Error ? err.message : String(err) });
232
+ }
164
233
  });
165
- if (result.kind === "degraded") {
166
- return {
167
- hasFreshProducer: false,
168
- hasAck: false,
169
- freshProducerContent: null,
170
- ackContent: null,
171
- totalEntries: 0,
172
- degraded: result.reason,
173
- };
174
- }
175
- return evaluateEntries(result.entries, opts.now ?? new Date());
176
234
  }
177
- function blockJson(toolName, branch, detail, protectedList, ux, sessionId) {
178
- // When the pack config declares `ux:`, the agent-facing surface
179
- // becomes the plain-language `{ cannot, required, run }` shape and
180
- // the legacy "branch-protection: refusing ..." vocabulary is
181
- // suppressed. The stderr BLOCK diagnostic keeps the engine reason
182
- // (`detail`) for operator audit. `${BRANCH}` / `${TOOL_NAME}` /
183
- // `${SESSION_ID}` substitute against the pack runtime context.
184
- let reasonText;
185
- if (ux) {
186
- reasonText = renderAgentFacing(ux, {
187
- BRANCH: branch,
188
- TOOL_NAME: toolName,
189
- SESSION_ID: sessionId,
190
- });
191
- }
192
- else {
193
- const minutes = Math.round(PRODUCER_FRESHNESS_MS / 60000);
194
- reasonText =
195
- `branch-protection: refusing ${toolName} on protected branch "${branch}". ` +
196
- `${detail}\n` +
197
- `To proceed, cut a feature branch and re-run the producer:\n` +
198
- ` git checkout -b <feature-slug>\n` +
199
- ` harness session-start branch-check\n` +
200
- `Once the gate sees a fresh ${NON_PROTECTED_TAG_PREFIX} tag (within ${minutes}m), this tool call will succeed.\n` +
201
- `\n` +
202
- `Override (operator only): the operator runs, from an un-hooked shell:\n` +
203
- ` harness approve branch-protection --session ${sessionId}\n` +
204
- `which writes the canonical approval marker the gate consults. ` +
205
- `A \`${ACK_TAG_PREFIX}:<reason>\` ledger tag is no longer a sufficient override on its own ` +
206
- `(it is agent-writable); the marker file under harness.generated/ is the trusted signal.\n` +
207
- `\n` +
208
- `Protected branches: ${protectedList.join(", ")}.`;
209
- }
235
+ function claudeBlockEnvelope(reason) {
210
236
  return JSON.stringify({
211
237
  decision: "block",
212
- reason: reasonText,
238
+ reason,
213
239
  hookSpecificOutput: {
214
240
  hookEventName: "PreToolUse",
215
241
  permissionDecision: "deny",
216
- permissionDecisionReason: reasonText,
242
+ permissionDecisionReason: reason,
217
243
  },
218
244
  });
219
245
  }
220
- async function runPackHookBranchProtectionCliInner(opts = {}) {
221
- const stdin = opts.stdin ?? process.stdin;
246
+ /** Agent-facing text for a protected branch: the ux block, or the default. */
247
+ function protectedBranchText(toolName, branch, dir, protectedList, ux, sessionId) {
248
+ if (ux) {
249
+ return renderAgentFacing(ux, { BRANCH: branch, TOOL_NAME: toolName, SESSION_ID: sessionId });
250
+ }
251
+ return (`branch-protection: refusing ${toolName} on protected branch "${branch}" (checked in ${dir}).\n` +
252
+ `Create a feature branch first, then retry:\n` +
253
+ ` git checkout -b <feature>\n` +
254
+ `Protected branches: ${protectedList.join(", ")}.`);
255
+ }
256
+ /**
257
+ * `harness pack hook branch-protection`. `opts.runtime` selects the block
258
+ * contract; an unknown value refuses with exit 2, which both runtimes read as
259
+ * a block.
260
+ */
261
+ export async function runPackHookBranchProtectionCli(opts = {}) {
262
+ const now = opts.now ?? Date.now;
263
+ const startedAt = now();
222
264
  const stdout = opts.stdout ?? process.stdout;
223
265
  const stderr = opts.stderr ?? process.stderr;
266
+ // Before the first write of any kind: a reader that has gone makes a write
267
+ // fail with EPIPE, and the error is emitted while this function is still
268
+ // awaiting git, so a listener attached only at exit comes too late.
269
+ // The exit code is the decision's, whatever happens to the pipe.
270
+ tolerateClosedStdio([stdout, stderr]);
224
271
  const note = (msg) => {
225
272
  stderr.write(`harness pack hook branch-protection: ${msg}\n`);
226
273
  };
227
- // Defensive stdin parse. Empty / malformed input resolves to BLOCK
228
- // (the inverse of understanding-before-execution's allow-on-malformed
229
- // default): we'd rather block a Write we couldn't classify than let
230
- // it through silently.
231
- const raw = await readStdin(stdin);
232
- let event = {};
274
+ const allow = (diagnostic) => {
275
+ note(diagnostic);
276
+ return { exitCode: 0, blocked: false, diagnostic };
277
+ };
278
+ const runtime = opts.runtime ?? "claude-code";
279
+ if (!BRANCH_PROTECTION_RUNTIMES.includes(runtime)) {
280
+ // The value comes from the command line, so the diagnostic is bounded like every other block detail.
281
+ const diagnostic = boundUtf8(`BLOCK: unknown --runtime ${JSON.stringify(runtime)} (expected ${BRANCH_PROTECTION_RUNTIMES.join(" or ")}); refusing`);
282
+ note(diagnostic);
283
+ return { exitCode: CODEX_EXIT_BLOCK, blocked: true, diagnostic };
284
+ }
285
+ // Every block flows through here, so the detail and the agent text are cut
286
+ // to a fixed size once, whatever they embed (a manifest parse error grows
287
+ // with the manifest). The envelope is built from the cut text with
288
+ // JSON.stringify, so the cut cannot break the JSON.
289
+ const block = async (detail, agentText) => {
290
+ const diagnostic = boundUtf8(`BLOCK: ${detail}`);
291
+ const bounded = boundUtf8(agentText);
292
+ note(diagnostic);
293
+ if (runtime === "codex") {
294
+ stderr.write(`${bounded}\n`);
295
+ return { exitCode: CODEX_EXIT_BLOCK, blocked: true, diagnostic };
296
+ }
297
+ const written = await writeAndAwait(stdout, `${claudeBlockEnvelope(bounded)}\n`, STDIO_DRAIN_TIMEOUT_MS);
298
+ if (written.delivered)
299
+ return { exitCode: 0, blocked: true, diagnostic };
300
+ // Exit 0 without the envelope would be read as an allow, so the block
301
+ // falls back to the exit code both runtimes read as one.
302
+ try {
303
+ stderr.write(`harness pack hook branch-protection: the block envelope could not be written to stdout (${written.why}); ` +
304
+ `exiting ${CODEX_EXIT_BLOCK} so the refusal still counts as a block.\n${bounded}\n`);
305
+ }
306
+ catch {
307
+ // best effort: stderr may be gone as well; the exit code carries the decision
308
+ }
309
+ return { exitCode: CODEX_EXIT_BLOCK, blocked: true, diagnostic };
310
+ };
311
+ // A read that timed out never received the whole event, so nothing can be
312
+ // judged: refuse (fail closed).
313
+ const read = await readStdinChecked(opts.stdin ?? process.stdin);
314
+ if (read.timedOut) {
315
+ const reason = `stdin timeout: no complete event arrived and closed on stdin within ${read.idleTimeoutMs} ms, ` +
316
+ `so branch-protection cannot judge the tool call and refuses it (fail closed). Retry the tool call.`;
317
+ return await block(reason, reason);
318
+ }
319
+ let parsed;
233
320
  try {
234
- event = JSON.parse(raw.trim() || "{}");
321
+ parsed = JSON.parse(read.text);
235
322
  }
236
323
  catch {
237
- /* event stays {} — handled by the sessionId check below */
324
+ parsed = undefined;
238
325
  }
239
- // Pause sentinel — even branch-protection (the strictest gate) yields
240
- // to an operator pause. The whole point of the incident-mode flow is
241
- // pushing a hotfix to a protected branch when normal gates are in the
242
- // way.
243
- if (checkHookPause("branch-protection", stderr, opts).paused) {
244
- const diagnostic = "harness paused; branch-protection allowing without evaluating.";
245
- return { exitCode: 0, blocked: false, diagnostic };
326
+ if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) {
327
+ const detail = "the event on stdin is not a JSON object";
328
+ return await block(detail, `branch-protection: refusing the tool call: ${detail}, so it cannot be judged.`);
246
329
  }
247
- const sessionId = (typeof event.session_id === "string" ? event.session_id : undefined) ??
248
- process.env.CLAUDE_CODE_SESSION_ID ??
249
- process.env.CLAUDE_SESSION_ID ??
250
- "";
251
- const toolName = typeof event.tool_name === "string" ? event.tool_name : "(unknown)";
252
- const cwd = typeof opts.cwd === "string" && opts.cwd.length > 0
253
- ? opts.cwd
254
- : typeof event.cwd === "string" && event.cwd.length > 0
255
- ? event.cwd
256
- : process.cwd();
257
- // Load manifest to resolve the protected-branches list AND the
258
- // grounding-mcp wiring. A manifest load failure forces BLOCK with a
259
- // clear hint — we can't know if the gate should fire if we can't
260
- // read its config.
261
- // Resolved manifest path feeds the harness.generated/ lookup below (the
262
- // override-marker directory). An injected manifest (tests) has no
263
- // on-disk path, so `generatedDir` falls back to opts.generatedDir.
330
+ const event = parsed;
331
+ const toolName = pickString(event.tool_name, event.tool) ?? "(unknown)";
332
+ const sessionId = pickString(event.session_id) ?? "";
333
+ const cwdText = pickString(opts.cwd, event.cwd) ?? process.cwd();
334
+ // Without the manifest the gate cannot know whether it is enabled or what
335
+ // is protected, so a load failure refuses.
264
336
  let manifest;
265
- let manifestPath;
266
337
  try {
267
- ({ manifest, manifestPath } = loadManifestOrInjected(opts, opts.manifest));
338
+ ({ manifest } = loadManifestOrInjected(opts, opts.manifest));
268
339
  }
269
340
  catch (err) {
270
- const reason = `manifest load failed (${err.message}); refusing on failsafe`;
271
- const diagnostic = `BLOCK — ${reason}`;
272
- note(diagnostic);
273
- // Manifest didn't load, so no ux config to honour; legacy
274
- // envelope is the only available surface here.
275
- stdout.write(`${blockJson(toolName, "(unresolvable)", reason, DEFAULT_PROTECTED_BRANCHES, undefined, sessionId)}\n`);
276
- return { exitCode: 0, blocked: true, diagnostic };
341
+ const detail = `the harness manifest could not be loaded (${err.message})`;
342
+ return await block(`${detail}; refusing on failsafe`, `branch-protection: refusing ${toolName}: ${detail}.`);
277
343
  }
278
344
  const pack = manifest.policy_packs.find((p) => p.name === PACK_NAME);
279
- if (!pack) {
280
- const diagnostic = `pack "${PACK_NAME}" not declared in manifest, allowing`;
281
- note(diagnostic);
282
- return { exitCode: 0, blocked: false, diagnostic };
283
- }
284
- if (!pack.enabled) {
285
- const diagnostic = `pack "${PACK_NAME}" is enabled:false, allowing`;
286
- note(diagnostic);
287
- return { exitCode: 0, blocked: false, diagnostic };
288
- }
345
+ if (!pack)
346
+ return allow(`pack "${PACK_NAME}" not declared in manifest, allowing`);
347
+ if (!pack.enabled)
348
+ return allow(`pack "${PACK_NAME}" is enabled:false, allowing`);
289
349
  const { branches: protectedList } = resolveProtectedBranches(pack);
290
350
  const configUx = parseConfigUx(pack.config["ux"], stderr, "harness pack hook branch-protection");
291
- // Resolve the branch context to gate against. For tools that target a
292
- // single file (Write, Edit, MultiEdit, NotebookEdit), the relevant
293
- // branch is whatever repo OWNS the target path — not cwd. Without this
294
- // step, a Write to `~/.claude/memory/foo.md` from inside a checkout on
295
- // a protected branch would be wrongly blocked, even though the target
296
- // is outside any repo (memory files), or inside an unrelated repo, and
297
- // the protection rules of cwd's repo have no bearing on it. For
298
- // path-less tools (Bash, etc.) we fall back to cwd as before.
299
- const targetPath = extractTargetPath(toolName, event.tool_input);
300
- let branchSourceDir = cwd;
301
- let branchSource = "cwd";
302
- if (targetPath !== null) {
303
- const absTarget = path.isAbsolute(targetPath)
304
- ? targetPath
305
- : path.resolve(cwd, targetPath);
306
- branchSourceDir = path.dirname(absTarget);
307
- branchSource = "target";
308
- }
309
- const { branch } = resolveGitContext(branchSourceDir);
310
- // Outside a git work tree (or detached HEAD) we can't tell what the
311
- // edit would land on. We choose to allow here — the alternative is
312
- // blocking every Write in non-git workspaces, which would be hostile
313
- // to standalone-script workflows and to writes that target machine
314
- // state under $HOME / /tmp. A detached HEAD on an in-repo target also
315
- // lands here; arguably should block, but detached-HEAD edits don't
316
- // auto-push to a protected ref so the downstream
317
- // `preflight-before-push` gate still catches the actual hazard.
318
- if (branch === "") {
319
- const diagnostic = `${branchSource} is not on a named branch (detached HEAD or outside a git work tree); allowing`;
320
- note(diagnostic);
321
- return { exitCode: 0, blocked: false, diagnostic };
322
- }
323
- if (!protectedList.includes(branch)) {
324
- const diagnostic = `branch "${branch}" is not in the protected list (${protectedList.join(", ")}); allowing`;
325
- note(diagnostic);
326
- return { exitCode: 0, blocked: false, diagnostic };
327
- }
328
- // On a protected branch: probe the ledger for either gate path.
329
- if (sessionId === "") {
330
- const reason = `no session_id resolvable from stdin or $CLAUDE_CODE_SESSION_ID/$CLAUDE_SESSION_ID; cannot consult ledger`;
331
- const diagnostic = `BLOCK — ${reason}`;
332
- note(diagnostic);
333
- stdout.write(`${blockJson(toolName, branch, reason, protectedList, configUx, sessionId)}\n`);
334
- return { exitCode: 0, blocked: true, diagnostic };
335
- }
336
- const check = await probeLedger(manifest, sessionId, opts);
337
- // Override path (operator-only). The canonical override signal is a
338
- // marker file under harness.generated/.approvals/ that only a process
339
- // the operator launched can write — NOT the `branch-protection-ack`
340
- // ledger tag, which the agent can self-write via its own ledger_add MCP
341
- // access (audit finding #39; the understanding gate closed the identical
342
- // backdoor in agent-tasks/88ca4bb3). The ledger ack, if present, is
343
- // surfaced as a best-effort audit echo only. `generatedDir` is
344
- // unresolvable only on the test-injection path (an injected manifest has
345
- // no on-disk path and no opts.generatedDir); there the override is
346
- // simply unavailable and the gate falls through to the producer check.
347
- const generatedDir = opts.generatedDir ??
348
- (manifestPath !== undefined
349
- ? resolveGeneratedDir({
350
- ...(opts.homeDir !== undefined ? { homeDir: opts.homeDir } : {}),
351
- manifestPath,
352
- })
353
- : undefined);
354
- // Best-effort audit echo of the now-untrusted ledger ack, appended to
355
- // diagnostics so an operator chasing the gate can see the historic tag
356
- // without it being mistaken for the thing that opened (or failed to
357
- // open) the gate.
358
- const ackEcho = check.hasAck
359
- ? ` [audit: ledger ${check.ackContent ?? ACK_TAG_PREFIX} present, no longer satisfies the gate]`
360
- : "";
361
- // Distinct audit note when the override marker FILE existed but failed
362
- // signature verification (harness/f9485cc7) — missing/invalid signature,
363
- // wrong alg, or a tampered payload — so it reads apart from the routine
364
- // "no operator override marker" case below.
365
- let markerForgedNote = "";
366
- if (generatedDir !== undefined) {
367
- const markerCheck = checkBranchProtectionMarker(generatedDir, sessionId);
368
- if (markerCheck.matched) {
369
- const diagnostic = `branch-protection override marker active (${markerCheck.detail}); allowing${ackEcho}`;
370
- note(diagnostic);
371
- return { exitCode: 0, blocked: false, diagnostic };
372
- }
373
- if (markerCheck.forged) {
374
- markerForgedNote = ` [forged/unsigned override marker rejected: ${markerCheck.detail}]`;
351
+ const deadlineMs = opts.gitDeadlineMs ?? GIT_READ_DEADLINE_MS;
352
+ const perCallMs = opts.gitTimeoutMs ?? GIT_BRANCH_TIMEOUT_MS;
353
+ const deadline = startedAt + deadlineMs;
354
+ const bound = { overBound: () => now() >= deadline, memo: new Map() };
355
+ const asWritten = {
356
+ targets: (res) => asWrittenTargets(toolName, event.tool_input, path.resolve(cwdText), res),
357
+ at: (dir) => ({ kind: "path", path: dir }),
358
+ };
359
+ const physical = {
360
+ targets: (res) => checkTargets(toolName, event, absolutePath(cwdText), res),
361
+ at: resolveDirectory,
362
+ };
363
+ // Both judgments, the as-written one first: the hook allows only what both allow.
364
+ const judgments = [asWritten, physical];
365
+ // Each directory git ran in is read once per event.
366
+ const answers = new Map();
367
+ const sources = [];
368
+ const seen = [];
369
+ try {
370
+ for (const judgment of judgments) {
371
+ const targets = judgment.targets(bound);
372
+ if (!sources.includes(targets.source))
373
+ sources.push(targets.source);
374
+ for (const dir of targets.dirs) {
375
+ const remaining = deadline - now();
376
+ if (remaining <= 0) {
377
+ const detail = `the branch of ${dir} was not checked: the hook passed its ${deadlineMs} ms bound`;
378
+ return await block(detail, `branch-protection: refusing ${toolName}: git could not report the branch of ${dir} (${detail}).`);
379
+ }
380
+ const at = judgment.at(dir);
381
+ let branchRead;
382
+ if (at.kind === "error") {
383
+ branchRead = at;
384
+ }
385
+ else {
386
+ const known = answers.get(at.path);
387
+ if (known !== undefined)
388
+ continue;
389
+ branchRead = await readBranchAt(at.path, {
390
+ ...(opts.gitReader !== undefined ? { reader: opts.gitReader } : {}),
391
+ timeoutMs: Math.min(perCallMs, remaining),
392
+ });
393
+ answers.set(at.path, branchRead);
394
+ }
395
+ switch (branchRead.kind) {
396
+ case "error":
397
+ return await block(`git could not report the branch of ${dir}: ${branchRead.detail}`, `branch-protection: refusing ${toolName}: git could not report the branch of ${dir} (${branchRead.detail}).`);
398
+ case "branch":
399
+ if (isProtectedBranch(branchRead.name, protectedList)) {
400
+ return await block(`branch "${branchRead.name}" of ${dir} is protected (${protectedList.join(", ")})`, protectedBranchText(toolName, branchRead.name, dir, protectedList, configUx, sessionId));
401
+ }
402
+ seen.push(`${dir}: branch "${branchRead.name}" is not in the protected list (${protectedList.join(", ")})`);
403
+ break;
404
+ case "detached":
405
+ seen.push(`${dir}: detached HEAD`);
406
+ break;
407
+ case "outside":
408
+ seen.push(`${dir}: outside any git repository`);
409
+ break;
410
+ }
411
+ }
375
412
  }
376
413
  }
377
- if (check.hasFreshProducer) {
378
- const diagnostic = `fresh producer tag (${check.freshProducerContent ?? NON_PROTECTED_TAG_PREFIX}); allowing`;
379
- note(diagnostic);
380
- return { exitCode: 0, blocked: false, diagnostic };
414
+ catch (err) {
415
+ // Fail closed: a path that could not be resolved within the bound, or
416
+ // any other failure while judging, refuses.
417
+ const detail = err instanceof PathBoundError
418
+ ? `the paths of the tool call were not resolved: the hook passed its ${deadlineMs} ms bound`
419
+ : `the tool call could not be judged (${err instanceof Error ? err.message : String(err)})`;
420
+ return await block(detail, `branch-protection: refusing ${toolName}: ${detail}.`);
381
421
  }
382
- const why = check.degraded !== null
383
- ? `ledger degraded (${check.degraded}); refusing on failsafe`
384
- : `no fresh ${NON_PROTECTED_TAG_PREFIX} tag (${check.totalEntries} entries scanned) and no operator override marker${ackEcho}${markerForgedNote}`;
385
- const diagnostic = `BLOCK — ${why}`;
386
- note(diagnostic);
387
- stdout.write(`${blockJson(toolName, branch, why, protectedList, configUx, sessionId)}\n`);
388
- return { exitCode: 0, blocked: true, diagnostic };
389
- }
390
- /**
391
- * `harness pack hook branch-protection`. A stdin read that times out is refused here
392
- * instead of being handed to the gate as an empty or truncated event it would
393
- * treat as malformed input (task 7dfdcaaf). The operator pause still wins;
394
- * every other input runs the gate unchanged.
395
- */
396
- export function runPackHookBranchProtectionCli(opts = {}) {
397
- return runGateWithStdinRefusal(opts, (stderr) => checkHookPause("branch-protection", stderr, opts).paused, stdoutBlockRefusal("branch-protection"), runPackHookBranchProtectionCliInner);
422
+ return allow(`${sources.join("+")} ${seen.join("; ")}; allowing`);
398
423
  }
399
424
  //# sourceMappingURL=hook-branch-protection.js.map