@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,797 +0,0 @@
1
- // `harness session-start toolchain-parity` — SessionStart hook entrypoint,
2
- // third sibling of `harness session-start preflight` / `branch-check`.
3
- //
4
- // Anlass: the 2026-07-22 PATH-shim incident, where a machine ran an entire
5
- // session unnoticed on Node 22 + understanding-gate 0.4.6 instead of the
6
- // intended Node 26 + 0.4.9 — nothing on that machine ever compared its own
7
- // toolchain against any other machine's. This producer closes that gap,
8
- // purely advisorily:
9
- //
10
- // (a) writes a toolchain snapshot of THIS machine to
11
- // `<machineStateDir>/<ownProfile>.json` (owner-writes-only — every
12
- // OTHER `*.json` in that directory is read-only input, never
13
- // touched);
14
- // (b) compares the local LIVE toolchain state against every peer
15
- // snapshot file already in that directory;
16
- // (c) reports drift as stderr warning lines plus a single
17
- // `toolchain-parity:ok` / `toolchain-parity:drift:<n>` ledger fact,
18
- // with a `:unparseable-peer:<n>` suffix appended whenever one or more
19
- // peer files failed to parse as JSON (task 690fba7c, follow-up from
20
- // the agent-memory 06d09cde incident: an unparseable peer snapshot is
21
- // a real corruption/drift signal and must not vanish from `drift:N`
22
- // as if it had been a complete comparison).
23
- //
24
- // Transport of the snapshot files BETWEEN machines is entirely
25
- // agent-memory-sync's job (agent-memory PR #64, already shipped) — this
26
- // module only ever reads/writes the local directory.
27
- //
28
- // SessionStart contract, same as the two siblings: `blocking:false`. Every
29
- // failure path (not configured, mkdir/write/read failure, a broken peer
30
- // file, a spawn timeout, a ledger-write failure) logs one line to stderr
31
- // and exits 0. There is no "gate" this producer can leave closed — it is
32
- // purely advisory, so degrading silently (well, LOUDLY on stderr, just
33
- // never blocking) is always the right move.
34
- import { execFile } from "node:child_process";
35
- import * as fs from "node:fs";
36
- import * as os from "node:os";
37
- import * as path from "node:path";
38
- import { readTopLevelMcpServers, resolveClaudeUserRegistryPath, } from "../../io/claude-mcp.js";
39
- import { assertNoRealSpawnInTests } from "../../runtime/hermetic-spawn-guard.js";
40
- import { resolveManifestLedgerWriter } from "../../runtime/ledger-writer.js";
41
- import { resolveReadSessionId, } from "../../runtime/session-id.js";
42
- import { loadManifest } from "../loader.js";
43
- import { classifySessionSource, explicitSessionId, FALLBACK_SESSION, malformedEventReason, readSessionStartEvent, resolveEventCwd, } from "./shared-options.js";
44
- const LEDGER_SOURCE = "harness-session-start-toolchain-parity";
45
- const SNAPSHOT_SCHEMA_VERSION = 1;
46
- // Individual spawn ceilings, not the expected duration: `node --version`
47
- // and `npm ls -g --depth=0 --json` run IN PARALLEL (Promise.all in
48
- // collectLocalSnapshot below), so the wall-time contribution of the two
49
- // spawns together is max(nodeTimeoutMs, npmTimeoutMs), not their sum.
50
- // Combined with two near-instant fs reads (OW-Kit version, MCP registry)
51
- // and a SEQUENTIAL ledger write afterwards, the worst-case wall-time this
52
- // hook needs against its configured `budget_ms` (and how much headroom
53
- // that leaves) is analyzed once, at the hook's own `budget_ms`
54
- // declaration in src/cli/init/templates.ts — search "toolchain-parity"
55
- // there. That comment is the single place the number lives; this one
56
- // deliberately does not restate it (task c1b5ade5 R2, closing a drift
57
- // between the two comments a prior round introduced).
58
- const DEFAULT_NODE_TIMEOUT_MS = 2_000;
59
- const DEFAULT_NPM_GLOBALS_TIMEOUT_MS = 4_000;
60
- /**
61
- * Profile names land in a filename; strip anything not filename-safe.
62
- * Exported (task 13919613) so `harness doctor`'s toolchain-parity section
63
- * can resolve the SAME own-profile filename this producer would, without
64
- * re-implementing the sanitization rule. Pure export, no behaviour change
65
- * to any call site in this module.
66
- */
67
- export function sanitizeProfileName(value) {
68
- const cleaned = value.replace(/[^a-zA-Z0-9._-]/g, "-");
69
- return cleaned.length > 0 ? cleaned : "profile";
70
- }
71
- function isRecordOfStrings(x) {
72
- return (typeof x === "object" &&
73
- x !== null &&
74
- !Array.isArray(x) &&
75
- Object.values(x).every((v) => typeof v === "string"));
76
- }
77
- /**
78
- * Parse a stored snapshot JSON. Rejects (`ok:false`) only on the shapes
79
- * that make comparison meaningless — not valid JSON, not an object,
80
- * missing/invalid `profile` or `timestamp`. Every other field degrades
81
- * leniently (missing/malformed -> empty/absent) rather than rejecting the
82
- * whole file, since a peer snapshot written by a future schema version
83
- * should still compare on the fields this version understands.
84
- */
85
- export function parseSnapshotJson(raw) {
86
- let parsed;
87
- try {
88
- parsed = JSON.parse(raw);
89
- }
90
- catch (err) {
91
- return { ok: false, reason: `not valid JSON: ${err.message}` };
92
- }
93
- if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) {
94
- return { ok: false, reason: "not a JSON object" };
95
- }
96
- const p = parsed;
97
- if (typeof p["profile"] !== "string" || p["profile"].length === 0) {
98
- return { ok: false, reason: "missing or invalid `profile` field" };
99
- }
100
- if (typeof p["timestamp"] !== "string" || Number.isNaN(Date.parse(p["timestamp"]))) {
101
- return { ok: false, reason: "missing or invalid `timestamp` field" };
102
- }
103
- const snapshot = {
104
- schemaVersion: SNAPSHOT_SCHEMA_VERSION,
105
- profile: p["profile"],
106
- timestamp: p["timestamp"],
107
- npmGlobals: isRecordOfStrings(p["npmGlobals"]) ? p["npmGlobals"] : {},
108
- mcpServers: Array.isArray(p["mcpServers"]) && p["mcpServers"].every((v) => typeof v === "string")
109
- ? p["mcpServers"]
110
- : [],
111
- };
112
- if (typeof p["node"] === "string")
113
- snapshot.node = p["node"];
114
- if (typeof p["nodeError"] === "string")
115
- snapshot.nodeError = p["nodeError"];
116
- if (typeof p["npmGlobalsError"] === "string")
117
- snapshot.npmGlobalsError = p["npmGlobalsError"];
118
- if (typeof p["owKitVersion"] === "string")
119
- snapshot.owKitVersion = p["owKitVersion"];
120
- if (typeof p["owKitError"] === "string")
121
- snapshot.owKitError = p["owKitError"];
122
- if (typeof p["mcpServersError"] === "string")
123
- snapshot.mcpServersError = p["mcpServersError"];
124
- return { ok: true, snapshot };
125
- }
126
- /**
127
- * Hermetic guard (mirrors `realNpmExec` in src/cli/doctor/npm-bin-path.ts):
128
- * asserts BEFORE touching `child_process` that we are not running under
129
- * vitest without a test having injected `runNodeVersion`. This function has
130
- * no try/catch around the assertion, and its only caller,
131
- * `collectLocalSnapshot`, calls it (via the `runNodeVersion` param, defaulted
132
- * to this function in `runSessionStartToolchainParity`) with no surrounding
133
- * try/catch either — see src/runtime/hermetic-spawn-guard.ts for why that
134
- * matters (a thrown `HermeticSpawnViolationError` must propagate, not be
135
- * folded into an ordinary "collection failed" outcome).
136
- *
137
- * PATH-resolved deliberately: `execFile("node", ...)` does a PATH lookup for
138
- * the literal string "node", NOT `process.execPath` — the entire point of
139
- * this collector is capturing the PATH state of the *shell* the session
140
- * runs in (the PATH-shim incident this task follows up on was exactly a
141
- * PATH pointing at the wrong node), which `process.version` (the node
142
- * running THIS harness process) would silently paper over.
143
- *
144
- * Exported (task 13919613) so `harness doctor`'s toolchain-parity section
145
- * can default its own `runNodeVersion` injection knob to the SAME real
146
- * collector this producer uses — the whole point of the reuse is that
147
- * doctor never re-implements this spawn/parse logic. No behaviour change:
148
- * this is the exact function every existing call site already used.
149
- */
150
- export function realNodeVersionSpawn(timeoutMs) {
151
- assertNoRealSpawnInTests("node --version", "Inject a fake `runNodeVersion` (SessionStartToolchainParityOptions.runNodeVersion) instead of exercising the real spawn path.");
152
- return new Promise((resolve) => {
153
- execFile("node", ["--version"], { timeout: timeoutMs, encoding: "utf8" }, (err, stdout) => {
154
- const text = (stdout ?? "").trim();
155
- if (text.length > 0) {
156
- resolve({ ok: true, version: text });
157
- return;
158
- }
159
- if (err) {
160
- const e = err;
161
- if (e.code === "ENOENT") {
162
- resolve({ ok: false, reason: "`node` not on PATH" });
163
- return;
164
- }
165
- if (e.killed) {
166
- resolve({ ok: false, reason: `\`node --version\` timed out after ${timeoutMs}ms` });
167
- return;
168
- }
169
- resolve({ ok: false, reason: `\`node --version\` failed: ${e.message}` });
170
- return;
171
- }
172
- resolve({ ok: false, reason: "`node --version` produced no output" });
173
- });
174
- });
175
- }
176
- /**
177
- * Hermetic guard, same shape/rationale as {@link realNodeVersionSpawn} —
178
- * see that function's doc. Tolerant of a non-zero exit the same way
179
- * `spawnPreflight` (session-start/index.ts) is tolerant of `preflight run`'s
180
- * exit code: `npm ls -g` can exit non-zero on an unrelated extraneous/
181
- * invalid global entry while still emitting a perfectly parseable
182
- * `dependencies` JSON block, so a parseable stdout wins over the exit code.
183
- *
184
- * Exported (task 13919613) for the same reuse reason as
185
- * {@link realNodeVersionSpawn} — `harness doctor`'s toolchain-parity
186
- * section defaults to this real collector rather than duplicating it.
187
- */
188
- export function realNpmGlobalsSpawn(timeoutMs) {
189
- assertNoRealSpawnInTests("npm ls -g --depth=0 --json", "Inject a fake `runNpmGlobals` (SessionStartToolchainParityOptions.runNpmGlobals) instead of exercising the real spawn path.");
190
- return new Promise((resolve) => {
191
- execFile("npm", ["ls", "-g", "--depth=0", "--json"], { timeout: timeoutMs, maxBuffer: 8 * 1024 * 1024, encoding: "utf8" }, (err, stdout) => {
192
- const text = (stdout ?? "").trim();
193
- if (text.length > 0) {
194
- try {
195
- const parsed = JSON.parse(text);
196
- const packages = {};
197
- for (const [name, entry] of Object.entries(parsed.dependencies ?? {})) {
198
- if (typeof entry?.version === "string")
199
- packages[name] = entry.version;
200
- }
201
- resolve({ ok: true, packages });
202
- return;
203
- }
204
- catch {
205
- /* fall through to the error path */
206
- }
207
- }
208
- if (err) {
209
- const e = err;
210
- if (e.code === "ENOENT") {
211
- resolve({ ok: false, reason: "`npm` not on PATH" });
212
- return;
213
- }
214
- if (e.killed) {
215
- resolve({
216
- ok: false,
217
- reason: `\`npm ls -g --depth=0 --json\` timed out after ${timeoutMs}ms`,
218
- });
219
- return;
220
- }
221
- resolve({ ok: false, reason: `\`npm ls -g\` failed: ${e.message}` });
222
- return;
223
- }
224
- resolve({ ok: false, reason: "`npm ls -g --depth=0 --json` produced no parseable JSON" });
225
- });
226
- });
227
- }
228
- /**
229
- * Read `<workspaceRoot>/.ai/workflow/manifest.json`'s `version` field
230
- * (the orchestrator-workflow kit's own version marker). A missing file is
231
- * the expected common case (most repos are not OW-kit-managed) and is
232
- * NOT an error — it degrades silently to `{}`. Malformed JSON or a
233
- * non-string `version` field on a manifest that DOES exist is noteworthy
234
- * (something is there but broken), so that degrades to `{ error }`.
235
- *
236
- * Exported (task 13919613) for the same reuse reason as
237
- * {@link realNodeVersionSpawn}.
238
- */
239
- export function realReadOwKitVersion(workspaceRoot) {
240
- const manifestPath = path.join(workspaceRoot, ".ai", "workflow", "manifest.json");
241
- let raw;
242
- try {
243
- raw = fs.readFileSync(manifestPath, "utf8");
244
- }
245
- catch (err) {
246
- const e = err;
247
- if (e.code === "ENOENT")
248
- return {};
249
- return { error: `cannot read ${manifestPath}: ${e.message}` };
250
- }
251
- let parsed;
252
- try {
253
- parsed = JSON.parse(raw);
254
- }
255
- catch (err) {
256
- return { error: `${manifestPath} is not valid JSON: ${err.message}` };
257
- }
258
- if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) {
259
- return { error: `${manifestPath} is not a JSON object` };
260
- }
261
- const version = parsed["version"];
262
- if (typeof version !== "string" || version.length === 0) {
263
- return { error: `${manifestPath} has no string \`version\` field` };
264
- }
265
- return { version };
266
- }
267
- /**
268
- * MCP server names from Claude Code's user-scope registry — a pure FILE
269
- * READ (never a spawn), reusing the exact primitive `harness doctor`'s
270
- * claude-mcp check ultimately compares against
271
- * (`resolveClaudeUserRegistryPath` + `readTopLevelMcpServers` in
272
- * src/io/claude-mcp.ts — the same functions `adopt`/`detect` use for the
273
- * same "read the effective registration from outside io/claude-mcp.ts"
274
- * purpose). Deliberately NOT `claude mcp list` (a spawn): the brief calls
275
- * for a file-read source for the NAMES here, and this is it.
276
- *
277
- * Exported (task 13919613) for the same reuse reason as
278
- * {@link realNodeVersionSpawn}.
279
- */
280
- export function realReadMcpServerNames() {
281
- const registryPath = resolveClaudeUserRegistryPath();
282
- const { servers, error } = readTopLevelMcpServers(registryPath);
283
- if (error !== null)
284
- return { names: [], error };
285
- return { names: Object.keys(servers).sort() };
286
- }
287
- /**
288
- * Collect the local, LIVE toolchain snapshot. Never throws (every
289
- * collector above degrades to `{ok:false,reason}` / `{error}` instead of
290
- * rejecting/throwing) — a collection failure is reported both inline on
291
- * the returned snapshot (the matching `*Error` field) AND as a `notes`
292
- * line for the caller to log, but never stops the other collectors from
293
- * running. node/npm run in PARALLEL (see the timeout constants' comment
294
- * above for why).
295
- *
296
- * Exported (task 13919613): `harness doctor`'s toolchain-parity section
297
- * imports this directly as its Collector core — see that module's header
298
- * for the reuse rationale. No behaviour change to this function or any
299
- * existing call site.
300
- */
301
- export async function collectLocalSnapshot(opts) {
302
- const notes = [];
303
- const [nodeResult, npmResult] = await Promise.all([
304
- opts.runNodeVersion(opts.nodeTimeoutMs),
305
- opts.runNpmGlobals(opts.npmTimeoutMs),
306
- ]);
307
- const owKit = opts.readOwKitVersion(opts.workspaceRoot);
308
- const mcp = opts.readMcpServerNames();
309
- const snapshot = {
310
- schemaVersion: SNAPSHOT_SCHEMA_VERSION,
311
- profile: opts.profile,
312
- timestamp: opts.now.toISOString(),
313
- npmGlobals: {},
314
- mcpServers: [],
315
- };
316
- if (nodeResult.ok) {
317
- snapshot.node = nodeResult.version;
318
- }
319
- else {
320
- snapshot.nodeError = nodeResult.reason;
321
- notes.push(`node --version: ${nodeResult.reason}`);
322
- }
323
- if (npmResult.ok) {
324
- snapshot.npmGlobals = npmResult.packages;
325
- }
326
- else {
327
- snapshot.npmGlobalsError = npmResult.reason;
328
- notes.push(`npm ls -g: ${npmResult.reason}`);
329
- }
330
- if (owKit.version !== undefined)
331
- snapshot.owKitVersion = owKit.version;
332
- if (owKit.error !== undefined) {
333
- snapshot.owKitError = owKit.error;
334
- notes.push(`OW-Kit version: ${owKit.error}`);
335
- }
336
- if (mcp.error !== undefined) {
337
- snapshot.mcpServersError = mcp.error;
338
- notes.push(`MCP server names: ${mcp.error}`);
339
- }
340
- else {
341
- snapshot.mcpServers = mcp.names;
342
- }
343
- return { snapshot, notes };
344
- }
345
- // ---------------------------------------------------------------------
346
- // Snapshot write (own profile only) + peer comparison
347
- // ---------------------------------------------------------------------
348
- /**
349
- * Write ONLY `<machineStateDir>/<ownFileName>` (mkdir -p first). Never
350
- * touches any other file in the directory — the caller passes exactly
351
- * `sanitizeProfileName(profile) + ".json"`, so there is no path this
352
- * function could take that reaches a peer's file.
353
- */
354
- function writeOwnSnapshot(machineStateDir, ownFileName, snapshot) {
355
- const filePath = path.join(machineStateDir, ownFileName);
356
- try {
357
- fs.writeFileSync(filePath, `${JSON.stringify(snapshot, null, 2)}\n`, "utf8");
358
- return { ok: true, path: filePath };
359
- }
360
- catch (err) {
361
- return { ok: false, reason: err.message };
362
- }
363
- }
364
- /** `"just now"` / `"<n>m"` / `"<n>h"` / `"<n>d"` — coarse, human-scannable. */
365
- export function formatSnapshotAge(ageMs) {
366
- if (ageMs < 60_000)
367
- return "just now";
368
- const minutes = Math.floor(ageMs / 60_000);
369
- if (minutes < 60)
370
- return `${minutes}m`;
371
- const hours = Math.floor(minutes / 60);
372
- if (hours < 48)
373
- return `${hours}h`;
374
- return `${Math.floor(hours / 24)}d`;
375
- }
376
- /**
377
- * Compare the local LIVE snapshot against one peer's stored snapshot.
378
- * Node / OW-Kit drift only fires when BOTH sides collected that field
379
- * successfully (an unavailable field reads as "unknown", not "match" or
380
- * "drift"). The npm-globals and MCP-name comparisons additionally gate on
381
- * the WHOLE field having collected without error on both sides — an
382
- * `npmGlobalsError`/`mcpServersError` on either side means that side's map
383
- * is "unknown", not "empty", and treating it as empty would fabricate a
384
- * wall of "missing on N packages" drift instead of the real gap (which the
385
- * caller's own note()s already surface separately, from collectLocalSnapshot's
386
- * `notes` and the peer-unreadable path).
387
- */
388
- export function compareToPeer(local, peer, now) {
389
- const drift = [];
390
- const peerProfile = peer.profile;
391
- if (local.node !== undefined && peer.node !== undefined && local.node !== peer.node) {
392
- drift.push({
393
- kind: "node",
394
- message: `node version: local ${local.node} vs peer ${peerProfile} ${peer.node}`,
395
- });
396
- }
397
- if (local.owKitVersion !== undefined &&
398
- peer.owKitVersion !== undefined &&
399
- local.owKitVersion !== peer.owKitVersion) {
400
- drift.push({
401
- kind: "ow_kit",
402
- message: `orchestrator-workflow kit version: local ${local.owKitVersion} vs peer ${peerProfile} ${peer.owKitVersion}`,
403
- });
404
- }
405
- if (local.npmGlobalsError === undefined && peer.npmGlobalsError === undefined) {
406
- const names = [...new Set([...Object.keys(local.npmGlobals), ...Object.keys(peer.npmGlobals)])].sort();
407
- for (const name of names) {
408
- const lv = local.npmGlobals[name];
409
- const pv = peer.npmGlobals[name];
410
- if (lv !== undefined && pv !== undefined) {
411
- if (lv !== pv) {
412
- drift.push({
413
- kind: "npm_package_version",
414
- message: `npm global \`${name}\`: local ${lv} vs peer ${peerProfile} ${pv}`,
415
- });
416
- }
417
- }
418
- else if (lv !== undefined) {
419
- drift.push({
420
- kind: "npm_package_missing_peer",
421
- message: `npm global \`${name}\`: local ${lv}, missing on peer ${peerProfile}`,
422
- });
423
- }
424
- else if (pv !== undefined) {
425
- drift.push({
426
- kind: "npm_package_missing_local",
427
- message: `npm global \`${name}\`: missing locally, peer ${peerProfile} has ${pv}`,
428
- });
429
- }
430
- }
431
- }
432
- if (local.mcpServersError === undefined && peer.mcpServersError === undefined) {
433
- const localSet = new Set(local.mcpServers);
434
- const peerSet = new Set(peer.mcpServers);
435
- const names = [...new Set([...localSet, ...peerSet])].sort();
436
- for (const name of names) {
437
- if (localSet.has(name) && !peerSet.has(name)) {
438
- drift.push({
439
- kind: "mcp_missing_peer",
440
- message: `mcp server \`${name}\`: registered locally, missing on peer ${peerProfile}`,
441
- });
442
- }
443
- else if (!localSet.has(name) && peerSet.has(name)) {
444
- drift.push({
445
- kind: "mcp_missing_local",
446
- message: `mcp server \`${name}\`: missing locally, registered on peer ${peerProfile}`,
447
- });
448
- }
449
- }
450
- }
451
- const peerTimeMs = Date.parse(peer.timestamp);
452
- const ageMs = Number.isFinite(peerTimeMs) ? Math.max(0, now.getTime() - peerTimeMs) : 0;
453
- return { peerProfile, ageMs, drift };
454
- }
455
- /**
456
- * Exported (task 13919613) so `harness doctor`'s toolchain-parity section
457
- * resolves the SAME default machine-state directory this producer writes
458
- * to when `toolchain_parity.machine_state_dir` is omitted from the
459
- * manifest — reusing the constant instead of re-deriving it.
460
- */
461
- export function defaultMachineStateDir() {
462
- return path.join(os.homedir(), ".harness", "machine-state");
463
- }
464
- export async function runSessionStartToolchainParity(opts = {}) {
465
- const stdin = opts.stdin ?? process.stdin;
466
- const stderr = opts.stderr ?? process.stderr;
467
- const now = opts.now ?? new Date();
468
- const nodeTimeoutMs = opts.nodeTimeoutMs ?? DEFAULT_NODE_TIMEOUT_MS;
469
- const npmTimeoutMs = opts.npmTimeoutMs ?? DEFAULT_NPM_GLOBALS_TIMEOUT_MS;
470
- const note = (msg) => {
471
- // CR/LF strip, ONCE, at this choke point (task c1b5ade5 R2b, closing
472
- // what R2's per-site sanitizeProfileName wraps left open): every
473
- // note() call writes exactly one stderr line prefixed with
474
- // "harness session-start toolchain-parity: ". Untrusted, cross-machine-
475
- // synced content reaches a note() argument through roughly ten call
476
- // sites below — a peer's `profile` field, a peer filename, and an
477
- // npm/mcp/node/owKitVersion value embedded in a compareToPeer drift
478
- // message — and R2 sanitized only 2 of them (the collision and stale
479
- // notes), leaving the rest (the "ok against"/"drift:N against" lines,
480
- // every individual drift message, and two of the three peer-file-read
481
- // notes) able to have a crafted `\n` forge a standalone fake parity
482
- // line. Stripping CR/LF here closes the whole class by construction,
483
- // regardless of which site the untrusted string flows through or
484
- // whether a future site remembers to sanitize its own argument.
485
- stderr.write(`harness session-start toolchain-parity: ${msg.replace(/[\r\n]/g, " ")}\n`);
486
- };
487
- const done = (wrote, profile, peersCompared, driftCount, sessionId, sessionSource, reason, unparseablePeerCount = 0) => ({
488
- exitCode: 0,
489
- wrote,
490
- profile,
491
- peersCompared,
492
- driftCount,
493
- unparseablePeerCount,
494
- sessionId,
495
- sessionSource,
496
- ...(reason !== undefined && { reason }),
497
- });
498
- let event;
499
- try {
500
- event = await readSessionStartEvent(stdin, {
501
- onTimeout: note,
502
- ...(opts.stdinIdleTimeoutMs !== undefined && { idleTimeoutMs: opts.stdinIdleTimeoutMs }),
503
- });
504
- }
505
- catch (err) {
506
- const reason = malformedEventReason(err);
507
- note(reason);
508
- return done(false, "", 0, 0, FALLBACK_SESSION, "default", reason);
509
- }
510
- const cwd = resolveEventCwd(opts.cwd, event);
511
- // Session id resolution: same precedence chain as the two siblings, so
512
- // all three producers stay symmetric.
513
- const explicit = explicitSessionId(opts.session, event);
514
- const resolveSession = opts.resolveSession ?? resolveReadSessionId;
515
- // Defensive (task c1b5ade5): a session resolver that throws (real or
516
- // injected) must degrade to the same FALLBACK_SESSION every OTHER "no
517
- // session known" path already uses, not crash a producer whose whole
518
- // contract is "never break the session loop". Unlike collectLocalSnapshot
519
- // below, this call is NOT part of the hermetic-spawn-guard contract, so
520
- // wrapping it here does not swallow a HermeticSpawnViolationError.
521
- let sessionId;
522
- // Task c1b5ade5 R2 (finding 3): a throw here always degrades sessionId to
523
- // FALLBACK_SESSION below, but sessionSource's ternary was computed purely
524
- // from `opts.session`/`event.session_id`/`sessionId` — so a stdin event
525
- // that DID carry a `session_id` still reported sessionSource "stdin" even
526
- // though the id actually recorded was "default" (the resolver never ran
527
- // to completion). That both misrepresents the ledger fact's provenance
528
- // and suppresses the AC5 "resolved to default" warning below, which only
529
- // fires when sessionSource === "default". `resolverThrew` short-circuits
530
- // sessionSource to "default" whenever the catch below fired, regardless
531
- // of what `explicit`/`event.session_id` looked like.
532
- let resolverThrew = false;
533
- try {
534
- sessionId = resolveSession(explicit, {});
535
- }
536
- catch (err) {
537
- note(`session id resolution failed: ${err.message}; falling back to session "${FALLBACK_SESSION}"`);
538
- sessionId = FALLBACK_SESSION;
539
- resolverThrew = true;
540
- }
541
- const sessionSource = classifySessionSource(opts.session, event, sessionId, resolverThrew);
542
- let manifest;
543
- if (opts.manifest) {
544
- manifest = opts.manifest;
545
- }
546
- else {
547
- try {
548
- manifest = loadManifest(opts).manifest;
549
- }
550
- catch (err) {
551
- const reason = `manifest load failed: ${err.message}`;
552
- note(reason);
553
- return done(false, "", 0, 0, sessionId, sessionSource, reason);
554
- }
555
- }
556
- const config = manifest.toolchain_parity;
557
- if (!config.enabled) {
558
- const reason = "not configured (add `toolchain_parity: { enabled: true }` to harness.yaml); skipping";
559
- note(reason);
560
- return done(false, "", 0, 0, sessionId, sessionSource, reason);
561
- }
562
- const machineStateDir = config.machine_state_dir ?? defaultMachineStateDir();
563
- const profile = config.profile ?? sanitizeProfileName(os.hostname());
564
- const workspaceRoot = config.workspace_root ?? cwd;
565
- const sanitizedProfile = sanitizeProfileName(profile);
566
- const ownFileName = `${sanitizedProfile}.json`;
567
- // Advisory staleness threshold (AC3, task c1b5ade5): undefined disables
568
- // the check entirely, matching the schema's default-off comment.
569
- const staleAfterMs = config.stale_after_days !== undefined ? config.stale_after_days * 24 * 60 * 60 * 1000 : undefined;
570
- try {
571
- fs.mkdirSync(machineStateDir, { recursive: true });
572
- }
573
- catch (err) {
574
- const reason = `cannot create/access machine-state dir ${machineStateDir}: ${err.message}`;
575
- note(reason);
576
- return done(false, profile, 0, 0, sessionId, sessionSource, reason);
577
- }
578
- // Lossy-sanitization advisory (task c1b5ade5): a `profile` configured
579
- // with characters that are not filename-safe silently loses information
580
- // when sanitizeProfileName strips/replaces them. That is invisible to an
581
- // operator unless flagged — worse, two DIFFERENT configured profiles can
582
- // sanitize to the SAME filename (e.g. "mac/mini" and "mac-mini" both land
583
- // on "mac-mini.json"), in which case this run's write is about to
584
- // silently overwrite what looked like a peer's snapshot. Both cases are
585
- // advisory-only: this producer still writes its own snapshot and
586
- // continues normally either way.
587
- if (sanitizedProfile !== profile) {
588
- note(`configured profile "${profile}" is not filename-safe; using sanitized "${sanitizedProfile}" for the snapshot file (${ownFileName})`);
589
- }
590
- // Collision check (task c1b5ade5 R2, finding 2): this must run on EVERY
591
- // invocation, not only when THIS machine's own profile happens to be
592
- // lossy — the collision is equally caused by a DIFFERENT (peer)
593
- // machine's lossy profile landing on the SAME sanitized filename as
594
- // this machine's own, already filename-safe, profile. Gating this read
595
- // on `sanitizedProfile !== profile` meant only the lossy side of such a
596
- // pair ever warned; the filename-safe side silently overwrote the lossy
597
- // peer's snapshot with no signal at all (and that peer would then never
598
- // show up in `peersCompared`). Only the "not filename-safe" note above
599
- // stays scoped to the lossy case — it is about THIS profile, not about
600
- // a collision.
601
- try {
602
- const existingRaw = fs.readFileSync(path.join(machineStateDir, ownFileName), "utf8");
603
- const existingParsed = parseSnapshotJson(existingRaw);
604
- if (existingParsed.ok && existingParsed.snapshot.profile !== profile) {
605
- // The existing snapshot's `profile` field is untrusted, cross-machine
606
- // synced content, shown RAW here (task c1b5ade5 R2b, reverting R2's
607
- // sanitizeProfileName wrap at this site): note() now strips CR/LF at
608
- // the choke point above, so a per-site sanitize is redundant AND
609
- // would mangle a legitimate non-ASCII profile name into a label that
610
- // no longer matches what actually collided. sanitizeProfileName
611
- // stays reserved for the FILENAME path (ownFileName, writeOwnSnapshot
612
- // below) — never for this stderr-display path.
613
- note(`WARNING: sanitized filename "${ownFileName}" collides with an existing snapshot for a DIFFERENT profile ("${existingParsed.snapshot.profile}"); this run's write is about to overwrite it — set a distinct \`toolchain_parity.profile\` on one of the machines`);
614
- }
615
- }
616
- catch (err) {
617
- // No existing file for this sanitized name yet (first run for this
618
- // profile/filename) is the expected common case — ENOENT stays a
619
- // silent skip; writeOwnSnapshot below reports its own write failures
620
- // separately. Anything else (EACCES, EISDIR, ...) means the collision
621
- // check silently did NOT run, which is a different, noteworthy outcome
622
- // from "no collision found" (task c1b5ade5 R2b, narrowing the
623
- // previously-bare catch): re-noted as one line rather than swallowed.
624
- const e = err;
625
- if (e.code !== "ENOENT") {
626
- note(`could not check for a profile-name collision on ${ownFileName}: ${e.message}`);
627
- }
628
- }
629
- const runNodeVersion = opts.runNodeVersion ?? realNodeVersionSpawn;
630
- const runNpmGlobals = opts.runNpmGlobals ?? realNpmGlobalsSpawn;
631
- const readOwKitVersion = opts.readOwKitVersion ?? realReadOwKitVersion;
632
- const readMcpServerNames = opts.readMcpServerNames ?? realReadMcpServerNames;
633
- const { snapshot: localSnapshot, notes } = await collectLocalSnapshot({
634
- profile,
635
- now,
636
- workspaceRoot,
637
- nodeTimeoutMs,
638
- npmTimeoutMs,
639
- runNodeVersion,
640
- runNpmGlobals,
641
- readOwKitVersion,
642
- readMcpServerNames,
643
- });
644
- for (const n of notes)
645
- note(n);
646
- const written = writeOwnSnapshot(machineStateDir, ownFileName, localSnapshot);
647
- if (!written.ok) {
648
- note(`could not write own snapshot: ${written.reason}`);
649
- }
650
- let entries;
651
- try {
652
- entries = fs.readdirSync(machineStateDir);
653
- }
654
- catch (err) {
655
- const reason = `cannot list machine-state dir ${machineStateDir}: ${err.message}`;
656
- note(reason);
657
- return done(false, profile, 0, 0, sessionId, sessionSource, reason);
658
- }
659
- const peerFiles = entries.filter((name) => name.endsWith(".json") && name !== ownFileName).sort();
660
- if (peerFiles.length === 0) {
661
- const reason = `no peer snapshots found in ${machineStateDir}; nothing to compare (normal for the first machine, or before any peer has run this companion)`;
662
- note(reason);
663
- return done(false, profile, 0, 0, sessionId, sessionSource, reason);
664
- }
665
- let peersCompared = 0;
666
- let driftTotal = 0;
667
- // Peer files that were present but failed to parse as valid JSON —
668
- // AC2 (task 690fba7c): these must not vanish silently from `drift:N`, so
669
- // their (file-derived) labels are surfaced both as a distinct stderr tag
670
- // and as a `:unparseable-peer:<n>` suffix on the ledger fact below.
671
- const unparseablePeers = [];
672
- for (const fileName of peerFiles) {
673
- const filePath = path.join(machineStateDir, fileName);
674
- let raw;
675
- try {
676
- raw = fs.readFileSync(filePath, "utf8");
677
- }
678
- catch (err) {
679
- note(`peer snapshot ${fileName} unreadable: ${err.message}`);
680
- continue;
681
- }
682
- const parsed = parseSnapshotJson(raw);
683
- if (!parsed.ok) {
684
- // The profile field itself failed to parse, so the filename (minus
685
- // its `.json` suffix) is the best available peer identifier. Files
686
- // this producer did NOT write are untrusted input (the machine-state
687
- // dir is populated cross-machine by sync), but note() strips CR/LF
688
- // at the choke point above (task c1b5ade5 R2b, reverting R2's
689
- // sanitizeProfileName wrap at this site), so the label is shown RAW
690
- // here — a crafted filename still cannot forge a standalone parity
691
- // line, and sanitizeProfileName stays reserved for the FILENAME
692
- // path, not this stderr-display one. The `|| fileName` keeps a
693
- // degenerate name like a literal `.json` from producing an empty
694
- // label.
695
- const peerLabel = fileName.replace(/\.json$/, "") || fileName;
696
- note(`peer snapshot ${fileName} is corrupt: ${parsed.reason}`);
697
- note(`parity:unparseable-peer:${peerLabel}`);
698
- unparseablePeers.push(peerLabel);
699
- continue;
700
- }
701
- const comparison = compareToPeer(localSnapshot, parsed.snapshot, now);
702
- peersCompared += 1;
703
- driftTotal += comparison.drift.length;
704
- const age = formatSnapshotAge(comparison.ageMs);
705
- if (comparison.drift.length === 0) {
706
- note(`ok against ${comparison.peerProfile} (snapshot age ${age})`);
707
- }
708
- else {
709
- note(`drift:${comparison.drift.length} against ${comparison.peerProfile} (snapshot age ${age})`);
710
- for (const item of comparison.drift)
711
- note(`drift — ${item.message}`);
712
- }
713
- // AC3 (task c1b5ade5): a stale peer is a trustworthiness CAVEAT on the
714
- // comparison above, not a drift finding — it never touches driftTotal.
715
- // Only fires when `stale_after_days` is explicitly configured.
716
- if (staleAfterMs !== undefined && comparison.ageMs > staleAfterMs) {
717
- // comparison.peerProfile is untrusted, cross-machine synced content,
718
- // shown RAW here for the same reason as the collision-warning note
719
- // above (task c1b5ade5 R2b, reverting R2's sanitizeProfileName wrap
720
- // at this site): note() strips CR/LF at the choke point, and this
721
- // also keeps the label identical to the "ok against"/"drift:N
722
- // against" line for the SAME peer just above, instead of showing two
723
- // different sanitized-vs-raw spellings of one peer's name in the
724
- // same run.
725
- note(`peer ${comparison.peerProfile} snapshot is stale (age ${age}, exceeds the configured ${config.stale_after_days}d threshold); its comparison may not reflect that machine's CURRENT toolchain`);
726
- }
727
- }
728
- if (peersCompared === 0) {
729
- const reason = `no comparable peer snapshots (all ${peerFiles.length} peer file(s) in ${machineStateDir} were unreadable/corrupt)`;
730
- note(reason);
731
- return done(false, profile, 0, 0, sessionId, sessionSource, reason, unparseablePeers.length);
732
- }
733
- // AC2 (task 690fba7c): a non-zero `unparseablePeers` count means the
734
- // comparison below is PARTIAL, so it is appended to the ledger fact
735
- // itself — the artifact an operator is most likely to read after the
736
- // fact via `harness audit` — not just to the stderr notes above. Absent
737
- // any unparseable peer, `content` is byte-identical to the pre-existing
738
- // format (AC3: no behaviour change for the all-valid-peers case).
739
- const unparseableSuffix = unparseablePeers.length > 0 ? `:unparseable-peer:${unparseablePeers.length}` : "";
740
- const content = (driftTotal === 0 ? "toolchain-parity:ok" : `toolchain-parity:drift:${driftTotal}`) + unparseableSuffix;
741
- let writeLedger = opts.writeLedger;
742
- if (!writeLedger) {
743
- // No try/catch here (task c1b5ade5 R2, finding 4 — orchestrator
744
- // decision): resolveManifestLedgerWriter is a pure function over an
745
- // already-validated `manifest` with no throw path (findGroundingMcp is
746
- // a plain array `.find`, mcpCommandList a plain string split) and no
747
- // I/O seam to fail — unlike `resolveSession` above and `writeLedger`
748
- // below, which DO wrap real I/O/spawn boundaries and stay caught. A
749
- // try/catch here had no exercisable throw path and was dead,
750
- // untested code (round-1 review finding); removed rather than built
751
- // out into a fake seam.
752
- const resolved = resolveManifestLedgerWriter(manifest, {
753
- ...(opts.ledgerTimeoutMs !== undefined ? { ledgerTimeoutMs: opts.ledgerTimeoutMs } : {}),
754
- });
755
- if (!resolved.ok) {
756
- const reason = `${resolved.reason}; cannot record ${content}`;
757
- note(reason);
758
- return done(false, profile, peersCompared, driftTotal, sessionId, sessionSource, reason, unparseablePeers.length);
759
- }
760
- writeLedger = resolved.write;
761
- }
762
- // Defensive (task c1b5ade5): an injected or real writeLedger that REJECTS
763
- // instead of resolving to `{ ok: false, reason }` must degrade the same
764
- // way the `!result.ok` branch below already does, not propagate as an
765
- // unhandled rejection out of a SessionStart hook.
766
- let result;
767
- try {
768
- result = await writeLedger({ sessionId, content, source: LEDGER_SOURCE });
769
- }
770
- catch (err) {
771
- const reason = `ledger write threw: ${err.message}`;
772
- note(reason);
773
- return done(false, profile, peersCompared, driftTotal, sessionId, sessionSource, reason, unparseablePeers.length);
774
- }
775
- if (!result.ok) {
776
- // `?? "unknown error"` is unreachable through any type-checked caller
777
- // (`AddLedgerFactResult`'s `!ok` arm types `reason` as a non-optional
778
- // string) — but unlike the try/catch removed around
779
- // resolveManifestLedgerWriter above (a private, non-injectable pure
780
- // function only ever called from this same typed module, so genuinely
781
- // dead), `writeLedger` IS an injectable public seam
782
- // (SessionStartToolchainParityOptions.writeLedger): a JS-level or
783
- // otherwise untyped caller can hand back `{ ok: false }` with no
784
- // `reason` at runtime, so this fallback stays (task c1b5ade5 R2b).
785
- const reason = `ledger write failed: ${result.reason ?? "unknown error"}`;
786
- note(reason);
787
- return done(false, profile, peersCompared, driftTotal, sessionId, sessionSource, reason, unparseablePeers.length);
788
- }
789
- note(`recorded ${content} for session ${sessionId}`);
790
- if (sessionSource === "default") {
791
- note("WARNING: session resolved to the literal \"default\". This tag is audit-only (no gate " +
792
- "consumes toolchain-parity: yet), but pipe SessionStart event JSON on stdin, export " +
793
- "$CLAUDE_SESSION_ID, or pass --session <id> for manual / scripted use to keep the audit trail useful.");
794
- }
795
- return done(true, profile, peersCompared, driftTotal, sessionId, sessionSource, undefined, unparseablePeers.length);
796
- }
797
- //# sourceMappingURL=toolchain-parity.js.map