approval-md 0.0.1 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (722) hide show
  1. package/LICENSE +176 -0
  2. package/NOTICE +5 -0
  3. package/README.md +940 -4
  4. package/SPEC.md +476 -34
  5. package/cli.js +29 -3
  6. package/dist/src/adapters/agentmail.d.ts +426 -0
  7. package/dist/src/adapters/agentmail.js +1200 -0
  8. package/dist/src/adapters/agentmail.js.map +1 -0
  9. package/dist/src/adapters/conformance.d.ts +149 -0
  10. package/dist/src/adapters/conformance.js +461 -0
  11. package/dist/src/adapters/conformance.js.map +1 -0
  12. package/dist/src/adapters/contract.d.ts +628 -0
  13. package/dist/src/adapters/contract.js +1035 -0
  14. package/dist/src/adapters/contract.js.map +1 -0
  15. package/dist/src/adapters/email.d.ts +324 -0
  16. package/dist/src/adapters/email.js +749 -0
  17. package/dist/src/adapters/email.js.map +1 -0
  18. package/dist/src/adapters/env-passphrase.d.ts +93 -0
  19. package/dist/src/adapters/env-passphrase.js +132 -0
  20. package/dist/src/adapters/env-passphrase.js.map +1 -0
  21. package/dist/src/adapters/public.d.ts +11 -0
  22. package/dist/src/adapters/public.js +11 -0
  23. package/dist/src/adapters/public.js.map +1 -0
  24. package/dist/src/adapters/registry.d.ts +59 -0
  25. package/dist/src/adapters/registry.js +77 -0
  26. package/dist/src/adapters/registry.js.map +1 -0
  27. package/dist/src/adapters/smtp.d.ts +213 -0
  28. package/dist/src/adapters/smtp.js +499 -0
  29. package/dist/src/adapters/smtp.js.map +1 -0
  30. package/dist/src/adapters/vault-provider.d.ts +114 -0
  31. package/dist/src/adapters/vault-provider.js +161 -0
  32. package/dist/src/adapters/vault-provider.js.map +1 -0
  33. package/dist/src/adapters/zzz.d.ts +66 -0
  34. package/dist/src/adapters/zzz.js +299 -0
  35. package/dist/src/adapters/zzz.js.map +1 -0
  36. package/dist/src/channels/batch.d.ts +109 -0
  37. package/dist/src/channels/batch.js +121 -0
  38. package/dist/src/channels/batch.js.map +1 -0
  39. package/dist/src/channels/cli.d.ts +193 -0
  40. package/dist/src/channels/cli.js +468 -0
  41. package/dist/src/channels/cli.js.map +1 -0
  42. package/dist/src/channels/conformance.d.ts +92 -0
  43. package/dist/src/channels/conformance.js +445 -0
  44. package/dist/src/channels/conformance.js.map +1 -0
  45. package/dist/src/channels/contract.d.ts +623 -0
  46. package/dist/src/channels/contract.js +494 -0
  47. package/dist/src/channels/contract.js.map +1 -0
  48. package/dist/src/channels/payload-view.d.ts +35 -0
  49. package/dist/src/channels/payload-view.js +43 -0
  50. package/dist/src/channels/payload-view.js.map +1 -0
  51. package/dist/src/channels/render-queue.d.ts +149 -0
  52. package/dist/src/channels/render-queue.js +564 -0
  53. package/dist/src/channels/render-queue.js.map +1 -0
  54. package/dist/src/channels/tagging.d.ts +196 -0
  55. package/dist/src/channels/tagging.js +723 -0
  56. package/dist/src/channels/tagging.js.map +1 -0
  57. package/dist/src/channels/telegram.d.ts +1832 -0
  58. package/dist/src/channels/telegram.js +3190 -0
  59. package/dist/src/channels/telegram.js.map +1 -0
  60. package/dist/src/channels/web.d.ts +341 -0
  61. package/dist/src/channels/web.js +903 -0
  62. package/dist/src/channels/web.js.map +1 -0
  63. package/dist/src/cli/adapter.d.ts +90 -0
  64. package/dist/src/cli/adapter.js +288 -0
  65. package/dist/src/cli/adapter.js.map +1 -0
  66. package/dist/src/cli/amend.d.ts +59 -0
  67. package/dist/src/cli/amend.js +2171 -0
  68. package/dist/src/cli/amend.js.map +1 -0
  69. package/dist/src/cli/args.d.ts +43 -0
  70. package/dist/src/cli/args.js +86 -0
  71. package/dist/src/cli/args.js.map +1 -0
  72. package/dist/src/cli/attest.d.ts +41 -0
  73. package/dist/src/cli/attest.js +307 -0
  74. package/dist/src/cli/attest.js.map +1 -0
  75. package/dist/src/cli/audit-card.d.ts +62 -0
  76. package/dist/src/cli/audit-card.js +201 -0
  77. package/dist/src/cli/audit-card.js.map +1 -0
  78. package/dist/src/cli/audit.d.ts +59 -0
  79. package/dist/src/cli/audit.js +460 -0
  80. package/dist/src/cli/audit.js.map +1 -0
  81. package/dist/src/cli/channel-telegram.d.ts +806 -0
  82. package/dist/src/cli/channel-telegram.js +2063 -0
  83. package/dist/src/cli/channel-telegram.js.map +1 -0
  84. package/dist/src/cli/channel-web.d.ts +131 -0
  85. package/dist/src/cli/channel-web.js +357 -0
  86. package/dist/src/cli/channel-web.js.map +1 -0
  87. package/dist/src/cli/channel.d.ts +71 -0
  88. package/dist/src/cli/channel.js +438 -0
  89. package/dist/src/cli/channel.js.map +1 -0
  90. package/dist/src/cli/checkpoint-tap.d.ts +169 -0
  91. package/dist/src/cli/checkpoint-tap.js +238 -0
  92. package/dist/src/cli/checkpoint-tap.js.map +1 -0
  93. package/dist/src/cli/codex.d.ts +2 -0
  94. package/dist/src/cli/codex.js +172 -0
  95. package/dist/src/cli/codex.js.map +1 -0
  96. package/dist/src/cli/coverage.d.ts +61 -0
  97. package/dist/src/cli/coverage.js +343 -0
  98. package/dist/src/cli/coverage.js.map +1 -0
  99. package/dist/src/cli/daemon.d.ts +120 -0
  100. package/dist/src/cli/daemon.js +631 -0
  101. package/dist/src/cli/daemon.js.map +1 -0
  102. package/dist/src/cli/doctor.d.ts +129 -0
  103. package/dist/src/cli/doctor.js +2762 -0
  104. package/dist/src/cli/doctor.js.map +1 -0
  105. package/dist/src/cli/env.d.ts +65 -0
  106. package/dist/src/cli/env.js +302 -0
  107. package/dist/src/cli/env.js.map +1 -0
  108. package/dist/src/cli/execute.d.ts +202 -0
  109. package/dist/src/cli/execute.js +1682 -0
  110. package/dist/src/cli/execute.js.map +1 -0
  111. package/dist/src/cli/exit-codes.d.ts +73 -0
  112. package/dist/src/cli/exit-codes.js +82 -0
  113. package/dist/src/cli/exit-codes.js.map +1 -0
  114. package/dist/src/cli/feedback.d.ts +60 -0
  115. package/dist/src/cli/feedback.js +205 -0
  116. package/dist/src/cli/feedback.js.map +1 -0
  117. package/dist/src/cli/gate-window.d.ts +40 -0
  118. package/dist/src/cli/gate-window.js +294 -0
  119. package/dist/src/cli/gate-window.js.map +1 -0
  120. package/dist/src/cli/gate.d.ts +68 -0
  121. package/dist/src/cli/gate.js +557 -0
  122. package/dist/src/cli/gate.js.map +1 -0
  123. package/dist/src/cli/git-scope.d.ts +190 -0
  124. package/dist/src/cli/git-scope.js +295 -0
  125. package/dist/src/cli/git-scope.js.map +1 -0
  126. package/dist/src/cli/gloss-attach.d.ts +85 -0
  127. package/dist/src/cli/gloss-attach.js +107 -0
  128. package/dist/src/cli/gloss-attach.js.map +1 -0
  129. package/dist/src/cli/gloss-codex-child.d.ts +9 -0
  130. package/dist/src/cli/gloss-codex-child.js +149 -0
  131. package/dist/src/cli/gloss-codex-child.js.map +1 -0
  132. package/dist/src/cli/gloss-codex.d.ts +24 -0
  133. package/dist/src/cli/gloss-codex.js +255 -0
  134. package/dist/src/cli/gloss-codex.js.map +1 -0
  135. package/dist/src/cli/gloss-options.d.ts +42 -0
  136. package/dist/src/cli/gloss-options.js +79 -0
  137. package/dist/src/cli/gloss-options.js.map +1 -0
  138. package/dist/src/cli/gloss.d.ts +265 -0
  139. package/dist/src/cli/gloss.js +362 -0
  140. package/dist/src/cli/gloss.js.map +1 -0
  141. package/dist/src/cli/help.d.ts +103 -0
  142. package/dist/src/cli/help.js +2339 -0
  143. package/dist/src/cli/help.js.map +1 -0
  144. package/dist/src/cli/hook-codex.d.ts +78 -0
  145. package/dist/src/cli/hook-codex.js +167 -0
  146. package/dist/src/cli/hook-codex.js.map +1 -0
  147. package/dist/src/cli/hook.d.ts +331 -0
  148. package/dist/src/cli/hook.js +2849 -0
  149. package/dist/src/cli/hook.js.map +1 -0
  150. package/dist/src/cli/import.d.ts +35 -0
  151. package/dist/src/cli/import.js +175 -0
  152. package/dist/src/cli/import.js.map +1 -0
  153. package/dist/src/cli/init.d.ts +84 -0
  154. package/dist/src/cli/init.js +336 -0
  155. package/dist/src/cli/init.js.map +1 -0
  156. package/dist/src/cli/instructions.d.ts +23 -0
  157. package/dist/src/cli/instructions.js +262 -0
  158. package/dist/src/cli/instructions.js.map +1 -0
  159. package/dist/src/cli/journal.d.ts +41 -0
  160. package/dist/src/cli/journal.js +238 -0
  161. package/dist/src/cli/journal.js.map +1 -0
  162. package/dist/src/cli/log-advance.d.ts +287 -0
  163. package/dist/src/cli/log-advance.js +840 -0
  164. package/dist/src/cli/log-advance.js.map +1 -0
  165. package/dist/src/cli/log-anchor.d.ts +176 -0
  166. package/dist/src/cli/log-anchor.js +387 -0
  167. package/dist/src/cli/log-anchor.js.map +1 -0
  168. package/dist/src/cli/log-checkpoint.d.ts +22 -0
  169. package/dist/src/cli/log-checkpoint.js +128 -0
  170. package/dist/src/cli/log-checkpoint.js.map +1 -0
  171. package/dist/src/cli/log-sync.d.ts +243 -0
  172. package/dist/src/cli/log-sync.js +849 -0
  173. package/dist/src/cli/log-sync.js.map +1 -0
  174. package/dist/src/cli/log-verbs.d.ts +16 -0
  175. package/dist/src/cli/log-verbs.js +360 -0
  176. package/dist/src/cli/log-verbs.js.map +1 -0
  177. package/dist/src/cli/long-help.d.ts +70 -0
  178. package/dist/src/cli/long-help.js +148 -0
  179. package/dist/src/cli/long-help.js.map +1 -0
  180. package/dist/src/cli/main.d.ts +77 -0
  181. package/dist/src/cli/main.js +1206 -0
  182. package/dist/src/cli/main.js.map +1 -0
  183. package/dist/src/cli/mcp.d.ts +52 -0
  184. package/dist/src/cli/mcp.js +306 -0
  185. package/dist/src/cli/mcp.js.map +1 -0
  186. package/dist/src/cli/paths.d.ts +56 -0
  187. package/dist/src/cli/paths.js +79 -0
  188. package/dist/src/cli/paths.js.map +1 -0
  189. package/dist/src/cli/payload.d.ts +58 -0
  190. package/dist/src/cli/payload.js +253 -0
  191. package/dist/src/cli/payload.js.map +1 -0
  192. package/dist/src/cli/policy.d.ts +43 -0
  193. package/dist/src/cli/policy.js +229 -0
  194. package/dist/src/cli/policy.js.map +1 -0
  195. package/dist/src/cli/preflight.d.ts +363 -0
  196. package/dist/src/cli/preflight.js +1175 -0
  197. package/dist/src/cli/preflight.js.map +1 -0
  198. package/dist/src/cli/progress.d.ts +78 -0
  199. package/dist/src/cli/progress.js +112 -0
  200. package/dist/src/cli/progress.js.map +1 -0
  201. package/dist/src/cli/prompt.d.ts +209 -0
  202. package/dist/src/cli/prompt.js +312 -0
  203. package/dist/src/cli/prompt.js.map +1 -0
  204. package/dist/src/cli/quickstart.d.ts +46 -0
  205. package/dist/src/cli/quickstart.js +297 -0
  206. package/dist/src/cli/quickstart.js.map +1 -0
  207. package/dist/src/cli/records.d.ts +34 -0
  208. package/dist/src/cli/records.js +66 -0
  209. package/dist/src/cli/records.js.map +1 -0
  210. package/dist/src/cli/render.d.ts +22 -0
  211. package/dist/src/cli/render.js +132 -0
  212. package/dist/src/cli/render.js.map +1 -0
  213. package/dist/src/cli/sandbox.d.ts +51 -0
  214. package/dist/src/cli/sandbox.js +150 -0
  215. package/dist/src/cli/sandbox.js.map +1 -0
  216. package/dist/src/cli/scaffold.d.ts +79 -0
  217. package/dist/src/cli/scaffold.js +137 -0
  218. package/dist/src/cli/scaffold.js.map +1 -0
  219. package/dist/src/cli/setup-adapter.d.ts +137 -0
  220. package/dist/src/cli/setup-adapter.js +509 -0
  221. package/dist/src/cli/setup-adapter.js.map +1 -0
  222. package/dist/src/cli/setup-channel.d.ts +117 -0
  223. package/dist/src/cli/setup-channel.js +635 -0
  224. package/dist/src/cli/setup-channel.js.map +1 -0
  225. package/dist/src/cli/setup-checkpoint.d.ts +57 -0
  226. package/dist/src/cli/setup-checkpoint.js +196 -0
  227. package/dist/src/cli/setup-checkpoint.js.map +1 -0
  228. package/dist/src/cli/setup-common.d.ts +275 -0
  229. package/dist/src/cli/setup-common.js +376 -0
  230. package/dist/src/cli/setup-common.js.map +1 -0
  231. package/dist/src/cli/setup-flow.d.ts +287 -0
  232. package/dist/src/cli/setup-flow.js +476 -0
  233. package/dist/src/cli/setup-flow.js.map +1 -0
  234. package/dist/src/cli/setup-service.d.ts +96 -0
  235. package/dist/src/cli/setup-service.js +308 -0
  236. package/dist/src/cli/setup-service.js.map +1 -0
  237. package/dist/src/cli/setup.d.ts +202 -0
  238. package/dist/src/cli/setup.js +473 -0
  239. package/dist/src/cli/setup.js.map +1 -0
  240. package/dist/src/cli/style.d.ts +320 -0
  241. package/dist/src/cli/style.js +469 -0
  242. package/dist/src/cli/style.js.map +1 -0
  243. package/dist/src/cli/token.d.ts +39 -0
  244. package/dist/src/cli/token.js +274 -0
  245. package/dist/src/cli/token.js.map +1 -0
  246. package/dist/src/cli/up.d.ts +155 -0
  247. package/dist/src/cli/up.js +849 -0
  248. package/dist/src/cli/up.js.map +1 -0
  249. package/dist/src/cli/usage.d.ts +37 -0
  250. package/dist/src/cli/usage.js +91 -0
  251. package/dist/src/cli/usage.js.map +1 -0
  252. package/dist/src/cli/values.d.ts +40 -0
  253. package/dist/src/cli/values.js +189 -0
  254. package/dist/src/cli/values.js.map +1 -0
  255. package/dist/src/cli/vault.d.ts +59 -0
  256. package/dist/src/cli/vault.js +362 -0
  257. package/dist/src/cli/vault.js.map +1 -0
  258. package/dist/src/cli/verb-registry.d.ts +76 -0
  259. package/dist/src/cli/verb-registry.js +2341 -0
  260. package/dist/src/cli/verb-registry.js.map +1 -0
  261. package/dist/src/cli/wordmark.d.ts +31 -0
  262. package/dist/src/cli/wordmark.js +52 -0
  263. package/dist/src/cli/wordmark.js.map +1 -0
  264. package/dist/src/codex/doctor.d.ts +13 -0
  265. package/dist/src/codex/doctor.js +41 -0
  266. package/dist/src/codex/doctor.js.map +1 -0
  267. package/dist/src/codex/manifest.d.ts +49 -0
  268. package/dist/src/codex/manifest.js +103 -0
  269. package/dist/src/codex/manifest.js.map +1 -0
  270. package/dist/src/codex/templates.d.ts +41 -0
  271. package/dist/src/codex/templates.js +319 -0
  272. package/dist/src/codex/templates.js.map +1 -0
  273. package/dist/src/codex/trust.d.ts +19 -0
  274. package/dist/src/codex/trust.js +183 -0
  275. package/dist/src/codex/trust.js.map +1 -0
  276. package/dist/src/codex/workspace-plan.d.ts +131 -0
  277. package/dist/src/codex/workspace-plan.js +561 -0
  278. package/dist/src/codex/workspace-plan.js.map +1 -0
  279. package/dist/src/core/actor.d.ts +2 -0
  280. package/dist/src/core/actor.js +5 -0
  281. package/dist/src/core/actor.js.map +1 -0
  282. package/dist/src/core/advance-cycle.d.ts +170 -0
  283. package/dist/src/core/advance-cycle.js +200 -0
  284. package/dist/src/core/advance-cycle.js.map +1 -0
  285. package/dist/src/core/agents-md.d.ts +276 -0
  286. package/dist/src/core/agents-md.js +747 -0
  287. package/dist/src/core/agents-md.js.map +1 -0
  288. package/dist/src/core/apply-patch.d.ts +49 -0
  289. package/dist/src/core/apply-patch.js +266 -0
  290. package/dist/src/core/apply-patch.js.map +1 -0
  291. package/dist/src/core/attest.d.ts +420 -0
  292. package/dist/src/core/attest.js +589 -0
  293. package/dist/src/core/attest.js.map +1 -0
  294. package/dist/src/core/audit.d.ts +492 -0
  295. package/dist/src/core/audit.js +882 -0
  296. package/dist/src/core/audit.js.map +1 -0
  297. package/dist/src/core/budgets.d.ts +238 -0
  298. package/dist/src/core/budgets.js +449 -0
  299. package/dist/src/core/budgets.js.map +1 -0
  300. package/dist/src/core/checkpoint.d.ts +500 -0
  301. package/dist/src/core/checkpoint.js +738 -0
  302. package/dist/src/core/checkpoint.js.map +1 -0
  303. package/dist/src/core/child-env.d.ts +88 -0
  304. package/dist/src/core/child-env.js +86 -0
  305. package/dist/src/core/child-env.js.map +1 -0
  306. package/dist/src/core/clock.d.ts +52 -0
  307. package/dist/src/core/clock.js +43 -0
  308. package/dist/src/core/clock.js.map +1 -0
  309. package/dist/src/core/command-class.d.ts +543 -0
  310. package/dist/src/core/command-class.js +2356 -0
  311. package/dist/src/core/command-class.js.map +1 -0
  312. package/dist/src/core/coverage-sources/adapter.d.ts +40 -0
  313. package/dist/src/core/coverage-sources/adapter.js +71 -0
  314. package/dist/src/core/coverage-sources/adapter.js.map +1 -0
  315. package/dist/src/core/coverage-sources/gh.d.ts +48 -0
  316. package/dist/src/core/coverage-sources/gh.js +136 -0
  317. package/dist/src/core/coverage-sources/gh.js.map +1 -0
  318. package/dist/src/core/coverage-sources/git.d.ts +101 -0
  319. package/dist/src/core/coverage-sources/git.js +269 -0
  320. package/dist/src/core/coverage-sources/git.js.map +1 -0
  321. package/dist/src/core/coverage.d.ts +217 -0
  322. package/dist/src/core/coverage.js +337 -0
  323. package/dist/src/core/coverage.js.map +1 -0
  324. package/dist/src/core/credential-spec.d.ts +72 -0
  325. package/dist/src/core/credential-spec.js +23 -0
  326. package/dist/src/core/credential-spec.js.map +1 -0
  327. package/dist/src/core/dark-session.d.ts +331 -0
  328. package/dist/src/core/dark-session.js +714 -0
  329. package/dist/src/core/dark-session.js.map +1 -0
  330. package/dist/src/core/decision-refusal.d.ts +185 -0
  331. package/dist/src/core/decision-refusal.js +265 -0
  332. package/dist/src/core/decision-refusal.js.map +1 -0
  333. package/dist/src/core/env-file.d.ts +450 -0
  334. package/dist/src/core/env-file.js +837 -0
  335. package/dist/src/core/env-file.js.map +1 -0
  336. package/dist/src/core/execute.d.ts +858 -0
  337. package/dist/src/core/execute.js +1271 -0
  338. package/dist/src/core/execute.js.map +1 -0
  339. package/dist/src/core/frontmatter.d.ts +78 -0
  340. package/dist/src/core/frontmatter.js +100 -0
  341. package/dist/src/core/frontmatter.js.map +1 -0
  342. package/dist/src/core/gate-window.d.ts +312 -0
  343. package/dist/src/core/gate-window.js +506 -0
  344. package/dist/src/core/gate-window.js.map +1 -0
  345. package/dist/src/core/gate.d.ts +1364 -0
  346. package/dist/src/core/gate.js +3002 -0
  347. package/dist/src/core/gate.js.map +1 -0
  348. package/dist/src/core/git-run.d.ts +73 -0
  349. package/dist/src/core/git-run.js +93 -0
  350. package/dist/src/core/git-run.js.map +1 -0
  351. package/dist/src/core/harness-version.d.ts +157 -0
  352. package/dist/src/core/harness-version.js +211 -0
  353. package/dist/src/core/harness-version.js.map +1 -0
  354. package/dist/src/core/harness-wait.d.ts +55 -0
  355. package/dist/src/core/harness-wait.js +58 -0
  356. package/dist/src/core/harness-wait.js.map +1 -0
  357. package/dist/src/core/head-retry.d.ts +107 -0
  358. package/dist/src/core/head-retry.js +121 -0
  359. package/dist/src/core/head-retry.js.map +1 -0
  360. package/dist/src/core/instance.d.ts +253 -0
  361. package/dist/src/core/instance.js +319 -0
  362. package/dist/src/core/instance.js.map +1 -0
  363. package/dist/src/core/intake-limits.d.ts +247 -0
  364. package/dist/src/core/intake-limits.js +350 -0
  365. package/dist/src/core/intake-limits.js.map +1 -0
  366. package/dist/src/core/jcs.d.ts +52 -0
  367. package/dist/src/core/jcs.js +132 -0
  368. package/dist/src/core/jcs.js.map +1 -0
  369. package/dist/src/core/journal.d.ts +144 -0
  370. package/dist/src/core/journal.js +200 -0
  371. package/dist/src/core/journal.js.map +1 -0
  372. package/dist/src/core/live-draw.d.ts +436 -0
  373. package/dist/src/core/live-draw.js +703 -0
  374. package/dist/src/core/live-draw.js.map +1 -0
  375. package/dist/src/core/log-reconcile.d.ts +89 -0
  376. package/dist/src/core/log-reconcile.js +136 -0
  377. package/dist/src/core/log-reconcile.js.map +1 -0
  378. package/dist/src/core/log-subscribe.d.ts +36 -0
  379. package/dist/src/core/log-subscribe.js +162 -0
  380. package/dist/src/core/log-subscribe.js.map +1 -0
  381. package/dist/src/core/log.d.ts +278 -0
  382. package/dist/src/core/log.js +546 -0
  383. package/dist/src/core/log.js.map +1 -0
  384. package/dist/src/core/loop.d.ts +274 -0
  385. package/dist/src/core/loop.js +487 -0
  386. package/dist/src/core/loop.js.map +1 -0
  387. package/dist/src/core/md-fence.d.ts +41 -0
  388. package/dist/src/core/md-fence.js +74 -0
  389. package/dist/src/core/md-fence.js.map +1 -0
  390. package/dist/src/core/money.d.ts +147 -0
  391. package/dist/src/core/money.js +195 -0
  392. package/dist/src/core/money.js.map +1 -0
  393. package/dist/src/core/payload-census.d.ts +74 -0
  394. package/dist/src/core/payload-census.js +146 -0
  395. package/dist/src/core/payload-census.js.map +1 -0
  396. package/dist/src/core/payload-store.d.ts +175 -0
  397. package/dist/src/core/payload-store.js +340 -0
  398. package/dist/src/core/payload-store.js.map +1 -0
  399. package/dist/src/core/payload.d.ts +71 -0
  400. package/dist/src/core/payload.js +80 -0
  401. package/dist/src/core/payload.js.map +1 -0
  402. package/dist/src/core/policy-diff.d.ts +292 -0
  403. package/dist/src/core/policy-diff.js +588 -0
  404. package/dist/src/core/policy-diff.js.map +1 -0
  405. package/dist/src/core/policy-expectations.d.ts +199 -0
  406. package/dist/src/core/policy-expectations.js +394 -0
  407. package/dist/src/core/policy-expectations.js.map +1 -0
  408. package/dist/src/core/policy-explain.d.ts +150 -0
  409. package/dist/src/core/policy-explain.js +258 -0
  410. package/dist/src/core/policy-explain.js.map +1 -0
  411. package/dist/src/core/policy-load.d.ts +527 -0
  412. package/dist/src/core/policy-load.js +536 -0
  413. package/dist/src/core/policy-load.js.map +1 -0
  414. package/dist/src/core/policy-match.d.ts +281 -0
  415. package/dist/src/core/policy-match.js +478 -0
  416. package/dist/src/core/policy-match.js.map +1 -0
  417. package/dist/src/core/policy-proposal.d.ts +265 -0
  418. package/dist/src/core/policy-proposal.js +458 -0
  419. package/dist/src/core/policy-proposal.js.map +1 -0
  420. package/dist/src/core/prompt-layout.d.ts +221 -0
  421. package/dist/src/core/prompt-layout.js +422 -0
  422. package/dist/src/core/prompt-layout.js.map +1 -0
  423. package/dist/src/core/protected-path-guard.d.ts +453 -0
  424. package/dist/src/core/protected-path-guard.js +1566 -0
  425. package/dist/src/core/protected-path-guard.js.map +1 -0
  426. package/dist/src/core/registration.d.ts +25 -0
  427. package/dist/src/core/registration.js +39 -0
  428. package/dist/src/core/registration.js.map +1 -0
  429. package/dist/src/core/reindex.d.ts +99 -0
  430. package/dist/src/core/reindex.js +336 -0
  431. package/dist/src/core/reindex.js.map +1 -0
  432. package/dist/src/core/sampler.d.ts +313 -0
  433. package/dist/src/core/sampler.js +388 -0
  434. package/dist/src/core/sampler.js.map +1 -0
  435. package/dist/src/core/sandbox.d.ts +290 -0
  436. package/dist/src/core/sandbox.js +424 -0
  437. package/dist/src/core/sandbox.js.map +1 -0
  438. package/dist/src/core/seal.d.ts +165 -0
  439. package/dist/src/core/seal.js +290 -0
  440. package/dist/src/core/seal.js.map +1 -0
  441. package/dist/src/core/state.d.ts +505 -0
  442. package/dist/src/core/state.js +1009 -0
  443. package/dist/src/core/state.js.map +1 -0
  444. package/dist/src/core/task-file.d.ts +185 -0
  445. package/dist/src/core/task-file.js +464 -0
  446. package/dist/src/core/task-file.js.map +1 -0
  447. package/dist/src/core/telegram-config.d.ts +93 -0
  448. package/dist/src/core/telegram-config.js +114 -0
  449. package/dist/src/core/telegram-config.js.map +1 -0
  450. package/dist/src/core/token.d.ts +409 -0
  451. package/dist/src/core/token.js +561 -0
  452. package/dist/src/core/token.js.map +1 -0
  453. package/dist/src/core/validate.d.ts +138 -0
  454. package/dist/src/core/validate.js +0 -0
  455. package/dist/src/core/validate.js.map +1 -0
  456. package/dist/src/core/values.d.ts +137 -0
  457. package/dist/src/core/values.js +153 -0
  458. package/dist/src/core/values.js.map +1 -0
  459. package/dist/src/core/vault.d.ts +291 -0
  460. package/dist/src/core/vault.js +612 -0
  461. package/dist/src/core/vault.js.map +1 -0
  462. package/dist/src/core/verified-snapshot.d.ts +204 -0
  463. package/dist/src/core/verified-snapshot.js +506 -0
  464. package/dist/src/core/verified-snapshot.js.map +1 -0
  465. package/dist/src/core/verify.d.ts +336 -0
  466. package/dist/src/core/verify.js +549 -0
  467. package/dist/src/core/verify.js.map +1 -0
  468. package/dist/src/core/version.d.ts +8 -0
  469. package/dist/src/core/version.js +9 -0
  470. package/dist/src/core/version.js.map +1 -0
  471. package/dist/src/core/wysiwys.d.ts +370 -0
  472. package/dist/src/core/wysiwys.js +728 -0
  473. package/dist/src/core/wysiwys.js.map +1 -0
  474. package/dist/src/daemon/advance-child.d.ts +39 -0
  475. package/dist/src/daemon/advance-child.js +78 -0
  476. package/dist/src/daemon/advance-child.js.map +1 -0
  477. package/dist/src/daemon/advance.d.ts +466 -0
  478. package/dist/src/daemon/advance.js +849 -0
  479. package/dist/src/daemon/advance.js.map +1 -0
  480. package/dist/src/daemon/audit.d.ts +87 -0
  481. package/dist/src/daemon/audit.js +90 -0
  482. package/dist/src/daemon/audit.js.map +1 -0
  483. package/dist/src/daemon/daemon.d.ts +1180 -0
  484. package/dist/src/daemon/daemon.js +1988 -0
  485. package/dist/src/daemon/daemon.js.map +1 -0
  486. package/dist/src/daemon/dark-session.d.ts +64 -0
  487. package/dist/src/daemon/dark-session.js +119 -0
  488. package/dist/src/daemon/dark-session.js.map +1 -0
  489. package/dist/src/daemon/draw-child.d.ts +36 -0
  490. package/dist/src/daemon/draw-child.js +132 -0
  491. package/dist/src/daemon/draw-child.js.map +1 -0
  492. package/dist/src/daemon/draw.d.ts +154 -0
  493. package/dist/src/daemon/draw.js +458 -0
  494. package/dist/src/daemon/draw.js.map +1 -0
  495. package/dist/src/daemon/git-evidence.d.ts +173 -0
  496. package/dist/src/daemon/git-evidence.js +345 -0
  497. package/dist/src/daemon/git-evidence.js.map +1 -0
  498. package/dist/src/daemon/projection.d.ts +180 -0
  499. package/dist/src/daemon/projection.js +233 -0
  500. package/dist/src/daemon/projection.js.map +1 -0
  501. package/dist/src/daemon/prune.d.ts +207 -0
  502. package/dist/src/daemon/prune.js +376 -0
  503. package/dist/src/daemon/prune.js.map +1 -0
  504. package/dist/src/mcp/http.d.ts +113 -0
  505. package/dist/src/mcp/http.js +343 -0
  506. package/dist/src/mcp/http.js.map +1 -0
  507. package/dist/src/mcp/server.d.ts +265 -0
  508. package/dist/src/mcp/server.js +602 -0
  509. package/dist/src/mcp/server.js.map +1 -0
  510. package/docs/adapter-api.md +106 -0
  511. package/docs/cli-reference.md +5716 -0
  512. package/docs/codex-enforced-session.md +30 -0
  513. package/package.json +53 -4
  514. package/schema/.gitkeep +0 -0
  515. package/schema/LICENSE +117 -0
  516. package/schema/codex-instance.schema.json +82 -0
  517. package/schema/envelope.schema.json +137 -0
  518. package/schema/event.schema.json +1811 -0
  519. package/schema/fixtures/codex-instance/invalid/unpinned-codex-version.json +40 -0
  520. package/schema/fixtures/codex-instance/valid/canonical.json +40 -0
  521. package/schema/fixtures/envelope/invalid/action-missing-idempotency-key.json +15 -0
  522. package/schema/fixtures/envelope/invalid/action-unknown-class-format.json +14 -0
  523. package/schema/fixtures/envelope/invalid/confidence-out-of-range.json +11 -0
  524. package/schema/fixtures/envelope/invalid/est-cost-bare-number.json +14 -0
  525. package/schema/fixtures/envelope/invalid/est-cost-noncanonical-string.json +14 -0
  526. package/schema/fixtures/envelope/invalid/malformed-assignee.json +10 -0
  527. package/schema/fixtures/envelope/invalid/malformed-created-by.json +7 -0
  528. package/schema/fixtures/envelope/invalid/malformed-max-latency.json +11 -0
  529. package/schema/fixtures/envelope/invalid/malformed-payload-hash.json +14 -0
  530. package/schema/fixtures/envelope/invalid/max-cost-bare-number.json +11 -0
  531. package/schema/fixtures/envelope/invalid/missing-origin.json +3 -0
  532. package/schema/fixtures/envelope/invalid/negative-est-cost.json +14 -0
  533. package/schema/fixtures/envelope/invalid/unknown-state.json +7 -0
  534. package/schema/fixtures/envelope/invalid/unknown-top-level-field.json +8 -0
  535. package/schema/fixtures/envelope/valid/action-payload-hash.json +17 -0
  536. package/schema/fixtures/envelope/valid/actions-without-budget.json +18 -0
  537. package/schema/fixtures/envelope/valid/canonical.json +25 -0
  538. package/schema/fixtures/envelope/valid/minimal.json +7 -0
  539. package/schema/fixtures/envelope/valid/multi-action-executed.json +30 -0
  540. package/schema/fixtures/envelope/valid/record-write-stage.json +22 -0
  541. package/schema/fixtures/event/invalid/approval-granted-agent-actor.json +15 -0
  542. package/schema/fixtures/event/invalid/approval-granted-empty-batch-delivery-id.json +17 -0
  543. package/schema/fixtures/event/invalid/approval-granted-fifth-reaction.json +16 -0
  544. package/schema/fixtures/event/invalid/approval-granted-missing-actor.json +14 -0
  545. package/schema/fixtures/event/invalid/approval-requested-missing-action-key.json +14 -0
  546. package/schema/fixtures/event/invalid/approval-withdrawn-agent-policy-drift.json +15 -0
  547. package/schema/fixtures/event/invalid/approval-withdrawn-missing-reason.json +15 -0
  548. package/schema/fixtures/event/invalid/approval-withdrawn-system-actor.json +15 -0
  549. package/schema/fixtures/event/invalid/audit-decision-refused-human-actor.json +17 -0
  550. package/schema/fixtures/event/invalid/audit-decision-refused-missing-code.json +16 -0
  551. package/schema/fixtures/event/invalid/audit-reviewed-agent-actor.json +15 -0
  552. package/schema/fixtures/event/invalid/audit-reviewed-loved-no-note.json +16 -0
  553. package/schema/fixtures/event/invalid/audit-reviewed-system-actor.json +15 -0
  554. package/schema/fixtures/event/invalid/bad-actor-prefix.json +15 -0
  555. package/schema/fixtures/event/invalid/est-cost-bare-number.json +17 -0
  556. package/schema/fixtures/event/invalid/execution-completed-fabricated-exit-code.json +16 -0
  557. package/schema/fixtures/event/invalid/execution-completed-provider-ref-empty-id.json +18 -0
  558. package/schema/fixtures/event/invalid/execution-completed-provider-ref-extra-field.json +19 -0
  559. package/schema/fixtures/event/invalid/execution-completed-provider-ref-id-not-string.json +18 -0
  560. package/schema/fixtures/event/invalid/execution-completed-provider-ref-missing-adapter.json +17 -0
  561. package/schema/fixtures/event/invalid/execution-failed-open-reported-by.json +16 -0
  562. package/schema/fixtures/event/invalid/execution-indeterminate-open-reason.json +14 -0
  563. package/schema/fixtures/event/invalid/execution-reconciled-agent-actor.json +17 -0
  564. package/schema/fixtures/event/invalid/execution-started-negative-env-stripped.json +16 -0
  565. package/schema/fixtures/event/invalid/gate-bypassed-missing-opened-seq.json +15 -0
  566. package/schema/fixtures/event/invalid/gate-closed-non-integer-opened-seq.json +13 -0
  567. package/schema/fixtures/event/invalid/gate-opened-agent-actor.json +16 -0
  568. package/schema/fixtures/event/invalid/gate-organ-attested-absolute-path.json +14 -0
  569. package/schema/fixtures/event/invalid/gate-organ-attested-agent-actor.json +14 -0
  570. package/schema/fixtures/event/invalid/gate-organ-attested-missing-organ-path.json +13 -0
  571. package/schema/fixtures/event/invalid/harness-unknown-kind.json +18 -0
  572. package/schema/fixtures/event/invalid/harness-version-multiline.json +16 -0
  573. package/schema/fixtures/event/invalid/log-checkpoint-agent-actor.json +17 -0
  574. package/schema/fixtures/event/invalid/log-checkpoint-missing-signature.json +16 -0
  575. package/schema/fixtures/event/invalid/log-checkpoint-short-signed-hash.json +17 -0
  576. package/schema/fixtures/event/invalid/log-checkpoint-unknown-signature-alg.json +17 -0
  577. package/schema/fixtures/event/invalid/malformed-ts.json +15 -0
  578. package/schema/fixtures/event/invalid/missing-alg.json +14 -0
  579. package/schema/fixtures/event/invalid/missing-hash.json +14 -0
  580. package/schema/fixtures/event/invalid/non-integer-seq.json +15 -0
  581. package/schema/fixtures/event/invalid/payload-pruned-human-actor.json +14 -0
  582. package/schema/fixtures/event/invalid/payload-pruned-missing-hash.json +14 -0
  583. package/schema/fixtures/event/invalid/policy-declined-agent-actor.json +15 -0
  584. package/schema/fixtures/event/invalid/policy-proposed-missing-diff.json +19 -0
  585. package/schema/fixtures/event/invalid/policy-proposed-system-actor.json +26 -0
  586. package/schema/fixtures/event/invalid/short-hash.json +15 -0
  587. package/schema/fixtures/event/invalid/unknown-alg.json +15 -0
  588. package/schema/fixtures/event/invalid/unknown-event-type.json +15 -0
  589. package/schema/fixtures/event/invalid/unknown-top-level-field.json +16 -0
  590. package/schema/fixtures/event/valid/approval-expired.json +15 -0
  591. package/schema/fixtures/event/valid/approval-granted-batch.json +19 -0
  592. package/schema/fixtures/event/valid/approval-granted-reaction.json +16 -0
  593. package/schema/fixtures/event/valid/approval-granted.json +15 -0
  594. package/schema/fixtures/event/valid/approval-rejected.json +15 -0
  595. package/schema/fixtures/event/valid/approval-requested.json +19 -0
  596. package/schema/fixtures/event/valid/approval-revoked.json +15 -0
  597. package/schema/fixtures/event/valid/approval-withdrawn-policy-drift.json +17 -0
  598. package/schema/fixtures/event/valid/approval-withdrawn.json +16 -0
  599. package/schema/fixtures/event/valid/audit-decision-refused.json +20 -0
  600. package/schema/fixtures/event/valid/audit-reviewed-reaction.json +17 -0
  601. package/schema/fixtures/event/valid/audit-reviewed.json +15 -0
  602. package/schema/fixtures/event/valid/audit-sampled.json +14 -0
  603. package/schema/fixtures/event/valid/budget-exceeded.json +21 -0
  604. package/schema/fixtures/event/valid/envelope-drift.json +16 -0
  605. package/schema/fixtures/event/valid/execution-completed-harness-report.json +16 -0
  606. package/schema/fixtures/event/valid/execution-completed-provider-ref.json +18 -0
  607. package/schema/fixtures/event/valid/execution-completed.json +15 -0
  608. package/schema/fixtures/event/valid/execution-failed-harness-report.json +16 -0
  609. package/schema/fixtures/event/valid/execution-failed.json +15 -0
  610. package/schema/fixtures/event/valid/execution-indeterminate.json +15 -0
  611. package/schema/fixtures/event/valid/execution-reconciled.json +17 -0
  612. package/schema/fixtures/event/valid/execution-started-env-stripped.json +17 -0
  613. package/schema/fixtures/event/valid/execution-started.json +14 -0
  614. package/schema/fixtures/event/valid/gate-bypassed-harness-version.json +18 -0
  615. package/schema/fixtures/event/valid/gate-bypassed.json +19 -0
  616. package/schema/fixtures/event/valid/gate-closed.json +14 -0
  617. package/schema/fixtures/event/valid/gate-opened.json +16 -0
  618. package/schema/fixtures/event/valid/gate-organ-attested.json +14 -0
  619. package/schema/fixtures/event/valid/genesis-null-prev.json +14 -0
  620. package/schema/fixtures/event/valid/log-checkpoint.json +17 -0
  621. package/schema/fixtures/event/valid/payload-pruned-orphan.json +13 -0
  622. package/schema/fixtures/event/valid/payload-pruned.json +17 -0
  623. package/schema/fixtures/event/valid/policy-declined.json +16 -0
  624. package/schema/fixtures/event/valid/policy-proposed.json +35 -0
  625. package/schema/fixtures/event/valid/policy-updated.json +14 -0
  626. package/schema/fixtures/event/valid/reconciliation-required.json +18 -0
  627. package/schema/fixtures/event/valid/reconciliation-satisfied.json +17 -0
  628. package/schema/fixtures/event/valid/route-accepted.json +15 -0
  629. package/schema/fixtures/event/valid/route-proposed.json +16 -0
  630. package/schema/fixtures/event/valid/spec-example.json +15 -0
  631. package/schema/fixtures/event/valid/task-registered-harness-version.json +23 -0
  632. package/schema/fixtures/event/valid/task-registered.json +14 -0
  633. package/schema/fixtures/hash/known-answer-pre-121.json +74 -0
  634. package/schema/fixtures/hash/known-answer.json +74 -0
  635. package/schema/fixtures/policy/invalid/bad-approval-ttl.json +7 -0
  636. package/schema/fixtures/policy/invalid/bad-web-port.json +4 -0
  637. package/schema/fixtures/policy/invalid/checkpoint-key-not-base64.json +6 -0
  638. package/schema/fixtures/policy/invalid/class-rule-missing-autonomy.json +9 -0
  639. package/schema/fixtures/policy/invalid/empty-class-key.json +6 -0
  640. package/schema/fixtures/policy/invalid/live-rate-on-human-only.json +7 -0
  641. package/schema/fixtures/policy/invalid/malformed-class-key.json +6 -0
  642. package/schema/fixtures/policy/invalid/missing-version.json +8 -0
  643. package/schema/fixtures/policy/invalid/negative-limit.json +9 -0
  644. package/schema/fixtures/policy/invalid/non-numeric-limit.json +9 -0
  645. package/schema/fixtures/policy/invalid/non-positive-max-pending.json +9 -0
  646. package/schema/fixtures/policy/invalid/on-expiry-grant.json +8 -0
  647. package/schema/fixtures/policy/invalid/payload-retention-bare-number.json +4 -0
  648. package/schema/fixtures/policy/invalid/payload-retention-compound.json +4 -0
  649. package/schema/fixtures/policy/invalid/payload-retention-fractional.json +4 -0
  650. package/schema/fixtures/policy/invalid/payload-retention-zero.json +4 -0
  651. package/schema/fixtures/policy/invalid/protected-paths-escape.json +4 -0
  652. package/schema/fixtures/policy/invalid/protected-paths-glob.json +4 -0
  653. package/schema/fixtures/policy/invalid/retro-rate-on-human-only.json +7 -0
  654. package/schema/fixtures/policy/invalid/retro-rate-on-manual.json +7 -0
  655. package/schema/fixtures/policy/invalid/retro-rate-zero.json +7 -0
  656. package/schema/fixtures/policy/invalid/sample-rate-too-high.json +5 -0
  657. package/schema/fixtures/policy/invalid/sampling-secret-env-empty.json +7 -0
  658. package/schema/fixtures/policy/invalid/sampling-secret-env-not-string.json +6 -0
  659. package/schema/fixtures/policy/invalid/skew-tolerance-compound.json +6 -0
  660. package/schema/fixtures/policy/invalid/unknown-autonomy.json +7 -0
  661. package/schema/fixtures/policy/invalid/unknown-class-rule-key.json +6 -0
  662. package/schema/fixtures/policy/invalid/unknown-top-level-key.json +7 -0
  663. package/schema/fixtures/policy/invalid/vault-passphrase-env-empty.json +6 -0
  664. package/schema/fixtures/policy/invalid/vault-passphrase-literal.json +6 -0
  665. package/schema/fixtures/policy/invalid/version-not-string.json +4 -0
  666. package/schema/fixtures/policy/valid/canonical.json +47 -0
  667. package/schema/fixtures/policy/valid/checkpoint-keys.json +18 -0
  668. package/schema/fixtures/policy/valid/class-approvers-limits.json +25 -0
  669. package/schema/fixtures/policy/valid/class-retro-rate.json +17 -0
  670. package/schema/fixtures/policy/valid/global-budgets.json +19 -0
  671. package/schema/fixtures/policy/valid/human-only.json +9 -0
  672. package/schema/fixtures/policy/valid/minimal.json +6 -0
  673. package/schema/fixtures/policy/valid/protected-paths.json +10 -0
  674. package/schema/fixtures/policy/valid/record-namespace.json +13 -0
  675. package/schema/fixtures/policy/valid/request-volume-limits.json +26 -0
  676. package/schema/fixtures/policy/valid/retention-and-sampling-secret.json +16 -0
  677. package/schema/fixtures/policy/valid/skew-tolerance.json +15 -0
  678. package/schema/fixtures/policy/valid/vault-passphrase-env.json +14 -0
  679. package/schema/fixtures/policy/valid/wildcards.json +15 -0
  680. package/schema/fixtures/policy-md/invalid/alias-bomb.md +15 -0
  681. package/schema/fixtures/policy-md/invalid/no-fence.md +7 -0
  682. package/schema/fixtures/policy-md/invalid/protected-route-not-a-subclass.md +16 -0
  683. package/schema/fixtures/policy-md/invalid/schema-invalid-autonomy.md +16 -0
  684. package/schema/fixtures/policy-md/invalid/schema-invalid-read-proof.md +17 -0
  685. package/schema/fixtures/policy-md/invalid/two-fences.md +19 -0
  686. package/schema/fixtures/policy-md/invalid/unclosed-fence.md +11 -0
  687. package/schema/fixtures/policy-md/invalid/wrong-info-string.md +11 -0
  688. package/schema/fixtures/policy-md/invalid/yaml-syntax-error.md +13 -0
  689. package/schema/fixtures/policy-md/precedence/both/APPROVAL.md +7 -0
  690. package/schema/fixtures/policy-md/precedence/both/APPROVALS.md +7 -0
  691. package/schema/fixtures/policy-md/precedence/fallback-only/APPROVALS.md +7 -0
  692. package/schema/fixtures/policy-md/valid/canonical.md +50 -0
  693. package/schema/fixtures/policy-md/valid/daemon-read-proof.md +18 -0
  694. package/schema/fixtures/policy-md/valid/minimal.md +3 -0
  695. package/schema/fixtures/policy-md/valid/prose-lookalikes.md +54 -0
  696. package/schema/fixtures/policy-md/valid/routed-protected-paths.md +49 -0
  697. package/schema/fixtures/policy-md/valid/with-values.md +79 -0
  698. package/schema/fixtures/sample-record/invalid/bad-date-time.json +4 -0
  699. package/schema/fixtures/sample-record/invalid/missing-required-field.json +3 -0
  700. package/schema/fixtures/sample-record/invalid/unknown-top-level-field.json +5 -0
  701. package/schema/fixtures/sample-record/invalid/wrong-type.json +4 -0
  702. package/schema/fixtures/sample-record/valid/minimal.json +4 -0
  703. package/schema/fixtures/sample-record/valid/with-note.json +5 -0
  704. package/schema/fixtures/values/invalid/class-shaped.json +9 -0
  705. package/schema/fixtures/values/invalid/duplicate-entry.json +4 -0
  706. package/schema/fixtures/values/invalid/non-string-item.json +4 -0
  707. package/schema/fixtures/values/invalid/over-cap.json +26 -0
  708. package/schema/fixtures/values/invalid/unknown-key.json +5 -0
  709. package/schema/fixtures/values/invalid/version-string.json +1 -0
  710. package/schema/fixtures/values/valid/empty-lists.json +7 -0
  711. package/schema/fixtures/values/valid/full.json +20 -0
  712. package/schema/fixtures/values/valid/minimal.json +1 -0
  713. package/schema/fixtures/values-md/invalid/schema-invalid.md +62 -0
  714. package/schema/fixtures/values-md/invalid/two-blocks.md +69 -0
  715. package/schema/fixtures/values-md/invalid/unterminated.md +61 -0
  716. package/schema/fixtures/values-md/invalid/yaml-error.md +63 -0
  717. package/schema/fixtures/values-md/valid/absent.md +50 -0
  718. package/schema/fixtures/values-md/valid/with-values.md +79 -0
  719. package/schema/policy.schema.json +501 -0
  720. package/schema/sample-record.schema.json +26 -0
  721. package/schema/values.schema.json +55 -0
  722. package/templates/codex/README.md +9 -0
@@ -0,0 +1,703 @@
1
+ /**
2
+ * The daemon-answered live draw (APRV-208).
3
+ *
4
+ * ## The hole this closes
5
+ *
6
+ * `supervised-live` (APRV-127) puts a declared fraction of a class through the
7
+ * human gate, chosen by HMAC over the payload hash under an operator-held
8
+ * secret. `core/sampler.ts`'s {@link import("./sampler.js").resolveLiveSelector}
9
+ * reads that secret out of the DECIDING PROCESS's own environment, and the
10
+ * deciding process is usually the harness hook — a short-lived child of an
11
+ * agent session. Nothing sources the secret there, and nothing may: a secret an
12
+ * agent-launched process can read is a secret the agent can read, and an agent
13
+ * that can compute its own luck can grind its payload until the draw comes up
14
+ * unsampled. SPEC.md §5.2 forbids exactly that.
15
+ *
16
+ * So the draw failed closed, correctly and permanently: measured on this
17
+ * repository's own log, 15 of 15 supervised-live actions since the seq 5147
18
+ * ceremony gated to a human (APRV-184). A class an operator asked to sample at
19
+ * 10% was gated at 100%, which is safe and is also the setting never once
20
+ * having been live.
21
+ *
22
+ * The fix is not to hand the hook the secret. It is to move the DRAW to the one
23
+ * process that legitimately holds it — the daemon, started by the operator in a
24
+ * terminal where `eval "$(approval env)"` has run — and let the hook ASK.
25
+ *
26
+ * ## The protocol, and what each part is for
27
+ *
28
+ * One owner-only Unix socket under the approval home
29
+ * (`.approval/daemon/draw.sock`, directory 0700, socket 0600). One JSON line in,
30
+ * one JSON line out, connection closed.
31
+ *
32
+ * ```
33
+ * -> {"v":1,"action_key":"...","payload_hash":"<64hex>","policy_hash":"<64hex>","live_rate":0.1}
34
+ * <- {"v":1,"question":{...},"selected":true,"mac":"<64hex>","daemon_pid":123,"answered_at":"..."}
35
+ * ```
36
+ *
37
+ * - **The question is a PROPOSAL; the echoed question is the daemon's own
38
+ * derivation.** The daemon does not take `live_rate` or `policy_hash` on the
39
+ * asker's word — it resolves the class from its own policy and echoes what it
40
+ * derived. The asker requires the echo to equal what it asked. A daemon and a
41
+ * hook reading different policies therefore fail closed instead of agreeing on
42
+ * the wrong rate, and no answer is ever MAC'd over a rate the daemon did not
43
+ * itself compute.
44
+ * - **The MAC binds the whole question AND the verdict.** `HMAC-SHA-256(secret,
45
+ * domain || canonical question || "\n" || selected)`. An answer is worth
46
+ * nothing without it: the asker cannot check it (it holds no secret), so it
47
+ * records it, and an operator who holds the secret recomputes it later from
48
+ * the record's own `action_key`, `payload_hash` and `policy_sha256`. That is
49
+ * what keeps SPEC.md §11's "self-reported fields never reduce scrutiny" true
50
+ * here — the answer is not believed, it is EVIDENCED, and an answer that
51
+ * cannot be evidenced (absent daemon, dead daemon, malformed reply) is refused
52
+ * and the action gates.
53
+ * - **A domain separator.** The MAC message is prefixed with
54
+ * {@link DRAW_MAC_DOMAIN} so a MAC can never be confused with, or substituted
55
+ * for, the selection value `core/sampler.ts` derives from the same key over a
56
+ * bare payload hash.
57
+ *
58
+ * ## Why the socket is not a free oracle
59
+ *
60
+ * An owner-only socket is reachable by any process of the same user, and an
61
+ * agent session runs as that user. If the daemon answered any question put to
62
+ * it, the agent could ask "would these bytes be sampled?" for a thousand
63
+ * candidate payloads and pick one that is not — the very grinding attack the
64
+ * secret exists to prevent, restored through the front door.
65
+ *
66
+ * `daemon/draw.ts` closes it by refusing to answer for an action that is not
67
+ * ALREADY REGISTERED in the verified log with exactly this payload hash. To ask
68
+ * a question you must first append a `task.registered` naming the bytes, so
69
+ * every candidate an agent grinds is permanently in the append-only log, in
70
+ * order, countable by anyone. The oracle still exists; it just cannot be
71
+ * consulted in secret, which is the property this project trades in.
72
+ *
73
+ * ## The secret is never here
74
+ *
75
+ * This module takes a secret as a parameter in exactly two pure functions
76
+ * ({@link drawMac}, {@link verifyDrawAnswer}) and stores it nowhere. Nothing in
77
+ * the client half ever sees one: the asking process holds no secret, which is
78
+ * the entire point.
79
+ */
80
+ import { spawnSync } from "node:child_process";
81
+ import { createHmac, timingSafeEqual } from "node:crypto";
82
+ import { existsSync, statSync } from "node:fs";
83
+ import { connect } from "node:net";
84
+ import { dirname, join, resolve } from "node:path";
85
+ import { fileURLToPath } from "node:url";
86
+ import { canonicalize } from "./jcs.js";
87
+ /** The protocol version. A mismatch is a refusal, never a negotiation. */
88
+ export const DRAW_PROTOCOL_VERSION = 1;
89
+ /** The socket's basename under the approval home's `daemon/` directory. */
90
+ export const DRAW_SOCKET_NAME = "draw.sock";
91
+ /** The MAC's domain separator. See the module header. */
92
+ export const DRAW_MAC_DOMAIN = "approval.md/live-draw/v1";
93
+ /**
94
+ * The longest socket path this runtime will bind or dial.
95
+ *
96
+ * `sockaddr_un.sun_path` is 104 bytes on macOS and 108 on Linux, and a `bind`
97
+ * past it fails with a message an operator cannot act on. Checked on both sides
98
+ * so the daemon reports it as a refusal to serve and the asker reports it as an
99
+ * absent daemon, rather than either of them producing an `ENAMETOOLONG` nobody
100
+ * expected.
101
+ */
102
+ export const DRAW_SOCKET_PATH_LIMIT = 100;
103
+ /** How long the asking child waits for a connection and an answer. */
104
+ export const DRAW_TIMEOUT_MS = 500;
105
+ /** The whole child invocation, including Node's own start. */
106
+ export const DRAW_SPAWN_TIMEOUT_MS = 5_000;
107
+ // ---------------------------------------------------------------------------
108
+ // Where the socket lives
109
+ // ---------------------------------------------------------------------------
110
+ /**
111
+ * The approval home's `daemon/` directory for a log, derived and never
112
+ * configured.
113
+ *
114
+ * `logPath` is `<home>/log/events.jsonl`, so the home is two levels up. One log
115
+ * has one daemon directory: a reader that had to be TOLD where to look could be
116
+ * pointed at another instance's daemon, and answers would cross between
117
+ * instances that share a machine.
118
+ */
119
+ export function drawDirFor(logPath) {
120
+ return join(dirname(dirname(resolve(logPath))), "daemon");
121
+ }
122
+ /** Where the draw socket for `logPath` lives. */
123
+ export function drawSocketPathFor(logPath) {
124
+ return join(drawDirFor(logPath), DRAW_SOCKET_NAME);
125
+ }
126
+ /**
127
+ * Which class patterns this policy declares `supervised-live`, sorted.
128
+ *
129
+ * The one question that decides whether any of this machinery is the operator's
130
+ * business at all: with no live class, no draw is ever made, so a missing
131
+ * socket is not a fault, an unset secret is not a misconfiguration, and neither
132
+ * deserves a doctor row or a line on the daemon's stderr. Shared by the doctor
133
+ * row and the daemon's server so the two cannot come to different conclusions
134
+ * about the same file.
135
+ *
136
+ * `defaults.autonomy` is not consulted, and cannot be: `supervised-live` carries
137
+ * a required rate that `defaults` has no field to hold, which `policy.schema.json`
138
+ * enforces. Only a class rule can be live.
139
+ */
140
+ export function liveClassesOf(policy) {
141
+ return Object.entries(policy.classes ?? {})
142
+ .filter(([, rule]) => rule?.autonomy === "supervised-live")
143
+ .map(([pattern]) => pattern)
144
+ .sort();
145
+ }
146
+ /** Is this a well-formed 64-character lowercase hex digest? */
147
+ export function isHex64(value) {
148
+ return typeof value === "string" && /^[a-f0-9]{64}$/u.test(value);
149
+ }
150
+ /**
151
+ * The canonical bytes a MAC covers: RFC 8785 over the question.
152
+ *
153
+ * `core/jcs.ts` is the runtime's one canonicalizer, so the asker, the daemon and
154
+ * a later verifier cannot drift apart over key order or number spelling.
155
+ */
156
+ export function canonicalQuestion(question) {
157
+ return canonicalize({
158
+ action_key: question.action_key,
159
+ live_rate: question.live_rate,
160
+ payload_hash: question.payload_hash,
161
+ policy_hash: question.policy_hash,
162
+ v: question.v,
163
+ });
164
+ }
165
+ /** `HMAC-SHA-256(secret, domain || question || verdict)`, lowercase hex. */
166
+ export function drawMac(secret, question, selected) {
167
+ return createHmac("sha256", secret)
168
+ .update(`${DRAW_MAC_DOMAIN}\n${canonicalQuestion(question)}\n${selected ? "1" : "0"}`, "utf8")
169
+ .digest("hex");
170
+ }
171
+ /**
172
+ * Does this MAC belong to this question and this verdict, under this secret?
173
+ *
174
+ * Constant-time, which costs nothing and removes the argument about whether it
175
+ * matters. A malformed MAC is `false` rather than a throw: this is a verifier,
176
+ * and every wrong answer is one answer.
177
+ */
178
+ export function verifyDrawAnswer(secret, question, selected, mac) {
179
+ if (!isHex64(mac))
180
+ return false;
181
+ const expected = Buffer.from(drawMac(secret, question, selected), "hex");
182
+ const actual = Buffer.from(mac, "hex");
183
+ if (expected.length !== actual.length)
184
+ return false;
185
+ return timingSafeEqual(expected, actual);
186
+ }
187
+ // ---------------------------------------------------------------------------
188
+ // Refusals
189
+ // ---------------------------------------------------------------------------
190
+ /**
191
+ * Why a delegated draw produced no usable answer. Machine-readable, closed and
192
+ * DISTINCT (SPEC.md §11 invariant 6), because the operator's action differs:
193
+ * "start the daemon", "your daemon is wedged or was killed", "something
194
+ * answered and it was not a daemon holding your secret".
195
+ *
196
+ * Every one of them gates the action, exactly as an unavailable secret does
197
+ * today. None of them is a degraded mode.
198
+ */
199
+ export const DRAW_REFUSAL_REASONS = [
200
+ /** No socket at the derived path: no daemon has ever served draws here. */
201
+ "draw-daemon-absent",
202
+ /** A socket that cannot be dialled, times out, or names a pid that is gone. */
203
+ "draw-daemon-stale",
204
+ /** An answer that is malformed, off-version, off-question, or badly MAC'd. */
205
+ "draw-answer-invalid",
206
+ ];
207
+ /**
208
+ * Recompute a recorded delegation, from the record and the operator's secret.
209
+ *
210
+ * This is the whole point of the MAC, and it is deliberately a function of the
211
+ * RECORD rather than of anything the asker kept: `action_key` and
212
+ * `payload_hash` are the request's own fields and `policy_sha256` is assigned at
213
+ * the write boundary, so a verifier reconstructs the question from bytes the
214
+ * requester could not choose freely and could not alter afterwards without
215
+ * breaking the chain.
216
+ *
217
+ * `false` for a record with no MAC (a refusal), for a tampered MAC, and for a
218
+ * flipped verdict. Never throws.
219
+ */
220
+ export function verifyLiveDrawRecord(secret, fields) {
221
+ const { draw } = fields;
222
+ if (draw.source !== "daemon")
223
+ return false;
224
+ if (typeof draw.selected !== "boolean" || draw.mac === undefined)
225
+ return false;
226
+ const question = {
227
+ v: draw.v,
228
+ action_key: fields.actionKey,
229
+ payload_hash: fields.payloadHash,
230
+ policy_hash: fields.policyHash,
231
+ live_rate: draw.live_rate,
232
+ };
233
+ return verifyDrawAnswer(secret, question, draw.selected, draw.mac);
234
+ }
235
+ // ---------------------------------------------------------------------------
236
+ // Parsing an answer
237
+ // ---------------------------------------------------------------------------
238
+ function sameQuestion(a, b) {
239
+ return (a.v === b.v &&
240
+ a.action_key === b.action_key &&
241
+ a.payload_hash === b.payload_hash &&
242
+ a.policy_hash === b.policy_hash &&
243
+ a.live_rate === b.live_rate);
244
+ }
245
+ /**
246
+ * Read one answer line against the question that was asked.
247
+ *
248
+ * Every check can only REJECT. The asker holds no secret, so it cannot check the
249
+ * MAC; what it CAN check is that the answer is this protocol's version, is an
250
+ * answer to this exact question (the daemon's own derivation, field for field),
251
+ * carries a MAC of the right shape, and names a live process. Anything else is
252
+ * `draw-answer-invalid` and the action gates.
253
+ */
254
+ export function parseDrawAnswer(text, asked) {
255
+ let parsed;
256
+ try {
257
+ parsed = JSON.parse(text);
258
+ }
259
+ catch {
260
+ return { ok: false, reason: "draw-answer-invalid", detail: "the answer was not JSON" };
261
+ }
262
+ if (typeof parsed !== "object" || parsed === null) {
263
+ return { ok: false, reason: "draw-answer-invalid", detail: "the answer was not an object" };
264
+ }
265
+ const body = parsed;
266
+ if (body["v"] !== DRAW_PROTOCOL_VERSION) {
267
+ return {
268
+ ok: false,
269
+ reason: "draw-answer-invalid",
270
+ detail: `the answer declares protocol version ${JSON.stringify(body["v"])}, not ${String(DRAW_PROTOCOL_VERSION)}`,
271
+ };
272
+ }
273
+ const echoed = body["question"];
274
+ if (typeof echoed !== "object" || echoed === null) {
275
+ return { ok: false, reason: "draw-answer-invalid", detail: "the answer echoed no question" };
276
+ }
277
+ const question = echoed;
278
+ const derived = {
279
+ v: typeof question["v"] === "number" ? question["v"] : -1,
280
+ action_key: typeof question["action_key"] === "string" ? question["action_key"] : "",
281
+ payload_hash: typeof question["payload_hash"] === "string" ? question["payload_hash"] : "",
282
+ policy_hash: typeof question["policy_hash"] === "string" ? question["policy_hash"] : "",
283
+ live_rate: typeof question["live_rate"] === "number" ? question["live_rate"] : Number.NaN,
284
+ };
285
+ if (!sameQuestion(derived, asked)) {
286
+ return {
287
+ ok: false,
288
+ reason: "draw-answer-invalid",
289
+ detail: "the daemon answered a different question than the one asked; it resolved this action against a policy or a rate this process did not",
290
+ };
291
+ }
292
+ if (typeof body["selected"] !== "boolean") {
293
+ return { ok: false, reason: "draw-answer-invalid", detail: "the verdict was not a boolean" };
294
+ }
295
+ if (!isHex64(body["mac"])) {
296
+ return { ok: false, reason: "draw-answer-invalid", detail: "the answer carried no usable MAC" };
297
+ }
298
+ const pid = body["daemon_pid"];
299
+ if (typeof pid !== "number" || !Number.isInteger(pid) || pid <= 0) {
300
+ return { ok: false, reason: "draw-answer-invalid", detail: "the answer named no daemon pid" };
301
+ }
302
+ return {
303
+ ok: true,
304
+ answer: {
305
+ v: DRAW_PROTOCOL_VERSION,
306
+ question: derived,
307
+ selected: body["selected"],
308
+ mac: body["mac"],
309
+ daemon_pid: pid,
310
+ answered_at: typeof body["answered_at"] === "string" ? body["answered_at"] : "",
311
+ },
312
+ };
313
+ }
314
+ /** Where the relay child lives, beside this module in the built tree. */
315
+ export function drawChildPath() {
316
+ return fileURLToPath(new URL("../daemon/draw-child.js", import.meta.url));
317
+ }
318
+ /**
319
+ * What an asker concludes about the socket file, before anything is dialled.
320
+ *
321
+ * Exported since APRV-281 for a second, non-asking caller: the hook prints a
322
+ * line saying where a request went and whether anything is there to consume it,
323
+ * and "anything is there" is exactly this question. Nothing is connected here,
324
+ * so a `{ ok: true }` says the file looks like this user's live daemon rather
325
+ * than that the far side answers; a caller that needs the stronger claim asks a
326
+ * question through {@link askDaemonDraw}.
327
+ *
328
+ * One predicate rather than a copy per caller, for the reason `liveClassesOf`
329
+ * is shared: two readers of the same file that reach different conclusions
330
+ * about whether a daemon is up would each be right in its own words and
331
+ * useless together.
332
+ */
333
+ export function drawSocketUsable(path) {
334
+ if (path.length > DRAW_SOCKET_PATH_LIMIT) {
335
+ return {
336
+ ok: false,
337
+ reason: "draw-daemon-absent",
338
+ detail: `the derived socket path is ${String(path.length)} bytes, past the ${String(DRAW_SOCKET_PATH_LIMIT)}-byte limit a Unix socket can carry; no daemon can serve draws for this log`,
339
+ };
340
+ }
341
+ if (!existsSync(path)) {
342
+ return {
343
+ ok: false,
344
+ reason: "draw-daemon-absent",
345
+ detail: `no draw socket at ${path}; supervised-live needs \`approval daemon run\` (or \`approval up\`) started in a terminal where the sampling secret resolves`,
346
+ };
347
+ }
348
+ let stats;
349
+ try {
350
+ stats = statSync(path);
351
+ }
352
+ catch (cause) {
353
+ return {
354
+ ok: false,
355
+ reason: "draw-daemon-stale",
356
+ detail: `${path} could not be stat'd: ${cause instanceof Error ? cause.message : String(cause)}`,
357
+ };
358
+ }
359
+ if (!stats.isSocket()) {
360
+ return { ok: false, reason: "draw-daemon-stale", detail: `${path} is not a socket` };
361
+ }
362
+ const euid = typeof process.geteuid === "function" ? process.geteuid() : null;
363
+ if (euid === null) {
364
+ return {
365
+ ok: false,
366
+ reason: "draw-daemon-stale",
367
+ detail: "socket ownership cannot be established on this platform, so no answer from it can be attributed to this user's daemon",
368
+ };
369
+ }
370
+ if (stats.uid !== euid) {
371
+ return {
372
+ ok: false,
373
+ reason: "draw-daemon-stale",
374
+ detail: `${path} is owned by uid ${String(stats.uid)}, not by this user (${String(euid)})`,
375
+ };
376
+ }
377
+ if ((stats.mode & 0o077) !== 0) {
378
+ return {
379
+ ok: false,
380
+ reason: "draw-daemon-stale",
381
+ detail: `${path} is reachable by group or other (mode ${(stats.mode & 0o777).toString(8)}); an answer from a socket anyone can bind is an answer from nobody in particular`,
382
+ };
383
+ }
384
+ return { ok: true };
385
+ }
386
+ /**
387
+ * Ask the daemon, synchronously, from a process that holds no secret.
388
+ *
389
+ * A child process, and the module header of `daemon/draw-child.ts` says why:
390
+ * the gate's request path is synchronous end to end (APRV-188 measured and
391
+ * documented the same constraint), `node:net` is not, and there is no
392
+ * synchronous Unix-socket client in Node. So one `spawnSync` of a tiny relay,
393
+ * about 20-40 ms of Node start. That cost is affordable HERE and nowhere else:
394
+ * this runs only for a `supervised-live` class whose deciding process has no
395
+ * secret, which is off the pass-through path entirely — no `Read`, no ordinary
396
+ * `Edit`, no autonomous class ever reaches it.
397
+ *
398
+ * The child is given a deliberately bare environment. It needs `PATH` for
399
+ * nothing and holds no secret; passing the session's environment to it would
400
+ * hand a relay every credential the session was launched with, which is the
401
+ * scrub `core/child-env.ts` exists to prevent.
402
+ */
403
+ export function askDaemonDraw(logPath, question) {
404
+ const path = drawSocketPathFor(logPath);
405
+ const usable = drawSocketUsable(path);
406
+ if (!usable.ok)
407
+ return usable;
408
+ const child = spawnSync(process.execPath, [drawChildPath(), path], {
409
+ input: `${JSON.stringify(question)}\n`,
410
+ encoding: "utf8",
411
+ timeout: DRAW_SPAWN_TIMEOUT_MS,
412
+ env: {},
413
+ });
414
+ if (child.error !== undefined && child.error !== null) {
415
+ return {
416
+ ok: false,
417
+ reason: "draw-daemon-stale",
418
+ detail: `the draw relay could not be run: ${child.error.message}`,
419
+ };
420
+ }
421
+ const line = (child.stdout ?? "").trim();
422
+ if (line.length === 0) {
423
+ return {
424
+ ok: false,
425
+ reason: "draw-daemon-stale",
426
+ detail: `the draw relay said nothing (exit ${String(child.status)})`,
427
+ };
428
+ }
429
+ let relayed;
430
+ try {
431
+ relayed = JSON.parse(line);
432
+ }
433
+ catch {
434
+ return { ok: false, reason: "draw-answer-invalid", detail: "the relay did not emit JSON" };
435
+ }
436
+ const body = relayed;
437
+ if (body["ok"] !== true) {
438
+ const reason = body["reason"];
439
+ return {
440
+ ok: false,
441
+ reason: DRAW_REFUSAL_REASONS.includes(reason)
442
+ ? reason
443
+ : "draw-daemon-stale",
444
+ detail: typeof body["detail"] === "string" ? body["detail"] : "the relay refused without a reason",
445
+ };
446
+ }
447
+ const outcome = parseDrawAnswer(JSON.stringify(body["answer"]), question);
448
+ if (!outcome.ok)
449
+ return outcome;
450
+ // A pid that is gone means the socket outlived its server: something answered
451
+ // from a file nobody is listening on, which cannot happen, or the daemon died
452
+ // between answering and now, which can. Either way the answer is not one a
453
+ // running daemon stands behind.
454
+ try {
455
+ process.kill(outcome.answer.daemon_pid, 0);
456
+ }
457
+ catch (cause) {
458
+ if (cause.code === "ESRCH") {
459
+ return {
460
+ ok: false,
461
+ reason: "draw-daemon-stale",
462
+ detail: `the answering daemon (pid ${String(outcome.answer.daemon_pid)}) is no longer running`,
463
+ };
464
+ }
465
+ // EPERM means it exists and belongs to someone else, which the socket
466
+ // ownership check above has already ruled out for the socket itself.
467
+ }
468
+ return outcome;
469
+ }
470
+ // ---------------------------------------------------------------------------
471
+ // The status question (APRV-271)
472
+ // ---------------------------------------------------------------------------
473
+ /**
474
+ * The second thing this socket answers: not "would these bytes be sampled" but
475
+ * "is your sampler running at all" (APRV-271).
476
+ *
477
+ * ## Why the socket, and not the asker's own environment
478
+ *
479
+ * `approval doctor`'s `audit-sampling` row read `APPROVAL_SAMPLING_SECRET` out
480
+ * of the shell doctor was launched in, and reported `secret-unset` whenever it
481
+ * was not there. It is never there: the secret lives in the ONE terminal the
482
+ * operator ran `eval "$(approval env)"` in and started the daemon from, and
483
+ * `core/child-env.ts` strips `APPROVAL_*` from every child. So the row was red
484
+ * on machines where sampling was running perfectly, which is the same shape of
485
+ * bug APRV-208 fixed for the draw itself, in the row next door.
486
+ *
487
+ * The process that legitimately knows is the daemon. This asks it.
488
+ *
489
+ * ## What it deliberately is not
490
+ *
491
+ * **Not MAC'd, and not believed the way a draw is.** A draw answer decides a
492
+ * verdict, so it is evidenced: recorded with a MAC an operator recomputes later
493
+ * (see {@link LiveDrawRecord}). This one decides nothing. It authorizes no
494
+ * action, spends no budget, gates nothing and is written to no log; it changes
495
+ * the wording and the colour of one diagnostic row. What bounds who may make
496
+ * the claim is the socket itself, which {@link askDaemonSampling} requires to
497
+ * be owner-only and owned by this euid before it will dial it.
498
+ *
499
+ * That bound is why the caller must keep the question narrow. The only sampler
500
+ * state another process may honestly answer for is `secret-unset`, which is a
501
+ * fact about a PROCESS ENVIRONMENT. Every other disabled reason (`rate-absent`,
502
+ * `rate-invalid`, `rate-zero`, `secret-env-unnamed`, `policy-unreadable`) is a
503
+ * fact about the policy FILE, which the asker is reading for itself and no
504
+ * daemon's answer may soften. `cli/doctor.ts` consults this on that one branch
505
+ * and nowhere else.
506
+ *
507
+ * **Never the secret.** The report carries the variable's NAME, which the
508
+ * policy file already states in the open, and the rate, which it also states.
509
+ * The value is in one field of one process and leaves it in nothing but a MAC.
510
+ */
511
+ export const SAMPLING_QUERY = "sampling";
512
+ /** Is this line a status question rather than a draw? Used by the server. */
513
+ export function isSamplingQuery(line) {
514
+ let parsed;
515
+ try {
516
+ parsed = JSON.parse(line);
517
+ }
518
+ catch {
519
+ return false;
520
+ }
521
+ if (typeof parsed !== "object" || parsed === null)
522
+ return false;
523
+ const body = parsed;
524
+ return body["v"] === DRAW_PROTOCOL_VERSION && body["query"] === SAMPLING_QUERY;
525
+ }
526
+ /**
527
+ * Read one status answer.
528
+ *
529
+ * Every field is taken apart and rebuilt rather than passed through, so an
530
+ * answer carrying keys this protocol never defined loses them here: a report
531
+ * printed by a diagnostic must not be able to carry text of the answerer's
532
+ * choosing into an operator's terminal.
533
+ */
534
+ export function parseSamplingAnswer(text) {
535
+ let parsed;
536
+ try {
537
+ parsed = JSON.parse(text);
538
+ }
539
+ catch {
540
+ return { ok: false, reason: "draw-answer-invalid", detail: "the answer was not JSON" };
541
+ }
542
+ if (typeof parsed !== "object" || parsed === null) {
543
+ return { ok: false, reason: "draw-answer-invalid", detail: "the answer was not an object" };
544
+ }
545
+ const body = parsed;
546
+ if (body["ok"] === false) {
547
+ // An older daemon, or one that read this line as a malformed draw. It said
548
+ // no, which is the safe direction: the caller reports no daemon answered.
549
+ return {
550
+ ok: false,
551
+ reason: "draw-answer-invalid",
552
+ detail: typeof body["detail"] === "string"
553
+ ? body["detail"]
554
+ : "the daemon refused the status question",
555
+ };
556
+ }
557
+ if (body["v"] !== DRAW_PROTOCOL_VERSION) {
558
+ return {
559
+ ok: false,
560
+ reason: "draw-answer-invalid",
561
+ detail: `the answer declares protocol version ${JSON.stringify(body["v"])}, not ${String(DRAW_PROTOCOL_VERSION)}`,
562
+ };
563
+ }
564
+ const reported = body["sampling"];
565
+ if (typeof reported !== "object" || reported === null) {
566
+ return { ok: false, reason: "draw-answer-invalid", detail: "the answer carried no sampling report" };
567
+ }
568
+ const report = reported;
569
+ if (typeof report["enabled"] !== "boolean") {
570
+ return { ok: false, reason: "draw-answer-invalid", detail: "the report did not say whether sampling is enabled" };
571
+ }
572
+ const pid = body["daemon_pid"];
573
+ if (typeof pid !== "number" || !Number.isInteger(pid) || pid <= 0) {
574
+ return { ok: false, reason: "draw-answer-invalid", detail: "the answer named no daemon pid" };
575
+ }
576
+ const classes = report["live_classes"];
577
+ return {
578
+ ok: true,
579
+ answer: {
580
+ v: DRAW_PROTOCOL_VERSION,
581
+ sampling: {
582
+ enabled: report["enabled"],
583
+ reason: typeof report["reason"] === "string" ? report["reason"] : null,
584
+ secret_env: typeof report["secret_env"] === "string" ? report["secret_env"] : null,
585
+ rate: typeof report["rate"] === "number" && Number.isFinite(report["rate"]) ? report["rate"] : null,
586
+ live_classes: Array.isArray(classes)
587
+ ? classes.filter((entry) => typeof entry === "string")
588
+ : [],
589
+ },
590
+ daemon_pid: pid,
591
+ answered_at: typeof body["answered_at"] === "string" ? body["answered_at"] : "",
592
+ },
593
+ };
594
+ }
595
+ /**
596
+ * Open the draw socket, optionally exchange one line, and hang up.
597
+ *
598
+ * ASYNCHRONOUS, unlike {@link askDaemonDraw}, and that difference is the whole
599
+ * reason it can exist without a relay child. The draw is asked from the gate's
600
+ * synchronous request path, which is why it pays for a `spawnSync`; every
601
+ * caller of this one is a diagnostic that is already inside an async function,
602
+ * so it dials the socket directly and costs no process at all.
603
+ *
604
+ * `request` of `null` connects and closes without saying anything, which is how
605
+ * a caller asks the only question a socket file cannot answer by existing:
606
+ * whether anything is listening on it.
607
+ */
608
+ export async function dialDrawSocket(path, request, timeoutMs = DRAW_TIMEOUT_MS) {
609
+ return await new Promise((settleWith) => {
610
+ let settled = false;
611
+ let buffer = "";
612
+ const socket = connect(path);
613
+ const settle = (outcome) => {
614
+ if (settled)
615
+ return;
616
+ settled = true;
617
+ socket.destroy();
618
+ settleWith(outcome);
619
+ };
620
+ socket.setEncoding("utf8");
621
+ socket.setTimeout(timeoutMs);
622
+ socket.on("connect", () => {
623
+ if (request === null) {
624
+ settle({ ok: true, line: null });
625
+ return;
626
+ }
627
+ socket.write(`${request}\n`);
628
+ });
629
+ socket.on("data", (chunk) => {
630
+ buffer += chunk;
631
+ const newline = buffer.indexOf("\n");
632
+ if (newline < 0) {
633
+ if (buffer.length > 8192) {
634
+ settle({ ok: false, reason: "draw-answer-invalid", detail: "the answer had no line ending" });
635
+ }
636
+ return;
637
+ }
638
+ settle({ ok: true, line: buffer.slice(0, newline) });
639
+ });
640
+ socket.on("timeout", () => {
641
+ settle({
642
+ ok: false,
643
+ reason: "draw-daemon-stale",
644
+ detail: `nothing answered within ${String(timeoutMs)}ms; the socket is there and the daemon behind it is not serving`,
645
+ });
646
+ });
647
+ socket.on("error", (cause) => {
648
+ settle({
649
+ ok: false,
650
+ reason: "draw-daemon-stale",
651
+ detail: `the socket refused the connection: ${cause.message}`,
652
+ });
653
+ });
654
+ socket.on("close", () => {
655
+ settle({
656
+ ok: false,
657
+ reason: "draw-daemon-stale",
658
+ detail: "the daemon closed the connection without answering",
659
+ });
660
+ });
661
+ });
662
+ }
663
+ /**
664
+ * Ask the running daemon what its own sampler is doing.
665
+ *
666
+ * The same pre-checks a draw makes, for the same reasons: a path past the
667
+ * address limit, an absent file, a foreign owner and a group- or world-writable
668
+ * mode each mean no answer from here can be attributed to this user's daemon.
669
+ * The pid is checked for liveness afterwards, because a socket that outlived
670
+ * its server is a file answering for a process that is gone.
671
+ */
672
+ export async function askDaemonSampling(logPath, timeoutMs = DRAW_TIMEOUT_MS) {
673
+ const socket = drawSocketPathFor(logPath);
674
+ const usable = drawSocketUsable(socket);
675
+ if (!usable.ok)
676
+ return { ok: false, reason: usable.reason, detail: usable.detail, socket };
677
+ const dialled = await dialDrawSocket(socket, JSON.stringify({ v: DRAW_PROTOCOL_VERSION, query: SAMPLING_QUERY }), timeoutMs);
678
+ if (!dialled.ok)
679
+ return { ok: false, reason: dialled.reason, detail: dialled.detail, socket };
680
+ if (dialled.line === null) {
681
+ return { ok: false, reason: "draw-answer-invalid", detail: "the daemon said nothing", socket };
682
+ }
683
+ const parsed = parseSamplingAnswer(dialled.line);
684
+ if (!parsed.ok)
685
+ return { ok: false, reason: parsed.reason, detail: parsed.detail, socket };
686
+ try {
687
+ process.kill(parsed.answer.daemon_pid, 0);
688
+ }
689
+ catch (cause) {
690
+ if (cause.code === "ESRCH") {
691
+ return {
692
+ ok: false,
693
+ reason: "draw-daemon-stale",
694
+ detail: `the answering daemon (pid ${String(parsed.answer.daemon_pid)}) is no longer running`,
695
+ socket,
696
+ };
697
+ }
698
+ // EPERM means it exists and belongs to someone else, which the socket's
699
+ // own ownership check has already ruled out.
700
+ }
701
+ return { ok: true, answer: parsed.answer, socket };
702
+ }
703
+ //# sourceMappingURL=live-draw.js.map