open-multi-agent-kit 0.90.8 → 0.90.9

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 (306) hide show
  1. package/CHANGELOG.md +22 -0
  2. package/README.md +7 -1
  3. package/dist/cli/args.d.ts.map +1 -1
  4. package/dist/cli/args.js +4 -0
  5. package/dist/cli/args.js.map +1 -1
  6. package/dist/commands/doctor-provider-cli.d.ts +33 -0
  7. package/dist/commands/doctor-provider-cli.d.ts.map +1 -0
  8. package/dist/commands/doctor-provider-cli.js +215 -0
  9. package/dist/commands/doctor-provider-cli.js.map +1 -0
  10. package/dist/commands/doctor-provider-transport.d.ts +35 -0
  11. package/dist/commands/doctor-provider-transport.d.ts.map +1 -0
  12. package/dist/commands/doctor-provider-transport.js +185 -0
  13. package/dist/commands/doctor-provider-transport.js.map +1 -0
  14. package/dist/commands/doctor-provider.d.ts +121 -7
  15. package/dist/commands/doctor-provider.d.ts.map +1 -1
  16. package/dist/commands/doctor-provider.js +1295 -102
  17. package/dist/commands/doctor-provider.js.map +1 -1
  18. package/dist/commands/session-doctor-cli.d.ts +43 -0
  19. package/dist/commands/session-doctor-cli.d.ts.map +1 -0
  20. package/dist/commands/session-doctor-cli.js +494 -0
  21. package/dist/commands/session-doctor-cli.js.map +1 -0
  22. package/dist/commands/verify-ci.d.ts +21 -0
  23. package/dist/commands/verify-ci.d.ts.map +1 -0
  24. package/dist/commands/verify-ci.js +66 -0
  25. package/dist/commands/verify-ci.js.map +1 -0
  26. package/dist/core/agent-session-services.d.ts +3 -0
  27. package/dist/core/agent-session-services.d.ts.map +1 -1
  28. package/dist/core/agent-session-services.js +3 -0
  29. package/dist/core/agent-session-services.js.map +1 -1
  30. package/dist/core/agent-session.d.ts +113 -2
  31. package/dist/core/agent-session.d.ts.map +1 -1
  32. package/dist/core/agent-session.js +993 -72
  33. package/dist/core/agent-session.js.map +1 -1
  34. package/dist/core/agent-tool-settings.d.ts +35 -0
  35. package/dist/core/agent-tool-settings.d.ts.map +1 -0
  36. package/dist/core/agent-tool-settings.js +155 -0
  37. package/dist/core/agent-tool-settings.js.map +1 -0
  38. package/dist/core/atomic-session-file.d.ts +14 -0
  39. package/dist/core/atomic-session-file.d.ts.map +1 -0
  40. package/dist/core/atomic-session-file.js +104 -0
  41. package/dist/core/atomic-session-file.js.map +1 -0
  42. package/dist/core/compaction/compaction.d.ts +6 -0
  43. package/dist/core/compaction/compaction.d.ts.map +1 -1
  44. package/dist/core/compaction/compaction.js +12 -1
  45. package/dist/core/compaction/compaction.js.map +1 -1
  46. package/dist/core/compaction/hysteresis.d.ts +27 -0
  47. package/dist/core/compaction/hysteresis.d.ts.map +1 -0
  48. package/dist/core/compaction/hysteresis.js +84 -0
  49. package/dist/core/compaction/hysteresis.js.map +1 -0
  50. package/dist/core/compaction/index.d.ts +2 -0
  51. package/dist/core/compaction/index.d.ts.map +1 -1
  52. package/dist/core/compaction/index.js +2 -0
  53. package/dist/core/compaction/index.js.map +1 -1
  54. package/dist/core/compaction/transaction.d.ts +172 -0
  55. package/dist/core/compaction/transaction.d.ts.map +1 -0
  56. package/dist/core/compaction/transaction.js +824 -0
  57. package/dist/core/compaction/transaction.js.map +1 -0
  58. package/dist/core/context-budget-governor-v2.d.ts +2 -1
  59. package/dist/core/context-budget-governor-v2.d.ts.map +1 -1
  60. package/dist/core/context-budget-governor-v2.js +2 -1
  61. package/dist/core/context-budget-governor-v2.js.map +1 -1
  62. package/dist/core/context-budget-reserved-tokens.d.ts +110 -0
  63. package/dist/core/context-budget-reserved-tokens.d.ts.map +1 -0
  64. package/dist/core/context-budget-reserved-tokens.js +188 -0
  65. package/dist/core/context-budget-reserved-tokens.js.map +1 -0
  66. package/dist/core/context-budget-v2-cache-invalidation.d.ts +133 -0
  67. package/dist/core/context-budget-v2-cache-invalidation.d.ts.map +1 -0
  68. package/dist/core/context-budget-v2-cache-invalidation.js +452 -0
  69. package/dist/core/context-budget-v2-cache-invalidation.js.map +1 -0
  70. package/dist/core/context-budget-v2-cache-keys.d.ts +3 -0
  71. package/dist/core/context-budget-v2-cache-keys.d.ts.map +1 -1
  72. package/dist/core/context-budget-v2-cache-keys.js +6 -0
  73. package/dist/core/context-budget-v2-cache-keys.js.map +1 -1
  74. package/dist/core/context-budget-v2-cache-provider.d.ts +4 -0
  75. package/dist/core/context-budget-v2-cache-provider.d.ts.map +1 -1
  76. package/dist/core/context-budget-v2-cache-provider.js +19 -0
  77. package/dist/core/context-budget-v2-cache-provider.js.map +1 -1
  78. package/dist/core/context-budget-v2-plan-cache-keys.d.ts.map +1 -1
  79. package/dist/core/context-budget-v2-plan-cache-keys.js +1 -0
  80. package/dist/core/context-budget-v2-plan-cache-keys.js.map +1 -1
  81. package/dist/core/context-budget-v2-planner.d.ts.map +1 -1
  82. package/dist/core/context-budget-v2-planner.js +1 -0
  83. package/dist/core/context-budget-v2-planner.js.map +1 -1
  84. package/dist/core/context-budget-v2-types.d.ts +4 -0
  85. package/dist/core/context-budget-v2-types.d.ts.map +1 -1
  86. package/dist/core/context-budget-v2-types.js.map +1 -1
  87. package/dist/core/durable-file-directory.d.ts +4 -0
  88. package/dist/core/durable-file-directory.d.ts.map +1 -0
  89. package/dist/core/durable-file-directory.js +76 -0
  90. package/dist/core/durable-file-directory.js.map +1 -0
  91. package/dist/core/durable-file-identity.d.ts +26 -0
  92. package/dist/core/durable-file-identity.d.ts.map +1 -0
  93. package/dist/core/durable-file-identity.js +118 -0
  94. package/dist/core/durable-file-identity.js.map +1 -0
  95. package/dist/core/durable-file-io.d.ts +29 -0
  96. package/dist/core/durable-file-io.d.ts.map +1 -0
  97. package/dist/core/durable-file-io.js +179 -0
  98. package/dist/core/durable-file-io.js.map +1 -0
  99. package/dist/core/durable-file-lock-cleanup.d.ts +12 -0
  100. package/dist/core/durable-file-lock-cleanup.d.ts.map +1 -0
  101. package/dist/core/durable-file-lock-cleanup.js +39 -0
  102. package/dist/core/durable-file-lock-cleanup.js.map +1 -0
  103. package/dist/core/durable-file-lock-owner.d.ts +18 -0
  104. package/dist/core/durable-file-lock-owner.d.ts.map +1 -0
  105. package/dist/core/durable-file-lock-owner.js +78 -0
  106. package/dist/core/durable-file-lock-owner.js.map +1 -0
  107. package/dist/core/durable-file-lock-storage.d.ts +35 -0
  108. package/dist/core/durable-file-lock-storage.d.ts.map +1 -0
  109. package/dist/core/durable-file-lock-storage.js +263 -0
  110. package/dist/core/durable-file-lock-storage.js.map +1 -0
  111. package/dist/core/durable-file-mode.d.ts +8 -0
  112. package/dist/core/durable-file-mode.d.ts.map +1 -0
  113. package/dist/core/durable-file-mode.js +41 -0
  114. package/dist/core/durable-file-mode.js.map +1 -0
  115. package/dist/core/extensions/loader.d.ts +12 -0
  116. package/dist/core/extensions/loader.d.ts.map +1 -1
  117. package/dist/core/extensions/loader.js +46 -37
  118. package/dist/core/extensions/loader.js.map +1 -1
  119. package/dist/core/index.d.ts +6 -2
  120. package/dist/core/index.d.ts.map +1 -1
  121. package/dist/core/index.js +5 -0
  122. package/dist/core/index.js.map +1 -1
  123. package/dist/core/model-resolver.d.ts.map +1 -1
  124. package/dist/core/model-resolver.js +1 -1
  125. package/dist/core/model-resolver.js.map +1 -1
  126. package/dist/core/redaction.d.ts +8 -0
  127. package/dist/core/redaction.d.ts.map +1 -0
  128. package/dist/core/redaction.js +31 -0
  129. package/dist/core/redaction.js.map +1 -0
  130. package/dist/core/resource-loader.d.ts.map +1 -1
  131. package/dist/core/resource-loader.js +36 -0
  132. package/dist/core/resource-loader.js.map +1 -1
  133. package/dist/core/run-journal-store.d.ts +53 -0
  134. package/dist/core/run-journal-store.d.ts.map +1 -0
  135. package/dist/core/run-journal-store.js +278 -0
  136. package/dist/core/run-journal-store.js.map +1 -0
  137. package/dist/core/run-journal.d.ts +172 -0
  138. package/dist/core/run-journal.d.ts.map +1 -0
  139. package/dist/core/run-journal.js +1053 -0
  140. package/dist/core/run-journal.js.map +1 -0
  141. package/dist/core/sdk.d.ts +7 -0
  142. package/dist/core/sdk.d.ts.map +1 -1
  143. package/dist/core/sdk.js +94 -3
  144. package/dist/core/sdk.js.map +1 -1
  145. package/dist/core/session-doctor-plan.d.ts +128 -0
  146. package/dist/core/session-doctor-plan.d.ts.map +1 -0
  147. package/dist/core/session-doctor-plan.js +833 -0
  148. package/dist/core/session-doctor-plan.js.map +1 -0
  149. package/dist/core/session-file-compaction.d.ts +6 -0
  150. package/dist/core/session-file-compaction.d.ts.map +1 -0
  151. package/dist/core/session-file-compaction.js +169 -0
  152. package/dist/core/session-file-compaction.js.map +1 -0
  153. package/dist/core/session-file-head.d.ts +10 -0
  154. package/dist/core/session-file-head.d.ts.map +1 -0
  155. package/dist/core/session-file-head.js +78 -0
  156. package/dist/core/session-file-head.js.map +1 -0
  157. package/dist/core/session-file-persistence.d.ts +30 -0
  158. package/dist/core/session-file-persistence.d.ts.map +1 -0
  159. package/dist/core/session-file-persistence.js +106 -0
  160. package/dist/core/session-file-persistence.js.map +1 -0
  161. package/dist/core/session-integrity.d.ts +43 -0
  162. package/dist/core/session-integrity.d.ts.map +1 -0
  163. package/dist/core/session-integrity.js +420 -0
  164. package/dist/core/session-integrity.js.map +1 -0
  165. package/dist/core/session-manager.d.ts +24 -4
  166. package/dist/core/session-manager.d.ts.map +1 -1
  167. package/dist/core/session-manager.js +242 -125
  168. package/dist/core/session-manager.js.map +1 -1
  169. package/dist/core/session-owner-lease.d.ts +22 -0
  170. package/dist/core/session-owner-lease.d.ts.map +1 -0
  171. package/dist/core/session-owner-lease.js +176 -0
  172. package/dist/core/session-owner-lease.js.map +1 -0
  173. package/dist/core/session-path-policy.d.ts +132 -0
  174. package/dist/core/session-path-policy.d.ts.map +1 -0
  175. package/dist/core/session-path-policy.js +780 -0
  176. package/dist/core/session-path-policy.js.map +1 -0
  177. package/dist/core/session-repair-plan.d.ts +49 -0
  178. package/dist/core/session-repair-plan.d.ts.map +1 -0
  179. package/dist/core/session-repair-plan.js +202 -0
  180. package/dist/core/session-repair-plan.js.map +1 -0
  181. package/dist/core/session-termination.d.ts +100 -0
  182. package/dist/core/session-termination.d.ts.map +1 -0
  183. package/dist/core/session-termination.js +403 -0
  184. package/dist/core/session-termination.js.map +1 -0
  185. package/dist/core/settings-manager.d.ts +22 -0
  186. package/dist/core/settings-manager.d.ts.map +1 -1
  187. package/dist/core/settings-manager.js +37 -5
  188. package/dist/core/settings-manager.js.map +1 -1
  189. package/dist/core/system-prompt.d.ts.map +1 -1
  190. package/dist/core/system-prompt.js +1 -1
  191. package/dist/core/system-prompt.js.map +1 -1
  192. package/dist/core/verified-bash-adapter.d.ts +36 -0
  193. package/dist/core/verified-bash-adapter.d.ts.map +1 -0
  194. package/dist/core/verified-bash-adapter.js +90 -0
  195. package/dist/core/verified-bash-adapter.js.map +1 -0
  196. package/dist/guardrails/command-redaction.d.ts +32 -0
  197. package/dist/guardrails/command-redaction.d.ts.map +1 -0
  198. package/dist/guardrails/command-redaction.js +776 -0
  199. package/dist/guardrails/command-redaction.js.map +1 -0
  200. package/dist/guardrails/evidence-attestation.d.ts +31 -0
  201. package/dist/guardrails/evidence-attestation.d.ts.map +1 -0
  202. package/dist/guardrails/evidence-attestation.js +178 -0
  203. package/dist/guardrails/evidence-attestation.js.map +1 -0
  204. package/dist/guardrails/evidence-receipt-store.d.ts +33 -0
  205. package/dist/guardrails/evidence-receipt-store.d.ts.map +1 -0
  206. package/dist/guardrails/evidence-receipt-store.js +446 -0
  207. package/dist/guardrails/evidence-receipt-store.js.map +1 -0
  208. package/dist/guardrails/evidence-receipt.d.ts +58 -0
  209. package/dist/guardrails/evidence-receipt.d.ts.map +1 -0
  210. package/dist/guardrails/evidence-receipt.js +389 -0
  211. package/dist/guardrails/evidence-receipt.js.map +1 -0
  212. package/dist/guardrails/evidence-system.d.ts +39 -15
  213. package/dist/guardrails/evidence-system.d.ts.map +1 -1
  214. package/dist/guardrails/evidence-system.js +255 -97
  215. package/dist/guardrails/evidence-system.js.map +1 -1
  216. package/dist/guardrails/replay-ledger-io.d.ts +6 -0
  217. package/dist/guardrails/replay-ledger-io.d.ts.map +1 -0
  218. package/dist/guardrails/replay-ledger-io.js +42 -0
  219. package/dist/guardrails/replay-ledger-io.js.map +1 -0
  220. package/dist/guardrails/replay-ledger-lock-owner.d.ts +32 -0
  221. package/dist/guardrails/replay-ledger-lock-owner.d.ts.map +1 -0
  222. package/dist/guardrails/replay-ledger-lock-owner.js +138 -0
  223. package/dist/guardrails/replay-ledger-lock-owner.js.map +1 -0
  224. package/dist/guardrails/replay-ledger-lock.d.ts +24 -0
  225. package/dist/guardrails/replay-ledger-lock.d.ts.map +1 -0
  226. package/dist/guardrails/replay-ledger-lock.js +135 -0
  227. package/dist/guardrails/replay-ledger-lock.js.map +1 -0
  228. package/dist/guardrails/replay-ledger-mutation-gate.d.ts +24 -0
  229. package/dist/guardrails/replay-ledger-mutation-gate.d.ts.map +1 -0
  230. package/dist/guardrails/replay-ledger-mutation-gate.js +205 -0
  231. package/dist/guardrails/replay-ledger-mutation-gate.js.map +1 -0
  232. package/dist/guardrails/replay-ledger-quarantine.d.ts +2 -0
  233. package/dist/guardrails/replay-ledger-quarantine.d.ts.map +1 -0
  234. package/dist/guardrails/replay-ledger-quarantine.js +19 -0
  235. package/dist/guardrails/replay-ledger-quarantine.js.map +1 -0
  236. package/dist/guardrails/replay-ledger-store.d.ts +32 -0
  237. package/dist/guardrails/replay-ledger-store.d.ts.map +1 -0
  238. package/dist/guardrails/replay-ledger-store.js +211 -0
  239. package/dist/guardrails/replay-ledger-store.js.map +1 -0
  240. package/dist/guardrails/shell-command-name-glob.d.ts +3 -0
  241. package/dist/guardrails/shell-command-name-glob.d.ts.map +1 -0
  242. package/dist/guardrails/shell-command-name-glob.js +233 -0
  243. package/dist/guardrails/shell-command-name-glob.js.map +1 -0
  244. package/dist/guardrails/shell-command-option.d.ts +7 -0
  245. package/dist/guardrails/shell-command-option.d.ts.map +1 -0
  246. package/dist/guardrails/shell-command-option.js +24 -0
  247. package/dist/guardrails/shell-command-option.js.map +1 -0
  248. package/dist/guardrails/shell-command-tokenizer.d.ts +29 -0
  249. package/dist/guardrails/shell-command-tokenizer.d.ts.map +1 -0
  250. package/dist/guardrails/shell-command-tokenizer.js +145 -0
  251. package/dist/guardrails/shell-command-tokenizer.js.map +1 -0
  252. package/dist/guardrails/shell-command-wrapper.d.ts +18 -0
  253. package/dist/guardrails/shell-command-wrapper.d.ts.map +1 -0
  254. package/dist/guardrails/shell-command-wrapper.js +42 -0
  255. package/dist/guardrails/shell-command-wrapper.js.map +1 -0
  256. package/dist/guardrails/verified-executor.d.ts +65 -0
  257. package/dist/guardrails/verified-executor.d.ts.map +1 -0
  258. package/dist/guardrails/verified-executor.js +171 -0
  259. package/dist/guardrails/verified-executor.js.map +1 -0
  260. package/dist/guardrails/workspace-fingerprint.d.ts +23 -0
  261. package/dist/guardrails/workspace-fingerprint.d.ts.map +1 -0
  262. package/dist/guardrails/workspace-fingerprint.js +634 -0
  263. package/dist/guardrails/workspace-fingerprint.js.map +1 -0
  264. package/dist/index.d.ts +15 -3
  265. package/dist/index.d.ts.map +1 -1
  266. package/dist/index.js +13 -1
  267. package/dist/index.js.map +1 -1
  268. package/dist/main.d.ts.map +1 -1
  269. package/dist/main.js +12 -0
  270. package/dist/main.js.map +1 -1
  271. package/dist/modes/interactive/interactive-mode.d.ts +3 -0
  272. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  273. package/dist/modes/interactive/interactive-mode.js +59 -9
  274. package/dist/modes/interactive/interactive-mode.js.map +1 -1
  275. package/dist/modes/print-mode.d.ts.map +1 -1
  276. package/dist/modes/print-mode.js +43 -2
  277. package/dist/modes/print-mode.js.map +1 -1
  278. package/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
  279. package/dist/modes/rpc/rpc-mode.js +23 -5
  280. package/dist/modes/rpc/rpc-mode.js.map +1 -1
  281. package/dist/modes/rpc/rpc-types.d.ts +3 -0
  282. package/dist/modes/rpc/rpc-types.d.ts.map +1 -1
  283. package/dist/modes/rpc/rpc-types.js.map +1 -1
  284. package/dist/types/evidence.d.ts +211 -1
  285. package/dist/types/evidence.d.ts.map +1 -1
  286. package/dist/types/evidence.js.map +1 -1
  287. package/dist/verify-ci.d.ts +3 -0
  288. package/dist/verify-ci.d.ts.map +1 -0
  289. package/dist/verify-ci.js +30 -0
  290. package/dist/verify-ci.js.map +1 -0
  291. package/docs/compaction.md +38 -4
  292. package/docs/extensions.md +2 -0
  293. package/docs/sdk.md +238 -1
  294. package/docs/settings.md +50 -2
  295. package/docs/usage.md +38 -0
  296. package/examples/extensions/custom-provider-anthropic/package-lock.json +5 -5
  297. package/examples/extensions/custom-provider-anthropic/package.json +1 -1
  298. package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
  299. package/examples/extensions/gondolin/package-lock.json +2 -2
  300. package/examples/extensions/gondolin/package.json +1 -1
  301. package/examples/extensions/sandbox/package-lock.json +2 -2
  302. package/examples/extensions/sandbox/package.json +1 -1
  303. package/examples/extensions/with-deps/package-lock.json +4 -4
  304. package/examples/extensions/with-deps/package.json +1 -1
  305. package/npm-shrinkwrap.json +12 -12
  306. package/package.json +4 -4
@@ -1 +1 @@
1
- {"version":3,"file":"evidence-system.js","sourceRoot":"","sources":["../../src/guardrails/evidence-system.ts"],"names":[],"mappings":"AAAA,kGAAkG;AAClG,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,cAAc,EAAE,UAAU,EAAE,SAAS,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAC7F,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAW1C,SAAS,MAAM,CAAC,KAAa,EAAU;IACtC,OAAO,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;AAAA,CACxD;AAED,SAAS,SAAS,CAAC,IAAY,EAAQ;IACtC,MAAM,GAAG,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC1B,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;QACtB,SAAS,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IACrC,CAAC;AAAA,CACD;AAED,+EAA+E;AAC/E,eAAe;AACf,+EAA+E;AAE/E,MAAM,OAAO,mBAAmB;IACvB,MAAM,CAAS;IACf,eAAe,GAAW,EAAE,CAAC;IAC7B,gBAAgB,GAAmB,EAAE,CAAC;IACtC,SAAS,GAAW,EAAE,CAAC;IACvB,OAAO,GAAoC,MAAM,CAAC;IAClD,SAAS,CAAS;IAClB,SAAS,CAAS;IAE1B,YAAY,MAAc,EAAE;QAC3B,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;QACrB,MAAM,GAAG,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;QACrC,IAAI,CAAC,SAAS,GAAG,GAAG,CAAC;QACrB,IAAI,CAAC,SAAS,GAAG,GAAG,CAAC;IAAA,CACrB;IAED,QAAQ,CAAC,KAAa,EAAQ;QAC7B,IAAI,CAAC,eAAe,GAAG,KAAK,CAAC;QAC7B,IAAI,CAAC,KAAK,EAAE,CAAC;QACb,OAAO,IAAI,CAAC;IAAA,CACZ;IAED,mBAAmB,CAAC,QAAoD,EAAQ;QAC/E,IAAI,CAAC,gBAAgB,CAAC,IAAI,CAAC;YAC1B,GAAG,QAAQ;YACX,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;YACnC,MAAM,EAAE,SAAS;SACjB,CAAC,CAAC;QACH,IAAI,CAAC,KAAK,EAAE,CAAC;QACb,OAAO,IAAI,CAAC;IAAA,CACZ;IAED,YAAY,CAAC,IAAY,EAAQ;QAChC,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC;QACtB,IAAI,CAAC,KAAK,EAAE,CAAC;QACb,OAAO,IAAI,CAAC;IAAA,CACZ;IAED,UAAU,CAAC,OAAwC,EAAQ;QAC1D,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;QACvB,IAAI,CAAC,KAAK,EAAE,CAAC;QACb,OAAO,IAAI,CAAC;IAAA,CACZ;IAED,oBAAoB,CAAC,KAAa,EAAE,MAAsB,EAAE,SAAkB,EAAQ;QACrF,MAAM,IAAI,GAAG,IAAI,CAAC,gBAAgB,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,KAAK,KAAK,CAAC,CAAC;QAClE,IAAI,IAAI,EAAE,CAAC;YACV,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;YACrB,IAAI,CAAC,SAAS,GAAG,SAAS,CAAC;YAC3B,IAAI,CAAC,SAAS,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;YAC1C,IAAI,CAAC,KAAK,EAAE,CAAC;QACd,CAAC;QACD,OAAO,IAAI,CAAC;IAAA,CACZ;IAEO,KAAK,GAAS;QACrB,IAAI,CAAC,SAAS,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;IAAA,CAC1C;IAED,KAAK,GAAiB;QACrB,OAAO,eAAe,CAAC;YACtB,MAAM,EAAE,IAAI,CAAC,MAAM;YACnB,eAAe,EAAE,IAAI,CAAC,eAAe;YACrC,gBAAgB,EAAE,IAAI,CAAC,gBAAgB;YACvC,SAAS,EAAE,IAAI,CAAC,SAAS;YACzB,OAAO,EAAE,IAAI,CAAC,OAAO;YACrB,SAAS,EAAE,IAAI,CAAC,SAAS;YACzB,SAAS,EAAE,IAAI,CAAC,SAAS;SACzB,CAAC,CAAC;IAAA,CACH;IAED,yFAAyF;IACzF,MAAM,CAAC,QAAQ,CAAC,IAAY,EAAgB;QAC3C,MAAM,GAAG,GAAY,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QACtC,IAAI,GAAG,KAAK,IAAI,IAAI,OAAO,GAAG,KAAK,QAAQ,IAAI,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC;YACnE,MAAM,IAAI,KAAK,CAAC,qCAAqC,CAAC,CAAC;QACxD,CAAC;QACD,MAAM,EAAE,MAAM,EAAE,eAAe,EAAE,SAAS,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,gBAAgB,EAAE,GAAG,GAG/F,CAAC;QACF,IACC,OAAO,MAAM,KAAK,QAAQ;YAC1B,OAAO,eAAe,KAAK,QAAQ;YACnC,OAAO,SAAS,KAAK,QAAQ;YAC7B,OAAO,SAAS,KAAK,QAAQ;YAC7B,OAAO,SAAS,KAAK,QAAQ,EAC5B,CAAC;YACF,MAAM,IAAI,KAAK,CAAC,yDAAyD,CAAC,CAAC;QAC5E,CAAC;QACD,IAAI,OAAO,KAAK,MAAM,IAAI,OAAO,KAAK,MAAM,IAAI,OAAO,KAAK,aAAa,EAAE,CAAC;YAC3E,MAAM,IAAI,KAAK,CAAC,2DAA2D,MAAM,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;QAC/F,CAAC;QACD,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,gBAAgB,CAAC,EAAE,CAAC;YACtC,MAAM,IAAI,KAAK,CAAC,gDAAgD,CAAC,CAAC;QACnE,CAAC;QACD,OAAO;YACN,MAAM;YACN,eAAe;YACf,SAAS;YACT,OAAO;YACP,SAAS;YACT,SAAS;YACT,gBAAgB,EAAE,gBAAgB,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC,iBAAiB,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;SACvF,CAAC;IAAA,CACF;IAED,MAAM,CAAC,MAAM,CAAC,QAAsB,EAAU;QAC7C,OAAO,IAAI,CAAC,SAAS,CAAC,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;IAAA,CACzC;CACD;AAED,MAAM,iBAAiB,GAAwB,IAAI,GAAG,CAAC,CAAC,SAAS,EAAE,WAAW,EAAE,WAAW,EAAE,QAAQ,EAAE,QAAQ,CAAC,CAAC,CAAC;AAElH,SAAS,mBAAmB,CAAC,KAAc,EAAE,KAAa,EAAE,KAAa,EAAsB;IAC9F,IAAI,KAAK,KAAK,SAAS,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;QACtD,MAAM,IAAI,KAAK,CAAC,yBAAyB,KAAK,KAAK,KAAK,gCAAgC,CAAC,CAAC;IAC3F,CAAC;IACD,OAAO,KAAK,CAAC;AAAA,CACb;AAED,SAAS,iBAAiB,CAAC,GAAY,EAAE,KAAa,EAAgB;IACrE,IAAI,GAAG,KAAK,IAAI,IAAI,OAAO,GAAG,KAAK,QAAQ,IAAI,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC;QACnE,MAAM,IAAI,KAAK,CAAC,yBAAyB,KAAK,qBAAqB,CAAC,CAAC;IACtE,CAAC;IACD,MAAM,IAAI,GAAG,GAA8B,CAAC;IAC5C,MAAM,EAAE,KAAK,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,EAAE,GAAG,IAAI,CAAC;IACpD,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,OAAO,QAAQ,KAAK,QAAQ,IAAI,OAAO,SAAS,KAAK,QAAQ,EAAE,CAAC;QAChG,MAAM,IAAI,KAAK,CAAC,yBAAyB,KAAK,kCAAkC,CAAC,CAAC;IACnF,CAAC;IACD,IAAI,OAAO,MAAM,KAAK,QAAQ,IAAI,CAAC,iBAAiB,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC;QAClE,MAAM,IAAI,KAAK,CAAC,yBAAyB,KAAK,wBAAwB,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;IACzF,CAAC;IACD,OAAO;QACN,KAAK;QACL,QAAQ,EAAE,QAAoC;QAC9C,SAAS;QACT,MAAM,EAAE,MAAwB;QAChC,YAAY,EAAE,mBAAmB,CAAC,IAAI,CAAC,YAAY,EAAE,cAAc,EAAE,KAAK,CAAC;QAC3E,mBAAmB,EAAE,mBAAmB,CAAC,IAAI,CAAC,mBAAmB,EAAE,qBAAqB,EAAE,KAAK,CAAC;QAChG,IAAI,EAAE,mBAAmB,CAAC,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,CAAC;QACnD,SAAS,EAAE,mBAAmB,CAAC,IAAI,CAAC,SAAS,EAAE,WAAW,EAAE,KAAK,CAAC;KAClE,CAAC;AAAA,CACF;AAED,+EAA+E;AAC/E,eAAe;AACf,+EAA+E;AAE/E,+DAA+D;AAC/D,MAAM,YAAY,GAAG,SAAS,CAAC;AAE/B,SAAS,gBAAgB,CAAC,KAAqC,EAAU;IACxE,OAAO,MAAM,CACZ,IAAI,CAAC,SAAS,CAAC;QACd,KAAK,CAAC,GAAG;QACT,KAAK,CAAC,IAAI;QACV,KAAK,CAAC,SAAS;QACf,KAAK,CAAC,MAAM;QACZ,KAAK,CAAC,MAAM,IAAI,IAAI;QACpB,KAAK,CAAC,WAAW;QACjB,KAAK,CAAC,QAAQ;KACd,CAAC,CACF,CAAC;AAAA,CACF;AAED,SAAS,oBAAoB,CAAC,IAAY,EAAE,UAAkB,EAAe;IAC5E,IAAI,GAAY,CAAC;IACjB,IAAI,CAAC;QACJ,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IACxB,CAAC;IAAC,MAAM,CAAC;QACR,MAAM,IAAI,KAAK,CAAC,mCAAmC,UAAU,gBAAgB,CAAC,CAAC;IAChF,CAAC;IACD,IAAI,GAAG,KAAK,IAAI,IAAI,OAAO,GAAG,KAAK,QAAQ,IAAI,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC;QACnE,MAAM,IAAI,KAAK,CAAC,mCAAmC,UAAU,2BAA2B,CAAC,CAAC;IAC3F,CAAC;IACD,MAAM,KAAK,GAAG,GAA8B,CAAC;IAC7C,MAAM,EAAE,GAAG,EAAE,IAAI,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,WAAW,EAAE,QAAQ,EAAE,SAAS,EAAE,GAAG,KAAK,CAAC;IACzF,IACC,OAAO,GAAG,KAAK,QAAQ;QACvB,OAAO,IAAI,KAAK,QAAQ;QACxB,OAAO,SAAS,KAAK,QAAQ;QAC7B,OAAO,MAAM,KAAK,QAAQ;QAC1B,OAAO,WAAW,KAAK,QAAQ;QAC/B,OAAO,QAAQ,KAAK,QAAQ;QAC5B,OAAO,SAAS,KAAK,QAAQ;QAC7B,CAAC,MAAM,KAAK,SAAS,IAAI,OAAO,MAAM,KAAK,QAAQ,CAAC;QACpD,CAAC,CAAC,SAAS,IAAI,KAAK,CAAC,EACpB,CAAC;QACF,MAAM,IAAI,KAAK,CAAC,mCAAmC,UAAU,wCAAwC,CAAC,CAAC;IACxG,CAAC;IACD,OAAO;QACN,GAAG;QACH,IAAI,EAAE,IAA2B;QACjC,SAAS;QACT,MAAM;QACN,MAAM;QACN,OAAO,EAAE,KAAK,CAAC,OAAO;QACtB,WAAW;QACX,QAAQ;QACR,SAAS;KACT,CAAC;AAAA,CACF;AAED,MAAM,OAAO,mBAAmB;IACvB,MAAM,CAAe;IACrB,OAAO,CAAS;IAExB,YAAY,MAAc,EAAE,UAAkB,EAAE;QAC/C,SAAS,CAAC,UAAU,CAAC,CAAC;QACtB,IAAI,CAAC,MAAM,GAAG;YACb,MAAM;YACN,MAAM,EAAE,EAAE;YACV,UAAU;YACV,gBAAgB,EAAE,CAAC;SACnB,CAAC;QACF,IAAI,CAAC,OAAO,GAAG,CAAC,CAAC;QACjB,IAAI,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC;YAC5B,IAAI,CAAC,IAAI,EAAE,CAAC;QACb,CAAC;IAAA,CACD;IAED,MAAM,CAAC,KAAwF,EAAe;QAC7G,MAAM,UAAU,GAAG,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;QACjD,MAAM,QAAQ,GAAG,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;QACnE,MAAM,OAAO,GAAmC;YAC/C,GAAG,KAAK;YACR,GAAG,EAAE,IAAI,CAAC,OAAO,EAAE;YACnB,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;YACnC,WAAW,EAAE,MAAM,CAAC,UAAU,CAAC;YAC/B,QAAQ,EAAE,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC,CAAC,YAAY;SACtD,CAAC;QACF,MAAM,SAAS,GAAgB,EAAE,GAAG,OAAO,EAAE,SAAS,EAAE,gBAAgB,CAAC,OAAO,CAAC,EAAE,CAAC;QACpF,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;QACnC,OAAO,SAAS,CAAC;IAAA,CACjB;IAED,OAAO,GAAS;QACf,IAAI,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO;QAC5C,MAAM,IAAI,GAAG,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;QAC/D,IAAI,IAAI,CAAC,GAAG,IAAI,IAAI,CAAC,MAAM,CAAC,gBAAgB;YAAE,OAAO;QAErD,MAAM,SAAS,GAAG,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,GAAG,GAAG,IAAI,CAAC,MAAM,CAAC,gBAAgB,CAAC,CAAC;QACzF,MAAM,KAAK,GAAG,GAAG,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC;QACxE,cAAc,CAAC,IAAI,CAAC,MAAM,CAAC,UAAU,EAAE,KAAK,EAAE,OAAO,CAAC,CAAC;QACvD,IAAI,CAAC,MAAM,CAAC,gBAAgB,GAAG,IAAI,CAAC,GAAG,CAAC;IAAA,CACxC;IAED;;;;;OAKG;IACH,IAAI,GAAS;QACZ,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC;YAAE,OAAO;QAChD,MAAM,OAAO,GAAG,YAAY,CAAC,IAAI,CAAC,MAAM,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC;QAC9D,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;QAC3E,MAAM,MAAM,GAAkB,EAAE,CAAC;QACjC,IAAI,QAAQ,GAAG,YAAY,CAAC;QAC5B,KAAK,IAAI,KAAK,GAAG,CAAC,EAAE,KAAK,GAAG,KAAK,CAAC,MAAM,EAAE,KAAK,EAAE,EAAE,CAAC;YACnD,MAAM,KAAK,GAAG,oBAAoB,CAAC,KAAK,CAAC,KAAK,CAAC,EAAE,KAAK,GAAG,CAAC,CAAC,CAAC;YAC5D,IAAI,KAAK,CAAC,GAAG,KAAK,KAAK,GAAG,CAAC,EAAE,CAAC;gBAC7B,MAAM,IAAI,KAAK,CACd,mCAAmC,KAAK,GAAG,CAAC,kBAAkB,KAAK,GAAG,CAAC,SAAS,KAAK,CAAC,GAAG,EAAE,CAC3F,CAAC;YACH,CAAC;YACD,IAAI,KAAK,CAAC,QAAQ,KAAK,QAAQ,EAAE,CAAC;gBACjC,MAAM,IAAI,KAAK,CACd,sCAAsC,KAAK,GAAG,CAAC,gDAAgD,CAC/F,CAAC;YACH,CAAC;YACD,IAAI,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,KAAK,KAAK,CAAC,WAAW,EAAE,CAAC;gBACjE,MAAM,IAAI,KAAK,CAAC,0CAA0C,KAAK,GAAG,CAAC,SAAS,KAAK,CAAC,GAAG,GAAG,CAAC,CAAC;YAC3F,CAAC;YACD,IAAI,gBAAgB,CAAC,KAAK,CAAC,KAAK,KAAK,CAAC,SAAS,EAAE,CAAC;gBACjD,MAAM,IAAI,KAAK,CAAC,6CAA6C,KAAK,GAAG,CAAC,SAAS,KAAK,CAAC,GAAG,GAAG,CAAC,CAAC;YAC9F,CAAC;YACD,QAAQ,GAAG,KAAK,CAAC,SAAS,CAAC;YAC3B,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACpB,CAAC;QACD,IAAI,CAAC,MAAM,CAAC,MAAM,GAAG,MAAM,CAAC;QAC5B,IAAI,CAAC,MAAM,CAAC,gBAAgB,GAAG,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;QACrF,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC,MAAM,CAAC,gBAAgB,GAAG,CAAC,CAAC;IAAA,CAChD;IAED,SAAS,GAA+B;QACvC,OAAO,eAAe,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;IAAA,CAC3C;IAED,SAAS,GAA2B;QACnC,OAAO,eAAe,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IAAA,CACpC;IAED,MAAM,CAAI,OAA8C,EAAO;QAC9D,MAAM,OAAO,GAAQ,EAAE,CAAC;QACxB,KAAK,MAAM,KAAK,IAAI,IAAI,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC;YACxC,MAAM,MAAM,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC;YAC9B,IAAI,MAAM,KAAK,SAAS,EAAE,CAAC;gBAC1B,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;YACtB,CAAC;QACF,CAAC;QACD,OAAO,OAAO,CAAC;IAAA,CACf;IAED,YAAY,CAAC,IAAY,EAAQ;QAChC,SAAS,CAAC,IAAI,CAAC,CAAC;QAChB,aAAa,CAAC,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC;IAAA,CAC1E;CACD;AAeD,MAAM,OAAO,YAAY;IAChB,OAAO,CAAsB;IAErC,YAAY,OAAO,GAAwB,EAAE,EAAE;QAC9C,IAAI,CAAC,OAAO,GAAG;YACd,gBAAgB,EAAE,CAAC;YACnB,WAAW,EAAE,IAAI;YACjB,0BAA0B,EAAE,IAAI;YAChC,GAAG,OAAO;SACV,CAAC;IAAA,CACF;IAED,KAAK,CAAC,QAAsB,EAAmB;QAC9C,MAAM,QAAQ,GAAG,QAAQ,CAAC,gBAAgB,CAAC;QAC3C,MAAM,SAAS,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,KAAK,WAAW,CAAC,CAAC;QACnE,MAAM,MAAM,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,KAAK,QAAQ,CAAC,CAAC;QAC7D,MAAM,OAAO,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,KAAK,SAAS,IAAI,CAAC,CAAC,MAAM,KAAK,WAAW,CAAC,CAAC;QAE3F,MAAM,MAAM,GAAa,EAAE,CAAC;QAE5B,kCAAkC;QAClC,IAAI,SAAS,CAAC,MAAM,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,gBAAgB,IAAI,CAAC,CAAC,EAAE,CAAC;YAC7D,MAAM,CAAC,IAAI,CAAC,QAAQ,SAAS,CAAC,MAAM,IAAI,IAAI,CAAC,OAAO,CAAC,gBAAgB,qCAAqC,CAAC,CAAC;QAC7G,CAAC;QAED,8BAA8B;QAC9B,IAAI,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACvB,MAAM,CAAC,IAAI,CAAC,GAAG,MAAM,CAAC,MAAM,2BAA2B,CAAC,CAAC;QAC1D,CAAC;QAED,wBAAwB;QACxB,IAAI,IAAI,CAAC,OAAO,CAAC,WAAW,EAAE,CAAC;YAC9B,MAAM,MAAM,GAAG,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;YACpE,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;gBACzB,MAAM,CAAC,IAAI,CAAC,2CAA2C,CAAC,CAAC;YAC1D,CAAC;QACF,CAAC;QAED,wCAAwC;QACxC,IAAI,IAAI,CAAC,OAAO,CAAC,0BAA0B,EAAE,CAAC;YAC7C,MAAM,WAAW,GAAG,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,mBAAmB,IAAI,CAAC,CAAC,mBAAmB,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;YACvG,IAAI,WAAW,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;gBAC9B,MAAM,CAAC,IAAI,CAAC,mDAAmD,CAAC,CAAC;YAClE,CAAC;QACF,CAAC;QAED,4BAA4B;QAC5B,IAAI,QAAQ,CAAC,OAAO,KAAK,MAAM,EAAE,CAAC;YACjC,MAAM,CAAC,IAAI,CAAC,kCAAkC,CAAC,CAAC;QACjD,CAAC;QAED,IAAI,MAAuB,CAAC;QAC5B,IAAI,MAAc,CAAC;QACnB,IAAI,UAA8B,CAAC;QAEnC,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACzB,MAAM,GAAG,MAAM,CAAC;YAChB,MAAM,GAAG,yBAAyB,SAAS,CAAC,MAAM,IAAI,QAAQ,CAAC,MAAM,4BAA4B,CAAC;QACnG,CAAC;aAAM,CAAC;YACP,uFAAuF;YACvF,MAAM,cAAc,GAAG,MAAM,CAAC,MAAM,GAAG,CAAC,IAAI,QAAQ,CAAC,OAAO,KAAK,MAAM,CAAC;YACxE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,SAAS,CAAC;YAC3E,MAAM,GAAG,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YAC3B,UAAU,GAAG,8BAA8B,OAAO,CAAC,MAAM,oCAAoC,CAAC;QAC/F,CAAC;QAED,OAAO;YACN,MAAM,EAAE,eAAe;YACvB,MAAM;YACN,MAAM;YACN,UAAU;YACV,eAAe,EAAE,QAAQ;SACzB,CAAC;IAAA,CACF;CACD;AAED,+EAA+E;AAC/E,sBAAsB;AACtB,+EAA+E;AAE/E,MAAM,OAAO,mBAAmB;IACvB,KAAK,CAAiB;IAE9B,YAAY,KAAK,GAAmB,CAAC,IAAI,YAAY,EAAE,CAAC,EAAE;QACzD,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC;IAAA,CACnB;IAED,KAAK,CAAC,QAAsB,EAAmB;QAC9C,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC;QAC/D,MAAM,OAAO,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,KAAK,SAAS,CAAC,CAAC;QAC9D,MAAM,WAAW,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,KAAK,aAAa,CAAC,CAAC;QAEtE,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACxB,OAAO;gBACN,MAAM,EAAE,wBAAwB;gBAChC,MAAM,EAAE,SAAS;gBACjB,MAAM,EAAE,cAAc,OAAO,CAAC,MAAM,aAAa,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE;gBAC1F,UAAU,EAAE,+CAA+C;gBAC3D,eAAe,EAAE,QAAQ,CAAC,gBAAgB;aAC1C,CAAC;QACH,CAAC;QAED,IAAI,WAAW,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAC5B,OAAO;gBACN,MAAM,EAAE,wBAAwB;gBAChC,MAAM,EAAE,aAAa;gBACrB,MAAM,EAAE,qBAAqB,WAAW,CAAC,MAAM,mCAAmC;gBAClF,UAAU,EAAE,4DAA4D;gBACxE,eAAe,EAAE,QAAQ,CAAC,gBAAgB;aAC1C,CAAC;QACH,CAAC;QAED,OAAO;YACN,MAAM,EAAE,wBAAwB;YAChC,MAAM,EAAE,MAAM;YACd,MAAM,EAAE,+EAA+E;YACvF,eAAe,EAAE,QAAQ,CAAC,gBAAgB;SAC1C,CAAC;IAAA,CACF;CACD;AAED,+EAA+E;AAC/E,qBAAqB;AACrB,+EAA+E;AAE/E,oGAAoG;AACpG,SAAS,eAAe,CAAC,KAAa,EAAU;IAC/C,OAAO,KAAK,CAAC,OAAO,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC,OAAO,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAC;AAAA,CACjF;AAOD,MAAM,OAAO,gBAAgB;IACpB,OAAO,CAA0B;IAEzC,YAAY,OAAgC,EAAE;QAC7C,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;IAAA,CACvB;IAED,MAAM,CAAC,QAAsB,EAAE,SAA0B,EAAU;QAClE,MAAM,KAAK,GAAa;YACvB,qCAAmC,QAAQ,CAAC,MAAM,EAAE;YACpD,EAAE;YACF,cAAc;YACd,EAAE;YACF,mBAAmB;YACnB,mBAAmB;YACnB,aAAa,eAAe,CAAC,QAAQ,CAAC,eAAe,CAAC,IAAI;YAC1D,eAAe,QAAQ,CAAC,OAAO,IAAI;YACnC,kBAAkB,eAAe,CAAC,QAAQ,CAAC,SAAS,CAAC,IAAI;YACzD,EAAE;YACF,cAAc;YACd,EAAE;YACF,yCAAyC;YACzC,0CAA0C;SAC1C,CAAC;QAEF,KAAK,MAAM,EAAE,IAAI,QAAQ,CAAC,gBAAgB,EAAE,CAAC;YAC5C,KAAK,CAAC,IAAI,CACT,KAAK,eAAe,CAAC,EAAE,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC,MAAM,MAAM,eAAe,CAAC,EAAE,CAAC,YAAY,IAAI,KAAG,CAAC,MAAM,eAAe,CAAC,EAAE,CAAC,mBAAmB,IAAI,KAAG,CAAC,IAAI,CAClJ,CAAC;QACH,CAAC;QAED,KAAK,CAAC,IAAI,CACT,EAAE,EACF,gBAAgB,EAChB,EAAE,EACF,4BAA4B,EAC5B,4BAA4B,EAC5B,KAAK,SAAS,CAAC,MAAM,MAAM,SAAS,CAAC,MAAM,MAAM,eAAe,CAAC,SAAS,CAAC,MAAM,CAAC,IAAI,EACtF,EAAE,CACF,CAAC;QAEF,IAAI,SAAS,CAAC,UAAU,EAAE,CAAC;YAC1B,KAAK,CAAC,IAAI,CAAC,mBAAmB,SAAS,CAAC,UAAU,EAAE,EAAE,EAAE,CAAC,CAAC;QAC3D,CAAC;QAED,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAAA,CACxB;IAED,KAAK,CAAC,QAAsB,EAAE,SAA0B,EAAU;QACjE,MAAM,QAAQ,GAAG,IAAI,CAAC,MAAM,CAAC,QAAQ,EAAE,SAAS,CAAC,CAAC;QAClD,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,SAAS,EAAE,GAAG,IAAI,CAAC,OAAO,CAAC,MAAM,YAAY,CAAC,CAAC;QAC9E,SAAS,CAAC,IAAI,CAAC,CAAC;QAChB,aAAa,CAAC,IAAI,EAAE,QAAQ,EAAE,OAAO,CAAC,CAAC;QACvC,OAAO,IAAI,CAAC;IAAA,CACZ;CACD","sourcesContent":["// allow: SIZE_OK - evidence ledger guardrails: tamper-evident replay chain + fail-closed parsing.\nimport { createHash } from \"node:crypto\";\nimport { appendFileSync, existsSync, mkdirSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { dirname, join } from \"node:path\";\nimport type {\n\tEvidenceItem,\n\tEvidenceStatus,\n\tMergeGateResult,\n\tMergeGateStatus,\n\tReplayEvent,\n\tReplayLedger,\n\tTaskContract,\n} from \"../types/evidence.ts\";\n\nfunction sha256(input: string): string {\n\treturn createHash(\"sha256\").update(input).digest(\"hex\");\n}\n\nfunction ensureDir(path: string): void {\n\tconst dir = dirname(path);\n\tif (!existsSync(dir)) {\n\t\tmkdirSync(dir, { recursive: true });\n\t}\n}\n\n// ============================================================================\n// TaskContract\n// ============================================================================\n\nexport class TaskContractBuilder {\n\tprivate goalId: string;\n\tprivate completionClaim: string = \"\";\n\tprivate requiredEvidence: EvidenceItem[] = [];\n\tprivate finalRisk: string = \"\";\n\tprivate verdict: \"pass\" | \"fail\" | \"conditional\" = \"fail\";\n\tprivate createdAt: string;\n\tprivate updatedAt: string;\n\n\tconstructor(goalId: string) {\n\t\tthis.goalId = goalId;\n\t\tconst now = new Date().toISOString();\n\t\tthis.createdAt = now;\n\t\tthis.updatedAt = now;\n\t}\n\n\tsetClaim(claim: string): this {\n\t\tthis.completionClaim = claim;\n\t\tthis.touch();\n\t\treturn this;\n\t}\n\n\taddRequiredEvidence(evidence: Omit<EvidenceItem, \"timestamp\" | \"status\">): this {\n\t\tthis.requiredEvidence.push({\n\t\t\t...evidence,\n\t\t\ttimestamp: new Date().toISOString(),\n\t\t\tstatus: \"pending\",\n\t\t});\n\t\tthis.touch();\n\t\treturn this;\n\t}\n\n\tsetFinalRisk(risk: string): this {\n\t\tthis.finalRisk = risk;\n\t\tthis.touch();\n\t\treturn this;\n\t}\n\n\tsetVerdict(verdict: \"pass\" | \"fail\" | \"conditional\"): this {\n\t\tthis.verdict = verdict;\n\t\tthis.touch();\n\t\treturn this;\n\t}\n\n\tupdateEvidenceStatus(claim: string, status: EvidenceStatus, gapReason?: string): this {\n\t\tconst item = this.requiredEvidence.find((e) => e.claim === claim);\n\t\tif (item) {\n\t\t\titem.status = status;\n\t\t\titem.gapReason = gapReason;\n\t\t\titem.timestamp = new Date().toISOString();\n\t\t\tthis.touch();\n\t\t}\n\t\treturn this;\n\t}\n\n\tprivate touch(): void {\n\t\tthis.updatedAt = new Date().toISOString();\n\t}\n\n\tbuild(): TaskContract {\n\t\treturn structuredClone({\n\t\t\tgoalId: this.goalId,\n\t\t\tcompletionClaim: this.completionClaim,\n\t\t\trequiredEvidence: this.requiredEvidence,\n\t\t\tfinalRisk: this.finalRisk,\n\t\t\tverdict: this.verdict,\n\t\t\tcreatedAt: this.createdAt,\n\t\t\tupdatedAt: this.updatedAt,\n\t\t});\n\t}\n\n\t/** Parse and validate a serialized TaskContract. Fails closed on any shape violation. */\n\tstatic fromJSON(json: string): TaskContract {\n\t\tconst raw: unknown = JSON.parse(json);\n\t\tif (raw === null || typeof raw !== \"object\" || Array.isArray(raw)) {\n\t\t\tthrow new Error(\"TaskContract JSON must be an object\");\n\t\t}\n\t\tconst { goalId, completionClaim, finalRisk, verdict, createdAt, updatedAt, requiredEvidence } = raw as Record<\n\t\t\tstring,\n\t\t\tunknown\n\t\t>;\n\t\tif (\n\t\t\ttypeof goalId !== \"string\" ||\n\t\t\ttypeof completionClaim !== \"string\" ||\n\t\t\ttypeof finalRisk !== \"string\" ||\n\t\t\ttypeof createdAt !== \"string\" ||\n\t\t\ttypeof updatedAt !== \"string\"\n\t\t) {\n\t\t\tthrow new Error(\"TaskContract JSON has missing or mistyped string fields\");\n\t\t}\n\t\tif (verdict !== \"pass\" && verdict !== \"fail\" && verdict !== \"conditional\") {\n\t\t\tthrow new Error(`TaskContract verdict must be pass|fail|conditional, got ${String(verdict)}`);\n\t\t}\n\t\tif (!Array.isArray(requiredEvidence)) {\n\t\t\tthrow new Error(\"TaskContract requiredEvidence must be an array\");\n\t\t}\n\t\treturn {\n\t\t\tgoalId,\n\t\t\tcompletionClaim,\n\t\t\tfinalRisk,\n\t\t\tverdict,\n\t\t\tcreatedAt,\n\t\t\tupdatedAt,\n\t\t\trequiredEvidence: requiredEvidence.map((item, index) => parseEvidenceItem(item, index)),\n\t\t};\n\t}\n\n\tstatic toJSON(contract: TaskContract): string {\n\t\treturn JSON.stringify(contract, null, 2);\n\t}\n}\n\nconst EVIDENCE_STATUSES: ReadonlySet<string> = new Set([\"pending\", \"gathering\", \"satisfied\", \"failed\", \"waived\"]);\n\nfunction optionalStringField(value: unknown, field: string, index: number): string | undefined {\n\tif (value !== undefined && typeof value !== \"string\") {\n\t\tthrow new Error(`TaskContract evidence[${index}].${field} must be a string when present`);\n\t}\n\treturn value;\n}\n\nfunction parseEvidenceItem(raw: unknown, index: number): EvidenceItem {\n\tif (raw === null || typeof raw !== \"object\" || Array.isArray(raw)) {\n\t\tthrow new Error(`TaskContract evidence[${index}] must be an object`);\n\t}\n\tconst item = raw as Record<string, unknown>;\n\tconst { claim, category, timestamp, status } = item;\n\tif (typeof claim !== \"string\" || typeof category !== \"string\" || typeof timestamp !== \"string\") {\n\t\tthrow new Error(`TaskContract evidence[${index}] has missing or mistyped fields`);\n\t}\n\tif (typeof status !== \"string\" || !EVIDENCE_STATUSES.has(status)) {\n\t\tthrow new Error(`TaskContract evidence[${index}] has invalid status ${String(status)}`);\n\t}\n\treturn {\n\t\tclaim,\n\t\tcategory: category as EvidenceItem[\"category\"],\n\t\ttimestamp,\n\t\tstatus: status as EvidenceStatus,\n\t\tartifactPath: optionalStringField(item.artifactPath, \"artifactPath\", index),\n\t\tverificationCommand: optionalStringField(item.verificationCommand, \"verificationCommand\", index),\n\t\thash: optionalStringField(item.hash, \"hash\", index),\n\t\tgapReason: optionalStringField(item.gapReason, \"gapReason\", index),\n\t};\n}\n\n// ============================================================================\n// ReplayLedger\n// ============================================================================\n\n/** prevHash sentinel for the first event in a replay chain. */\nconst GENESIS_HASH = \"genesis\";\n\nfunction computeEventHash(event: Omit<ReplayEvent, \"eventHash\">): string {\n\treturn sha256(\n\t\tJSON.stringify([\n\t\t\tevent.seq,\n\t\t\tevent.type,\n\t\t\tevent.timestamp,\n\t\t\tevent.goalId,\n\t\t\tevent.laneId ?? null,\n\t\t\tevent.payloadHash,\n\t\t\tevent.prevHash,\n\t\t]),\n\t);\n}\n\nfunction parseReplayEventLine(line: string, lineNumber: number): ReplayEvent {\n\tlet raw: unknown;\n\ttry {\n\t\traw = JSON.parse(line);\n\t} catch {\n\t\tthrow new Error(`Replay ledger corrupted at line ${lineNumber}: invalid JSON`);\n\t}\n\tif (raw === null || typeof raw !== \"object\" || Array.isArray(raw)) {\n\t\tthrow new Error(`Replay ledger corrupted at line ${lineNumber}: event must be an object`);\n\t}\n\tconst event = raw as Record<string, unknown>;\n\tconst { seq, type, timestamp, goalId, laneId, payloadHash, prevHash, eventHash } = event;\n\tif (\n\t\ttypeof seq !== \"number\" ||\n\t\ttypeof type !== \"string\" ||\n\t\ttypeof timestamp !== \"string\" ||\n\t\ttypeof goalId !== \"string\" ||\n\t\ttypeof payloadHash !== \"string\" ||\n\t\ttypeof prevHash !== \"string\" ||\n\t\ttypeof eventHash !== \"string\" ||\n\t\t(laneId !== undefined && typeof laneId !== \"string\") ||\n\t\t!(\"payload\" in event)\n\t) {\n\t\tthrow new Error(`Replay ledger corrupted at line ${lineNumber}: event fields are missing or mistyped`);\n\t}\n\treturn {\n\t\tseq,\n\t\ttype: type as ReplayEvent[\"type\"],\n\t\ttimestamp,\n\t\tgoalId,\n\t\tlaneId,\n\t\tpayload: event.payload,\n\t\tpayloadHash,\n\t\tprevHash,\n\t\teventHash,\n\t};\n}\n\nexport class ReplayLedgerManager {\n\tprivate ledger: ReplayLedger;\n\tprivate nextSeq: number;\n\n\tconstructor(goalId: string, ledgerPath: string) {\n\t\tensureDir(ledgerPath);\n\t\tthis.ledger = {\n\t\t\tgoalId,\n\t\t\tevents: [],\n\t\t\tledgerPath,\n\t\t\tlastPersistedSeq: 0,\n\t\t};\n\t\tthis.nextSeq = 1;\n\t\tif (existsSync(ledgerPath)) {\n\t\t\tthis.load();\n\t\t}\n\t}\n\n\tappend(event: Omit<ReplayEvent, \"seq\" | \"timestamp\" | \"payloadHash\" | \"prevHash\" | \"eventHash\">): ReplayEvent {\n\t\tconst payloadStr = JSON.stringify(event.payload);\n\t\tconst previous = this.ledger.events[this.ledger.events.length - 1];\n\t\tconst chained: Omit<ReplayEvent, \"eventHash\"> = {\n\t\t\t...event,\n\t\t\tseq: this.nextSeq++,\n\t\t\ttimestamp: new Date().toISOString(),\n\t\t\tpayloadHash: sha256(payloadStr),\n\t\t\tprevHash: previous ? previous.eventHash : GENESIS_HASH,\n\t\t};\n\t\tconst fullEvent: ReplayEvent = { ...chained, eventHash: computeEventHash(chained) };\n\t\tthis.ledger.events.push(fullEvent);\n\t\treturn fullEvent;\n\t}\n\n\tpersist(): void {\n\t\tif (this.ledger.events.length === 0) return;\n\t\tconst last = this.ledger.events[this.ledger.events.length - 1];\n\t\tif (last.seq <= this.ledger.lastPersistedSeq) return;\n\n\t\tconst newEvents = this.ledger.events.filter((e) => e.seq > this.ledger.lastPersistedSeq);\n\t\tconst lines = `${newEvents.map((e) => JSON.stringify(e)).join(\"\\n\")}\\n`;\n\t\tappendFileSync(this.ledger.ledgerPath, lines, \"utf-8\");\n\t\tthis.ledger.lastPersistedSeq = last.seq;\n\t}\n\n\t/**\n\t * Load and verify the persisted ledger. Fails closed: any schema violation,\n\t * sequence gap, payload-hash mismatch, or broken event-hash chain throws, so\n\t * a tampered ledger (edited, deleted, inserted, or reordered lines) is never\n\t * loaded silently.\n\t */\n\tload(): void {\n\t\tif (!existsSync(this.ledger.ledgerPath)) return;\n\t\tconst content = readFileSync(this.ledger.ledgerPath, \"utf-8\");\n\t\tconst lines = content.split(\"\\n\").filter((line) => line.trim().length > 0);\n\t\tconst events: ReplayEvent[] = [];\n\t\tlet prevHash = GENESIS_HASH;\n\t\tfor (let index = 0; index < lines.length; index++) {\n\t\t\tconst event = parseReplayEventLine(lines[index], index + 1);\n\t\t\tif (event.seq !== index + 1) {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`Replay ledger corrupted at line ${index + 1}: expected seq ${index + 1}, got ${event.seq}`,\n\t\t\t\t);\n\t\t\t}\n\t\t\tif (event.prevHash !== prevHash) {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`Replay ledger chain broken at line ${index + 1}: an event was inserted, deleted, or reordered`,\n\t\t\t\t);\n\t\t\t}\n\t\t\tif (sha256(JSON.stringify(event.payload)) !== event.payloadHash) {\n\t\t\t\tthrow new Error(`Replay ledger payload tampered at line ${index + 1} (seq ${event.seq})`);\n\t\t\t}\n\t\t\tif (computeEventHash(event) !== event.eventHash) {\n\t\t\t\tthrow new Error(`Replay ledger event hash mismatch at line ${index + 1} (seq ${event.seq})`);\n\t\t\t}\n\t\t\tprevHash = event.eventHash;\n\t\t\tevents.push(event);\n\t\t}\n\t\tthis.ledger.events = events;\n\t\tthis.ledger.lastPersistedSeq = events.length > 0 ? events[events.length - 1].seq : 0;\n\t\tthis.nextSeq = this.ledger.lastPersistedSeq + 1;\n\t}\n\n\tgetEvents(): ReadonlyArray<ReplayEvent> {\n\t\treturn structuredClone(this.ledger.events);\n\t}\n\n\tgetLedger(): Readonly<ReplayLedger> {\n\t\treturn structuredClone(this.ledger);\n\t}\n\n\treplay<T>(handler: (event: ReplayEvent) => T | undefined): T[] {\n\t\tconst results: T[] = [];\n\t\tfor (const event of this.ledger.events) {\n\t\t\tconst result = handler(event);\n\t\t\tif (result !== undefined) {\n\t\t\t\tresults.push(result);\n\t\t\t}\n\t\t}\n\t\treturn results;\n\t}\n\n\texportToFile(path: string): void {\n\t\tensureDir(path);\n\t\twriteFileSync(path, JSON.stringify(this.ledger.events, null, 2), \"utf-8\");\n\t}\n}\n\n// ============================================================================\n// EvidenceGate\n// ============================================================================\n\nexport interface EvidenceGateOptions {\n\t/** Minimum number of satisfied evidence items required. */\n\tminEvidenceCount?: number;\n\t/** Require at least one artifact with a SHA-256 hash. */\n\trequireHash?: boolean;\n\t/** Require at least one verification command. */\n\trequireVerificationCommand?: boolean;\n}\n\nexport class EvidenceGate {\n\tprivate options: EvidenceGateOptions;\n\n\tconstructor(options: EvidenceGateOptions = {}) {\n\t\tthis.options = {\n\t\t\tminEvidenceCount: 1,\n\t\t\trequireHash: true,\n\t\t\trequireVerificationCommand: true,\n\t\t\t...options,\n\t\t};\n\t}\n\n\tcheck(contract: TaskContract): MergeGateResult {\n\t\tconst evidence = contract.requiredEvidence;\n\t\tconst satisfied = evidence.filter((e) => e.status === \"satisfied\");\n\t\tconst failed = evidence.filter((e) => e.status === \"failed\");\n\t\tconst pending = evidence.filter((e) => e.status === \"pending\" || e.status === \"gathering\");\n\n\t\tconst checks: string[] = [];\n\n\t\t// Check 1: minimum evidence count\n\t\tif (satisfied.length < (this.options.minEvidenceCount ?? 1)) {\n\t\t\tchecks.push(`Only ${satisfied.length}/${this.options.minEvidenceCount} required evidence items satisfied.`);\n\t\t}\n\n\t\t// Check 2: no failed evidence\n\t\tif (failed.length > 0) {\n\t\t\tchecks.push(`${failed.length} evidence item(s) failed.`);\n\t\t}\n\n\t\t// Check 3: require hash\n\t\tif (this.options.requireHash) {\n\t\t\tconst hashed = satisfied.filter((e) => e.hash && e.hash.length > 0);\n\t\t\tif (hashed.length === 0) {\n\t\t\t\tchecks.push(\"No satisfied evidence has a SHA-256 hash.\");\n\t\t\t}\n\t\t}\n\n\t\t// Check 4: require verification command\n\t\tif (this.options.requireVerificationCommand) {\n\t\t\tconst withCommand = satisfied.filter((e) => e.verificationCommand && e.verificationCommand.length > 0);\n\t\t\tif (withCommand.length === 0) {\n\t\t\t\tchecks.push(\"No satisfied evidence has a verification command.\");\n\t\t\t}\n\t\t}\n\n\t\t// Check 5: contract verdict\n\t\tif (contract.verdict === \"fail\") {\n\t\t\tchecks.push(\"Task contract verdict is 'fail'.\");\n\t\t}\n\n\t\tlet status: MergeGateStatus;\n\t\tlet reason: string;\n\t\tlet suggestion: string | undefined;\n\n\t\tif (checks.length === 0) {\n\t\t\tstatus = \"open\";\n\t\t\treason = `Evidence gate passed: ${satisfied.length}/${evidence.length} evidence items satisfied.`;\n\t\t} else {\n\t\t\t// If there are pending items and no hard failures, it's conditional; otherwise blocked\n\t\t\tconst hasHardFailure = failed.length > 0 || contract.verdict === \"fail\";\n\t\t\tstatus = pending.length > 0 && !hasHardFailure ? \"conditional\" : \"blocked\";\n\t\t\treason = checks.join(\"; \");\n\t\t\tsuggestion = `Gather remaining evidence (${pending.length} pending) and re-run verification.`;\n\t\t}\n\n\t\treturn {\n\t\t\tgateId: \"evidence-gate\",\n\t\t\tstatus,\n\t\t\treason,\n\t\t\tsuggestion,\n\t\t\tevidenceChecked: evidence,\n\t\t};\n\t}\n}\n\n// ============================================================================\n// FailClosedMergeGate\n// ============================================================================\n\nexport class FailClosedMergeGate {\n\tprivate gates: EvidenceGate[];\n\n\tconstructor(gates: EvidenceGate[] = [new EvidenceGate()]) {\n\t\tthis.gates = gates;\n\t}\n\n\tcheck(contract: TaskContract): MergeGateResult {\n\t\tconst results = this.gates.map((gate) => gate.check(contract));\n\t\tconst blocked = results.filter((r) => r.status === \"blocked\");\n\t\tconst conditional = results.filter((r) => r.status === \"conditional\");\n\n\t\tif (blocked.length > 0) {\n\t\t\treturn {\n\t\t\t\tgateId: \"fail-closed-merge-gate\",\n\t\t\t\tstatus: \"blocked\",\n\t\t\t\treason: `Blocked by ${blocked.length} gate(s): ${blocked.map((b) => b.reason).join(\"; \")}`,\n\t\t\t\tsuggestion: \"Resolve all blocking conditions before merge.\",\n\t\t\t\tevidenceChecked: contract.requiredEvidence,\n\t\t\t};\n\t\t}\n\n\t\tif (conditional.length > 0) {\n\t\t\treturn {\n\t\t\t\tgateId: \"fail-closed-merge-gate\",\n\t\t\t\tstatus: \"conditional\",\n\t\t\t\treason: `Conditional pass: ${conditional.length} gate(s) have pending conditions.`,\n\t\t\t\tsuggestion: \"Complete pending evidence or waive with explicit approval.\",\n\t\t\t\tevidenceChecked: contract.requiredEvidence,\n\t\t\t};\n\t\t}\n\n\t\treturn {\n\t\t\tgateId: \"fail-closed-merge-gate\",\n\t\t\tstatus: \"open\",\n\t\t\treason: \"All merge gates passed. Evidence verified and contract verdict is acceptable.\",\n\t\t\tevidenceChecked: contract.requiredEvidence,\n\t\t};\n\t}\n}\n\n// ============================================================================\n// Verify Reporter v2\n// ============================================================================\n\n/** Escape pipes/newlines so untrusted claim or command text cannot restructure the report table. */\nfunction escapeTableCell(value: string): string {\n\treturn value.replace(/\\\\/g, \"\\\\\\\\\").replace(/\\|/g, \"\\\\|\").replace(/\\r?\\n/g, \" \");\n}\n\nexport interface VerifyReporterV2Options {\n\toutputDir: string;\n\tgoalId: string;\n}\n\nexport class VerifyReporterV2 {\n\tprivate options: VerifyReporterV2Options;\n\n\tconstructor(options: VerifyReporterV2Options) {\n\t\tthis.options = options;\n\t}\n\n\trender(contract: TaskContract, mergeGate: MergeGateResult): string {\n\t\tconst lines: string[] = [\n\t\t\t`## OMK Verification Report v2 — ${contract.goalId}`,\n\t\t\t\"\",\n\t\t\t\"### Contract\",\n\t\t\t\"\",\n\t\t\t`| Field | Value |`,\n\t\t\t`|-------|-------|`,\n\t\t\t`| Claim | ${escapeTableCell(contract.completionClaim)} |`,\n\t\t\t`| Verdict | ${contract.verdict} |`,\n\t\t\t`| Final Risk | ${escapeTableCell(contract.finalRisk)} |`,\n\t\t\t\"\",\n\t\t\t\"### Evidence\",\n\t\t\t\"\",\n\t\t\t`| Claim | Status | Artifact | Command |`,\n\t\t\t`|-------|--------|----------|----------|`,\n\t\t];\n\n\t\tfor (const ev of contract.requiredEvidence) {\n\t\t\tlines.push(\n\t\t\t\t`| ${escapeTableCell(ev.claim)} | ${ev.status} | ${escapeTableCell(ev.artifactPath ?? \"—\")} | ${escapeTableCell(ev.verificationCommand ?? \"—\")} |`,\n\t\t\t);\n\t\t}\n\n\t\tlines.push(\n\t\t\t\"\",\n\t\t\t\"### Merge Gate\",\n\t\t\t\"\",\n\t\t\t`| Gate | Status | Reason |`,\n\t\t\t`|------|--------|--------|`,\n\t\t\t`| ${mergeGate.gateId} | ${mergeGate.status} | ${escapeTableCell(mergeGate.reason)} |`,\n\t\t\t\"\",\n\t\t);\n\n\t\tif (mergeGate.suggestion) {\n\t\t\tlines.push(`**Suggestion:** ${mergeGate.suggestion}`, \"\");\n\t\t}\n\n\t\treturn lines.join(\"\\n\");\n\t}\n\n\twrite(contract: TaskContract, mergeGate: MergeGateResult): string {\n\t\tconst markdown = this.render(contract, mergeGate);\n\t\tconst path = join(this.options.outputDir, `${this.options.goalId}.verify.md`);\n\t\tensureDir(path);\n\t\twriteFileSync(path, markdown, \"utf-8\");\n\t\treturn path;\n\t}\n}\n"]}
1
+ {"version":3,"file":"evidence-system.js","sourceRoot":"","sources":["../../src/guardrails/evidence-system.ts"],"names":[],"mappings":"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","sourcesContent":["// allow: SIZE_OK - evidence ledger guardrails: tamper-evident replay chain + fail-closed parsing.\nimport { createHash } from \"node:crypto\";\nimport { existsSync, mkdirSync, writeFileSync } from \"node:fs\";\nimport { dirname, join } from \"node:path\";\nimport type {\n\tEvidenceCommandDescriptor,\n\tEvidenceItem,\n\tEvidenceReceiptMode,\n\tEvidenceStatus,\n\tMergeGateResult,\n\tMergeGateStatus,\n\tReplayEvent,\n\tReplayLedger,\n\tReplayLedgerHead,\n\tTaskContract,\n\tVerifiedReplayLedgerSnapshot,\n\tWorkspaceScope,\n} from \"../types/evidence.ts\";\nimport { redactCommandDescriptor } from \"./command-redaction.ts\";\nimport {\n\ttype CommandHmacBinder,\n\tlatestRelevantWorkspaceMutationSeq,\n\tparseVerifiedLedgerSnapshot,\n\treplayPayloadMatches,\n\tverifyCommandAttestation,\n\tverifyWorkspaceBinding,\n} from \"./evidence-attestation.ts\";\n\nexport { latestRelevantWorkspaceMutationSeq } from \"./evidence-attestation.ts\";\n\nimport {\n\tcomputeEvidenceCommandSha256,\n\tconstantTimeSha256Equal,\n\tevidenceReceiptReplayPayload,\n\tparseSha256Hex,\n\tvalidateEvidenceReceipt,\n} from \"./evidence-receipt.ts\";\nimport { ReplayLedgerStore, replayLedgerHeadsEqual } from \"./replay-ledger-store.ts\";\n\nfunction sha256(input: string): string {\n\treturn createHash(\"sha256\").update(input).digest(\"hex\");\n}\n\nfunction ensureDir(path: string): void {\n\tconst dir = dirname(path);\n\tif (!existsSync(dir)) {\n\t\tmkdirSync(dir, { recursive: true });\n\t}\n}\n\n// ============================================================================\n// TaskContract\n// ============================================================================\n\nexport class TaskContractBuilder {\n\tprivate goalId: string;\n\tprivate completionClaim: string = \"\";\n\tprivate requiredEvidence: EvidenceItem[] = [];\n\tprivate finalRisk: string = \"\";\n\tprivate verdict: \"pass\" | \"fail\" | \"conditional\" = \"fail\";\n\tprivate createdAt: string;\n\tprivate updatedAt: string;\n\n\tconstructor(goalId: string) {\n\t\tthis.goalId = goalId;\n\t\tconst now = new Date().toISOString();\n\t\tthis.createdAt = now;\n\t\tthis.updatedAt = now;\n\t}\n\n\tsetClaim(claim: string): this {\n\t\tthis.completionClaim = claim;\n\t\tthis.touch();\n\t\treturn this;\n\t}\n\n\taddRequiredEvidence(evidence: Omit<EvidenceItem, \"timestamp\" | \"status\">): this {\n\t\tthis.requiredEvidence.push({\n\t\t\t...evidence,\n\t\t\ttimestamp: new Date().toISOString(),\n\t\t\tstatus: \"pending\",\n\t\t});\n\t\tthis.touch();\n\t\treturn this;\n\t}\n\n\tsetFinalRisk(risk: string): this {\n\t\tthis.finalRisk = risk;\n\t\tthis.touch();\n\t\treturn this;\n\t}\n\n\tsetVerdict(verdict: \"pass\" | \"fail\" | \"conditional\"): this {\n\t\tthis.verdict = verdict;\n\t\tthis.touch();\n\t\treturn this;\n\t}\n\n\tupdateEvidenceStatus(claim: string, status: EvidenceStatus, gapReason?: string): this {\n\t\tconst item = this.requiredEvidence.find((e) => e.claim === claim);\n\t\tif (item) {\n\t\t\titem.status = status;\n\t\t\titem.gapReason = gapReason;\n\t\t\titem.timestamp = new Date().toISOString();\n\t\t\tthis.touch();\n\t\t}\n\t\treturn this;\n\t}\n\n\tprivate touch(): void {\n\t\tthis.updatedAt = new Date().toISOString();\n\t}\n\n\tbuild(): TaskContract {\n\t\treturn structuredClone({\n\t\t\tgoalId: this.goalId,\n\t\t\tcompletionClaim: this.completionClaim,\n\t\t\trequiredEvidence: this.requiredEvidence,\n\t\t\tfinalRisk: this.finalRisk,\n\t\t\tverdict: this.verdict,\n\t\t\tcreatedAt: this.createdAt,\n\t\t\tupdatedAt: this.updatedAt,\n\t\t});\n\t}\n\n\t/** Parse and validate a serialized TaskContract. Fails closed on any shape violation. */\n\tstatic fromJSON(json: string): TaskContract {\n\t\tconst raw: unknown = JSON.parse(json);\n\t\tif (raw === null || typeof raw !== \"object\" || Array.isArray(raw)) {\n\t\t\tthrow new Error(\"TaskContract JSON must be an object\");\n\t\t}\n\t\tconst { goalId, completionClaim, finalRisk, verdict, createdAt, updatedAt, requiredEvidence } = raw as Record<\n\t\t\tstring,\n\t\t\tunknown\n\t\t>;\n\t\tif (\n\t\t\ttypeof goalId !== \"string\" ||\n\t\t\ttypeof completionClaim !== \"string\" ||\n\t\t\ttypeof finalRisk !== \"string\" ||\n\t\t\ttypeof createdAt !== \"string\" ||\n\t\t\ttypeof updatedAt !== \"string\"\n\t\t) {\n\t\t\tthrow new Error(\"TaskContract JSON has missing or mistyped string fields\");\n\t\t}\n\t\tif (verdict !== \"pass\" && verdict !== \"fail\" && verdict !== \"conditional\") {\n\t\t\tthrow new Error(`TaskContract verdict must be pass|fail|conditional, got ${String(verdict)}`);\n\t\t}\n\t\tif (!Array.isArray(requiredEvidence)) {\n\t\t\tthrow new Error(\"TaskContract requiredEvidence must be an array\");\n\t\t}\n\t\treturn {\n\t\t\tgoalId,\n\t\t\tcompletionClaim,\n\t\t\tfinalRisk,\n\t\t\tverdict,\n\t\t\tcreatedAt,\n\t\t\tupdatedAt,\n\t\t\trequiredEvidence: requiredEvidence.map((item, index) => parseEvidenceItem(item, index)),\n\t\t};\n\t}\n\n\tstatic toJSON(contract: TaskContract): string {\n\t\treturn JSON.stringify(contract, null, 2);\n\t}\n}\n\nconst EVIDENCE_STATUSES: ReadonlySet<string> = new Set([\"pending\", \"gathering\", \"satisfied\", \"failed\", \"waived\"]);\n\nfunction optionalStringField(value: unknown, field: string, index: number): string | undefined {\n\tif (value !== undefined && typeof value !== \"string\") {\n\t\tthrow new Error(`TaskContract evidence[${index}].${field} must be a string when present`);\n\t}\n\treturn value;\n}\n\nfunction parseEvidenceItem(raw: unknown, index: number): EvidenceItem {\n\tif (raw === null || typeof raw !== \"object\" || Array.isArray(raw)) {\n\t\tthrow new Error(`TaskContract evidence[${index}] must be an object`);\n\t}\n\tconst item = raw as Record<string, unknown>;\n\tconst { claim, category, timestamp, status } = item;\n\tif (typeof claim !== \"string\" || typeof category !== \"string\" || typeof timestamp !== \"string\") {\n\t\tthrow new Error(`TaskContract evidence[${index}] has missing or mistyped fields`);\n\t}\n\tif (typeof status !== \"string\" || !EVIDENCE_STATUSES.has(status)) {\n\t\tthrow new Error(`TaskContract evidence[${index}] has invalid status ${String(status)}`);\n\t}\n\tconst receiptSchemaVersion = item.receiptSchemaVersion;\n\tif (receiptSchemaVersion !== undefined && receiptSchemaVersion !== 3) {\n\t\tthrow new Error(`TaskContract evidence[${index}].receiptSchemaVersion must be 3 when present`);\n\t}\n\tconst receiptCommandSha256 = optionalStringField(item.receiptCommandSha256, \"receiptCommandSha256\", index);\n\treturn {\n\t\tclaim,\n\t\tcategory: category as EvidenceItem[\"category\"],\n\t\ttimestamp,\n\t\tstatus: status as EvidenceStatus,\n\t\tartifactPath: optionalStringField(item.artifactPath, \"artifactPath\", index),\n\t\tverificationCommand: optionalStringField(item.verificationCommand, \"verificationCommand\", index),\n\t\thash: optionalStringField(item.hash, \"hash\", index),\n\t\treceiptId: optionalStringField(item.receiptId, \"receiptId\", index),\n\t\treceiptSchemaVersion,\n\t\t...(receiptCommandSha256 !== undefined\n\t\t\t? { receiptCommandSha256: parseSha256Hex(receiptCommandSha256, \"receiptCommandSha256\") }\n\t\t\t: {}),\n\t\treceiptLaneId: optionalStringField(item.receiptLaneId, \"receiptLaneId\", index),\n\t\tgapReason: optionalStringField(item.gapReason, \"gapReason\", index),\n\t};\n}\n\n// ============================================================================\n// ReplayLedger\n// ============================================================================\n\n/** prevHash sentinel for the first event in a replay chain. */\nconst GENESIS_HASH = \"genesis\";\n\nfunction computeEventHash(event: Omit<ReplayEvent, \"eventHash\">): string {\n\treturn sha256(\n\t\tJSON.stringify([\n\t\t\tevent.seq,\n\t\t\tevent.type,\n\t\t\tevent.timestamp,\n\t\t\tevent.goalId,\n\t\t\tevent.laneId ?? null,\n\t\t\tevent.payloadHash,\n\t\t\tevent.prevHash,\n\t\t]),\n\t);\n}\n\nfunction parseReplayEventLine(line: string, lineNumber: number): ReplayEvent {\n\tlet raw: unknown;\n\ttry {\n\t\traw = JSON.parse(line);\n\t} catch {\n\t\tthrow new Error(`Replay ledger corrupted at line ${lineNumber}: invalid JSON`);\n\t}\n\tif (raw === null || typeof raw !== \"object\" || Array.isArray(raw)) {\n\t\tthrow new Error(`Replay ledger corrupted at line ${lineNumber}: event must be an object`);\n\t}\n\tconst event = raw as Record<string, unknown>;\n\tconst { seq, type, timestamp, goalId, laneId, payloadHash, prevHash, eventHash } = event;\n\tif (\n\t\ttypeof seq !== \"number\" ||\n\t\ttypeof type !== \"string\" ||\n\t\ttypeof timestamp !== \"string\" ||\n\t\ttypeof goalId !== \"string\" ||\n\t\ttypeof payloadHash !== \"string\" ||\n\t\ttypeof prevHash !== \"string\" ||\n\t\ttypeof eventHash !== \"string\" ||\n\t\t(laneId !== undefined && typeof laneId !== \"string\") ||\n\t\t!(\"payload\" in event)\n\t) {\n\t\tthrow new Error(`Replay ledger corrupted at line ${lineNumber}: event fields are missing or mistyped`);\n\t}\n\treturn {\n\t\tseq,\n\t\ttype: type as ReplayEvent[\"type\"],\n\t\ttimestamp,\n\t\tgoalId,\n\t\tlaneId,\n\t\tpayload: event.payload,\n\t\tpayloadHash,\n\t\tprevHash,\n\t\teventHash,\n\t};\n}\n\nfunction parseReplayLedgerBytes(bytes: Buffer, goalId: string): ReplayEvent[] {\n\tconst lines = bytes\n\t\t.toString(\"utf8\")\n\t\t.split(\"\\n\")\n\t\t.filter((line) => line.trim().length > 0);\n\tconst events: ReplayEvent[] = [];\n\tlet prevHash = GENESIS_HASH;\n\tfor (let index = 0; index < lines.length; index++) {\n\t\tconst event = parseReplayEventLine(lines[index], index + 1);\n\t\tif (event.goalId !== goalId) throw new Error(`Replay ledger goal mismatch at line ${index + 1}`);\n\t\tif (event.seq !== index + 1) {\n\t\t\tthrow new Error(`Replay ledger corrupted at line ${index + 1}: expected seq ${index + 1}, got ${event.seq}`);\n\t\t}\n\t\tif (event.prevHash !== prevHash) throw new Error(`Replay ledger chain broken at line ${index + 1}`);\n\t\tif (sha256(JSON.stringify(event.payload)) !== event.payloadHash) {\n\t\t\tthrow new Error(`Replay ledger payload tampered at line ${index + 1} (seq ${event.seq})`);\n\t\t}\n\t\tif (computeEventHash(event) !== event.eventHash) {\n\t\t\tthrow new Error(`Replay ledger event hash mismatch at line ${index + 1} (seq ${event.seq})`);\n\t\t}\n\t\tprevHash = event.eventHash;\n\t\tevents.push(event);\n\t}\n\treturn events;\n}\n\nexport class ReplayLedgerManager {\n\tprivate readonly goalId: string;\n\tprivate readonly ledgerPath: string;\n\tprivate readonly store: ReplayLedgerStore;\n\tprivate events: ReplayEvent[] = [];\n\tprivate committedHead: ReplayLedgerHead;\n\n\tconstructor(goalId: string, ledgerPath: string, expectedHead?: ReplayLedgerHead) {\n\t\tthis.goalId = goalId;\n\t\tthis.ledgerPath = ledgerPath;\n\t\tthis.committedHead = { fileIdentity: null, size: 0, lastSeq: 0, lastHash: GENESIS_HASH };\n\t\tthis.store = new ReplayLedgerStore(ledgerPath, (bytes) => {\n\t\t\tconst events = parseReplayLedgerBytes(bytes, goalId);\n\t\t\tconst last = events.at(-1);\n\t\t\treturn { lastSeq: last?.seq ?? 0, lastHash: last?.eventHash ?? GENESIS_HASH };\n\t\t});\n\t\tthis.refresh(expectedHead);\n\t}\n\n\tprivate refresh(expectedHead?: ReplayLedgerHead): void {\n\t\tconst snapshot = this.store.load(expectedHead);\n\t\tthis.events = parseReplayLedgerBytes(snapshot.bytes, this.goalId);\n\t\tthis.committedHead = snapshot.head;\n\t}\n\n\tappend(\n\t\tevent: Omit<ReplayEvent, \"seq\" | \"timestamp\" | \"payloadHash\" | \"prevHash\" | \"eventHash\">,\n\t\texpectedHead: ReplayLedgerHead = this.committedHead,\n\t): ReplayEvent {\n\t\tif (event.goalId !== this.goalId) throw new Error(\"Replay event goalId does not match the ledger\");\n\t\tif (!replayLedgerHeadsEqual(expectedHead, this.committedHead)) {\n\t\t\tthrow new Error(\"Replay manager expected-head CAS is stale\");\n\t\t}\n\t\tconst payloadHash = sha256(JSON.stringify(event.payload));\n\t\tconst chained: Omit<ReplayEvent, \"eventHash\"> = {\n\t\t\t...event,\n\t\t\tseq: expectedHead.lastSeq + 1,\n\t\t\ttimestamp: new Date().toISOString(),\n\t\t\tpayloadHash,\n\t\t\tprevHash: expectedHead.lastHash,\n\t\t};\n\t\tconst fullEvent: ReplayEvent = { ...chained, eventHash: computeEventHash(chained) };\n\t\tthis.committedHead = this.store.append(\n\t\t\tBuffer.from(`${JSON.stringify(fullEvent)}\\n`, \"utf8\"),\n\t\t\tfullEvent.seq,\n\t\t\tfullEvent.eventHash,\n\t\t\texpectedHead,\n\t\t);\n\t\tthis.events.push(fullEvent);\n\t\treturn structuredClone(fullEvent);\n\t}\n\n\t/** Compatibility no-op that still verifies the caller's expected committed head. */\n\tpersist(expectedHead: ReplayLedgerHead = this.committedHead): void {\n\t\tthis.getVerifiedSnapshot(expectedHead);\n\t}\n\n\tload(expectedHead: ReplayLedgerHead = this.committedHead): void {\n\t\tthis.refresh(expectedHead);\n\t}\n\n\tgetCommittedHead(): ReplayLedgerHead {\n\t\treturn structuredClone(this.committedHead);\n\t}\n\n\tgetVerifiedSnapshot(expectedHead: ReplayLedgerHead = this.committedHead): VerifiedReplayLedgerSnapshot {\n\t\tthis.refresh(expectedHead);\n\t\treturn structuredClone({ events: this.events, head: this.committedHead });\n\t}\n\n\tgetEvents(): ReadonlyArray<ReplayEvent> {\n\t\treturn structuredClone(this.events);\n\t}\n\n\tgetLedger(): Readonly<ReplayLedger> {\n\t\treturn structuredClone({\n\t\t\tgoalId: this.goalId,\n\t\t\tevents: this.events,\n\t\t\tledgerPath: this.ledgerPath,\n\t\t\tlastPersistedSeq: this.committedHead.lastSeq,\n\t\t});\n\t}\n\n\treplay<T>(handler: (event: ReplayEvent) => T | undefined): T[] {\n\t\treturn this.events.map(handler).filter((result): result is T => result !== undefined);\n\t}\n\n\texportToFile(path: string): void {\n\t\tensureDir(path);\n\t\twriteFileSync(path, JSON.stringify(this.events, null, 2), \"utf8\");\n\t}\n}\n\n// ============================================================================\n// EvidenceGate\n// ============================================================================\n\nexport interface EvidenceGateOptions {\n\t/** Minimum number of satisfied evidence items required. */\n\tminEvidenceCount?: number;\n\t/** Require at least one artifact with a SHA-256 hash in explicit legacy mode. */\n\trequireHash?: boolean;\n\t/** Require at least one verification command in explicit legacy mode. */\n\trequireVerificationCommand?: boolean;\n\t/** Receipt policy. Defaults to prefer; legacy must be selected explicitly. */\n\treceiptMode?: EvidenceReceiptMode;\n\t/** Resolve a serialized or decoded receipt by ID. The gate validates the returned value. */\n\tresolveReceipt?: (receiptId: string) => unknown;\n\t/** Strict source: one expected-head, file-identity, suffix, and chain-verified snapshot. */\n\tresolveVerifiedLedgerSnapshot?: () => VerifiedReplayLedgerSnapshot;\n\t/** Prefer-mode migration source; strict mode requires resolveVerifiedLedgerSnapshot. */\n\tresolveLedgerEvent?: (seq: number) => ReplayEvent | undefined;\n\t/** Recapture the receipt's workspace scope (same kind and scope) for freshness comparison. */\n\tcaptureWorkspaceFingerprint?: (scope: WorkspaceScope) => unknown;\n\t/**\n\t * Optional freshness source: the latest replay-ledger sequence of a workspace mutation\n\t * relevant to the given scope, or null/undefined when none is known. When configured,\n\t * the receipt's verified ledger seq must strictly exceed this value; a throwing or\n\t * out-of-contract source is a hard block (positive safe integers only).\n\t */\n\tresolveLatestWorkspaceMutationSeq?: (scope: WorkspaceScope) => number | null | undefined;\n\t/** Ephemeral trust anchor used to verify the original command's keyed attestation. */\n\tcommandAttestationBinder?: Pick<CommandHmacBinder, \"verify\">;\n\t/** Resolve the original command inside the same trust boundary as the binder. */\n\tresolveAttestedCommand?: (receiptId: string) => EvidenceCommandDescriptor | undefined;\n}\n\ninterface ReceiptCheckIssue {\n\treadonly message: string;\n\treadonly hard: boolean;\n}\n\nfunction receiptCheckIssue(message: string, hard: boolean): ReceiptCheckIssue {\n\treturn { message, hard };\n}\n\nfunction receiptIssue(\n\titem: EvidenceItem,\n\tcontract: TaskContract,\n\toptions: EvidenceGateOptions,\n): ReceiptCheckIssue | undefined {\n\tif (!item.receiptId) {\n\t\treturn receiptCheckIssue(`Execution receipt is missing for evidence \"${item.claim}\".`, false);\n\t}\n\tconst strict = options.receiptMode === \"strict\";\n\tif (item.receiptSchemaVersion !== 3 && (item.receiptSchemaVersion !== undefined || strict)) {\n\t\treturn receiptCheckIssue(`Execution receipt schema metadata is invalid for evidence \"${item.claim}\".`, true);\n\t}\n\tif (!options.resolveReceipt) {\n\t\treturn receiptCheckIssue(`Execution receipt resolver is missing for evidence \"${item.claim}\".`, false);\n\t}\n\n\tlet rawReceipt: unknown;\n\ttry {\n\t\trawReceipt = options.resolveReceipt(item.receiptId);\n\t} catch {\n\t\treturn receiptCheckIssue(`Execution receipt resolver failed for evidence \"${item.claim}\".`, true);\n\t}\n\tif (rawReceipt === undefined) {\n\t\treturn receiptCheckIssue(`Execution receipt is missing for evidence \"${item.claim}\".`, false);\n\t}\n\n\ttry {\n\t\tconst receipt = validateEvidenceReceipt(rawReceipt);\n\t\tif (receipt.core.receiptId !== item.receiptId) {\n\t\t\treturn receiptCheckIssue(`Execution receipt ID does not match evidence \"${item.claim}\".`, true);\n\t\t}\n\t\tif (receipt.core.goalId !== contract.goalId) {\n\t\t\treturn receiptCheckIssue(`Execution receipt goal does not match evidence \"${item.claim}\".`, true);\n\t\t}\n\t\tif (receipt.core.claim !== item.claim) {\n\t\t\treturn receiptCheckIssue(`Execution receipt claim does not match evidence \"${item.claim}\".`, true);\n\t\t}\n\t\tif (receipt.core.status !== \"passed\" || receipt.core.exitCode !== 0) {\n\t\t\treturn receiptCheckIssue(\n\t\t\t\t`Execution receipt for evidence \"${item.claim}\" did not pass with exit code 0.`,\n\t\t\t\ttrue,\n\t\t\t);\n\t\t}\n\n\t\tif (item.receiptCommandSha256 === undefined) {\n\t\t\treturn receiptCheckIssue(`Execution receipt command binding is missing for evidence \"${item.claim}\".`, false);\n\t\t}\n\t\tconst receiptCommandSha256 = computeEvidenceCommandSha256(receipt.core.command);\n\t\tif (!constantTimeSha256Equal(item.receiptCommandSha256, receiptCommandSha256)) {\n\t\t\treturn receiptCheckIssue(`Execution receipt command does not match evidence \"${item.claim}\".`, true);\n\t\t}\n\t\tconst attestationIssue = verifyCommandAttestation({\n\t\t\treceiptId: receipt.core.receiptId,\n\t\t\tbinding: receipt.core.commandBinding,\n\t\t\tpersistedCommand: receipt.core.command,\n\t\t\tpersistedSummary: receipt.core.commandRedaction,\n\t\t\tbinder: options.commandAttestationBinder,\n\t\t\tresolveCommand: options.resolveAttestedCommand,\n\t\t\tredact: redactCommandDescriptor,\n\t\t});\n\t\tif (attestationIssue !== undefined) {\n\t\t\treturn receiptCheckIssue(\n\t\t\t\t`Execution receipt command attestation ${attestationIssue.detail} for evidence \"${item.claim}\".`,\n\t\t\t\tattestationIssue.hard,\n\t\t\t);\n\t\t}\n\n\t\tif (receipt.core.laneId !== undefined && item.receiptLaneId === undefined) {\n\t\t\treturn receiptCheckIssue(`Execution receipt lane binding is missing for evidence \"${item.claim}\".`, false);\n\t\t}\n\t\tif (item.receiptLaneId !== receipt.core.laneId) {\n\t\t\treturn receiptCheckIssue(`Execution receipt lane does not match evidence \"${item.claim}\".`, true);\n\t\t}\n\n\t\tconst workspaceIssue = verifyWorkspaceBinding(receipt.core.workspaceAfter, options.captureWorkspaceFingerprint);\n\t\tif (workspaceIssue !== undefined) {\n\t\t\treturn receiptCheckIssue(\n\t\t\t\t`Execution receipt ${workspaceIssue.detail} for evidence \"${item.claim}\".`,\n\t\t\t\tworkspaceIssue.hard,\n\t\t\t);\n\t\t}\n\n\t\tlet snapshot: VerifiedReplayLedgerSnapshot | undefined;\n\t\tif (options.resolveVerifiedLedgerSnapshot !== undefined) {\n\t\t\ttry {\n\t\t\t\tsnapshot = parseVerifiedLedgerSnapshot(\n\t\t\t\t\toptions.resolveVerifiedLedgerSnapshot(),\n\t\t\t\t\tcontract.goalId,\n\t\t\t\t\tparseReplayLedgerBytes,\n\t\t\t\t);\n\t\t\t} catch {\n\t\t\t\treturn receiptCheckIssue(\n\t\t\t\t\t`Execution receipt verified ledger snapshot failed for evidence \"${item.claim}\".`,\n\t\t\t\t\ttrue,\n\t\t\t\t);\n\t\t\t}\n\t\t} else if (strict) {\n\t\t\treturn receiptCheckIssue(\n\t\t\t\t`Execution receipt verified ledger snapshot is missing for evidence \"${item.claim}\".`,\n\t\t\t\tfalse,\n\t\t\t);\n\t\t}\n\t\tlet latestMutationSeq =\n\t\t\tsnapshot === undefined\n\t\t\t\t? null\n\t\t\t\t: latestRelevantWorkspaceMutationSeq(snapshot.events, receipt.core.workspaceAfter.scope);\n\t\tif (snapshot === undefined && options.resolveLatestWorkspaceMutationSeq !== undefined) {\n\t\t\tlet resolved: unknown;\n\t\t\ttry {\n\t\t\t\tresolved = options.resolveLatestWorkspaceMutationSeq(receipt.core.workspaceAfter.scope);\n\t\t\t} catch {\n\t\t\t\treturn receiptCheckIssue(\n\t\t\t\t\t`Execution receipt workspace-mutation freshness source failed for evidence \"${item.claim}\".`,\n\t\t\t\t\ttrue,\n\t\t\t\t);\n\t\t\t}\n\t\t\tif (resolved !== null && resolved !== undefined) {\n\t\t\t\tif (!Number.isSafeInteger(resolved) || (resolved as number) <= 0) {\n\t\t\t\t\treturn receiptCheckIssue(\n\t\t\t\t\t\t`Execution receipt workspace-mutation freshness source is malformed for evidence \"${item.claim}\".`,\n\t\t\t\t\t\ttrue,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\tlatestMutationSeq = resolved as number;\n\t\t\t}\n\t\t}\n\n\t\tconst binding = receipt.envelope.ledgerBinding;\n\t\tif (!binding) {\n\t\t\treturn receiptCheckIssue(\n\t\t\t\t`Execution receipt ledger binding is missing for evidence \"${item.claim}\".`,\n\t\t\t\tlatestMutationSeq !== null,\n\t\t\t);\n\t\t}\n\t\tconst event = snapshot\n\t\t\t? snapshot.events.find((candidate) => candidate.seq === binding.seq)\n\t\t\t: options.resolveLedgerEvent?.(binding.seq);\n\t\tif (!event && snapshot === undefined && !options.resolveLedgerEvent) {\n\t\t\treturn receiptCheckIssue(\n\t\t\t\t`Execution receipt ledger resolver is missing for evidence \"${item.claim}\".`,\n\t\t\t\tlatestMutationSeq !== null,\n\t\t\t);\n\t\t}\n\t\tconst replayPayload = evidenceReceiptReplayPayload(receipt);\n\t\tif (\n\t\t\t!event ||\n\t\t\tevent.seq !== binding.seq ||\n\t\t\tevent.type !== \"evidence_receipt\" ||\n\t\t\tevent.goalId !== contract.goalId ||\n\t\t\tevent.laneId !== receipt.core.laneId ||\n\t\t\t!constantTimeSha256Equal(event.eventHash, binding.eventHash) ||\n\t\t\t!replayPayloadMatches(event.payload, replayPayload.receiptId, replayPayload.coreSha256)\n\t\t) {\n\t\t\treturn receiptCheckIssue(`Execution receipt ledger binding does not match evidence \"${item.claim}\".`, true);\n\t\t}\n\t\tif (latestMutationSeq !== null && event.seq <= latestMutationSeq) {\n\t\t\treturn receiptCheckIssue(\n\t\t\t\t`Execution receipt is stale: workspace mutation seq ${latestMutationSeq} does not precede receipt ledger seq ${event.seq} for evidence \"${item.claim}\".`,\n\t\t\t\ttrue,\n\t\t\t);\n\t\t}\n\t} catch {\n\t\treturn receiptCheckIssue(`Execution receipt is invalid for evidence \"${item.claim}\".`, true);\n\t}\n\treturn undefined;\n}\n\nexport class EvidenceGate {\n\tprivate options: EvidenceGateOptions;\n\n\tconstructor(options: EvidenceGateOptions = {}) {\n\t\tthis.options = {\n\t\t\tminEvidenceCount: 1,\n\t\t\trequireHash: true,\n\t\t\trequireVerificationCommand: true,\n\t\t\treceiptMode: \"prefer\",\n\t\t\t...options,\n\t\t};\n\t}\n\n\tcheck(contract: TaskContract): MergeGateResult {\n\t\tconst evidence = contract.requiredEvidence;\n\t\tconst satisfied = evidence.filter((e) => e.status === \"satisfied\");\n\t\tconst failed = evidence.filter((e) => e.status === \"failed\");\n\t\tconst pending = evidence.filter((e) => e.status === \"pending\" || e.status === \"gathering\");\n\t\tconst mode = this.options.receiptMode ?? \"prefer\";\n\t\tconst checks: string[] = [];\n\t\tlet hardReceiptFailure = false;\n\n\t\tif (satisfied.length < (this.options.minEvidenceCount ?? 1)) {\n\t\t\tchecks.push(`Only ${satisfied.length}/${this.options.minEvidenceCount} required evidence items satisfied.`);\n\t\t}\n\t\tif (failed.length > 0) {\n\t\t\tchecks.push(`${failed.length} evidence item(s) failed.`);\n\t\t}\n\n\t\tif (mode === \"legacy\") {\n\t\t\tif (this.options.requireHash) {\n\t\t\t\tconst hashed = satisfied.filter((e) => e.hash && e.hash.length > 0);\n\t\t\t\tif (hashed.length === 0) checks.push(\"No satisfied evidence has a SHA-256 hash.\");\n\t\t\t}\n\t\t\tif (this.options.requireVerificationCommand) {\n\t\t\t\tconst withCommand = satisfied.filter((e) => e.verificationCommand && e.verificationCommand.length > 0);\n\t\t\t\tif (withCommand.length === 0) checks.push(\"No satisfied evidence has a verification command.\");\n\t\t\t}\n\t\t} else {\n\t\t\tconst unsatisfied = evidence.filter((item) => item.status !== \"satisfied\");\n\t\t\tif (unsatisfied.length > 0) {\n\t\t\t\tchecks.push(`${unsatisfied.length} required evidence item(s) are not satisfied.`);\n\t\t\t}\n\t\t\tfor (const item of satisfied) {\n\t\t\t\tconst issue = receiptIssue(item, contract, this.options);\n\t\t\t\tif (issue) {\n\t\t\t\t\tchecks.push(issue.message);\n\t\t\t\t\thardReceiptFailure ||= issue.hard;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif (contract.verdict === \"fail\" || (mode !== \"legacy\" && contract.verdict !== \"pass\")) {\n\t\t\tchecks.push(`Task contract verdict is '${contract.verdict}'.`);\n\t\t}\n\n\t\tlet status: MergeGateStatus;\n\t\tlet reason: string;\n\t\tlet suggestion: string | undefined;\n\t\tif (checks.length === 0) {\n\t\t\tstatus = \"open\";\n\t\t\treason = `Evidence gate passed: ${satisfied.length}/${evidence.length} evidence items satisfied.`;\n\t\t} else {\n\t\t\tconst contractFailure = mode === \"legacy\" ? contract.verdict === \"fail\" : contract.verdict !== \"pass\";\n\t\t\tconst hasHardFailure = failed.length > 0 || contractFailure || hardReceiptFailure || mode === \"strict\";\n\t\t\tstatus = hasHardFailure ? \"blocked\" : mode === \"prefer\" || pending.length > 0 ? \"conditional\" : \"blocked\";\n\t\t\treason = checks.join(\"; \");\n\t\t\tsuggestion = `Gather remaining evidence (${pending.length} pending) and re-run verification.`;\n\t\t}\n\n\t\treturn {\n\t\t\tgateId: \"evidence-gate\",\n\t\t\tstatus,\n\t\t\treason,\n\t\t\tsuggestion,\n\t\t\tevidenceChecked: evidence,\n\t\t};\n\t}\n}\n\n// ============================================================================\n// FailClosedMergeGate\n// ============================================================================\n\nexport class FailClosedMergeGate {\n\tprivate gates: EvidenceGate[];\n\n\tconstructor(gates: EvidenceGate[] = [new EvidenceGate()]) {\n\t\tthis.gates = gates;\n\t}\n\n\tcheck(contract: TaskContract): MergeGateResult {\n\t\tconst results = this.gates.map((gate) => gate.check(contract));\n\t\tconst blocked = results.filter((r) => r.status === \"blocked\");\n\t\tconst conditional = results.filter((r) => r.status === \"conditional\");\n\n\t\tif (blocked.length > 0) {\n\t\t\treturn {\n\t\t\t\tgateId: \"fail-closed-merge-gate\",\n\t\t\t\tstatus: \"blocked\",\n\t\t\t\treason: `Blocked by ${blocked.length} gate(s): ${blocked.map((b) => b.reason).join(\"; \")}`,\n\t\t\t\tsuggestion: \"Resolve all blocking conditions before merge.\",\n\t\t\t\tevidenceChecked: contract.requiredEvidence,\n\t\t\t};\n\t\t}\n\n\t\tif (conditional.length > 0) {\n\t\t\treturn {\n\t\t\t\tgateId: \"fail-closed-merge-gate\",\n\t\t\t\tstatus: \"conditional\",\n\t\t\t\treason: `Conditional pass: ${conditional.length} gate(s) have pending conditions.`,\n\t\t\t\tsuggestion: \"Complete pending evidence or waive with explicit approval.\",\n\t\t\t\tevidenceChecked: contract.requiredEvidence,\n\t\t\t};\n\t\t}\n\n\t\treturn {\n\t\t\tgateId: \"fail-closed-merge-gate\",\n\t\t\tstatus: \"open\",\n\t\t\treason: \"All merge gates passed. Evidence verified and contract verdict is acceptable.\",\n\t\t\tevidenceChecked: contract.requiredEvidence,\n\t\t};\n\t}\n}\n\n// ============================================================================\n// Verify Reporter v2\n// ============================================================================\n\n/** Escape pipes/newlines so untrusted claim or command text cannot restructure the report table. */\nfunction escapeTableCell(value: string): string {\n\treturn value.replace(/\\\\/g, \"\\\\\\\\\").replace(/\\|/g, \"\\\\|\").replace(/\\r?\\n/g, \" \");\n}\n\nexport interface VerifyReporterV2Options {\n\toutputDir: string;\n\tgoalId: string;\n}\n\nexport class VerifyReporterV2 {\n\tprivate options: VerifyReporterV2Options;\n\n\tconstructor(options: VerifyReporterV2Options) {\n\t\tthis.options = options;\n\t}\n\n\trender(contract: TaskContract, mergeGate: MergeGateResult): string {\n\t\tconst lines: string[] = [\n\t\t\t`## OMK Verification Report v2 — ${contract.goalId}`,\n\t\t\t\"\",\n\t\t\t\"### Contract\",\n\t\t\t\"\",\n\t\t\t`| Field | Value |`,\n\t\t\t`|-------|-------|`,\n\t\t\t`| Claim | ${escapeTableCell(contract.completionClaim)} |`,\n\t\t\t`| Verdict | ${contract.verdict} |`,\n\t\t\t`| Final Risk | ${escapeTableCell(contract.finalRisk)} |`,\n\t\t\t\"\",\n\t\t\t\"### Evidence\",\n\t\t\t\"\",\n\t\t\t`| Claim | Status | Artifact | Command |`,\n\t\t\t`|-------|--------|----------|----------|`,\n\t\t];\n\n\t\tfor (const ev of contract.requiredEvidence) {\n\t\t\tlines.push(\n\t\t\t\t`| ${escapeTableCell(ev.claim)} | ${ev.status} | ${escapeTableCell(ev.artifactPath ?? \"—\")} | ${escapeTableCell(ev.verificationCommand ?? \"—\")} |`,\n\t\t\t);\n\t\t}\n\n\t\tlines.push(\n\t\t\t\"\",\n\t\t\t\"### Merge Gate\",\n\t\t\t\"\",\n\t\t\t`| Gate | Status | Reason |`,\n\t\t\t`|------|--------|--------|`,\n\t\t\t`| ${mergeGate.gateId} | ${mergeGate.status} | ${escapeTableCell(mergeGate.reason)} |`,\n\t\t\t\"\",\n\t\t);\n\n\t\tif (mergeGate.suggestion) {\n\t\t\tlines.push(`**Suggestion:** ${mergeGate.suggestion}`, \"\");\n\t\t}\n\n\t\treturn lines.join(\"\\n\");\n\t}\n\n\twrite(contract: TaskContract, mergeGate: MergeGateResult): string {\n\t\tconst markdown = this.render(contract, mergeGate);\n\t\tconst path = join(this.options.outputDir, `${this.options.goalId}.verify.md`);\n\t\tensureDir(path);\n\t\twriteFileSync(path, markdown, \"utf-8\");\n\t\treturn path;\n\t}\n}\n"]}
@@ -0,0 +1,6 @@
1
+ import type { LockOwner } from "./replay-ledger-lock-owner.ts";
2
+ export declare function writeAll(fd: number, bytes: Buffer): void;
3
+ export declare function fsyncDirectory(path: string): void;
4
+ export declare function createLockCandidate(path: string, owner: LockOwner): string;
5
+ export declare function removeLockCandidate(path: string): void;
6
+ //# sourceMappingURL=replay-ledger-io.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"replay-ledger-io.d.ts","sourceRoot":"","sources":["../../src/guardrails/replay-ledger-io.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,+BAA+B,CAAC;AAG/D,wBAAgB,QAAQ,CAAC,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,CAOxD;AAED,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAOjD;AAED,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,SAAS,GAAG,MAAM,CAU1E;AAED,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAMtD","sourcesContent":["import { closeSync, constants as fsConstants, fsyncSync, openSync, unlinkSync, writeSync } from \"node:fs\";\nimport type { LockOwner } from \"./replay-ledger-lock-owner.ts\";\nimport { errorCode, ReplayLedgerLockError } from \"./replay-ledger-lock-owner.ts\";\n\nexport function writeAll(fd: number, bytes: Buffer): void {\n\tlet offset = 0;\n\twhile (offset < bytes.byteLength) {\n\t\tconst written = writeSync(fd, bytes, offset, bytes.byteLength - offset);\n\t\tif (written <= 0) throw new ReplayLedgerLockError(\"replay lock owner record write did not complete\");\n\t\toffset += written;\n\t}\n}\n\nexport function fsyncDirectory(path: string): void {\n\tconst fd = openSync(path, fsConstants.O_RDONLY | (fsConstants.O_DIRECTORY ?? 0));\n\ttry {\n\t\tfsyncSync(fd);\n\t} finally {\n\t\tcloseSync(fd);\n\t}\n}\n\nexport function createLockCandidate(path: string, owner: LockOwner): string {\n\tconst candidate = `${path}.${owner.ownerId}.candidate`;\n\tconst fd = openSync(candidate, fsConstants.O_CREAT | fsConstants.O_EXCL | fsConstants.O_WRONLY, 0o600);\n\ttry {\n\t\twriteAll(fd, Buffer.from(`${JSON.stringify(owner)}\\n`, \"utf8\"));\n\t\tfsyncSync(fd);\n\t} finally {\n\t\tcloseSync(fd);\n\t}\n\treturn candidate;\n}\n\nexport function removeLockCandidate(path: string): void {\n\ttry {\n\t\tunlinkSync(path);\n\t} catch (error) {\n\t\tif (errorCode(error) !== \"ENOENT\") throw error;\n\t}\n}\n"]}
@@ -0,0 +1,42 @@
1
+ import { closeSync, constants as fsConstants, fsyncSync, openSync, unlinkSync, writeSync } from "node:fs";
2
+ import { errorCode, ReplayLedgerLockError } from "./replay-ledger-lock-owner.js";
3
+ export function writeAll(fd, bytes) {
4
+ let offset = 0;
5
+ while (offset < bytes.byteLength) {
6
+ const written = writeSync(fd, bytes, offset, bytes.byteLength - offset);
7
+ if (written <= 0)
8
+ throw new ReplayLedgerLockError("replay lock owner record write did not complete");
9
+ offset += written;
10
+ }
11
+ }
12
+ export function fsyncDirectory(path) {
13
+ const fd = openSync(path, fsConstants.O_RDONLY | (fsConstants.O_DIRECTORY ?? 0));
14
+ try {
15
+ fsyncSync(fd);
16
+ }
17
+ finally {
18
+ closeSync(fd);
19
+ }
20
+ }
21
+ export function createLockCandidate(path, owner) {
22
+ const candidate = `${path}.${owner.ownerId}.candidate`;
23
+ const fd = openSync(candidate, fsConstants.O_CREAT | fsConstants.O_EXCL | fsConstants.O_WRONLY, 0o600);
24
+ try {
25
+ writeAll(fd, Buffer.from(`${JSON.stringify(owner)}\n`, "utf8"));
26
+ fsyncSync(fd);
27
+ }
28
+ finally {
29
+ closeSync(fd);
30
+ }
31
+ return candidate;
32
+ }
33
+ export function removeLockCandidate(path) {
34
+ try {
35
+ unlinkSync(path);
36
+ }
37
+ catch (error) {
38
+ if (errorCode(error) !== "ENOENT")
39
+ throw error;
40
+ }
41
+ }
42
+ //# sourceMappingURL=replay-ledger-io.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"replay-ledger-io.js","sourceRoot":"","sources":["../../src/guardrails/replay-ledger-io.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,SAAS,IAAI,WAAW,EAAE,SAAS,EAAE,QAAQ,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AAE1G,OAAO,EAAE,SAAS,EAAE,qBAAqB,EAAE,MAAM,+BAA+B,CAAC;AAEjF,MAAM,UAAU,QAAQ,CAAC,EAAU,EAAE,KAAa,EAAQ;IACzD,IAAI,MAAM,GAAG,CAAC,CAAC;IACf,OAAO,MAAM,GAAG,KAAK,CAAC,UAAU,EAAE,CAAC;QAClC,MAAM,OAAO,GAAG,SAAS,CAAC,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,CAAC,UAAU,GAAG,MAAM,CAAC,CAAC;QACxE,IAAI,OAAO,IAAI,CAAC;YAAE,MAAM,IAAI,qBAAqB,CAAC,iDAAiD,CAAC,CAAC;QACrG,MAAM,IAAI,OAAO,CAAC;IACnB,CAAC;AAAA,CACD;AAED,MAAM,UAAU,cAAc,CAAC,IAAY,EAAQ;IAClD,MAAM,EAAE,GAAG,QAAQ,CAAC,IAAI,EAAE,WAAW,CAAC,QAAQ,GAAG,CAAC,WAAW,CAAC,WAAW,IAAI,CAAC,CAAC,CAAC,CAAC;IACjF,IAAI,CAAC;QACJ,SAAS,CAAC,EAAE,CAAC,CAAC;IACf,CAAC;YAAS,CAAC;QACV,SAAS,CAAC,EAAE,CAAC,CAAC;IACf,CAAC;AAAA,CACD;AAED,MAAM,UAAU,mBAAmB,CAAC,IAAY,EAAE,KAAgB,EAAU;IAC3E,MAAM,SAAS,GAAG,GAAG,IAAI,IAAI,KAAK,CAAC,OAAO,YAAY,CAAC;IACvD,MAAM,EAAE,GAAG,QAAQ,CAAC,SAAS,EAAE,WAAW,CAAC,OAAO,GAAG,WAAW,CAAC,MAAM,GAAG,WAAW,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAC;IACvG,IAAI,CAAC;QACJ,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,CAAC;QAChE,SAAS,CAAC,EAAE,CAAC,CAAC;IACf,CAAC;YAAS,CAAC;QACV,SAAS,CAAC,EAAE,CAAC,CAAC;IACf,CAAC;IACD,OAAO,SAAS,CAAC;AAAA,CACjB;AAED,MAAM,UAAU,mBAAmB,CAAC,IAAY,EAAQ;IACvD,IAAI,CAAC;QACJ,UAAU,CAAC,IAAI,CAAC,CAAC;IAClB,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QAChB,IAAI,SAAS,CAAC,KAAK,CAAC,KAAK,QAAQ;YAAE,MAAM,KAAK,CAAC;IAChD,CAAC;AAAA,CACD","sourcesContent":["import { closeSync, constants as fsConstants, fsyncSync, openSync, unlinkSync, writeSync } from \"node:fs\";\nimport type { LockOwner } from \"./replay-ledger-lock-owner.ts\";\nimport { errorCode, ReplayLedgerLockError } from \"./replay-ledger-lock-owner.ts\";\n\nexport function writeAll(fd: number, bytes: Buffer): void {\n\tlet offset = 0;\n\twhile (offset < bytes.byteLength) {\n\t\tconst written = writeSync(fd, bytes, offset, bytes.byteLength - offset);\n\t\tif (written <= 0) throw new ReplayLedgerLockError(\"replay lock owner record write did not complete\");\n\t\toffset += written;\n\t}\n}\n\nexport function fsyncDirectory(path: string): void {\n\tconst fd = openSync(path, fsConstants.O_RDONLY | (fsConstants.O_DIRECTORY ?? 0));\n\ttry {\n\t\tfsyncSync(fd);\n\t} finally {\n\t\tcloseSync(fd);\n\t}\n}\n\nexport function createLockCandidate(path: string, owner: LockOwner): string {\n\tconst candidate = `${path}.${owner.ownerId}.candidate`;\n\tconst fd = openSync(candidate, fsConstants.O_CREAT | fsConstants.O_EXCL | fsConstants.O_WRONLY, 0o600);\n\ttry {\n\t\twriteAll(fd, Buffer.from(`${JSON.stringify(owner)}\\n`, \"utf8\"));\n\t\tfsyncSync(fd);\n\t} finally {\n\t\tcloseSync(fd);\n\t}\n\treturn candidate;\n}\n\nexport function removeLockCandidate(path: string): void {\n\ttry {\n\t\tunlinkSync(path);\n\t} catch (error) {\n\t\tif (errorCode(error) !== \"ENOENT\") throw error;\n\t}\n}\n"]}
@@ -0,0 +1,32 @@
1
+ export type LockOwner = {
2
+ readonly schemaVersion: 2;
3
+ readonly pid: number;
4
+ readonly processStartToken: string | null;
5
+ readonly acquiredAtMs: number;
6
+ readonly ownerId: string;
7
+ };
8
+ export type LockOwnerSnapshot = {
9
+ readonly owner: LockOwner;
10
+ readonly dev: string;
11
+ readonly ino: string;
12
+ };
13
+ export type ReplayLedgerProcessIdentity = {
14
+ readonly state: "present";
15
+ readonly startToken: string;
16
+ } | {
17
+ readonly state: "absent";
18
+ } | {
19
+ readonly state: "unavailable";
20
+ };
21
+ export type ReplayLedgerProcessIdentityReader = (pid: number) => ReplayLedgerProcessIdentity;
22
+ export declare class ReplayLedgerLockError extends Error {
23
+ readonly name = "ReplayLedgerLockError";
24
+ }
25
+ export declare function errorCode(error: unknown): string | undefined;
26
+ export declare function readLockOwner(path: string): LockOwnerSnapshot;
27
+ export declare function lockOwnersEqual(left: LockOwnerSnapshot, right: LockOwnerSnapshot): boolean;
28
+ export declare function createLockOwner(processIdentity: ReplayLedgerProcessIdentityReader): LockOwner;
29
+ export declare function lockOwnerIsDead(owner: LockOwner, processIdentity: ReplayLedgerProcessIdentityReader): boolean;
30
+ export declare function parseLinuxProcessIdentityStat(stat: string): ReplayLedgerProcessIdentity;
31
+ export declare function inspectProcessIdentity(pid: number): ReplayLedgerProcessIdentity;
32
+ //# sourceMappingURL=replay-ledger-lock-owner.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"replay-ledger-lock-owner.d.ts","sourceRoot":"","sources":["../../src/guardrails/replay-ledger-lock-owner.ts"],"names":[],"mappings":"AAQA,MAAM,MAAM,SAAS,GAAG;IACvB,QAAQ,CAAC,aAAa,EAAE,CAAC,CAAC;IAC1B,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,iBAAiB,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1C,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;CACzB,CAAC;AAEF,MAAM,MAAM,iBAAiB,GAAG;IAC/B,QAAQ,CAAC,KAAK,EAAE,SAAS,CAAC;IAC1B,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;CACrB,CAAC;AAEF,MAAM,MAAM,2BAA2B,GACpC;IAAE,QAAQ,CAAC,KAAK,EAAE,SAAS,CAAC;IAAC,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAA;CAAE,GAC1D;IAAE,QAAQ,CAAC,KAAK,EAAE,QAAQ,CAAA;CAAE,GAC5B;IAAE,QAAQ,CAAC,KAAK,EAAE,aAAa,CAAA;CAAE,CAAC;AAErC,MAAM,MAAM,iCAAiC,GAAG,CAAC,GAAG,EAAE,MAAM,KAAK,2BAA2B,CAAC;AAE7F,qBAAa,qBAAsB,SAAQ,KAAK;IAC/C,QAAQ,CAAC,IAAI,2BAA2B;CACxC;AAED,wBAAgB,SAAS,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,GAAG,SAAS,CAG5D;AA6CD,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,iBAAiB,CAqB7D;AAED,wBAAgB,eAAe,CAAC,IAAI,EAAE,iBAAiB,EAAE,KAAK,EAAE,iBAAiB,GAAG,OAAO,CAS1F;AAED,wBAAgB,eAAe,CAAC,eAAe,EAAE,iCAAiC,GAAG,SAAS,CAY7F;AAED,wBAAgB,eAAe,CAAC,KAAK,EAAE,SAAS,EAAE,eAAe,EAAE,iCAAiC,GAAG,OAAO,CAU7G;AAED,wBAAgB,6BAA6B,CAAC,IAAI,EAAE,MAAM,GAAG,2BAA2B,CAavF;AAED,wBAAgB,sBAAsB,CAAC,GAAG,EAAE,MAAM,GAAG,2BAA2B,CAQ/E","sourcesContent":["import { randomUUID } from \"node:crypto\";\nimport { closeSync, constants as fsConstants, fstatSync, openSync, readFileSync } from \"node:fs\";\n\nconst MAX_LOCK_RECORD_BYTES = 512;\nconst MAX_CLOCK_SKEW_MS = 60_000;\nconst OWNER_ID = /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/;\nconst PROCESS_START_TOKEN = /^[A-Za-z0-9._:-]{1,128}$/;\n\nexport type LockOwner = {\n\treadonly schemaVersion: 2;\n\treadonly pid: number;\n\treadonly processStartToken: string | null;\n\treadonly acquiredAtMs: number;\n\treadonly ownerId: string;\n};\n\nexport type LockOwnerSnapshot = {\n\treadonly owner: LockOwner;\n\treadonly dev: string;\n\treadonly ino: string;\n};\n\nexport type ReplayLedgerProcessIdentity =\n\t| { readonly state: \"present\"; readonly startToken: string }\n\t| { readonly state: \"absent\" }\n\t| { readonly state: \"unavailable\" };\n\nexport type ReplayLedgerProcessIdentityReader = (pid: number) => ReplayLedgerProcessIdentity;\n\nexport class ReplayLedgerLockError extends Error {\n\treadonly name = \"ReplayLedgerLockError\";\n}\n\nexport function errorCode(error: unknown): string | undefined {\n\tif (typeof error !== \"object\" || error === null || !(\"code\" in error)) return undefined;\n\treturn typeof error.code === \"string\" ? error.code : undefined;\n}\n\nfunction ownerInteger(value: unknown): number {\n\tif (typeof value !== \"number\" || !Number.isSafeInteger(value) || value <= 0) {\n\t\tthrow new ReplayLedgerLockError(\"replay lock owner record is invalid\");\n\t}\n\treturn value;\n}\n\nfunction parseOwner(bytes: Buffer): LockOwner {\n\tif (bytes.byteLength === 0 || bytes.byteLength > MAX_LOCK_RECORD_BYTES) {\n\t\tthrow new ReplayLedgerLockError(\"replay lock owner record is outside its size bound\");\n\t}\n\tlet value: unknown;\n\ttry {\n\t\tvalue = JSON.parse(bytes.toString(\"utf8\"));\n\t} catch (error) {\n\t\tthrow new ReplayLedgerLockError(\"replay lock owner record is malformed\", { cause: error });\n\t}\n\tif (\n\t\ttypeof value !== \"object\" ||\n\t\tvalue === null ||\n\t\tArray.isArray(value) ||\n\t\tObject.keys(value).sort().join(\",\") !== \"acquiredAtMs,ownerId,pid,processStartToken,schemaVersion\" ||\n\t\t!(\"schemaVersion\" in value) ||\n\t\tvalue.schemaVersion !== 2 ||\n\t\t!(\"pid\" in value) ||\n\t\t!(\"processStartToken\" in value) ||\n\t\t!(\"acquiredAtMs\" in value) ||\n\t\t!(\"ownerId\" in value) ||\n\t\ttypeof value.ownerId !== \"string\" ||\n\t\t!OWNER_ID.test(value.ownerId) ||\n\t\t(value.processStartToken !== null &&\n\t\t\t(typeof value.processStartToken !== \"string\" || !PROCESS_START_TOKEN.test(value.processStartToken)))\n\t) {\n\t\tthrow new ReplayLedgerLockError(\"replay lock owner record is invalid\");\n\t}\n\tconst pid = ownerInteger(value.pid);\n\tconst acquiredAtMs = ownerInteger(value.acquiredAtMs);\n\tif (acquiredAtMs > Date.now() + MAX_CLOCK_SKEW_MS) {\n\t\tthrow new ReplayLedgerLockError(\"replay lock owner record is invalid\");\n\t}\n\treturn { schemaVersion: 2, pid, processStartToken: value.processStartToken, acquiredAtMs, ownerId: value.ownerId };\n}\n\nexport function readLockOwner(path: string): LockOwnerSnapshot {\n\tconst fd = openSync(path, fsConstants.O_RDONLY | (fsConstants.O_NOFOLLOW ?? 0));\n\ttry {\n\t\tconst before = fstatSync(fd, { bigint: true });\n\t\tif (!before.isFile() || before.size <= 0n || before.size > BigInt(MAX_LOCK_RECORD_BYTES)) {\n\t\t\tthrow new ReplayLedgerLockError(\"replay lock owner record is outside its size bound\");\n\t\t}\n\t\tconst bytes = readFileSync(fd);\n\t\tconst after = fstatSync(fd, { bigint: true });\n\t\tif (\n\t\t\tbefore.dev !== after.dev ||\n\t\t\tbefore.ino !== after.ino ||\n\t\t\tbefore.size !== after.size ||\n\t\t\tafter.size !== BigInt(bytes.length)\n\t\t) {\n\t\t\tthrow new ReplayLedgerLockError(\"replay lock owner record changed during inspection\");\n\t\t}\n\t\treturn { owner: parseOwner(bytes), dev: String(after.dev), ino: String(after.ino) };\n\t} finally {\n\t\tcloseSync(fd);\n\t}\n}\n\nexport function lockOwnersEqual(left: LockOwnerSnapshot, right: LockOwnerSnapshot): boolean {\n\treturn (\n\t\tleft.dev === right.dev &&\n\t\tleft.ino === right.ino &&\n\t\tleft.owner.ownerId === right.owner.ownerId &&\n\t\tleft.owner.pid === right.owner.pid &&\n\t\tleft.owner.processStartToken === right.owner.processStartToken &&\n\t\tleft.owner.acquiredAtMs === right.owner.acquiredAtMs\n\t);\n}\n\nexport function createLockOwner(processIdentity: ReplayLedgerProcessIdentityReader): LockOwner {\n\tconst identity = processIdentity(process.pid);\n\tif (identity.state !== \"present\" || !PROCESS_START_TOKEN.test(identity.startToken)) {\n\t\tthrow new ReplayLedgerLockError(\"replay lock acquisition requires process-start identity\");\n\t}\n\treturn {\n\t\tschemaVersion: 2,\n\t\tpid: process.pid,\n\t\tprocessStartToken: identity.startToken,\n\t\tacquiredAtMs: Date.now(),\n\t\townerId: randomUUID(),\n\t};\n}\n\nexport function lockOwnerIsDead(owner: LockOwner, processIdentity: ReplayLedgerProcessIdentityReader): boolean {\n\tconst current = processIdentity(owner.pid);\n\tif (current.state === \"unavailable\") {\n\t\tthrow new ReplayLedgerLockError(\"replay lock owner liveness could not be established\");\n\t}\n\tif (current.state === \"absent\") return true;\n\tif (owner.processStartToken === null) {\n\t\tthrow new ReplayLedgerLockError(\"replay lock recovery requires process-start identity\");\n\t}\n\treturn current.startToken !== owner.processStartToken;\n}\n\nexport function parseLinuxProcessIdentityStat(stat: string): ReplayLedgerProcessIdentity {\n\tif (stat.length > 4_096) return { state: \"unavailable\" };\n\tconst close = stat.lastIndexOf(\")\");\n\tif (close < 0) return { state: \"unavailable\" };\n\tconst fields = stat\n\t\t.slice(close + 2)\n\t\t.trim()\n\t\t.split(/\\s+/);\n\tif ([\"Z\", \"X\", \"x\"].includes(fields[0] ?? \"\")) return { state: \"absent\" };\n\tconst startTime = fields[19];\n\treturn startTime !== undefined && /^\\d+$/.test(startTime)\n\t\t? { state: \"present\", startToken: `linux:${startTime}` }\n\t\t: { state: \"unavailable\" };\n}\n\nexport function inspectProcessIdentity(pid: number): ReplayLedgerProcessIdentity {\n\tif (process.platform !== \"linux\") return { state: \"unavailable\" };\n\ttry {\n\t\treturn parseLinuxProcessIdentityStat(readFileSync(`/proc/${pid}/stat`, \"utf8\"));\n\t} catch (error) {\n\t\tif (!(error instanceof Error)) throw error;\n\t\treturn errorCode(error) === \"ENOENT\" ? { state: \"absent\" } : { state: \"unavailable\" };\n\t}\n}\n"]}
@@ -0,0 +1,138 @@
1
+ import { randomUUID } from "node:crypto";
2
+ import { closeSync, constants as fsConstants, fstatSync, openSync, readFileSync } from "node:fs";
3
+ const MAX_LOCK_RECORD_BYTES = 512;
4
+ const MAX_CLOCK_SKEW_MS = 60_000;
5
+ const OWNER_ID = /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/;
6
+ const PROCESS_START_TOKEN = /^[A-Za-z0-9._:-]{1,128}$/;
7
+ export class ReplayLedgerLockError extends Error {
8
+ name = "ReplayLedgerLockError";
9
+ }
10
+ export function errorCode(error) {
11
+ if (typeof error !== "object" || error === null || !("code" in error))
12
+ return undefined;
13
+ return typeof error.code === "string" ? error.code : undefined;
14
+ }
15
+ function ownerInteger(value) {
16
+ if (typeof value !== "number" || !Number.isSafeInteger(value) || value <= 0) {
17
+ throw new ReplayLedgerLockError("replay lock owner record is invalid");
18
+ }
19
+ return value;
20
+ }
21
+ function parseOwner(bytes) {
22
+ if (bytes.byteLength === 0 || bytes.byteLength > MAX_LOCK_RECORD_BYTES) {
23
+ throw new ReplayLedgerLockError("replay lock owner record is outside its size bound");
24
+ }
25
+ let value;
26
+ try {
27
+ value = JSON.parse(bytes.toString("utf8"));
28
+ }
29
+ catch (error) {
30
+ throw new ReplayLedgerLockError("replay lock owner record is malformed", { cause: error });
31
+ }
32
+ if (typeof value !== "object" ||
33
+ value === null ||
34
+ Array.isArray(value) ||
35
+ Object.keys(value).sort().join(",") !== "acquiredAtMs,ownerId,pid,processStartToken,schemaVersion" ||
36
+ !("schemaVersion" in value) ||
37
+ value.schemaVersion !== 2 ||
38
+ !("pid" in value) ||
39
+ !("processStartToken" in value) ||
40
+ !("acquiredAtMs" in value) ||
41
+ !("ownerId" in value) ||
42
+ typeof value.ownerId !== "string" ||
43
+ !OWNER_ID.test(value.ownerId) ||
44
+ (value.processStartToken !== null &&
45
+ (typeof value.processStartToken !== "string" || !PROCESS_START_TOKEN.test(value.processStartToken)))) {
46
+ throw new ReplayLedgerLockError("replay lock owner record is invalid");
47
+ }
48
+ const pid = ownerInteger(value.pid);
49
+ const acquiredAtMs = ownerInteger(value.acquiredAtMs);
50
+ if (acquiredAtMs > Date.now() + MAX_CLOCK_SKEW_MS) {
51
+ throw new ReplayLedgerLockError("replay lock owner record is invalid");
52
+ }
53
+ return { schemaVersion: 2, pid, processStartToken: value.processStartToken, acquiredAtMs, ownerId: value.ownerId };
54
+ }
55
+ export function readLockOwner(path) {
56
+ const fd = openSync(path, fsConstants.O_RDONLY | (fsConstants.O_NOFOLLOW ?? 0));
57
+ try {
58
+ const before = fstatSync(fd, { bigint: true });
59
+ if (!before.isFile() || before.size <= 0n || before.size > BigInt(MAX_LOCK_RECORD_BYTES)) {
60
+ throw new ReplayLedgerLockError("replay lock owner record is outside its size bound");
61
+ }
62
+ const bytes = readFileSync(fd);
63
+ const after = fstatSync(fd, { bigint: true });
64
+ if (before.dev !== after.dev ||
65
+ before.ino !== after.ino ||
66
+ before.size !== after.size ||
67
+ after.size !== BigInt(bytes.length)) {
68
+ throw new ReplayLedgerLockError("replay lock owner record changed during inspection");
69
+ }
70
+ return { owner: parseOwner(bytes), dev: String(after.dev), ino: String(after.ino) };
71
+ }
72
+ finally {
73
+ closeSync(fd);
74
+ }
75
+ }
76
+ export function lockOwnersEqual(left, right) {
77
+ return (left.dev === right.dev &&
78
+ left.ino === right.ino &&
79
+ left.owner.ownerId === right.owner.ownerId &&
80
+ left.owner.pid === right.owner.pid &&
81
+ left.owner.processStartToken === right.owner.processStartToken &&
82
+ left.owner.acquiredAtMs === right.owner.acquiredAtMs);
83
+ }
84
+ export function createLockOwner(processIdentity) {
85
+ const identity = processIdentity(process.pid);
86
+ if (identity.state !== "present" || !PROCESS_START_TOKEN.test(identity.startToken)) {
87
+ throw new ReplayLedgerLockError("replay lock acquisition requires process-start identity");
88
+ }
89
+ return {
90
+ schemaVersion: 2,
91
+ pid: process.pid,
92
+ processStartToken: identity.startToken,
93
+ acquiredAtMs: Date.now(),
94
+ ownerId: randomUUID(),
95
+ };
96
+ }
97
+ export function lockOwnerIsDead(owner, processIdentity) {
98
+ const current = processIdentity(owner.pid);
99
+ if (current.state === "unavailable") {
100
+ throw new ReplayLedgerLockError("replay lock owner liveness could not be established");
101
+ }
102
+ if (current.state === "absent")
103
+ return true;
104
+ if (owner.processStartToken === null) {
105
+ throw new ReplayLedgerLockError("replay lock recovery requires process-start identity");
106
+ }
107
+ return current.startToken !== owner.processStartToken;
108
+ }
109
+ export function parseLinuxProcessIdentityStat(stat) {
110
+ if (stat.length > 4_096)
111
+ return { state: "unavailable" };
112
+ const close = stat.lastIndexOf(")");
113
+ if (close < 0)
114
+ return { state: "unavailable" };
115
+ const fields = stat
116
+ .slice(close + 2)
117
+ .trim()
118
+ .split(/\s+/);
119
+ if (["Z", "X", "x"].includes(fields[0] ?? ""))
120
+ return { state: "absent" };
121
+ const startTime = fields[19];
122
+ return startTime !== undefined && /^\d+$/.test(startTime)
123
+ ? { state: "present", startToken: `linux:${startTime}` }
124
+ : { state: "unavailable" };
125
+ }
126
+ export function inspectProcessIdentity(pid) {
127
+ if (process.platform !== "linux")
128
+ return { state: "unavailable" };
129
+ try {
130
+ return parseLinuxProcessIdentityStat(readFileSync(`/proc/${pid}/stat`, "utf8"));
131
+ }
132
+ catch (error) {
133
+ if (!(error instanceof Error))
134
+ throw error;
135
+ return errorCode(error) === "ENOENT" ? { state: "absent" } : { state: "unavailable" };
136
+ }
137
+ }
138
+ //# sourceMappingURL=replay-ledger-lock-owner.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"replay-ledger-lock-owner.js","sourceRoot":"","sources":["../../src/guardrails/replay-ledger-lock-owner.ts"],"names":[],"mappings":"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","sourcesContent":["import { randomUUID } from \"node:crypto\";\nimport { closeSync, constants as fsConstants, fstatSync, openSync, readFileSync } from \"node:fs\";\n\nconst MAX_LOCK_RECORD_BYTES = 512;\nconst MAX_CLOCK_SKEW_MS = 60_000;\nconst OWNER_ID = /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/;\nconst PROCESS_START_TOKEN = /^[A-Za-z0-9._:-]{1,128}$/;\n\nexport type LockOwner = {\n\treadonly schemaVersion: 2;\n\treadonly pid: number;\n\treadonly processStartToken: string | null;\n\treadonly acquiredAtMs: number;\n\treadonly ownerId: string;\n};\n\nexport type LockOwnerSnapshot = {\n\treadonly owner: LockOwner;\n\treadonly dev: string;\n\treadonly ino: string;\n};\n\nexport type ReplayLedgerProcessIdentity =\n\t| { readonly state: \"present\"; readonly startToken: string }\n\t| { readonly state: \"absent\" }\n\t| { readonly state: \"unavailable\" };\n\nexport type ReplayLedgerProcessIdentityReader = (pid: number) => ReplayLedgerProcessIdentity;\n\nexport class ReplayLedgerLockError extends Error {\n\treadonly name = \"ReplayLedgerLockError\";\n}\n\nexport function errorCode(error: unknown): string | undefined {\n\tif (typeof error !== \"object\" || error === null || !(\"code\" in error)) return undefined;\n\treturn typeof error.code === \"string\" ? error.code : undefined;\n}\n\nfunction ownerInteger(value: unknown): number {\n\tif (typeof value !== \"number\" || !Number.isSafeInteger(value) || value <= 0) {\n\t\tthrow new ReplayLedgerLockError(\"replay lock owner record is invalid\");\n\t}\n\treturn value;\n}\n\nfunction parseOwner(bytes: Buffer): LockOwner {\n\tif (bytes.byteLength === 0 || bytes.byteLength > MAX_LOCK_RECORD_BYTES) {\n\t\tthrow new ReplayLedgerLockError(\"replay lock owner record is outside its size bound\");\n\t}\n\tlet value: unknown;\n\ttry {\n\t\tvalue = JSON.parse(bytes.toString(\"utf8\"));\n\t} catch (error) {\n\t\tthrow new ReplayLedgerLockError(\"replay lock owner record is malformed\", { cause: error });\n\t}\n\tif (\n\t\ttypeof value !== \"object\" ||\n\t\tvalue === null ||\n\t\tArray.isArray(value) ||\n\t\tObject.keys(value).sort().join(\",\") !== \"acquiredAtMs,ownerId,pid,processStartToken,schemaVersion\" ||\n\t\t!(\"schemaVersion\" in value) ||\n\t\tvalue.schemaVersion !== 2 ||\n\t\t!(\"pid\" in value) ||\n\t\t!(\"processStartToken\" in value) ||\n\t\t!(\"acquiredAtMs\" in value) ||\n\t\t!(\"ownerId\" in value) ||\n\t\ttypeof value.ownerId !== \"string\" ||\n\t\t!OWNER_ID.test(value.ownerId) ||\n\t\t(value.processStartToken !== null &&\n\t\t\t(typeof value.processStartToken !== \"string\" || !PROCESS_START_TOKEN.test(value.processStartToken)))\n\t) {\n\t\tthrow new ReplayLedgerLockError(\"replay lock owner record is invalid\");\n\t}\n\tconst pid = ownerInteger(value.pid);\n\tconst acquiredAtMs = ownerInteger(value.acquiredAtMs);\n\tif (acquiredAtMs > Date.now() + MAX_CLOCK_SKEW_MS) {\n\t\tthrow new ReplayLedgerLockError(\"replay lock owner record is invalid\");\n\t}\n\treturn { schemaVersion: 2, pid, processStartToken: value.processStartToken, acquiredAtMs, ownerId: value.ownerId };\n}\n\nexport function readLockOwner(path: string): LockOwnerSnapshot {\n\tconst fd = openSync(path, fsConstants.O_RDONLY | (fsConstants.O_NOFOLLOW ?? 0));\n\ttry {\n\t\tconst before = fstatSync(fd, { bigint: true });\n\t\tif (!before.isFile() || before.size <= 0n || before.size > BigInt(MAX_LOCK_RECORD_BYTES)) {\n\t\t\tthrow new ReplayLedgerLockError(\"replay lock owner record is outside its size bound\");\n\t\t}\n\t\tconst bytes = readFileSync(fd);\n\t\tconst after = fstatSync(fd, { bigint: true });\n\t\tif (\n\t\t\tbefore.dev !== after.dev ||\n\t\t\tbefore.ino !== after.ino ||\n\t\t\tbefore.size !== after.size ||\n\t\t\tafter.size !== BigInt(bytes.length)\n\t\t) {\n\t\t\tthrow new ReplayLedgerLockError(\"replay lock owner record changed during inspection\");\n\t\t}\n\t\treturn { owner: parseOwner(bytes), dev: String(after.dev), ino: String(after.ino) };\n\t} finally {\n\t\tcloseSync(fd);\n\t}\n}\n\nexport function lockOwnersEqual(left: LockOwnerSnapshot, right: LockOwnerSnapshot): boolean {\n\treturn (\n\t\tleft.dev === right.dev &&\n\t\tleft.ino === right.ino &&\n\t\tleft.owner.ownerId === right.owner.ownerId &&\n\t\tleft.owner.pid === right.owner.pid &&\n\t\tleft.owner.processStartToken === right.owner.processStartToken &&\n\t\tleft.owner.acquiredAtMs === right.owner.acquiredAtMs\n\t);\n}\n\nexport function createLockOwner(processIdentity: ReplayLedgerProcessIdentityReader): LockOwner {\n\tconst identity = processIdentity(process.pid);\n\tif (identity.state !== \"present\" || !PROCESS_START_TOKEN.test(identity.startToken)) {\n\t\tthrow new ReplayLedgerLockError(\"replay lock acquisition requires process-start identity\");\n\t}\n\treturn {\n\t\tschemaVersion: 2,\n\t\tpid: process.pid,\n\t\tprocessStartToken: identity.startToken,\n\t\tacquiredAtMs: Date.now(),\n\t\townerId: randomUUID(),\n\t};\n}\n\nexport function lockOwnerIsDead(owner: LockOwner, processIdentity: ReplayLedgerProcessIdentityReader): boolean {\n\tconst current = processIdentity(owner.pid);\n\tif (current.state === \"unavailable\") {\n\t\tthrow new ReplayLedgerLockError(\"replay lock owner liveness could not be established\");\n\t}\n\tif (current.state === \"absent\") return true;\n\tif (owner.processStartToken === null) {\n\t\tthrow new ReplayLedgerLockError(\"replay lock recovery requires process-start identity\");\n\t}\n\treturn current.startToken !== owner.processStartToken;\n}\n\nexport function parseLinuxProcessIdentityStat(stat: string): ReplayLedgerProcessIdentity {\n\tif (stat.length > 4_096) return { state: \"unavailable\" };\n\tconst close = stat.lastIndexOf(\")\");\n\tif (close < 0) return { state: \"unavailable\" };\n\tconst fields = stat\n\t\t.slice(close + 2)\n\t\t.trim()\n\t\t.split(/\\s+/);\n\tif ([\"Z\", \"X\", \"x\"].includes(fields[0] ?? \"\")) return { state: \"absent\" };\n\tconst startTime = fields[19];\n\treturn startTime !== undefined && /^\\d+$/.test(startTime)\n\t\t? { state: \"present\", startToken: `linux:${startTime}` }\n\t\t: { state: \"unavailable\" };\n}\n\nexport function inspectProcessIdentity(pid: number): ReplayLedgerProcessIdentity {\n\tif (process.platform !== \"linux\") return { state: \"unavailable\" };\n\ttry {\n\t\treturn parseLinuxProcessIdentityStat(readFileSync(`/proc/${pid}/stat`, \"utf8\"));\n\t} catch (error) {\n\t\tif (!(error instanceof Error)) throw error;\n\t\treturn errorCode(error) === \"ENOENT\" ? { state: \"absent\" } : { state: \"unavailable\" };\n\t}\n}\n"]}
@@ -0,0 +1,24 @@
1
+ import { type ReplayLedgerProcessIdentityReader } from "./replay-ledger-lock-owner.ts";
2
+ export { fsyncDirectory, writeAll } from "./replay-ledger-io.ts";
3
+ export type { ReplayLedgerProcessIdentity } from "./replay-ledger-lock-owner.ts";
4
+ export { ReplayLedgerLockError } from "./replay-ledger-lock-owner.ts";
5
+ export interface ReplayLedgerLockOptions {
6
+ readonly processIdentity?: ReplayLedgerProcessIdentityReader;
7
+ readonly beforeReclaimRemove?: () => void;
8
+ readonly beforeMutationGateReclaimRemove?: () => void;
9
+ readonly beforeMutationGateRelease?: () => void;
10
+ }
11
+ export declare class ReplayLedgerLock {
12
+ private readonly path;
13
+ private readonly gate;
14
+ private readonly processIdentity;
15
+ private readonly beforeReclaimRemove;
16
+ constructor(path: string, options?: ReplayLedgerLockOptions);
17
+ private withMutationGate;
18
+ private tryAcquire;
19
+ private reclaim;
20
+ private acquire;
21
+ private release;
22
+ run<T>(operation: () => T): T;
23
+ }
24
+ //# sourceMappingURL=replay-ledger-lock.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"replay-ledger-lock.d.ts","sourceRoot":"","sources":["../../src/guardrails/replay-ledger-lock.ts"],"names":[],"mappings":"AAGA,OAAO,EASN,KAAK,iCAAiC,EAEtC,MAAM,+BAA+B,CAAC;AAGvC,OAAO,EAAE,cAAc,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AACjE,YAAY,EAAE,2BAA2B,EAAE,MAAM,+BAA+B,CAAC;AACjF,OAAO,EAAE,qBAAqB,EAAE,MAAM,+BAA+B,CAAC;AAMtE,MAAM,WAAW,uBAAuB;IACvC,QAAQ,CAAC,eAAe,CAAC,EAAE,iCAAiC,CAAC;IAC7D,QAAQ,CAAC,mBAAmB,CAAC,EAAE,MAAM,IAAI,CAAC;IAC1C,QAAQ,CAAC,+BAA+B,CAAC,EAAE,MAAM,IAAI,CAAC;IACtD,QAAQ,CAAC,yBAAyB,CAAC,EAAE,MAAM,IAAI,CAAC;CAChD;AAED,qBAAa,gBAAgB;IAC5B,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAS;IAC9B,OAAO,CAAC,QAAQ,CAAC,IAAI,CAA2B;IAChD,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAoC;IACpE,OAAO,CAAC,QAAQ,CAAC,mBAAmB,CAA2B;IAE/D,YAAY,IAAI,EAAE,MAAM,EAAE,OAAO,GAAE,uBAA4B,EAS9D;IAED,OAAO,CAAC,gBAAgB;IAIxB,OAAO,CAAC,UAAU;IAiBlB,OAAO,CAAC,OAAO;IAwBf,OAAO,CAAC,OAAO;IA0Bf,OAAO,CAAC,OAAO;IAWf,GAAG,CAAC,CAAC,EAAE,SAAS,EAAE,MAAM,CAAC,GAAG,CAAC,CAmB5B;CACD","sourcesContent":["import { linkSync, unlinkSync } from \"node:fs\";\nimport { dirname } from \"node:path\";\nimport { createLockCandidate, fsyncDirectory, removeLockCandidate } from \"./replay-ledger-io.ts\";\nimport {\n\tcreateLockOwner,\n\terrorCode,\n\tinspectProcessIdentity,\n\ttype LockOwner,\n\ttype LockOwnerSnapshot,\n\tlockOwnerIsDead,\n\tlockOwnersEqual,\n\tReplayLedgerLockError,\n\ttype ReplayLedgerProcessIdentityReader,\n\treadLockOwner,\n} from \"./replay-ledger-lock-owner.ts\";\nimport { ReplayLedgerMutationGate } from \"./replay-ledger-mutation-gate.ts\";\n\nexport { fsyncDirectory, writeAll } from \"./replay-ledger-io.ts\";\nexport type { ReplayLedgerProcessIdentity } from \"./replay-ledger-lock-owner.ts\";\nexport { ReplayLedgerLockError } from \"./replay-ledger-lock-owner.ts\";\n\nconst LOCK_ATTEMPTS = 200;\nconst LOCK_WAIT_MS = 5;\nconst sleeper = new Int32Array(new SharedArrayBuffer(4));\n\nexport interface ReplayLedgerLockOptions {\n\treadonly processIdentity?: ReplayLedgerProcessIdentityReader;\n\treadonly beforeReclaimRemove?: () => void;\n\treadonly beforeMutationGateReclaimRemove?: () => void;\n\treadonly beforeMutationGateRelease?: () => void;\n}\n\nexport class ReplayLedgerLock {\n\tprivate readonly path: string;\n\tprivate readonly gate: ReplayLedgerMutationGate;\n\tprivate readonly processIdentity: ReplayLedgerProcessIdentityReader;\n\tprivate readonly beforeReclaimRemove: (() => void) | undefined;\n\n\tconstructor(path: string, options: ReplayLedgerLockOptions = {}) {\n\t\tthis.path = path;\n\t\tthis.processIdentity = options.processIdentity ?? inspectProcessIdentity;\n\t\tthis.beforeReclaimRemove = options.beforeReclaimRemove;\n\t\tthis.gate = new ReplayLedgerMutationGate(`${path}.reclaim`, {\n\t\t\tprocessIdentity: this.processIdentity,\n\t\t\tbeforeReclaimRemove: options.beforeMutationGateReclaimRemove,\n\t\t\tbeforeRelease: options.beforeMutationGateRelease,\n\t\t});\n\t}\n\n\tprivate withMutationGate<T>(operation: () => T): T {\n\t\treturn this.gate.run(operation);\n\t}\n\n\tprivate tryAcquire(candidate: string, expected: LockOwnerSnapshot): LockOwnerSnapshot | undefined {\n\t\treturn this.withMutationGate(() => {\n\t\t\ttry {\n\t\t\t\tlinkSync(candidate, this.path);\n\t\t\t\tfsyncDirectory(dirname(this.path));\n\t\t\t\tconst acquired = readLockOwner(this.path);\n\t\t\t\tif (!lockOwnersEqual(acquired, expected)) {\n\t\t\t\t\tthrow new ReplayLedgerLockError(\"replay lock ownership changed during acquisition\");\n\t\t\t\t}\n\t\t\t\treturn acquired;\n\t\t\t} catch (error) {\n\t\t\t\tif (errorCode(error) === \"EEXIST\") return undefined;\n\t\t\t\tthrow error;\n\t\t\t}\n\t\t});\n\t}\n\n\tprivate reclaim(observed: LockOwnerSnapshot): void {\n\t\tthis.withMutationGate(() => {\n\t\t\tlet current: LockOwnerSnapshot;\n\t\t\ttry {\n\t\t\t\tcurrent = readLockOwner(this.path);\n\t\t\t} catch (error) {\n\t\t\t\tif (errorCode(error) === \"ENOENT\") return;\n\t\t\t\tthrow error;\n\t\t\t}\n\t\t\tif (!lockOwnersEqual(current, observed)) return;\n\t\t\tthis.beforeReclaimRemove?.();\n\t\t\tlet finalOwner: LockOwnerSnapshot;\n\t\t\ttry {\n\t\t\t\tfinalOwner = readLockOwner(this.path);\n\t\t\t} catch (error) {\n\t\t\t\tif (errorCode(error) === \"ENOENT\") return;\n\t\t\t\tthrow error;\n\t\t\t}\n\t\t\tif (!lockOwnersEqual(finalOwner, observed)) return;\n\t\t\tunlinkSync(this.path);\n\t\t\tfsyncDirectory(dirname(this.path));\n\t\t});\n\t}\n\n\tprivate acquire(owner: LockOwner): LockOwnerSnapshot {\n\t\tconst candidate = createLockCandidate(this.path, owner);\n\t\ttry {\n\t\t\tconst expected = readLockOwner(candidate);\n\t\t\tfor (let attempt = 0; attempt < LOCK_ATTEMPTS; attempt++) {\n\t\t\t\tlet current: LockOwnerSnapshot;\n\t\t\t\ttry {\n\t\t\t\t\tcurrent = readLockOwner(this.path);\n\t\t\t\t} catch (error) {\n\t\t\t\t\tif (errorCode(error) !== \"ENOENT\") throw error;\n\t\t\t\t\tconst acquired = this.tryAcquire(candidate, expected);\n\t\t\t\t\tif (acquired !== undefined) return acquired;\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tif (lockOwnerIsDead(current.owner, this.processIdentity)) {\n\t\t\t\t\tthis.reclaim(current);\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tAtomics.wait(sleeper, 0, 0, LOCK_WAIT_MS);\n\t\t\t}\n\t\t\tthrow new ReplayLedgerLockError(\"replay ledger interprocess lock is unavailable\");\n\t\t} finally {\n\t\t\tremoveLockCandidate(candidate);\n\t\t}\n\t}\n\n\tprivate release(acquired: LockOwnerSnapshot): void {\n\t\tthis.withMutationGate(() => {\n\t\t\tconst current = readLockOwner(this.path);\n\t\t\tif (!lockOwnersEqual(current, acquired)) {\n\t\t\t\tthrow new ReplayLedgerLockError(\"replay lock ownership changed before release\");\n\t\t\t}\n\t\t\tunlinkSync(this.path);\n\t\t\tfsyncDirectory(dirname(this.path));\n\t\t});\n\t}\n\n\trun<T>(operation: () => T): T {\n\t\tconst acquired = this.acquire(createLockOwner(this.processIdentity));\n\t\tlet result: T;\n\t\ttry {\n\t\t\tresult = operation();\n\t\t} catch (error) {\n\t\t\tthis.release(acquired);\n\t\t\tthrow error;\n\t\t}\n\t\tif (\n\t\t\tresult !== null &&\n\t\t\t(typeof result === \"object\" || typeof result === \"function\") &&\n\t\t\t\"then\" in result &&\n\t\t\ttypeof result.then === \"function\"\n\t\t) {\n\t\t\treturn Promise.resolve(result).finally(() => this.release(acquired)) as T;\n\t\t}\n\t\tthis.release(acquired);\n\t\treturn result;\n\t}\n}\n"]}