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,93 @@
1
+ /**
2
+ * The vault passphrase, resolved from `.approval/env` inside a granted window
3
+ * (SPEC.md §10.4, §5.2; APRV-168).
4
+ *
5
+ * ## Why this narrows a load-bearing rule, and how far
6
+ *
7
+ * `core/env-file.ts` states the rule this module bends, and states it as the
8
+ * reason the file exists at all: **no verb in this runtime reads `.approval/env`
9
+ * into its own environment.** The argument there is `APPROVAL_HUMAN`. A
10
+ * working-tree file that could set human identity would move SPEC.md §11's trust
11
+ * boundary from "the local machine" to "anyone who can write a file in the
12
+ * repository", and every agent that can edit source can write a file in the
13
+ * repository. So the file is inert, one verb resolves it, and a human evaluates
14
+ * that verb's output in their own shell.
15
+ *
16
+ * The narrowing here keeps every part of that argument intact:
17
+ *
18
+ * 1. **One variable, named by the policy.** What this module resolves is the
19
+ * `vault.passphrase_env` variable and nothing else. It cannot be asked for
20
+ * `APPROVAL_HUMAN`, so it cannot be used to claim an identity, attest a
21
+ * policy, or grant a request. The whole human-only gate is untouched.
22
+ * 2. **One caller, inside a token window.** Reaching this function requires an
23
+ * {@link ExecutionGrant}, which `adapters/contract.ts` mints and no other
24
+ * module can construct: its brand is a `unique symbol` that is never
25
+ * exported, so a call site outside the contract's execution path does not
26
+ * type-check. A generic vault verb, `approval doctor`, `approval setup` and
27
+ * every other caller of `vaultCredentialProvider` have no way to produce one,
28
+ * which is the "no verb reads `.approval/env`" rule holding everywhere except
29
+ * the one path named here.
30
+ *
31
+ * The contract mints a grant in two phases and both are honoured, for a
32
+ * reason worth stating: the credential resolution APRV-169 moved AHEAD of the
33
+ * token spend runs in the `presented` phase, so a fallback that insisted on
34
+ * `consumed` would refuse the very execution it exists to enable. A
35
+ * `presented` grant is minted only when the caller's token matches the digest
36
+ * the log's `approval.granted` recorded for this action, so it is still proof
37
+ * that a human approved this action and that the caller holds the token that
38
+ * approval minted. What it does not prove is that the token may still be
39
+ * spent (TTL, revocation, single use), and it does not have to: those are
40
+ * checked in `startExecution` before anything is appended, and no side effect
41
+ * happens on the strength of this phase.
42
+ * 3. **The authority is the token, not the file.** A human looked at the
43
+ * payload on their phone, tapped Approve, and a token was minted, delivered,
44
+ * verified and consumed for exactly this action key and exactly these bytes.
45
+ * The question this module answers is narrower than "may this process act":
46
+ * that was already answered, by a person. It is "the action a human approved
47
+ * is about to run, and the credential it needs is described in the
48
+ * instance's own configuration; may the runtime read that description".
49
+ * 4. **Nothing is loaded into an environment.** The value is returned to the
50
+ * vault provider and used to derive one key. It is never written to
51
+ * `process.env`, never placed in an argv (`core/env-file.ts`'s helper
52
+ * lookups already pass a service NAME and take the secret on stdout), never
53
+ * logged, and never put in a message, a refusal, or a thrown error.
54
+ *
55
+ * What the demo case looks like, since it is the one that produced this task:
56
+ * the web-agent runner scrubs the agent child's environment of everything
57
+ * matching `APPROVAL|VAULT|TELEGRAM`, deliberately, because the server itself
58
+ * must hold no vault passphrase. The child then holds a granted token for one
59
+ * approved email and no way to open the vault that token is the key to. Before
60
+ * this module the only answers were to weaken the scrub or to send the mail by
61
+ * hand.
62
+ *
63
+ * ## What it does not defend
64
+ *
65
+ * Exactly what SPEC.md §10.4 and §11 already say the vault does not defend: a
66
+ * compromised host, and an agent that can read the passphrase. An agent that can
67
+ * read `.approval/env` and run the same helper lookups needs no adapter and no
68
+ * token; it decrypts the file directly. This module does not widen that
69
+ * exposure, because it reads what such an agent could already read. What it
70
+ * changes is that a process which holds a HUMAN'S GRANT and no passphrase can
71
+ * complete the action the human approved.
72
+ *
73
+ * Total and synchronous, like everything on the credential path: nothing here
74
+ * throws, and every failure is `null`. A `null` carries no detail on purpose;
75
+ * the caller's own refusal names the variable and the vault, and a diagnostic
76
+ * that quoted a keychain error would be the one string in this system that
77
+ * describes where a passphrase lives.
78
+ */
79
+ import { type SourceRunner } from "../core/env-file.js";
80
+ import type { ExecutionGrant } from "./contract.js";
81
+ /**
82
+ * Resolve `variable` from the source map at `envFilePath`, under `grant`.
83
+ *
84
+ * Returns the value, or `null` for every other outcome: no grant, a `consumed`
85
+ * grant from a path where no token was spent, no file, a file this runtime will
86
+ * not read (wrong mode, unparseable), no line for this variable, an `env:` line
87
+ * (which asserts the value comes from the shell and resolves to nothing on its
88
+ * own), a helper that is missing or declined, or an empty result.
89
+ *
90
+ * Not re-exported anywhere. `adapters/vault-provider.ts` is its only caller, and
91
+ * `tests/vault-provider.test.ts` pins that.
92
+ */
93
+ export declare function passphraseUnderGrant(grant: ExecutionGrant | null, envFilePath: string, variable: string, runner?: SourceRunner): string | null;
@@ -0,0 +1,11 @@
1
+ /**
2
+ * The supported adapter-author API.
3
+ *
4
+ * Keep this barrel deliberately small. Every name exported here is a package
5
+ * compatibility commitment; the surrounding adapter and core modules remain
6
+ * implementation details.
7
+ */
8
+ export { ADAPTER_REFUSAL_CODES, CREDENTIAL_REFUSAL_CODES, executeThroughAdapter, type ActInput, type ActOutcome, type Adapter, type AdapterExecuteOptions, type AdapterExecuteRequest, type AdapterExecuteResult, type AdapterExecuteSuccess, type AdapterRefusal, type AdapterRefusalCode, type CredentialProvider, type CredentialRefusalCode, type CredentialResult, type ExecutionGrant, type JsonValue, type PrecheckInput, type PrecheckOutcome, } from "./contract.js";
9
+ export { runAdapterConformance, type AdapterConformanceCase, type AdapterConformanceHarness, type ConformanceContext, } from "./conformance.js";
10
+ export { vaultCredentialProvider, type VaultLocation, type VaultProviderOptions, } from "./vault-provider.js";
11
+ export type { CredentialKind, CredentialSpec } from "../core/credential-spec.js";
@@ -0,0 +1,11 @@
1
+ /**
2
+ * The supported adapter-author API.
3
+ *
4
+ * Keep this barrel deliberately small. Every name exported here is a package
5
+ * compatibility commitment; the surrounding adapter and core modules remain
6
+ * implementation details.
7
+ */
8
+ export { ADAPTER_REFUSAL_CODES, CREDENTIAL_REFUSAL_CODES, executeThroughAdapter, } from "./contract.js";
9
+ export { runAdapterConformance, } from "./conformance.js";
10
+ export { vaultCredentialProvider, } from "./vault-provider.js";
11
+ //# sourceMappingURL=public.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"public.js","sourceRoot":"","sources":["../../../src/adapters/public.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EACL,qBAAqB,EACrB,wBAAwB,EACxB,qBAAqB,GAiBtB,MAAM,eAAe,CAAC;AAEvB,OAAO,EACL,qBAAqB,GAItB,MAAM,kBAAkB,CAAC;AAE1B,OAAO,EACL,uBAAuB,GAGxB,MAAM,qBAAqB,CAAC"}
@@ -0,0 +1,59 @@
1
+ /**
2
+ * The built-in adapters, keyed by the classes they serve (APRV-205).
3
+ *
4
+ * One question is asked of this module and one only: **which credential names
5
+ * did the adapters for this class declare they cannot act without?** `approval
6
+ * run` asks it before it spawns, because those names are the ones the scrub in
7
+ * `core/child-env.ts` lets through into the child's environment; everything
8
+ * else under the credential-bearing prefixes is withheld.
9
+ *
10
+ * The declaration is the adapter's own, static, and reached through no flag.
11
+ * That is the point: a caller-supplied list of variables to keep would be a
12
+ * caller-supplied way to get the token back, which is the hole this task
13
+ * closes rather than a feature of the fix. {@link declaredCredentialsForClass}
14
+ * therefore takes a class and nothing else, and reads {@link builtInAdapters}
15
+ * and nothing else.
16
+ *
17
+ * The list is deliberately tiny and deliberately here rather than in
18
+ * `src/core/`: core does not know about adapters and must not learn, so the
19
+ * lookup lives beside the adapters and the CLI does the joining.
20
+ *
21
+ * This roster is the build's answer to "which adapters exist". The CLI's own
22
+ * adapter table (`cli/adapter.ts`) answers a different question, "which
23
+ * adapters have a verb", and the two are kept side by side on purpose: an
24
+ * adapter with no CLI face still declares credentials, and this module must
25
+ * not depend on the CLI to know that.
26
+ */
27
+ import type { Adapter } from "./contract.js";
28
+ /**
29
+ * Every adapter this build ships. Since APRV-223 that is two, and both serve
30
+ * `communicate.email.external`: the union of their declared names is what the
31
+ * scrub lets through, which is the honest superset {@link
32
+ * unionRequiredCredentials} was written for rather than a collision to resolve.
33
+ *
34
+ * Constructed with defaults: the question asked
35
+ * here is about DECLARED names, and no default answers it differently from a
36
+ * configured instance except by renaming vault entries, which is a deployment's
37
+ * own business and not a reason to open a socket at lookup time.
38
+ */
39
+ export declare function builtInAdapters(): readonly Adapter[];
40
+ /**
41
+ * The credential names declared by `adapters` serving `cls`, deduplicated and
42
+ * in roster order.
43
+ *
44
+ * Every adapter that serves the class contributes, because "which adapter would
45
+ * have run this" is a question with no answer at this point in the flow, and
46
+ * the union of two adapters' declarations is the honest superset. Two adapters
47
+ * may serve one class, and when they do the scrub lets both sets of names
48
+ * through rather than guessing between them.
49
+ *
50
+ * Pure, and separated from {@link declaredCredentialsForClass} so the union can
51
+ * be tested over more adapters than a build happens to ship. It is not a seam
52
+ * for enforcement: nothing outside a test passes it a roster.
53
+ */
54
+ export declare function unionRequiredCredentials(adapters: readonly Adapter[], cls: string): readonly string[];
55
+ /**
56
+ * The credential names declared by the built-in adapters serving `cls`, or an
57
+ * empty list when no adapter serves it.
58
+ */
59
+ export declare function declaredCredentialsForClass(cls: string): readonly string[];
@@ -26,6 +26,7 @@
26
26
  */
27
27
  import { agentmailAdapter } from "./agentmail.js";
28
28
  import { emailAdapter } from "./email.js";
29
+ import { zzzAdapter } from "./zzz.js";
29
30
  /**
30
31
  * Every adapter this build ships. Since APRV-223 that is two, and both serve
31
32
  * `communicate.email.external`: the union of their declared names is what the
@@ -38,7 +39,7 @@ import { emailAdapter } from "./email.js";
38
39
  * own business and not a reason to open a socket at lookup time.
39
40
  */
40
41
  export function builtInAdapters() {
41
- return [emailAdapter(), agentmailAdapter()];
42
+ return [emailAdapter(), agentmailAdapter(), zzzAdapter()];
42
43
  }
43
44
  /**
44
45
  * The credential names declared by `adapters` serving `cls`, deduplicated and
@@ -1 +1 @@
1
- {"version":3,"file":"registry.js","sourceRoot":"","sources":["../../../src/adapters/registry.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AAEH,OAAO,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAClD,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAG1C;;;;;;;;;;GAUG;AACH,MAAM,UAAU,eAAe;IAC7B,OAAO,CAAC,YAAY,EAAE,EAAE,gBAAgB,EAAE,CAAC,CAAC;AAC9C,CAAC;AAED;;;;;;;;;;;;;GAaG;AACH,MAAM,UAAU,wBAAwB,CACtC,QAA4B,EAC5B,GAAW;IAEX,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;QAC/B,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAC;YAAE,SAAS;QAC7C,KAAK,MAAM,IAAI,IAAI,OAAO,CAAC,mBAAmB,IAAI,EAAE,EAAE,CAAC;YACrD,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,IAAI,CAAC;gBAAE,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC9C,CAAC;IACH,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,2BAA2B,CAAC,GAAW;IACrD,OAAO,wBAAwB,CAAC,eAAe,EAAE,EAAE,GAAG,CAAC,CAAC;AAC1D,CAAC"}
1
+ {"version":3,"file":"registry.js","sourceRoot":"","sources":["../../../src/adapters/registry.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AAEH,OAAO,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAClD,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAC1C,OAAO,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AAGtC;;;;;;;;;;GAUG;AACH,MAAM,UAAU,eAAe;IAC7B,OAAO,CAAC,YAAY,EAAE,EAAE,gBAAgB,EAAE,EAAE,UAAU,EAAE,CAAC,CAAC;AAC5D,CAAC;AAED;;;;;;;;;;;;;GAaG;AACH,MAAM,UAAU,wBAAwB,CACtC,QAA4B,EAC5B,GAAW;IAEX,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;QAC/B,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAC;YAAE,SAAS;QAC7C,KAAK,MAAM,IAAI,IAAI,OAAO,CAAC,mBAAmB,IAAI,EAAE,EAAE,CAAC;YACrD,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,IAAI,CAAC;gBAAE,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC9C,CAAC;IACH,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,2BAA2B,CAAC,GAAW;IACrD,OAAO,wBAAwB,CAAC,eAAe,EAAE,EAAE,GAAG,CAAC,CAAC;AAC1D,CAAC"}
@@ -0,0 +1,213 @@
1
+ /**
2
+ * A minimal SMTP client, for the email adapter and nothing else (APRV-69).
3
+ *
4
+ * ## Why this exists rather than a dependency
5
+ *
6
+ * `CLAUDE.md` and SPEC.md §14 both put minimal dependencies among this
7
+ * repository's invariants, and a mail library is a large surface to take on for
8
+ * one send: nodemailer pulls a templating layer, an attachment pipeline, a DKIM
9
+ * signer, OAuth2 token refresh, and a plugin system, all of it running inside
10
+ * the one call this project spends its whole design protecting. What is actually
11
+ * needed is RFC 5321's client half of a single transaction — greeting, EHLO,
12
+ * optionally STARTTLS, optionally AUTH, MAIL FROM, RCPT TO, DATA, QUIT — which
13
+ * is this file. `node:net` and `node:tls` and nothing else.
14
+ *
15
+ * ## What it deliberately does not do
16
+ *
17
+ * No connection pooling, no pipelining, no CHUNKING/BDAT, no SMTPUTF8, no DSN,
18
+ * no retry. One transaction per {@link sendMail} call, one message per
19
+ * transaction, and a failure is reported rather than retried: a retry inside an
20
+ * adapter would be a second side effect under one consumed token, and deciding
21
+ * to send again is a decision the gate exists to make.
22
+ *
23
+ * ## The probe, and the limit of what it proves
24
+ *
25
+ * {@link probeSmtp} runs the same session as {@link sendMail} up to and
26
+ * including AUTH, then says QUIT. It is the same code, one call away
27
+ * (`runSession` with no envelope), because a setup check that exercises a
28
+ * different client than the send does is a check that can pass while the send
29
+ * fails.
30
+ *
31
+ * A successful probe proves three things and no more: the host and port accept
32
+ * a connection, the requested transport security (implicit TLS, or the STARTTLS
33
+ * upgrade, with the same no-downgrade rule the send obeys) was actually
34
+ * established, and this server accepts this credential.
35
+ *
36
+ * It does **not** prove that a message would be accepted. MAIL FROM, RCPT TO
37
+ * and DATA are never issued, so nothing about the server's sender policy, its
38
+ * relaying rules, its recipient validation, its size limits or its content
39
+ * filtering is exercised. A probe that succeeds against a server which will
40
+ * later refuse `MAIL FROM:<…>` with a 550 is a probe behaving correctly. Any
41
+ * caller reporting the result to an operator (`setup adapter email` says
42
+ * "verified") owes them that distinction: the transport and the login are
43
+ * verified, the delivery is not.
44
+ *
45
+ * ## Failure vocabulary
46
+ *
47
+ * Everything is reported, nothing is thrown out of {@link sendMail}. Two
48
+ * families:
49
+ *
50
+ * - the transport codes in {@link SMTP_TRANSPORT_FAILURE_CODES}, which are a
51
+ * frozen, additive union (SPEC.md §11.1(6)); and
52
+ * - a reply-code family, `smtp-<NNN>`, minted from the server's own three-digit
53
+ * reply whenever the far side refuses a verb. It is a family rather than an
54
+ * enumeration because RFC 5321 lets a server answer with codes this repository
55
+ * cannot list in advance, and collapsing "mailbox unavailable" and
56
+ * "authentication failed" into one local name would throw away the one piece
57
+ * of information an operator needs. {@link SMTP_REPLY_CODE_PATTERN} pins the
58
+ * shape.
59
+ *
60
+ * ## What may appear in a failure message
61
+ *
62
+ * The verb, the reply code, and **the first line of the server's reply text**.
63
+ * Not the whole reply: a multi-line refusal can run to a screen of banner text,
64
+ * and everything after the first line is the server explaining itself to a human
65
+ * rather than telling the client what happened. Not the command: an `AUTH PLAIN
66
+ * <base64>` echoed into a diagnostic would publish the credential in the one
67
+ * string the adapter's caller is most likely to print.
68
+ *
69
+ * And even the first line is passed through {@link SmtpTransportOptions.redact}
70
+ * before it is returned, because a server is entitled to quote back the username
71
+ * it just refused ("535 5.7.8 authentication failed for bot@example.com"), and a
72
+ * deployment whose username IS the credential would otherwise leak it through a
73
+ * channel the adapter contract's own guard also covers but which this module
74
+ * should not be relying on. Two independent scrubs, by design.
75
+ *
76
+ * Deterministic apart from the network and the clock it does not read: no
77
+ * randomness, no ambient configuration, no environment reads.
78
+ */
79
+ /** How the connection is protected. */
80
+ export type SmtpSecurity =
81
+ /** TLS from the first byte (the submissions port, 465). */
82
+ "implicit"
83
+ /** Plaintext, then a mandatory STARTTLS upgrade (the submission port, 587). */
84
+ | "starttls"
85
+ /**
86
+ * Plaintext, and it stays that way. Only sane for a relay on the same host;
87
+ * the adapter refuses to AUTH over it, because a password on a cleartext
88
+ * socket is a password on the wire.
89
+ */
90
+ | "none";
91
+ export declare function isSmtpSecurity(value: unknown): value is SmtpSecurity;
92
+ /**
93
+ * Transport failures this client can report. Frozen union, additive only
94
+ * (SPEC.md §11.1(6)).
95
+ *
96
+ * They are distinguished because they call for four different responses: fix
97
+ * the address, fix the TLS configuration, look at why the far side is slow, and
98
+ * report a server that is not speaking SMTP.
99
+ */
100
+ export declare const SMTP_TRANSPORT_FAILURE_CODES: readonly [
101
+ /** The TCP connection could not be established at all. */
102
+ "smtp-connect-failed",
103
+ /** TLS could not be established, or the server would not offer STARTTLS. */
104
+ "smtp-tls-failed",
105
+ /** The session exceeded its whole-transaction budget. */
106
+ "smtp-timeout",
107
+ /** The far side sent something that is not an SMTP reply, or hung up. */
108
+ "smtp-protocol-error"];
109
+ export type SmtpTransportFailureCode = (typeof SMTP_TRANSPORT_FAILURE_CODES)[number];
110
+ /** The shape of a minted reply-code failure: `smtp-` and three digits. */
111
+ export declare const SMTP_REPLY_CODE_PATTERN: RegExp;
112
+ /** The default whole-session budget, in milliseconds. */
113
+ export declare const DEFAULT_SMTP_TIMEOUT_MS = 30000;
114
+ /** A parsed SMTP reply. `lines` holds the text of each line, code stripped. */
115
+ export interface SmtpReply {
116
+ code: number;
117
+ lines: string[];
118
+ /** The first line's text, which is the only part any message may quote. */
119
+ first: string;
120
+ }
121
+ export interface SmtpTransportOptions {
122
+ host: string;
123
+ port: number;
124
+ security: SmtpSecurity;
125
+ /** Omitted (or empty) means the session does not authenticate. */
126
+ user?: string;
127
+ password?: string;
128
+ /** Whole-session budget. Exceeding it is `smtp-timeout`. */
129
+ timeoutMs?: number;
130
+ /** The name this client gives in EHLO. */
131
+ clientName?: string;
132
+ /**
133
+ * TLS certificate verification. **Defaults to `true`, and production must
134
+ * leave it there.** The only sanctioned `false` is a test against a mock on
135
+ * 127.0.0.1 holding a self-signed fixture certificate.
136
+ */
137
+ tlsRejectUnauthorized?: boolean;
138
+ /** Applied to every string this module returns. See the module header. */
139
+ redact?(text: string): string;
140
+ }
141
+ /** The SMTP envelope, which is not the message's headers. */
142
+ export interface SmtpEnvelope {
143
+ /** MAIL FROM. The return path, not necessarily the From: header. */
144
+ from: string;
145
+ /** RCPT TO, once each: To, Cc, and **Bcc**, which appear in no header. */
146
+ recipients: readonly string[];
147
+ }
148
+ export type SmtpSendResult = {
149
+ ok: true;
150
+ /** The reply to the end-of-data terminator: the server accepting it. */
151
+ reply: {
152
+ code: number;
153
+ text: string;
154
+ };
155
+ /** `VERB code` for each step, in order. Never a command argument. */
156
+ transcript: string[];
157
+ /** Was the message handed over on an encrypted socket? */
158
+ secure: boolean;
159
+ /** Did the session authenticate, and with which mechanism? */
160
+ authenticated: "PLAIN" | "LOGIN" | null;
161
+ } | {
162
+ ok: false;
163
+ code: SmtpTransportFailureCode | `smtp-${number}`;
164
+ message: string;
165
+ transcript: string[];
166
+ secure: boolean;
167
+ };
168
+ /**
169
+ * What {@link probeSmtp} reports: {@link SmtpSendResult} without `reply`, since
170
+ * a probe never issues a verb whose reply is anything but a step of the
171
+ * session. The failure codes are the same union, from the same code path.
172
+ */
173
+ export type SmtpProbeResult = {
174
+ ok: true;
175
+ /** `VERB code` for each step, in order. Never a command argument. */
176
+ transcript: string[];
177
+ /** Was the session encrypted when it ended? */
178
+ secure: boolean;
179
+ /** Did the session authenticate, and with which mechanism? */
180
+ authenticated: "PLAIN" | "LOGIN" | null;
181
+ } | {
182
+ ok: false;
183
+ code: SmtpTransportFailureCode | `smtp-${number}`;
184
+ message: string;
185
+ transcript: string[];
186
+ secure: boolean;
187
+ };
188
+ /**
189
+ * Run one SMTP transaction and report how it went. Never throws.
190
+ *
191
+ * The whole of it is {@link runSession}; this is the entry point that supplies
192
+ * an envelope and a message, and its result is unchanged from the day it was
193
+ * the whole function.
194
+ */
195
+ export declare function sendMail(options: SmtpTransportOptions, envelope: SmtpEnvelope, message: string): Promise<SmtpSendResult>;
196
+ /**
197
+ * Open a session, authenticate, send nothing, and report. Never throws.
198
+ *
199
+ * Exactly {@link sendMail}'s session up to AUTH — the same connection, the same
200
+ * STARTTLS rules including the no-downgrade refusal and the response-injection
201
+ * guard, the same refusal to put a password on a cleartext socket, the same
202
+ * one-session budget, the same redaction of every string it returns — and then
203
+ * QUIT. See this module's header for what a success does and does not prove:
204
+ * transport, TLS mode and credential, never that a message would be delivered.
205
+ */
206
+ export declare function probeSmtp(options: SmtpTransportOptions): Promise<SmtpProbeResult>;
207
+ /**
208
+ * RFC 5321 §4.5.2: a line of the message that begins with `.` gets a second
209
+ * one, so the terminator cannot be forged by the message's own content. The
210
+ * terminating `.` line is NOT added here; {@link sendMail} sends it as its own
211
+ * command so the transcript records the reply to it.
212
+ */
213
+ export declare function dotStuff(message: string): string;
@@ -0,0 +1,114 @@
1
+ /**
2
+ * The vault as a {@link CredentialProvider} (SPEC.md §10.4; APRV-68).
3
+ *
4
+ * `adapters/contract.ts` left one seam open and named the task that would fill
5
+ * it: "No vault. {@link CredentialProvider} is the seam a real vault implements
6
+ * (APRV-68)." This module is that implementation, and it is deliberately thin.
7
+ * Everything about *when* a credential may be read belongs to the contract;
8
+ * everything about *how* the bytes are stored belongs to `core/vault.ts`. What
9
+ * is left here is the translation between the two vocabularies.
10
+ *
11
+ * ## The structural rule
12
+ *
13
+ * A provider built here is only ever handed to
14
+ * {@link executeThroughAdapter} through {@link AdapterExecuteOptions.credentials}.
15
+ * The contract wraps it in a window that closes the instant `act` returns, so
16
+ * every read during `act` is inside a verified execution. Manual and selected
17
+ * live paths consume a token; explicitly authorized supervised or autonomous
18
+ * paths do not. Three things hold that rule up, and none is a convention:
19
+ *
20
+ * 1. `core/vault.ts` exports exactly one function that returns a credential
21
+ * value (`getCredential`), and this module is its only caller in the
22
+ * repository. `tests/vault.test.ts` pins both halves.
23
+ * 2. There is no CLI verb that prints a value. `approval vault` can set, list
24
+ * (names), and remove; it cannot show. See `src/cli/vault.ts`.
25
+ * 3. The contract scans everything an adapter returns for the values the
26
+ * provider handed out and redacts them, so a leak by a careless adapter is
27
+ * caught mechanically rather than reviewed for.
28
+ *
29
+ * ## What this defends, and what it does not
30
+ *
31
+ * Exactly what the vault module's own threat model says, restated because a
32
+ * reader arriving from the adapter side deserves it here too. **Defended:**
33
+ * credentials at rest, and casual reads by an agent that can read files in the
34
+ * working tree — the ciphertext hides the names as well as the values.
35
+ * **Not defended (SPEC.md §11, plainly):** a compromised host, and an agent that
36
+ * can read the passphrase environment variable. Such an agent does not need this
37
+ * provider; it can decrypt the file directly. The vault raises the cost of a
38
+ * leak from reading a file to owning the session, and claims nothing beyond
39
+ * that.
40
+ *
41
+ * Total and synchronous, as {@link CredentialProvider} requires: nothing here
42
+ * throws, nothing blocks on a human, and every failure is one of the three
43
+ * {@link CREDENTIAL_REFUSAL_CODES}.
44
+ */
45
+ import { type SourceRunner } from "../core/env-file.js";
46
+ import type { CredentialProvider } from "./contract.js";
47
+ /**
48
+ * How to reach the vault. Either the vault file directly, or the log path the
49
+ * convention derives it from — never both, so there is one answer to "which
50
+ * file".
51
+ */
52
+ export type VaultLocation = {
53
+ vaultPath: string;
54
+ } | {
55
+ logPath: string;
56
+ };
57
+ export interface VaultProviderOptions {
58
+ /**
59
+ * The NAME of the environment variable holding the passphrase. Callers get
60
+ * this from `passphraseEnvFor(loadPolicy(...))`, so the policy's declaration
61
+ * is honoured and the default applies when it declares nothing.
62
+ */
63
+ passphraseEnv: string;
64
+ /** Injectable for tests. Defaults to this process's environment. */
65
+ env?: NodeJS.ProcessEnv;
66
+ /**
67
+ * The instance's `.approval/env`, enabling the scoped passphrase fallback
68
+ * (APRV-168). Absent, and the provider behaves exactly as it always did:
69
+ * the passphrase comes from the environment or it comes from nowhere.
70
+ *
71
+ * Supplied by `approval adapter <name>`, which executes through the contract
72
+ * and therefore inside a consumed-token window. It is deliberately NOT
73
+ * supplied by `approval setup adapter <name>`, `approval vault`, or anything
74
+ * else: those hold no token, so the fallback would have no authority behind
75
+ * it. See `adapters/env-passphrase.ts` for the whole argument.
76
+ */
77
+ envFilePath?: string;
78
+ /** The keychain / secret-service seam, injectable exactly as it is there. */
79
+ sourceRunner?: SourceRunner;
80
+ }
81
+ /**
82
+ * A provider that answers from the encrypted vault.
83
+ *
84
+ * **Lazy, and cached for the life of the provider.** The vault is not opened
85
+ * until an adapter actually asks for something, so an execution that needs no
86
+ * credential pays no scrypt cost and touches no ciphertext. Once opened, the
87
+ * derived value for a name is remembered, because a provider's life *is* one
88
+ * `act` call: the contract closes it when `act` returns, so the cache cannot
89
+ * outlive the token window it was built for, and the alternative — a fresh
90
+ * ~100 ms key derivation per credential — would put a visible tax on an adapter
91
+ * that needs two.
92
+ *
93
+ * The passphrase is read from the environment on every open rather than
94
+ * captured at construction, so a provider built before the operator exported the
95
+ * variable is not permanently poisoned.
96
+ *
97
+ * **The scoped fallback (APRV-168).** When {@link VaultProviderOptions.envFilePath}
98
+ * is supplied AND the contract has told this provider it is inside a token
99
+ * window, a passphrase absent from the environment is resolved from the
100
+ * instance's `.approval/env` instead. That is the one narrowing of
101
+ * `core/env-file.ts`'s "no verb reads this file" rule, and the whole argument
102
+ * for it lives in `adapters/env-passphrase.ts`. The short form: the authority is
103
+ * the token, and a human tapped Approve for exactly this action. The value is
104
+ * used to derive one key and reaches no environment, no argv, no log, and no
105
+ * message; the cache is dropped when the window closes, so a passphrase resolved
106
+ * under one grant opens nothing under the next.
107
+ *
108
+ * Messages name the environment VARIABLE and the credential NAME, and never a
109
+ * value: an adapter's failure message is one of the strings the contract hands
110
+ * back to a caller, and a diagnostic that quoted the secret would defeat the
111
+ * redaction guard by putting the secret in the one place the guard cannot know
112
+ * to look for it.
113
+ */
114
+ export declare function vaultCredentialProvider(location: VaultLocation, options: VaultProviderOptions): CredentialProvider;
@@ -13,9 +13,9 @@
13
13
  * A provider built here is only ever handed to
14
14
  * {@link executeThroughAdapter} through {@link AdapterExecuteOptions.credentials}.
15
15
  * The contract wraps it in a window that closes the instant `act` returns, so
16
- * every read is inside a verified, consumed, single-use token — which is what
17
- * SPEC.md §10.4 means by "the credentials only answer to tokens". Three things
18
- * hold that rule up, and none of them is a convention:
16
+ * every read during `act` is inside a verified execution. Manual and selected
17
+ * live paths consume a token; explicitly authorized supervised or autonomous
18
+ * paths do not. Three things hold that rule up, and none is a convention:
19
19
  *
20
20
  * 1. `core/vault.ts` exports exactly one function that returns a credential
21
21
  * value (`getCredential`), and this module is its only caller in the
@@ -0,0 +1,66 @@
1
+ /**
2
+ * Credential-custody transport for zzz.bot messages (APRV-320).
3
+ *
4
+ * The adapter sends only the JSON value a grant binds. Destination selection
5
+ * is a strict tagged union over two fixed service origins; neither the CLI nor
6
+ * the payload can supply an arbitrary URL. The Bearer credential comes only
7
+ * from the scoped provider opened by the shared adapter contract.
8
+ */
9
+ import type { CredentialSpec } from "../core/credential-spec.js";
10
+ import { type Adapter, type JsonValue } from "./contract.js";
11
+ export declare const ZZZ_CLASS = "communicate.zzz.external";
12
+ export declare const ZZZ_PRODUCTION_API_BASE = "https://zzz.bot";
13
+ export declare const ZZZ_PREVIEW_API_BASE = "https://zzz-preview.soycarts.workers.dev";
14
+ export declare const ZZZ_DEFAULT_TIMEOUT_MS = 15000;
15
+ export declare const ZZZ_TOKEN_NAME = "zzz.agent_token";
16
+ export declare const ZZZ_FAILURE_CODES: readonly ["zzz-payload-invalid", "zzz-config-invalid", "zzz-invalid-request", "zzz-unauthorized", "zzz-forbidden", "zzz-not-found", "zzz-idempotency-conflict", "zzz-payload-too-large", "zzz-rejected", "zzz-rate-limited", "zzz-unreachable", "zzz-cancelled", "credential-unavailable", "credential-refused", "credential-window-closed"];
17
+ export declare const ZZZ_CREDENTIAL_SPECS: readonly CredentialSpec[];
18
+ type Reference = {
19
+ kind: "external" | "post";
20
+ target: string;
21
+ label: string;
22
+ relationship: "source" | "context" | "supersedes";
23
+ };
24
+ type Message = {
25
+ body: string;
26
+ metadata?: JsonValue;
27
+ tags?: string[];
28
+ references?: Reference[];
29
+ };
30
+ export type ZzzPayload = ({
31
+ environment: "production" | "preview";
32
+ operation: "create_thread";
33
+ room_id: string;
34
+ title: string;
35
+ } & Message) | ({
36
+ environment: "production" | "preview";
37
+ operation: "create_reply";
38
+ thread_id: string;
39
+ } & Message);
40
+ type Validation = {
41
+ ok: true;
42
+ payload: ZzzPayload;
43
+ path: string;
44
+ body: Record<string, JsonValue>;
45
+ } | {
46
+ ok: false;
47
+ message: string;
48
+ };
49
+ export declare function validateZzzPayload(value: JsonValue): Validation;
50
+ export interface ZzzAdapterOptions {
51
+ fetch?: typeof globalThis.fetch;
52
+ timeoutMs?: number;
53
+ /** Constructor-only test seam. The CLI never exposes these values. */
54
+ origins?: Partial<Record<"production" | "preview", string>>;
55
+ }
56
+ export declare function zzzAdapter(options?: ZzzAdapterOptions): Adapter;
57
+ export type ZzzProbeResult = {
58
+ ok: true;
59
+ } | {
60
+ ok: false;
61
+ code: string;
62
+ message: string;
63
+ };
64
+ /** Read-only authentication probe. It proves no write scope or room access. */
65
+ export declare function probeZzz(token: string, options?: ZzzAdapterOptions): Promise<ZzzProbeResult>;
66
+ export {};