approval-md 0.1.0 → 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 (266) hide show
  1. package/README.md +584 -553
  2. package/SPEC.md +42 -13
  3. package/dist/src/adapters/agentmail.d.ts +426 -0
  4. package/dist/src/adapters/agentmail.js +2 -2
  5. package/dist/src/adapters/conformance.d.ts +149 -0
  6. package/dist/src/adapters/contract.d.ts +628 -0
  7. package/dist/src/adapters/contract.js +110 -16
  8. package/dist/src/adapters/contract.js.map +1 -1
  9. package/dist/src/adapters/email.d.ts +324 -0
  10. package/dist/src/adapters/env-passphrase.d.ts +93 -0
  11. package/dist/src/adapters/public.d.ts +11 -0
  12. package/dist/src/adapters/public.js +11 -0
  13. package/dist/src/adapters/public.js.map +1 -0
  14. package/dist/src/adapters/registry.d.ts +59 -0
  15. package/dist/src/adapters/registry.js +2 -1
  16. package/dist/src/adapters/registry.js.map +1 -1
  17. package/dist/src/adapters/smtp.d.ts +213 -0
  18. package/dist/src/adapters/vault-provider.d.ts +114 -0
  19. package/dist/src/adapters/vault-provider.js +3 -3
  20. package/dist/src/adapters/zzz.d.ts +66 -0
  21. package/dist/src/adapters/zzz.js +299 -0
  22. package/dist/src/adapters/zzz.js.map +1 -0
  23. package/dist/src/channels/batch.d.ts +109 -0
  24. package/dist/src/channels/cli.d.ts +193 -0
  25. package/dist/src/channels/conformance.d.ts +92 -0
  26. package/dist/src/channels/contract.d.ts +623 -0
  27. package/dist/src/channels/payload-view.d.ts +35 -0
  28. package/dist/src/channels/render-queue.d.ts +149 -0
  29. package/dist/src/channels/tagging.d.ts +196 -0
  30. package/dist/src/channels/telegram.d.ts +1832 -0
  31. package/dist/src/channels/web.d.ts +341 -0
  32. package/dist/src/cli/adapter.d.ts +90 -0
  33. package/dist/src/cli/adapter.js +25 -15
  34. package/dist/src/cli/adapter.js.map +1 -1
  35. package/dist/src/cli/amend.d.ts +59 -0
  36. package/dist/src/cli/args.d.ts +43 -0
  37. package/dist/src/cli/attest.d.ts +41 -0
  38. package/dist/src/cli/audit-card.d.ts +62 -0
  39. package/dist/src/cli/audit.d.ts +59 -0
  40. package/dist/src/cli/channel-telegram.d.ts +806 -0
  41. package/dist/src/cli/channel-web.d.ts +131 -0
  42. package/dist/src/cli/channel.d.ts +71 -0
  43. package/dist/src/cli/checkpoint-tap.d.ts +169 -0
  44. package/dist/src/cli/codex.d.ts +2 -0
  45. package/dist/src/cli/codex.js +172 -0
  46. package/dist/src/cli/codex.js.map +1 -0
  47. package/dist/src/cli/coverage.d.ts +61 -0
  48. package/dist/src/cli/daemon.d.ts +120 -0
  49. package/dist/src/cli/doctor.d.ts +129 -0
  50. package/dist/src/cli/doctor.js +119 -5
  51. package/dist/src/cli/doctor.js.map +1 -1
  52. package/dist/src/cli/env.d.ts +65 -0
  53. package/dist/src/cli/execute.d.ts +202 -0
  54. package/dist/src/cli/exit-codes.d.ts +73 -0
  55. package/dist/src/cli/feedback.d.ts +60 -0
  56. package/dist/src/cli/gate-window.d.ts +40 -0
  57. package/dist/src/cli/gate.d.ts +68 -0
  58. package/dist/src/cli/git-scope.d.ts +190 -0
  59. package/dist/src/cli/gloss-attach.d.ts +85 -0
  60. package/dist/src/cli/gloss-codex-child.d.ts +9 -0
  61. package/dist/src/cli/gloss-codex.d.ts +24 -0
  62. package/dist/src/cli/gloss-options.d.ts +42 -0
  63. package/dist/src/cli/gloss.d.ts +265 -0
  64. package/dist/src/cli/help.d.ts +103 -0
  65. package/dist/src/cli/help.js +173 -51
  66. package/dist/src/cli/help.js.map +1 -1
  67. package/dist/src/cli/hook-codex.d.ts +78 -0
  68. package/dist/src/cli/hook-codex.js +167 -0
  69. package/dist/src/cli/hook-codex.js.map +1 -0
  70. package/dist/src/cli/hook.d.ts +331 -0
  71. package/dist/src/cli/hook.js +186 -80
  72. package/dist/src/cli/hook.js.map +1 -1
  73. package/dist/src/cli/import.d.ts +35 -0
  74. package/dist/src/cli/init.d.ts +84 -0
  75. package/dist/src/cli/init.js +2 -2
  76. package/dist/src/cli/init.js.map +1 -1
  77. package/dist/src/cli/instructions.d.ts +23 -0
  78. package/dist/src/cli/journal.d.ts +41 -0
  79. package/dist/src/cli/log-advance.d.ts +287 -0
  80. package/dist/src/cli/log-advance.js +102 -11
  81. package/dist/src/cli/log-advance.js.map +1 -1
  82. package/dist/src/cli/log-anchor.d.ts +176 -0
  83. package/dist/src/cli/log-checkpoint.d.ts +22 -0
  84. package/dist/src/cli/log-sync.d.ts +243 -0
  85. package/dist/src/cli/log-verbs.d.ts +16 -0
  86. package/dist/src/cli/log-verbs.js +7 -1
  87. package/dist/src/cli/log-verbs.js.map +1 -1
  88. package/dist/src/cli/long-help.d.ts +70 -0
  89. package/dist/src/cli/main.d.ts +77 -0
  90. package/dist/src/cli/main.js +155 -5
  91. package/dist/src/cli/main.js.map +1 -1
  92. package/dist/src/cli/mcp.d.ts +52 -0
  93. package/dist/src/cli/paths.d.ts +56 -0
  94. package/dist/src/cli/payload.d.ts +58 -0
  95. package/dist/src/cli/policy.d.ts +43 -0
  96. package/dist/src/cli/preflight.d.ts +363 -0
  97. package/dist/src/cli/preflight.js +294 -7
  98. package/dist/src/cli/preflight.js.map +1 -1
  99. package/dist/src/cli/progress.d.ts +78 -0
  100. package/dist/src/cli/prompt.d.ts +209 -0
  101. package/dist/src/cli/quickstart.d.ts +46 -0
  102. package/dist/src/cli/quickstart.js +297 -0
  103. package/dist/src/cli/quickstart.js.map +1 -0
  104. package/dist/src/cli/records.d.ts +34 -0
  105. package/dist/src/cli/render.d.ts +22 -0
  106. package/dist/src/cli/sandbox.d.ts +51 -0
  107. package/dist/src/cli/scaffold.d.ts +79 -0
  108. package/dist/src/cli/setup-adapter.d.ts +137 -0
  109. package/dist/src/cli/setup-adapter.js +38 -4
  110. package/dist/src/cli/setup-adapter.js.map +1 -1
  111. package/dist/src/cli/setup-channel.d.ts +117 -0
  112. package/dist/src/cli/setup-checkpoint.d.ts +57 -0
  113. package/dist/src/cli/setup-common.d.ts +275 -0
  114. package/dist/src/cli/setup-flow.d.ts +287 -0
  115. package/dist/src/cli/setup-service.d.ts +96 -0
  116. package/dist/src/cli/setup.d.ts +202 -0
  117. package/dist/src/cli/style.d.ts +320 -0
  118. package/dist/src/cli/token.d.ts +39 -0
  119. package/dist/src/cli/up.d.ts +155 -0
  120. package/dist/src/cli/up.js +4 -2
  121. package/dist/src/cli/up.js.map +1 -1
  122. package/dist/src/cli/usage.d.ts +37 -0
  123. package/dist/src/cli/values.d.ts +40 -0
  124. package/dist/src/cli/vault.d.ts +59 -0
  125. package/dist/src/cli/vault.js +2 -2
  126. package/dist/src/cli/vault.js.map +1 -1
  127. package/dist/src/cli/verb-registry.d.ts +76 -0
  128. package/dist/src/cli/verb-registry.js +176 -8
  129. package/dist/src/cli/verb-registry.js.map +1 -1
  130. package/dist/src/cli/wordmark.d.ts +31 -0
  131. package/dist/src/cli/wordmark.js +2 -2
  132. package/dist/src/codex/doctor.d.ts +13 -0
  133. package/dist/src/codex/doctor.js +41 -0
  134. package/dist/src/codex/doctor.js.map +1 -0
  135. package/dist/src/codex/manifest.d.ts +49 -0
  136. package/dist/src/codex/manifest.js +103 -0
  137. package/dist/src/codex/manifest.js.map +1 -0
  138. package/dist/src/codex/templates.d.ts +41 -0
  139. package/dist/src/codex/templates.js +319 -0
  140. package/dist/src/codex/templates.js.map +1 -0
  141. package/dist/src/codex/trust.d.ts +19 -0
  142. package/dist/src/codex/trust.js +183 -0
  143. package/dist/src/codex/trust.js.map +1 -0
  144. package/dist/src/codex/workspace-plan.d.ts +131 -0
  145. package/dist/src/codex/workspace-plan.js +561 -0
  146. package/dist/src/codex/workspace-plan.js.map +1 -0
  147. package/dist/src/core/actor.d.ts +2 -0
  148. package/dist/src/core/actor.js +5 -0
  149. package/dist/src/core/actor.js.map +1 -0
  150. package/dist/src/core/advance-cycle.d.ts +170 -0
  151. package/dist/src/core/agents-md.d.ts +276 -0
  152. package/dist/src/core/apply-patch.d.ts +49 -0
  153. package/dist/src/core/apply-patch.js +266 -0
  154. package/dist/src/core/apply-patch.js.map +1 -0
  155. package/dist/src/core/attest.d.ts +420 -0
  156. package/dist/src/core/attest.js +13 -1
  157. package/dist/src/core/attest.js.map +1 -1
  158. package/dist/src/core/audit.d.ts +492 -0
  159. package/dist/src/core/budgets.d.ts +238 -0
  160. package/dist/src/core/checkpoint.d.ts +500 -0
  161. package/dist/src/core/child-env.d.ts +88 -0
  162. package/dist/src/core/clock.d.ts +52 -0
  163. package/dist/src/core/command-class.d.ts +543 -0
  164. package/dist/src/core/command-class.js +43 -8
  165. package/dist/src/core/command-class.js.map +1 -1
  166. package/dist/src/core/coverage-sources/adapter.d.ts +40 -0
  167. package/dist/src/core/coverage-sources/gh.d.ts +48 -0
  168. package/dist/src/core/coverage-sources/git.d.ts +101 -0
  169. package/dist/src/core/coverage.d.ts +217 -0
  170. package/dist/src/core/credential-spec.d.ts +72 -0
  171. package/dist/src/core/dark-session.d.ts +331 -0
  172. package/dist/src/core/decision-refusal.d.ts +185 -0
  173. package/dist/src/core/env-file.d.ts +450 -0
  174. package/dist/src/core/execute.d.ts +858 -0
  175. package/dist/src/core/execute.js +44 -6
  176. package/dist/src/core/execute.js.map +1 -1
  177. package/dist/src/core/frontmatter.d.ts +78 -0
  178. package/dist/src/core/gate-window.d.ts +312 -0
  179. package/dist/src/core/gate.d.ts +1364 -0
  180. package/dist/src/core/gate.js +68 -13
  181. package/dist/src/core/gate.js.map +1 -1
  182. package/dist/src/core/git-run.d.ts +73 -0
  183. package/dist/src/core/harness-version.d.ts +157 -0
  184. package/dist/src/core/harness-version.js +2 -1
  185. package/dist/src/core/harness-version.js.map +1 -1
  186. package/dist/src/core/harness-wait.d.ts +55 -0
  187. package/dist/src/core/head-retry.d.ts +107 -0
  188. package/dist/src/core/instance.d.ts +253 -0
  189. package/dist/src/core/intake-limits.d.ts +247 -0
  190. package/dist/src/core/jcs.d.ts +52 -0
  191. package/dist/src/core/journal.d.ts +144 -0
  192. package/dist/src/core/live-draw.d.ts +436 -0
  193. package/dist/src/core/log-reconcile.d.ts +89 -0
  194. package/dist/src/core/log-subscribe.d.ts +36 -0
  195. package/dist/src/core/log-subscribe.js +162 -0
  196. package/dist/src/core/log-subscribe.js.map +1 -0
  197. package/dist/src/core/log.d.ts +278 -0
  198. package/dist/src/core/loop.d.ts +274 -0
  199. package/dist/src/core/loop.js +11 -0
  200. package/dist/src/core/loop.js.map +1 -1
  201. package/dist/src/core/md-fence.d.ts +41 -0
  202. package/dist/src/core/money.d.ts +147 -0
  203. package/dist/src/core/payload-census.d.ts +74 -0
  204. package/dist/src/core/payload-store.d.ts +175 -0
  205. package/dist/src/core/payload.d.ts +71 -0
  206. package/dist/src/core/policy-diff.d.ts +292 -0
  207. package/dist/src/core/policy-diff.js +27 -4
  208. package/dist/src/core/policy-diff.js.map +1 -1
  209. package/dist/src/core/policy-expectations.d.ts +199 -0
  210. package/dist/src/core/policy-explain.d.ts +150 -0
  211. package/dist/src/core/policy-explain.js +31 -3
  212. package/dist/src/core/policy-explain.js.map +1 -1
  213. package/dist/src/core/policy-load.d.ts +527 -0
  214. package/dist/src/core/policy-load.js +15 -3
  215. package/dist/src/core/policy-load.js.map +1 -1
  216. package/dist/src/core/policy-match.d.ts +281 -0
  217. package/dist/src/core/policy-match.js +20 -9
  218. package/dist/src/core/policy-match.js.map +1 -1
  219. package/dist/src/core/policy-proposal.d.ts +265 -0
  220. package/dist/src/core/prompt-layout.d.ts +221 -0
  221. package/dist/src/core/protected-path-guard.d.ts +453 -0
  222. package/dist/src/core/protected-path-guard.js +514 -35
  223. package/dist/src/core/protected-path-guard.js.map +1 -1
  224. package/dist/src/core/registration.d.ts +25 -0
  225. package/dist/src/core/reindex.d.ts +99 -0
  226. package/dist/src/core/sampler.d.ts +313 -0
  227. package/dist/src/core/sandbox.d.ts +290 -0
  228. package/dist/src/core/seal.d.ts +165 -0
  229. package/dist/src/core/state.d.ts +505 -0
  230. package/dist/src/core/task-file.d.ts +185 -0
  231. package/dist/src/core/telegram-config.d.ts +93 -0
  232. package/dist/src/core/token.d.ts +409 -0
  233. package/dist/src/core/token.js +21 -38
  234. package/dist/src/core/token.js.map +1 -1
  235. package/dist/src/core/validate.d.ts +138 -0
  236. package/dist/src/core/values.d.ts +137 -0
  237. package/dist/src/core/vault.d.ts +291 -0
  238. package/dist/src/core/verified-snapshot.d.ts +204 -0
  239. package/dist/src/core/verify.d.ts +336 -0
  240. package/dist/src/core/version.d.ts +8 -0
  241. package/dist/src/core/wysiwys.d.ts +370 -0
  242. package/dist/src/daemon/advance-child.d.ts +39 -0
  243. package/dist/src/daemon/advance.d.ts +466 -0
  244. package/dist/src/daemon/audit.d.ts +87 -0
  245. package/dist/src/daemon/daemon.d.ts +1180 -0
  246. package/dist/src/daemon/dark-session.d.ts +64 -0
  247. package/dist/src/daemon/draw-child.d.ts +36 -0
  248. package/dist/src/daemon/draw.d.ts +154 -0
  249. package/dist/src/daemon/git-evidence.d.ts +173 -0
  250. package/dist/src/daemon/git-evidence.js +1 -1
  251. package/dist/src/daemon/projection.d.ts +180 -0
  252. package/dist/src/daemon/prune.d.ts +207 -0
  253. package/dist/src/mcp/http.d.ts +113 -0
  254. package/dist/src/mcp/server.d.ts +265 -0
  255. package/dist/src/mcp/server.js +9 -1
  256. package/dist/src/mcp/server.js.map +1 -1
  257. package/docs/adapter-api.md +106 -0
  258. package/docs/cli-reference.md +389 -36
  259. package/docs/codex-enforced-session.md +30 -0
  260. package/package.json +12 -2
  261. package/schema/codex-instance.schema.json +82 -0
  262. package/schema/event.schema.json +2 -1
  263. package/schema/fixtures/codex-instance/invalid/unpinned-codex-version.json +40 -0
  264. package/schema/fixtures/codex-instance/valid/canonical.json +40 -0
  265. package/schema/policy.schema.json +21 -1
  266. package/templates/codex/README.md +9 -0
@@ -0,0 +1,185 @@
1
+ /**
2
+ * What the log says when a human decided and the gate could not take it
3
+ * (APRV-235, amended SPEC.md §5.2).
4
+ *
5
+ * ## The fact this module is about
6
+ *
7
+ * Seen live on 2026-09-02, after the seq 13704 ceremony. Carter tapped approve
8
+ * on a request that had been asked under the previous policy. The gate refused
9
+ * `policy-drift`, which is right: the rules the approver was shown are not the
10
+ * rules in force, so a grant recorded there would claim a decision under a
11
+ * policy nobody put in front of them. But the refusal went to the operator's
12
+ * terminal and nowhere else. Nothing was appended, the request stayed pending
13
+ * in `QUEUE.md` and on Telegram, and the person who had tapped saw no reaction
14
+ * at all.
15
+ *
16
+ * Three things were wrong and this module fixes two of them (the third, the
17
+ * message edit, belongs to the channels).
18
+ *
19
+ * ## 1. A human's decision is a fact even when the gate cannot honour it
20
+ *
21
+ * The log is the truth. SPEC.md §11 makes human attention the audit budget, and
22
+ * an approver's tap SPENDS it whether or not an authorization comes out the
23
+ * other end. A reader looking at that log later found a request sitting
24
+ * unanswered with nothing to say a person had answered it, which is a question
25
+ * the log is supposed to be able to settle.
26
+ *
27
+ * So {@link recordRefusedDecision} appends one `audit.decision_refused`. It is
28
+ * an **audit-tier** record in the strict sense:
29
+ *
30
+ * - it grants nothing and mints no token;
31
+ * - `core/state.ts` does not settle a request on it, so no verdict moves;
32
+ * - `core/budgets.ts` charges nothing for it, so no budget moves;
33
+ * - `core/audit.ts` does not sample it and no streak counts it.
34
+ *
35
+ * `tests/decision-refusal.test.ts` asserts that last group by construction: the
36
+ * derived request state, the budget verdicts and the sampling draw are taken
37
+ * before and after and compared, and they are identical.
38
+ *
39
+ * ## The asymmetry: humans yes, agents no
40
+ *
41
+ * Gate-side refusals handed to an AGENT stay unlogged, and that is a choice
42
+ * rather than an omission. An agent that is refused reads the code, stops or
43
+ * asks again, and nothing was spent that a record could account for. A human
44
+ * who is refused has already spent the scarce thing, and cannot be asked to
45
+ * spend it again without the log saying the first spend happened. Recording
46
+ * every agent-side refusal would also put the busiest path in the runtime — a
47
+ * hook classifying every shell command — into the append path, which is a cost
48
+ * with no reader.
49
+ *
50
+ * ## 2. A request the gate calls void must stop being offered
51
+ *
52
+ * `policy-drift` is the one refusal where the gate does not merely decline this
53
+ * decision, it declares the REQUEST dead: "the pending request is void and the
54
+ * action must be requested again". Leaving it pending afterwards offers every
55
+ * approver on every channel a tap that cannot be honoured, forever, until the
56
+ * TTL lapses. So a drift refusal also appends `approval.withdrawn` with the
57
+ * runtime's own reason, `policy-drift` (APRV-106 gave the event; the schema's
58
+ * cross-rule makes that reason `system:`-only and `system:` that-reason-only).
59
+ * `approval queue`, `QUEUE.md` and every channel then read the request as
60
+ * settled, because they all derive state from `core/state.ts` and it settles on
61
+ * `approval.withdrawn` without looking at who wrote it or why.
62
+ *
63
+ * The action is not stranded: its caller requests it again, and the new request
64
+ * is routed, budgeted and displayed under the policy actually in force. That is
65
+ * what the refusal message already told them to do.
66
+ *
67
+ * ## Order, and what an interrupted write leaves behind
68
+ *
69
+ * The audit record is appended first and the withdrawal second, naming it in
70
+ * `payload.refused_seq`. Two appends are two records — the log never batches —
71
+ * so a crash between them is a state this code can reach, and the order is
72
+ * chosen for which half is safe to have alone. The explanation without the
73
+ * withdrawal leaves the request pending exactly as it is today, and a reader can
74
+ * see why. The withdrawal without the explanation would take a request out of a
75
+ * human's queue with nothing on the record saying who tapped, or why it was
76
+ * refused, which is the failure this task exists to end.
77
+ *
78
+ * ## Invariants
79
+ *
80
+ * - **Gate-typed events never accept caller timestamps** (§11.1). `ts` comes
81
+ * from the injected clock at the write boundary; there is no parameter.
82
+ * - **Every check-then-append passes through compare-and-append** (§11.1(5)).
83
+ * Both writes state the head they were derived against, and the whole cycle
84
+ * re-enters from a fresh read on `head-moved` through
85
+ * {@link withHeadRetry} — the same bounded retry APRV-236 gave `decide`.
86
+ * - **Self-reported fields never reduce scrutiny** (§11.1). Everything here only
87
+ * ADDS to what a reviewer sees. The approver's identity comes from the
88
+ * decision surface's configured actor, the same source a grant's does, and the
89
+ * record's own actor is `system:` so that neither party to the refusal is its
90
+ * author.
91
+ * - **Refusals stay machine-readable and distinct** (§11.1). The gate's code is
92
+ * copied verbatim; nothing here invents, merges or softens one.
93
+ *
94
+ * ## No attestation check, deliberately
95
+ *
96
+ * Nothing here asks whether the policy is attested, for the reason `reject` and
97
+ * `revoke` do not: this write confers no authority. Refusing to record a refusal
98
+ * because a file changed would be the strict direction pointing the wrong way,
99
+ * and the case where it would bite hardest is `policy-not-attested` itself —
100
+ * exactly the refusal an operator most needs the log to remember. The write
101
+ * boundary still validates every record, so what lands is still constrained.
102
+ */
103
+ import { type AppendError, type EventRecord } from "./log.js";
104
+ import { type Decision } from "./state.js";
105
+ import type { GateOptions } from "./gate.js";
106
+ /**
107
+ * The actor every record here carries. `system:`, and the same id the runtime's
108
+ * other unprompted writes use: this is the gate stating what the gate did.
109
+ */
110
+ export declare const DECISION_REFUSAL_ACTOR = "system:gate";
111
+ /** The runtime's withdrawal reason, closed to requesters by the event schema. */
112
+ export declare const POLICY_DRIFT_REASON = "policy-drift";
113
+ /** Who decided what, on which surface — everything the record needs about the tap. */
114
+ export interface RefusedDecision {
115
+ /** The action whose decision was refused. */
116
+ actionKey: string;
117
+ /** Which of the three human-only verbs was attempted. */
118
+ decision: Decision;
119
+ /** The approver, `human:<id>`, from the surface's configured identity. */
120
+ actor: string;
121
+ /** The surface that collected the gesture: `telegram`, `web`, `cli`. */
122
+ channel: string;
123
+ }
124
+ /** The gate refusal being recorded. Only these fields are ever read. */
125
+ export interface RefusalFacts {
126
+ /** The gate's code, verbatim. */
127
+ code: string;
128
+ /** The gate's message, verbatim. */
129
+ message: string;
130
+ /**
131
+ * The two policy hashes the gate compared, on `policy-drift` alone. Supplied
132
+ * by the refusal that made the comparison rather than re-derived here: a
133
+ * second derivation could disagree with the one that actually refused, and
134
+ * then the record would describe a comparison nobody made.
135
+ */
136
+ drift?: {
137
+ requested: string;
138
+ attested: string;
139
+ };
140
+ }
141
+ /** What the module could not do. Never thrown; the caller carries on regardless. */
142
+ export interface RefusalRecordFailure {
143
+ ok: false;
144
+ code: "log-unreadable" | "append-failed";
145
+ message: string;
146
+ append?: AppendError;
147
+ }
148
+ export type RecordRefusedDecisionResult = {
149
+ ok: true;
150
+ /**
151
+ * The `audit.decision_refused` record, or `null` when the refused actor
152
+ * was not a person and there was therefore nothing to record.
153
+ */
154
+ audit: EventRecord | null;
155
+ /** The `approval.withdrawn` record, on `policy-drift` alone; `null` otherwise. */
156
+ withdrawn: EventRecord | null;
157
+ } | RefusalRecordFailure;
158
+ /** Is this the refusal that declares the request itself void? */
159
+ export declare function voidsTheRequest(code: string): boolean;
160
+ /**
161
+ * Record that a human's decision was refused, and withdraw the request when the
162
+ * refusal was the gate declaring it void.
163
+ *
164
+ * Called by the decision SURFACES — `channels/contract.ts`'s
165
+ * `recordChannelDecision` and `cli/gate.ts`'s `commandDecide` — and never from
166
+ * inside `decide()`. That placement is deliberate twice over. `decide()`'s
167
+ * contract is that a refusal appends nothing, which is what lets a caller retry
168
+ * one without wondering what it wrote; and this record is about a HUMAN having
169
+ * decided, which is a fact only a surface that collected a human's gesture can
170
+ * assert.
171
+ *
172
+ * Best-effort by design: a failure here is returned, never thrown, and the
173
+ * caller shows the gate's refusal either way. The decision was already refused
174
+ * before this ran, and nothing about that outcome depends on this write landing.
175
+ *
176
+ * **Two writes, two retry cycles, and deliberately not one.** `head-retry.ts`
177
+ * asks that the unit of retry be a whole read-check-append cycle, and putting
178
+ * both appends inside one cycle would break that in the direction that matters:
179
+ * a moved head under the SECOND write would re-enter from the top and append a
180
+ * second `audit.decision_refused` for one tap. So each write has its own cycle,
181
+ * each re-reads and re-derives, and the withdrawal's cycle re-checks that the
182
+ * request is still pending — a decision or a withdrawal that landed in the
183
+ * window is the new verdict, and there is then nothing left to withdraw.
184
+ */
185
+ export declare function recordRefusedDecision(logPath: string, decided: RefusedDecision, refusal: RefusalFacts, options?: GateOptions): RecordRefusedDecisionResult;
@@ -0,0 +1,450 @@
1
+ /**
2
+ * `.approval/env` — the environment SOURCE MAP (SPEC.md §5.2, §11; APRV-73).
3
+ *
4
+ * Every secret this runtime touches is named by the policy and held in an
5
+ * environment variable: `channels.telegram.token_env` (§5.1), the chat id
6
+ * beside it, `audit.sampling_secret_env` (§5.2), `vault.passphrase_env` (§5.2),
7
+ * and `APPROVAL_HUMAN`, which is human identity itself (§11). The policy carries
8
+ * NAMES and never values, which is the right boundary and leaves an operator
9
+ * with five variables to get into a shell before any gate operation works, and
10
+ * no written-down place to say where they come from.
11
+ *
12
+ * This module is that written-down place. `.approval/env` is a source map, not
13
+ * a secret store: `KEY=VALUE` lines whose VALUE says WHERE the value lives.
14
+ *
15
+ * ```
16
+ * # one line per variable; # comments and blank lines are ignored
17
+ * APPROVAL_HUMAN=human:alice
18
+ * APPROVAL_TG_TOKEN=keychain:approval-telegram-token
19
+ * APPROVAL_VAULT_PASSPHRASE=secret-service:vault-passphrase
20
+ * APPROVAL_AUDIT_SECRET=env:
21
+ * ```
22
+ *
23
+ * Four value forms, and one of them is deliberately unpleasant:
24
+ *
25
+ * - `keychain:<service>` — macOS, `security find-generic-password -a "$USER"
26
+ * -s <service> -w`. The value comes back on stdout and is never in an argv.
27
+ * - `secret-service:<label>` — Linux desktop, `secret-tool lookup approval
28
+ * <label>`. Same property.
29
+ * - `env:` — inherited from the ambient environment. A documentation form: it
30
+ * asserts "this one comes from the shell that launched you", and resolves to
31
+ * nothing on its own.
32
+ * - a bare literal — permitted, and ALWAYS reported as plaintext. A rule people
33
+ * route around is not a control: an operator who is told plainly that their
34
+ * token is sitting in a file in the working tree can decide to accept that,
35
+ * and an operator who is forbidden from writing it there writes it into their
36
+ * shell profile instead, where nothing in this runtime can see it to say so.
37
+ *
38
+ * A value carrying some OTHER `word:` prefix is a literal, not an error, because
39
+ * `APPROVAL_HUMAN=human:alice` is the commonest line this file will ever hold.
40
+ * Near misses of the real schemes are reserved by name and refused rather than
41
+ * silently exported as text; see {@link RESERVED_SCHEMES}.
42
+ *
43
+ * ## THE LOAD-BEARING RULE: nothing loads this file implicitly
44
+ *
45
+ * No verb in this runtime reads `.approval/env` into its own environment. One
46
+ * verb, `approval env`, resolves it and prints an export block for a shell to
47
+ * evaluate; every other command sees only the environment the human who
48
+ * launched it had already established.
49
+ *
50
+ * The reason is `APPROVAL_HUMAN`. SPEC.md §11 states that human identity in v0.1
51
+ * is config-declared and that "the trust boundary is the local machine, and
52
+ * anyone who can set that configuration and write to the log is inside it". A
53
+ * working-tree file that could set `APPROVAL_HUMAN` would move that boundary to
54
+ * "anyone who can write a file in the repository": an agent that can edit source
55
+ * — which every agent working in a repository can — would thereby be able to
56
+ * attest a policy, grant its own request, and set a vault credential, on every
57
+ * invocation, as the human. The whole human-only gate would be one `echo >>`
58
+ * away from being nobody's gate.
59
+ *
60
+ * So the file is inert. A human evaluates `approval env` in their own shell,
61
+ * sees the export block that is about to run (or checks it value-free first with
62
+ * `--check`), and the process that performs a gate operation inherits an
63
+ * environment a human established. This is SPEC.md §11.1 invariant 7, and
64
+ * `tests/cli-env.test.ts` pins it by spawning `doctor`, `policy attest` and
65
+ * `channel telegram health` in a directory holding a complete `.approval/env`
66
+ * and asserting that none of them saw a byte of it.
67
+ *
68
+ * ## Mode 0600
69
+ *
70
+ * A file that may hold a literal secret is refused unless its mode is exactly
71
+ * `0600`, and the refusal prints the `chmod`. This is a lock on a door whose
72
+ * wall is missing (the same session can chmod it back), and it is worth having
73
+ * for the reason `umask` is worth having: the common failure is a
74
+ * world-readable file nobody looked at, not an adversary in the room.
75
+ *
76
+ * ## Determinism, and the one place it stops
77
+ *
78
+ * Parsing is a pure function of the bytes. Resolution is not: it shells out to
79
+ * helper binaries, which is why {@link SourceRunner} exists as an injectable
80
+ * seam and why the tests drive stub `security` / `secret-tool` scripts through
81
+ * PATH rather than touching a real Keychain.
82
+ *
83
+ * Nothing here throws. Every failure is a `{ ok: false, code, message }` from
84
+ * the frozen union {@link ENV_FILE_REFUSAL_CODES}. No credential VALUE appears
85
+ * in a refusal, a message, or a `source` label on any path.
86
+ */
87
+ import type { PolicyLoadResult } from "./policy-load.js";
88
+ /** The source map's filename, beside the log's home: `.approval/env`. */
89
+ export declare const ENV_FILENAME = "env";
90
+ /**
91
+ * The env file for a given log path — derived exactly as `vaultPathFor` derives
92
+ * the vault, so the log, the payload store, the vault and this file stay under
93
+ * one home: SPEC.md §9 fixes the log at `<home>/log/events.jsonl`, so the source
94
+ * map is `<home>/env`, a sibling of the log DIRECTORY and never inside it.
95
+ */
96
+ export declare function envFilePathFor(logPath: string): string;
97
+ /** The mode the file must have. Anything else is refused. */
98
+ export declare const ENV_FILE_REQUIRED_MODE = 384;
99
+ /**
100
+ * Everything this module can refuse. Frozen public API, per SPEC.md §11.1(6).
101
+ *
102
+ * Each code names a different repair, which is the test of whether a code earns
103
+ * its place. The three helper codes are separate for exactly that reason: "you
104
+ * are on a machine without `secret-tool`", "the item is not in your keychain",
105
+ * and "the helper ran and failed" are three different mornings.
106
+ */
107
+ export declare const ENV_FILE_REFUSAL_CODES: readonly [
108
+ /** The file's mode is not 0600. The refusal carries the `chmod` to run. */
109
+ "env-file-mode",
110
+ /**
111
+ * The file exists and could not be read, stat'd, or (APRV-74) written. A
112
+ * filesystem fact in every case, with a filesystem repair, which is why the
113
+ * write path reuses this code rather than adding a fourth I/O name to a
114
+ * frozen union: "the directory is read-only" and "the file is unreadable"
115
+ * are the same morning and the same exit code.
116
+ */
117
+ "env-file-io",
118
+ /** A line is neither blank, nor a comment, nor `KEY=VALUE`. */
119
+ "env-file-syntax",
120
+ /** A KEY does not match `[A-Z_][A-Z0-9_]*`. No `export ` prefix is accepted. */
121
+ "env-file-key-invalid",
122
+ /** The same KEY appears twice. Which one wins is not a thing to guess at. */
123
+ "env-file-duplicate-key",
124
+ /** A VALUE carries a `scheme:` prefix this build does not implement. */
125
+ "env-file-unknown-scheme",
126
+ /** A KEY with an empty VALUE. An empty secret is a configuration error. */
127
+ "env-file-empty-value",
128
+ /** The helper binary for a scheme is not on PATH. Not the operator's fault. */
129
+ "helper-binary-missing",
130
+ /** The helper ran and the named item is not there. Store it, or fix the name. */
131
+ "helper-item-missing",
132
+ /** The helper ran and failed for some other reason (locked keyring, …). */
133
+ "helper-failed",
134
+ /**
135
+ * A policy declared an `_env` NAME that is not a usable shell variable name.
136
+ * Never emitted as an `export` line: the export block is evaluated by a shell,
137
+ * and a name carrying a space or a `;` would be a policy file executing code.
138
+ */
139
+ "invalid-variable-name"];
140
+ export type EnvFileRefusalCode = (typeof ENV_FILE_REFUSAL_CODES)[number];
141
+ /** A whole-file failure. Nothing here throws. */
142
+ export interface EnvFileRefusal {
143
+ ok: false;
144
+ code: EnvFileRefusalCode;
145
+ message: string;
146
+ /** The file the refusal is about. */
147
+ path: string;
148
+ /** 1-based line number, for the parse refusals that have one. */
149
+ line?: number;
150
+ }
151
+ /** The four value forms. `literal` is the fallback and the explicit escape. */
152
+ export type EnvSourceKind = "keychain" | "secret-service" | "env" | "literal";
153
+ /** One `KEY=VALUE` line, parsed. */
154
+ export interface EnvFileEntry {
155
+ key: string;
156
+ kind: EnvSourceKind;
157
+ /**
158
+ * The service name, the label, or the literal value. Empty for `env:`.
159
+ *
160
+ * For `literal` this IS the secret, so it is never put in a message, a
161
+ * `source` label, or a refusal by anything in this module.
162
+ */
163
+ argument: string;
164
+ /** 1-based line number, so a diagnostic can point at the line. */
165
+ line: number;
166
+ }
167
+ /**
168
+ * Parse the file's text. No interpolation, no quote stripping, no `export `
169
+ * prefix, no line continuations: this is a source map, not a shell script, and
170
+ * every one of those features is a way for a file to mean something other than
171
+ * what it looks like.
172
+ *
173
+ * Quotes are NOT stripped, which is worth saying out loud because `.env` files
174
+ * elsewhere do strip them: here `A="b"` is the five-character literal `"b"`.
175
+ */
176
+ export declare function parseEnvFile(text: string, path: string): {
177
+ ok: true;
178
+ entries: EnvFileEntry[];
179
+ } | EnvFileRefusal;
180
+ /**
181
+ * The digest of an env file's bytes, as read.
182
+ *
183
+ * Not a secret and not derived from one in the sense that matters: the file may
184
+ * carry a plaintext literal, so this is a hash and never the text, and it is
185
+ * one-way. Its only consumer is `core/instance.ts`, which uses it to ask "was
186
+ * this exported value produced from the file as it now reads?" — a question
187
+ * about VERSIONS of a file, which needs an identifier for a version and nothing
188
+ * else (APRV-278).
189
+ */
190
+ export declare function envFileDigest(text: string): string;
191
+ /** An absent file's digest: the digest of the nothing that was read. */
192
+ export declare const ABSENT_ENV_FILE_DIGEST: string;
193
+ /** The file's contents, or the fact that there is no file. */
194
+ export type EnvFileRead = {
195
+ ok: true;
196
+ present: false;
197
+ path: string;
198
+ entries: [];
199
+ digest: string;
200
+ } | {
201
+ ok: true;
202
+ present: true;
203
+ path: string;
204
+ entries: EnvFileEntry[];
205
+ digest: string;
206
+ } | EnvFileRefusal;
207
+ /**
208
+ * Read and parse the source map.
209
+ *
210
+ * **An absent file is not an error.** Nobody has written one, which is the state
211
+ * of every working directory that keeps its variables in a shell profile, and it
212
+ * is the state `approval init` leaves behind. Every variable then falls to
213
+ * "inherited from the environment" or "unset", which is exactly the world
214
+ * before this file existed.
215
+ */
216
+ export declare function readEnvFile(path: string): EnvFileRead;
217
+ /** What one upserted KEY did to the file. */
218
+ export interface EnvFileChange {
219
+ key: string;
220
+ /** The line as it will now read: `KEY=VALUE`. Never a secret — see below. */
221
+ value: string;
222
+ /**
223
+ * The VALUE that was on the line before, or `null` when the key was added.
224
+ *
225
+ * This CAN be a plaintext secret, if the operator had written one as a bare
226
+ * literal, so it exists for a caller that needs to decide whether it is
227
+ * REPLACING something, and no caller in this repository prints it. The
228
+ * boolean below is what the CLI reports on.
229
+ */
230
+ previous: string | null;
231
+ /** The value is unchanged: the line already said exactly this. */
232
+ unchanged: boolean;
233
+ }
234
+ /** A successful write. */
235
+ export interface EnvFileWrite {
236
+ ok: true;
237
+ path: string;
238
+ /** The file did not exist and was created at 0600. */
239
+ created: boolean;
240
+ changes: EnvFileChange[];
241
+ }
242
+ /**
243
+ * Add or replace `KEY=VALUE` lines, preserving everything else in the file.
244
+ *
245
+ * **Line-oriented, not a rewrite.** The file is read as text, the line whose
246
+ * KEY matches is replaced IN PLACE, and a key that is not present is appended
247
+ * at the end. Comments, blank lines, ordering, and every entry this call was
248
+ * not asked about survive byte for byte. A writer that reparsed and re-emitted
249
+ * would be simpler and would quietly delete the operator's own comments the
250
+ * first time `approval setup channel telegram` ran — this file is one a human edits by
251
+ * hand, and round-trip fidelity for a hand-edited file is the same requirement
252
+ * the Backlog.md task files carry.
253
+ *
254
+ * The file is validated before it is touched: {@link readEnvFile}'s mode check
255
+ * and full parse both run, so `setup` never appends a line to a file it could
256
+ * not have read, and never lands a valid line in a file whose earlier line is a
257
+ * syntax error. A file that does not exist is created at 0600, along with its
258
+ * directory.
259
+ *
260
+ * Callers pass values, and a value here is a SOURCE (`keychain:<service>`), a
261
+ * chat id, or an identity — never a credential, except on the one path where an
262
+ * operator explicitly chose a plaintext literal after being told what it means.
263
+ * Nothing in this function prints anything.
264
+ */
265
+ export declare function upsertEnvFileEntries(path: string, entries: ReadonlyArray<{
266
+ key: string;
267
+ value: string;
268
+ }>): EnvFileWrite | EnvFileRefusal;
269
+ /** What a helper lookup produced. The value, or a distinct reason it did not. */
270
+ export type SourceOutcome = {
271
+ ok: true;
272
+ value: string;
273
+ } | {
274
+ ok: false;
275
+ code: "helper-binary-missing" | "helper-item-missing" | "helper-failed";
276
+ message: string;
277
+ };
278
+ /**
279
+ * The two helper lookups, injectable.
280
+ *
281
+ * A seam rather than a direct `spawnSync` because the alternative is a test
282
+ * suite that reads the machine's real Keychain, and there is no version of that
283
+ * which is acceptable: it would prompt, it would depend on the developer's own
284
+ * secrets, and on the wrong day it would print one. Tests pass a fake here, and
285
+ * the ONE test that exercises {@link defaultSourceRunner} does it by putting
286
+ * stub `security` / `secret-tool` scripts on the child process's PATH — a real
287
+ * PATH lookup of a real command name, with no test-only flag in the runtime.
288
+ */
289
+ export interface SourceRunner {
290
+ keychain(service: string): SourceOutcome;
291
+ secretService(label: string): SourceOutcome;
292
+ }
293
+ /**
294
+ * `security find-generic-password -a "$USER" -s <service> -w` and
295
+ * `secret-tool lookup approval <label>`.
296
+ *
297
+ * THE VALUE IS NEVER IN AN ARGV, in either direction: the argv carries a service
298
+ * name or a label, and the secret comes back on stdout. An argv is world-readable
299
+ * in `ps` for the length of the call, which is the whole reason `approval vault
300
+ * set` has no `--value` flag either.
301
+ *
302
+ * The exit-status readings are documented heuristics, not contracts. `security`
303
+ * exits 44 (`errSecItemNotFound`) for a missing item; `secret-tool` exits 0 with
304
+ * empty output when the lookup matches nothing. Anything else is
305
+ * {@link "helper-failed"}, which is the honest answer for a locked keyring or a
306
+ * D-Bus that is not running: the repair is not "store the item".
307
+ */
308
+ /**
309
+ * The prefix a deferred lookup carries. See {@link NON_RESOLVING_RUNNER}.
310
+ */
311
+ export declare const KEYSTORE_DEFERRED = "not resolved by doctor";
312
+ /**
313
+ * A {@link SourceRunner} that looks nothing up (moved here by APRV-178).
314
+ *
315
+ * `security find-generic-password -w` can raise a keychain-unlock or ACL dialog
316
+ * and `secret-tool lookup` can block on a keyring prompt. Either would hang a
317
+ * command run over ssh or from CI, and a command that pops a keychain prompt
318
+ * also TEACHES people to click through keychain prompts. So the diagnostics —
319
+ * `approval doctor`, and `approval up`'s cross-instance report — resolve
320
+ * keystore-backed variables not at all: they report the scheme and the service
321
+ * name, which `.approval/env` already carries in the open, and leave the actual
322
+ * lookup to `approval env --check`, which a human runs deliberately and watches.
323
+ *
324
+ * It lives beside {@link defaultSourceRunner} rather than in one of its callers
325
+ * because two of them now need it and a second copy would be a second set of
326
+ * words for the same refusal.
327
+ */
328
+ export declare const NON_RESOLVING_RUNNER: SourceRunner;
329
+ export declare const defaultSourceRunner: SourceRunner;
330
+ /** Where a resolved value came from, as a closed set. */
331
+ export type EnvVariableStatus = "set-in-environment" | "resolved-from-keychain" | "resolved-from-secret-service" | "resolved-literal" | "unset";
332
+ /** One variable, resolved. */
333
+ export interface ResolvedVariable {
334
+ /** The variable's NAME, as the policy or the runtime default gave it. */
335
+ name: string;
336
+ status: EnvVariableStatus;
337
+ /** The value, present only when the status is not `unset`. */
338
+ value?: string;
339
+ /**
340
+ * Where it came from, in words, and NEVER a value: `the environment`,
341
+ * `keychain:approval-tg-token`, `literal (plaintext in .approval/env)`,
342
+ * `unset`.
343
+ */
344
+ source: string;
345
+ /**
346
+ * The value is sitting in plaintext in the working tree: a secret-bearing
347
+ * variable resolved from a bare literal.
348
+ *
349
+ * `APPROVAL_HUMAN` and the Telegram chat id are literals in most real files
350
+ * and are not secrets, so they are `false` — but note the `source` label says
351
+ * "literal (plaintext in .approval/env)" for EVERY literal regardless, because
352
+ * the reader deciding whether a file may be committed wants to see all of
353
+ * them.
354
+ */
355
+ plaintext: boolean;
356
+ /** What to do about an `unset`. Absent when there is nothing to do. */
357
+ fix?: string;
358
+ /** Why a resolution failed, when one did. Distinct and machine-readable. */
359
+ refusal?: {
360
+ code: EnvFileRefusalCode;
361
+ message: string;
362
+ };
363
+ /**
364
+ * The policy NAMED this variable (rather than the runtime defaulting it).
365
+ * `approval env --check` fails on an unresolved declared variable and not on
366
+ * an unresolved defaulted one: a policy that asked for something is a promise;
367
+ * a default the operator never mentioned is an offer.
368
+ */
369
+ declared: boolean;
370
+ /** The value would be a secret if it had one: token, passphrase, sampling. */
371
+ secretBearing: boolean;
372
+ /**
373
+ * What the INSTANCE's own `.approval/env` says about this variable, whether
374
+ * or not that is where the value came from (APRV-178).
375
+ *
376
+ * The ambient environment wins over the file and the file is then not even
377
+ * consulted, which is correct and is invariant 7 — but it is also how a
378
+ * production bot token exported in a shell profile silently became a demo
379
+ * instance's channel credential. Nothing could report that, because the
380
+ * resolution discarded the file entry it had ignored. It is kept here so
381
+ * `approval env --check`, `approval doctor` and `approval up` can say "this
382
+ * value is not the one your instance's file names".
383
+ *
384
+ * Value-free by construction: {@link DeclaredSource.service} is filled only
385
+ * for the two keystore schemes, whose argument is a service name the file
386
+ * carries in the open. A `literal` entry's argument IS the secret, so only
387
+ * its KIND is recorded.
388
+ */
389
+ fileSource?: DeclaredSource;
390
+ }
391
+ /** A `.approval/env` line, reduced to what may be printed. */
392
+ export interface DeclaredSource {
393
+ kind: EnvSourceKind;
394
+ /** The service name or label, for `keychain:` and `secret-service:` only. */
395
+ service?: string;
396
+ /** 1-based line number in `.approval/env`. */
397
+ line: number;
398
+ }
399
+ /** A declared source in words, and never a value. */
400
+ export declare function describeDeclaredSource(source: DeclaredSource): string;
401
+ /** The whole answer. */
402
+ export interface EnvResolution {
403
+ ok: true;
404
+ /** Was there a file at all? */
405
+ present: boolean;
406
+ path: string;
407
+ /**
408
+ * {@link envFileDigest} of the bytes this resolution read (APRV-278), or
409
+ * {@link ABSENT_ENV_FILE_DIGEST} when there was no file. It identifies a
410
+ * VERSION of the file and carries none of its contents.
411
+ */
412
+ digest: string;
413
+ variables: ResolvedVariable[];
414
+ }
415
+ interface Wanted {
416
+ name: string;
417
+ declared: boolean;
418
+ secretBearing: boolean;
419
+ /** The repair for an unset one. */
420
+ fix: string;
421
+ }
422
+ /**
423
+ * The variables `approval env` answers for, in a stable order.
424
+ *
425
+ * Five by name — human identity, the Telegram token and chat id, the vault
426
+ * passphrase, and the sampling secret — plus whatever else the policy names by
427
+ * the `_env` convention.
428
+ *
429
+ * The sampling secret is the one conditional member: `audit.sampling_secret_env`
430
+ * has NO default (an unnamed one disables sampling, SPEC.md §5.2), so listing a
431
+ * made-up variable for it would invent configuration the operator never chose.
432
+ * The other four all have defaults and are always listed.
433
+ */
434
+ export declare function wantedVariables(load: PolicyLoadResult): Wanted[];
435
+ /**
436
+ * Resolve every variable the policy implies, against the ambient environment
437
+ * first and the source map second.
438
+ *
439
+ * **The ambient environment always wins.** A variable already exported in the
440
+ * calling shell is reported `set-in-environment` and its file entry is not even
441
+ * consulted: the human's shell is the authority (that is invariant 7's whole
442
+ * point), and a file that could override an exported value would be a file that
443
+ * silently redirects a gate operation's credentials.
444
+ *
445
+ * A whole-file refusal (bad mode, unreadable, unparseable) is returned as-is:
446
+ * partial resolution of a file the runtime cannot fully read is how a typo turns
447
+ * into a half-configured environment.
448
+ */
449
+ export declare function resolveEnvironment(load: PolicyLoadResult, envFilePath: string, runner?: SourceRunner, ambientEnv?: NodeJS.ProcessEnv): EnvResolution | EnvFileRefusal;
450
+ export {};