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,131 @@
1
+ /**
2
+ * `approval channel web` — the runtime half of the local web queue channel
3
+ * (SPEC.md §5.1 `channels.web.port`, §9, §10.3, §10.4, §11 — APRV-25).
4
+ *
5
+ * As everywhere else in this CLI, **no logic lives here**. Rendering and the
6
+ * HTTP server are `channels/web.ts`; turning a submitted form into an event is
7
+ * `channels/contract.ts`'s `recordChannelDecision` and `channels/batch.ts`'s
8
+ * `recordBatchDecisions`, both of which call the human-only `decide()` in
9
+ * `core/gate.ts`. This file resolves configuration, supplies the live pending
10
+ * queue, wires the two together, and chooses an exit code.
11
+ *
12
+ * Three things it does that the channel deliberately cannot:
13
+ *
14
+ * 1. **It reads the log.** {@link buildPendingQueue} runs here, once per page
15
+ * view, and the channel is handed the resulting {@link ChannelRequest}s. A
16
+ * channel that read the log would be deriving the facts it is meant to be
17
+ * transporting. Because that read happens per *request* rather than per
18
+ * process, this channel needs no dispatch of its own (APRV-55): a request
19
+ * appended while the server is running appears on the next page load, and a
20
+ * decided or TTL-lapsed one disappears the same way. Pull channels get for
21
+ * free what the Telegram listener has to arrange with a per-cycle send.
22
+ * 2. **It declares who is approving.** `--as` / `APPROVAL_HUMAN`, never
23
+ * anything the browser sent — there is nothing in an unauthenticated form
24
+ * post that could name a person. SPEC.md §11: identity is config-declared,
25
+ * the trust boundary is the local machine, and the page says so in a banner
26
+ * because the page is where the human is looking.
27
+ * 3. **It holds the token.** `recordChannelDecision` returns the raw execution
28
+ * token to *this* handler, which hands it back to the channel as one-shot
29
+ * *notice text* at render time and keeps no copy. See `channels/web.ts`'s
30
+ * header for why this channel shows the token on the page while the Telegram
31
+ * channel refuses to put it in a chat — that asymmetry is flagged there.
32
+ *
33
+ * ## Port precedence
34
+ *
35
+ * `--port` > `channels.web.port` in the attested policy > 4680. Nothing else:
36
+ * no environment variable, because a port that moves when an unrelated variable
37
+ * is exported is a port an operator will eventually fail to find, and no
38
+ * `--host` at any precedence at all (`channels/web.ts` explains).
39
+ *
40
+ * ## Identity is required at startup
41
+ *
42
+ * Unlike `approval channel cli`, which may merely *list* a queue, this verb
43
+ * exists to collect decisions: its only output is a page with Grant and Reject
44
+ * buttons on it. Starting a server whose buttons cannot record anything would
45
+ * spend a human's attention and then refuse their answer, so a missing or
46
+ * non-human identity is a usage error (2) before the socket is bound.
47
+ */
48
+ import type { Server } from "node:http";
49
+ import { type PayloadSource } from "../channels/tagging.js";
50
+ import { WebChannel } from "../channels/web.js";
51
+ import type { DecideOptions } from "../core/gate.js";
52
+ import { type PolicyLoadResult } from "../core/policy-load.js";
53
+ import type { Streams } from "./main.js";
54
+ /**
55
+ * `channels.web.port` from a loaded policy, or `null`.
56
+ *
57
+ * A policy that does not load, does not declare `channels`, or declares a port
58
+ * that is not a usable TCP port yields `null` — which means the default, not a
59
+ * crash: an operator whose policy has a typo in an optional cosmetic field
60
+ * should still get a queue page.
61
+ */
62
+ export declare function policyWebPort(load: PolicyLoadResult): number | null;
63
+ export type PortResolution = {
64
+ ok: true;
65
+ port: number;
66
+ } | {
67
+ ok: false;
68
+ message: string;
69
+ };
70
+ /** `--port` > policy `channels.web.port` > {@link WEB_DEFAULT_PORT}. */
71
+ export declare function resolveWebPort(portFlag: string | null, fromPolicy: number | null): PortResolution;
72
+ /**
73
+ * Payload material for one action key, from `--payload-dir` — the same shape
74
+ * `approval channel cli` uses, deliberately, so an operator's payload directory
75
+ * works with either channel.
76
+ *
77
+ * An override since APRV-28: with no flag the bytes come from the payload store
78
+ * beside the log, so the ordinary path needs no directory at all. This answers
79
+ * first for the keys it covers, and the store answers for the rest.
80
+ *
81
+ * The tagger re-hashes whatever this returns and refuses anything that does not
82
+ * match the recorded binding, so a wrong file produces a visible skip rather
83
+ * than a rendering of bytes the token would refuse to execute.
84
+ */
85
+ export declare function payloadSource(dir: string, complain: (message: string) => void): PayloadSource;
86
+ export interface StartWebChannelOptions {
87
+ /** The log to read the queue from, and to append decisions to. */
88
+ logPath: string;
89
+ /** The approver every decision is recorded against. Must be `human:<id>`. */
90
+ actor: string;
91
+ /** Where `APPROVAL.md` lives; passed to the tagger and to the gate. */
92
+ policy?: {
93
+ dir?: string;
94
+ file?: string;
95
+ };
96
+ /** Port to bind. `0` asks the OS for an ephemeral one (tests). */
97
+ port?: number;
98
+ /** Payload material for manual requests (SPEC.md §10.4). */
99
+ payload?: PayloadSource;
100
+ /** Where operational complaints go. Defaults to stderr. */
101
+ log?: (message: string) => void;
102
+ /** The display instant for each queue build. Injectable for tests. */
103
+ now?: () => string;
104
+ /** Extra gate options (an injected clock, a schema dir). */
105
+ gateOptions?: DecideOptions;
106
+ }
107
+ /** A running web channel. `close()` releases the socket. */
108
+ export interface RunningWebChannel {
109
+ server: Server;
110
+ channel: WebChannel;
111
+ port: number;
112
+ close(): Promise<void>;
113
+ }
114
+ /**
115
+ * Start the server and wire it to the gate.
116
+ *
117
+ * Exported for the tests and for the M5 daemon: the verb below is a thin shell
118
+ * around this, and a caller that wants a queue page inside its own process
119
+ * should not have to spawn a CLI to get one.
120
+ */
121
+ export declare function startWebChannel(options: StartWebChannelOptions): Promise<RunningWebChannel>;
122
+ /**
123
+ * `approval channel web` — serve the queue until interrupted.
124
+ *
125
+ * Long-lived, like `approval channel telegram listen`: it returns a promise
126
+ * that settles on SIGINT/SIGTERM, which is why `main` treats `channel`
127
+ * specially. There is no `--once`: a page is fetched by a human whenever they
128
+ * choose to look, so "handle exactly one request and exit" would be a shape
129
+ * nobody wants. Tests drive {@link startWebChannel} directly instead.
130
+ */
131
+ export declare function commandWeb(argv: string[], streams: Streams, cwd: string): number | Promise<number>;
@@ -0,0 +1,71 @@
1
+ /**
2
+ * `approval channel cli` (APRV-23) — the zero-config channel, driven over the
3
+ * plugin contract rather than around it.
4
+ *
5
+ * There is no second decision path in this codebase and this verb is not one.
6
+ * It builds the pending queue with `channels/tagging.ts`, hands each request to
7
+ * `channels/cli.ts` for rendering, and registers a decision handler whose entire
8
+ * body is a call to `recordChannelDecision` — which calls the human-only
9
+ * `decide()` in `core/gate.ts`. Every gate rule (human actor, TTL, budgets,
10
+ * attestation, idempotency, compare-and-append) applies here unchanged, because
11
+ * nothing here reimplements any of them.
12
+ *
13
+ * ## Interactive, and deliberately not by default
14
+ *
15
+ * A prompt that blocks is a prompt that hangs a pipeline. So the verb is
16
+ * interactive only when stdin is a TTY, or when `--interactive` says so
17
+ * explicitly; `--json` is never interactive. Anything else lists the queue and
18
+ * exits 0. That rule is in `--help` because an agent that shells out to this
19
+ * verb must be able to predict, before it spawns anything, whether the child
20
+ * will return.
21
+ *
22
+ * ## The reading aids (APRV-197)
23
+ *
24
+ * Two of them, and they are different in kind. The deterministic one is the
25
+ * `command_breakdown` line: derived by the classifier from the bound bytes,
26
+ * marked `[computed] (classifier)`, free, and always present for a command this
27
+ * runtime's own tokenizer can read. The other is the model gloss, which costs a
28
+ * subprocess and 10-15 seconds and is marked `(model, unverified)` on the line
29
+ * itself. Until APRV-197 only the Telegram listener attached the second, so an
30
+ * operator deciding here read the agent's raw summary and nothing else; the two
31
+ * surfaces now share `cli/gloss-attach.ts`. See {@link glossRunner} for when a
32
+ * model is asked at all — only under `--gloss`, and never on the `--json` path,
33
+ * which is not interactive and has nobody waiting at it.
34
+ *
35
+ * ## Identity is declared, not proved
36
+ *
37
+ * `--as human:<id>`, else `APPROVAL_HUMAN`. The trust boundary is the local
38
+ * machine: anyone who can set that variable and write to the log is inside it,
39
+ * so a decision recorded here proves that *someone with local control* answered,
40
+ * not *who*. Stated in `--help` rather than implied, because a reader who
41
+ * believes this authenticates anybody would be wrong in a way that matters. The
42
+ * identity is required only when a decision could be recorded — listing the
43
+ * queue asks nothing of anyone.
44
+ *
45
+ * ## Where the payload comes from
46
+ *
47
+ * v0.1's log records `payload_hash`, never the payload bytes, so the material to
48
+ * render comes from the payload store beside the log — `.approval/payloads/`,
49
+ * written by `approval request --payload` (APRV-28) — which is why this verb
50
+ * needs no flag at all in the ordinary case. `--payload-dir` remains as an
51
+ * override for an operator whose bytes live elsewhere: one JSON file per action
52
+ * key, consulted first. `channels/tagging.ts` hashes whatever it is given and refuses
53
+ * anything that does not match the recorded binding, so a wrong file is a
54
+ * refusal and never a rendering. A manual request with no material is *skipped*
55
+ * and reported — visibly, never silently, because a request missing from a queue
56
+ * is a request nobody will approve.
57
+ *
58
+ * ## The asynchronous exit code
59
+ *
60
+ * `main()` is synchronous by contract: `cli.js` assigns its return value to
61
+ * `process.exitCode`. The prompt loop is asynchronous (readline), so the
62
+ * interactive path returns {@link EXIT_OK} to `main` and assigns the real code
63
+ * to `process.exitCode` when the loop settles. Node exits with the last value
64
+ * assigned, so a refusal still exits 1. Every synchronous path — `--json`, a
65
+ * non-TTY listing, a usage error, an I/O fact — returns its code the ordinary
66
+ * way.
67
+ */
68
+ import type { Streams } from "./main.js";
69
+ export declare function commandChannelCli(argv: string[], streams: Streams, cwd: string): number;
70
+ /** `approval channel <subcommand>` — `cli`, `web` (APRV-25), `telegram`. */
71
+ export declare function commandChannel(argv: string[], streams: Streams, cwd: string): number | Promise<number>;
@@ -0,0 +1,169 @@
1
+ /**
2
+ * The checkpoint tap: custody, the offer, the prompt text, the signature
3
+ * (APRV-257, the delivery half of APRV-220).
4
+ *
5
+ * APRV-220 built the record and gave a human exactly one way to sign one:
6
+ * `approval log checkpoint` at a terminal, remembered. This file is what makes
7
+ * it happen without the remembering, and it is deliberately the ONLY file
8
+ * between a channel and a signature.
9
+ *
10
+ * ## Why custody lives here now
11
+ *
12
+ * `core/checkpoint.ts` takes the private key as a value and reads it from
13
+ * nowhere, so that one file decides where a checkpoint key may come from. Until
14
+ * this task that file was `cli/log-checkpoint.ts`, because the terminal verb was
15
+ * the only caller. It is not any more: the Telegram listener and the CLI channel
16
+ * both sign now. So the decision moved here rather than being copied, and
17
+ * `cli/log-checkpoint.ts` calls {@link resolveCheckpointKey} like everyone else.
18
+ * There is still exactly one place to read to learn every way a key can reach a
19
+ * signature, which was the whole property.
20
+ *
21
+ * Two sources, in this order, unchanged from APRV-220:
22
+ *
23
+ * 1. `--key-file <path>`, for a key an operator keeps outside the vault.
24
+ * 2. The credential vault, under `approval.checkpoint.key`. Encrypted at rest
25
+ * under the passphrase `vault.passphrase_env` names, which
26
+ * `core/child-env.ts` strips from every child this runtime spawns
27
+ * (APRV-205), behind a file whose reading classifies `account.credential`.
28
+ *
29
+ * There is no `--key` flag and no environment variable holding the key.
30
+ *
31
+ * ## Why an agent-launched process cannot reach any of this
32
+ *
33
+ * Three independent locks, and the tap adds none of its own — it inherits all
34
+ * three, which is why the tap can be built at all:
35
+ *
36
+ * 1. **Classification.** `approval log checkpoint` and `approval setup
37
+ * checkpoint` classify `policy.core` in `core/command-class.ts`, which the
38
+ * reference policy holds `human-only`, so the Claude Code hook denies both
39
+ * with `hook-class-human-only` before a process starts.
40
+ * 2. **The passphrase.** `core/child-env.ts` strips `vault.passphrase_env` from
41
+ * every child this runtime spawns, so a process an agent launched cannot
42
+ * open the vault even if it ran this code.
43
+ * 3. **The launch.** The listener holds the passphrase because a HUMAN
44
+ * exported it into the shell they started `approval up` in. Nothing an agent
45
+ * can do puts it into a process the agent controls.
46
+ *
47
+ * `tests/checkpoint-tap.test.ts` proves the first two and proves the third
48
+ * structurally: the hook's module graph never reaches this file.
49
+ *
50
+ * ## What the human is shown is what gets signed
51
+ *
52
+ * The offer carries a `(seq, hash)`; the prompt prints it; the signature covers
53
+ * it. The head may have moved several times over between the prompt and the tap
54
+ * — a phone is in a pocket and a daemon is not — and
55
+ * {@link ../core/checkpoint.js appendCheckpointAt} signs the head that was on
56
+ * the screen, checking first that this chain still carries those bytes at that
57
+ * seq. APRV-220's verify rule (a checkpoint signs any seq below its own) exists
58
+ * precisely so this is a legal record rather than a clever one.
59
+ */
60
+ import { type CheckpointOffer } from "../core/checkpoint.js";
61
+ /** Where a policy is, spelled the way every CLI verb spells it. */
62
+ export interface PolicyWhere {
63
+ file?: string;
64
+ dir?: string;
65
+ }
66
+ /** Everything a surface needs to offer and take a checkpoint. */
67
+ export interface CheckpointTap {
68
+ logPath: string;
69
+ policy: PolicyWhere;
70
+ /** `--key-file`, absolute, or `null` for the vault. */
71
+ keyFile: string | null;
72
+ /** An explicit vault path, or `null` for the one beside the log. */
73
+ vault: string | null;
74
+ schemaDir?: string;
75
+ }
76
+ /** Why no key could be had. One code: the repair is the message, not a branch. */
77
+ export declare const CHECKPOINT_KEY_REFUSAL = "checkpoint-key-unreadable";
78
+ export type KeyResolution = {
79
+ ok: true;
80
+ privateKey: string;
81
+ } | {
82
+ ok: false;
83
+ code: string;
84
+ message: string;
85
+ };
86
+ /**
87
+ * The private key, or a refusal naming which source failed and how to fix it.
88
+ *
89
+ * Moved verbatim from `cli/log-checkpoint.ts` (APRV-257) so that the terminal
90
+ * verb, the Telegram listener and the CLI channel share one answer to "where
91
+ * may a checkpoint key come from". The sentences are unchanged: an operator who
92
+ * has seen this refusal once should not meet it in new words on another
93
+ * surface.
94
+ */
95
+ export declare function resolveCheckpointKey(keyFile: string | null, logPath: string, vaultFlag: string | null, policyWhere: PolicyWhere, cwd: string,
96
+ /**
97
+ * Where the passphrase is read from. `process.env` in production.
98
+ *
99
+ * A seam and not a back door, and the same one `setup adapter` carries: it
100
+ * goes through {@link passphraseFrom}, which is the function `approval vault
101
+ * set` uses, and it never resolves `.approval/env` (SPEC.md §11.1 invariant
102
+ * 7). Injectable so a suite can prove the vault path without mutating an
103
+ * environment every other test in the process shares.
104
+ */
105
+ env?: NodeJS.ProcessEnv): KeyResolution;
106
+ /**
107
+ * The checkpoint this log is owed, or `null`.
108
+ *
109
+ * Reads the policy first and gives up the moment it names no cadence, so a
110
+ * dispatch cycle on a gate that has never turned checkpoints on pays one policy
111
+ * load and no log walk. Everything after that is
112
+ * {@link ../core/checkpoint.js checkpointDue} over verified records, which is
113
+ * the same call the daemon's warning and doctor's row make: three surfaces,
114
+ * one rule, no arrangement in which they disagree.
115
+ *
116
+ * A log that does not verify produces no offer and no complaint. A chain that
117
+ * is not fit to be read is not fit to be signed either, and the surfaces that
118
+ * exist to shout about a bad chain — `approval log verify`, the daemon's
119
+ * re-proof, doctor's `log` row — are already shouting.
120
+ */
121
+ export declare function checkpointOfferFor(tap: CheckpointTap, now?: number): CheckpointOffer | null;
122
+ /**
123
+ * What a human reads before they tap, on every channel.
124
+ *
125
+ * One text for every surface, because the thing being consented to is identical
126
+ * and a phone that phrased it differently from a terminal would be two claims
127
+ * about one gesture. The `(seq, hash)` is first and whole: it is the entire
128
+ * content of the signature, and an approver who cannot see what they are
129
+ * signing is not approving anything.
130
+ *
131
+ * The last line is the one that keeps this honest. Declining costs nothing —
132
+ * there is no path in this runtime from a checkpoint that is due to a refusal
133
+ * of anything — and a prompt that implied otherwise would be manufacturing
134
+ * pressure for a signature.
135
+ */
136
+ export declare function checkpointPromptLines(offer: CheckpointOffer): string[];
137
+ export type CheckpointTapResult = {
138
+ ok: true;
139
+ seq: number;
140
+ signed: {
141
+ seq: number;
142
+ hash: string;
143
+ };
144
+ fingerprint: string;
145
+ } | {
146
+ ok: false;
147
+ code: string;
148
+ message: string;
149
+ };
150
+ /**
151
+ * Sign one head and append the record, on the machine the channel runs on.
152
+ *
153
+ * `head` is the `(seq, hash)` that was on the screen, handed back by the
154
+ * channel unchanged. It is a head rather than the whole offer on purpose: by
155
+ * tap time the offer's cadence arithmetic is hours stale and nothing should be
156
+ * tempted to read it, while the head is the one part that must survive
157
+ * verbatim.
158
+ *
159
+ * The key is resolved at TAP time and not at offer time, and that ordering is
160
+ * the point: a prompt sitting on a phone for an hour holds no key material
161
+ * anywhere, and a listener whose vault the operator has since re-keyed refuses
162
+ * the tap with a sentence rather than signing with something stale.
163
+ */
164
+ export declare function signCheckpointOffer(tap: CheckpointTap, head: {
165
+ seq: number;
166
+ hash: string;
167
+ }, actor: string, channel: string, cwd: string): CheckpointTapResult;
168
+ /** What a channel says on the message it just edited, once a tap has landed. */
169
+ export declare function checkpointSignedLines(result: CheckpointTapResult): string[];
@@ -0,0 +1,2 @@
1
+ import type { Streams } from "./main.js";
2
+ export declare function commandCodex(argv: string[], streams: Streams, cwd: string): number;
@@ -0,0 +1,172 @@
1
+ import { resolve } from "node:path";
2
+ import { boolFlag, parseFlags, stringFlag } from "./args.js";
3
+ import { EXIT_INTEGRITY, EXIT_IO, EXIT_OK, EXIT_USAGE } from "./exit-codes.js";
4
+ import { CODEX_HELP } from "./help.js";
5
+ import { usageErrorText } from "./usage.js";
6
+ import { strictDoctor } from "../codex/doctor.js";
7
+ import { checkBundle, prepareBundle } from "../codex/templates.js";
8
+ function emitError(streams, json, code, message) {
9
+ if (json)
10
+ streams.err(`${JSON.stringify({ error: { code, message } })}\n`);
11
+ else
12
+ streams.err(`approval: ${message}\n`);
13
+ }
14
+ function usage(streams, json, message) {
15
+ if (json)
16
+ emitError(streams, true, "usage", message);
17
+ else
18
+ streams.err(usageErrorText(message, CODEX_HELP));
19
+ return EXIT_USAGE;
20
+ }
21
+ function required(flags, name) {
22
+ const value = stringFlag(flags, name);
23
+ return value === null || value.length === 0 ? null : value;
24
+ }
25
+ export function commandCodex(argv, streams, cwd) {
26
+ const json = argv.includes("--json");
27
+ const subcommand = argv[0];
28
+ const rest = argv.slice(1);
29
+ if (subcommand === undefined || subcommand === "--help" || subcommand === "-h") {
30
+ streams.out(`${CODEX_HELP}\n`);
31
+ return subcommand === undefined ? EXIT_USAGE : EXIT_OK;
32
+ }
33
+ if (subcommand === "prepare") {
34
+ const parsed = parseFlags(rest, {
35
+ "--instance": "string",
36
+ "--workspace": "string",
37
+ "--primary": "string",
38
+ "--install-root": "string",
39
+ "--output": "string",
40
+ "--codex": "string",
41
+ "--node": "string",
42
+ "--json": "boolean",
43
+ "--help": "boolean",
44
+ "-h": "boolean",
45
+ });
46
+ if (!parsed.ok)
47
+ return usage(streams, json, parsed.message);
48
+ if (boolFlag(parsed.flags, "--help") || boolFlag(parsed.flags, "-h")) {
49
+ streams.out(`${CODEX_HELP}\n`);
50
+ return EXIT_OK;
51
+ }
52
+ if (parsed.positionals.length > 0)
53
+ return usage(streams, json, "prepare takes flags only");
54
+ const names = ["--instance", "--workspace", "--primary", "--install-root", "--output", "--codex", "--node"];
55
+ const values = Object.fromEntries(names.map((name) => [name, required(parsed.flags, name)]));
56
+ const missing = names.find((name) => values[name] === null);
57
+ if (missing !== undefined)
58
+ return usage(streams, json, `prepare requires ${missing}`);
59
+ const result = prepareBundle({
60
+ instanceId: values["--instance"],
61
+ workspace: resolve(cwd, values["--workspace"]),
62
+ primary: resolve(cwd, values["--primary"]),
63
+ installRoot: resolve(cwd, values["--install-root"]),
64
+ output: resolve(cwd, values["--output"]),
65
+ codexExecutable: resolve(cwd, values["--codex"]),
66
+ nodeExecutable: resolve(cwd, values["--node"]),
67
+ });
68
+ if (!result.ok) {
69
+ emitError(streams, json, result.code, result.message);
70
+ return result.code === "manifest-invalid" || result.code === "output-overlap" ? EXIT_INTEGRITY : EXIT_IO;
71
+ }
72
+ if (json)
73
+ streams.out(`${JSON.stringify({ ok: true, inert: true, output: result.output, files: result.files, manifest: result.manifest })}\n`);
74
+ else
75
+ streams.out(`Prepared inert Codex host bundle at ${result.output}. Review it; no host configuration changed.\n`);
76
+ return EXIT_OK;
77
+ }
78
+ if (subcommand === "setup") {
79
+ const parsed = parseFlags(rest, {
80
+ "--check": "string",
81
+ "--json": "boolean",
82
+ "--help": "boolean",
83
+ "-h": "boolean",
84
+ });
85
+ if (!parsed.ok)
86
+ return usage(streams, json, parsed.message);
87
+ if (boolFlag(parsed.flags, "--help") || boolFlag(parsed.flags, "-h")) {
88
+ streams.out(`${CODEX_HELP}\n`);
89
+ return EXIT_OK;
90
+ }
91
+ if (parsed.positionals.length > 0)
92
+ return usage(streams, json, "setup takes flags only");
93
+ const directory = required(parsed.flags, "--check");
94
+ if (directory === null)
95
+ return usage(streams, json, "setup requires --check <bundle>");
96
+ const result = checkBundle(resolve(cwd, directory));
97
+ if (!result.ok) {
98
+ emitError(streams, json, result.code, result.message);
99
+ return EXIT_INTEGRITY;
100
+ }
101
+ const response = {
102
+ ok: true,
103
+ inert: true,
104
+ ready: false,
105
+ bundle: resolve(cwd, directory),
106
+ files: result.files,
107
+ reason: "broker-and-runner-not-shipped",
108
+ };
109
+ if (json)
110
+ streams.out(`${JSON.stringify(response)}\n`);
111
+ else
112
+ streams.out("Bundle is internally consistent and inert. Broker and runner are not shipped; do not activate it.\n");
113
+ return EXIT_OK;
114
+ }
115
+ if (subcommand === "doctor") {
116
+ const parsed = parseFlags(rest, {
117
+ "--manifest": "string",
118
+ "--strict": "boolean",
119
+ "--json": "boolean",
120
+ "--help": "boolean",
121
+ "-h": "boolean",
122
+ });
123
+ if (!parsed.ok)
124
+ return usage(streams, json, parsed.message);
125
+ if (boolFlag(parsed.flags, "--help") || boolFlag(parsed.flags, "-h")) {
126
+ streams.out(`${CODEX_HELP}\n`);
127
+ return EXIT_OK;
128
+ }
129
+ if (parsed.positionals.length > 0)
130
+ return usage(streams, json, "doctor takes flags only");
131
+ if (!boolFlag(parsed.flags, "--strict"))
132
+ return usage(streams, json, "doctor requires --strict");
133
+ const manifest = required(parsed.flags, "--manifest");
134
+ if (manifest === null)
135
+ return usage(streams, json, "doctor requires --manifest <path>");
136
+ const result = strictDoctor(resolve(cwd, manifest));
137
+ if (!result.ok) {
138
+ if (json)
139
+ streams.err(`${JSON.stringify({ ok: false, ready: false, error: { code: result.code, message: result.message }, findings: result.report?.findings ?? [] })}\n`);
140
+ else {
141
+ streams.err(`approval: ${result.message}\n`);
142
+ for (const finding of result.report?.findings ?? []) {
143
+ streams.err(` ${finding.code}${finding.path === undefined ? "" : ` ${finding.path}`}: ${finding.message}\n`);
144
+ }
145
+ }
146
+ return EXIT_INTEGRITY;
147
+ }
148
+ return EXIT_OK;
149
+ }
150
+ if (subcommand === "start" || subcommand === "serve") {
151
+ const parsed = parseFlags(rest, {
152
+ "--manifest": "string",
153
+ "--json": "boolean",
154
+ "--help": "boolean",
155
+ "-h": "boolean",
156
+ });
157
+ if (!parsed.ok)
158
+ return usage(streams, json, parsed.message);
159
+ if (boolFlag(parsed.flags, "--help") || boolFlag(parsed.flags, "-h")) {
160
+ streams.out(`${CODEX_HELP}\n`);
161
+ return EXIT_OK;
162
+ }
163
+ if (parsed.positionals.length > 0)
164
+ return usage(streams, json, `${subcommand} takes flags only`);
165
+ if (required(parsed.flags, "--manifest") === null)
166
+ return usage(streams, json, `${subcommand} requires --manifest <path>`);
167
+ emitError(streams, json, "codex-not-ready", `codex ${subcommand} is not implemented until APRV-325.2 and APRV-325.3 provide the broker and runner`);
168
+ return EXIT_INTEGRITY;
169
+ }
170
+ return usage(streams, json, `unknown codex subcommand ${JSON.stringify(subcommand)}`);
171
+ }
172
+ //# sourceMappingURL=codex.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"codex.js","sourceRoot":"","sources":["../../../src/cli/codex.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,61 @@
1
+ /**
2
+ * `approval coverage` — observed side effects, joined to the verified log
3
+ * (APRV-245, SPEC.md §10.1).
4
+ *
5
+ * ## What it answers
6
+ *
7
+ * "Here is everything the witnesses outside this runtime say happened, and here
8
+ * is what the log says about each one." Nothing more: the join is
9
+ * `core/coverage.ts`, the witnesses are `core/coverage-sources/`, and this file
10
+ * is argument parsing, source selection, and the rendering of a table.
11
+ *
12
+ * ## Why it exits 0 with gaps
13
+ *
14
+ * Because it is INFORMATIONAL, on exactly SPEC.md §10.1's rule for the APRV-145
15
+ * harness-start coverage in `approval status`: a coverage measurement is not an
16
+ * integrity verdict, and a control an operator learns to silence is worse than
17
+ * one that reports beside the verdict. A gap here is a question ("was this
18
+ * effect ever declared?"), and questions with legitimate answers must not fail
19
+ * a build. The two codes it can still emit are the filesystem's: 2 for a usage
20
+ * error and 4 for a log this process could not read, plus 3 for a torn tail,
21
+ * because a log it could not read is a report it did not make.
22
+ *
23
+ * ## Why a source that cannot be reached is not a gap
24
+ *
25
+ * A source reports `available: false` with a reason, and its effects are absent
26
+ * rather than uncovered. "`gh` is not on PATH" and "`gh` saw nothing" are
27
+ * different facts, and a report that flattened them would let a broken tool read
28
+ * as a clean bill of health. Every unavailable source prints its reason on its
29
+ * own line.
30
+ *
31
+ * ## Writes nothing, reads only verified records
32
+ *
33
+ * The log is read through `readVerifiedRecords` (SPEC.md §11.1 invariant 1) and
34
+ * nothing here appends, renders, or caches. Running it changes no state any
35
+ * later verdict depends on, which is what lets it be safe to run on a timer.
36
+ */
37
+ import { type CoverageEntry } from "../core/coverage.js";
38
+ import type { Streams } from "./main.js";
39
+ /** One source's contribution to the report, ready to print or serialize. */
40
+ interface RenderedSource {
41
+ name: string;
42
+ available: boolean;
43
+ reason: string | null;
44
+ entries: CoverageEntry[];
45
+ observed: number;
46
+ covered: number;
47
+ }
48
+ /**
49
+ * The evidence column, as one short string a reader can act on.
50
+ *
51
+ * The qualifier says how the record was found, so that a weaker match is never
52
+ * read as a stronger one and the strongest is not read as the ordinary one.
53
+ * `(id)` is APRV-251's: the record names this exact effect by the provider's own
54
+ * identifier, which is a different claim from "a record of this class sits in
55
+ * this effect's window" and prints as one.
56
+ */
57
+ export declare function evidenceText(entry: CoverageEntry): string;
58
+ /** The coverage line one source prints, in the shape the help promises. */
59
+ export declare function coverageLine(source: RenderedSource): string;
60
+ export declare function commandCoverage(argv: string[], streams: Streams, cwd: string): Promise<number>;
61
+ export {};