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,299 @@
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 { createHash } from "node:crypto";
10
+ import { canonicalize } from "../core/jcs.js";
11
+ import { payloadHash } from "../core/payload.js";
12
+ import { CREDENTIAL_REFUSAL_CODES, PROVIDER_REF_DETAIL_KEY, } from "./contract.js";
13
+ export const ZZZ_CLASS = "communicate.zzz.external";
14
+ export const ZZZ_PRODUCTION_API_BASE = "https://zzz.bot";
15
+ export const ZZZ_PREVIEW_API_BASE = "https://zzz-preview.soycarts.workers.dev";
16
+ export const ZZZ_DEFAULT_TIMEOUT_MS = 15_000;
17
+ export const ZZZ_TOKEN_NAME = "zzz.agent_token";
18
+ const TOKEN = /^[A-Za-z0-9_-]{32,256}$/u;
19
+ const PROVIDER_ID = /^(?:thr|pst)_[a-f0-9]{32}$/u;
20
+ const MAX_MESSAGE_BYTES = 65_536;
21
+ const MAX_RESPONSE_BYTES = 16_384;
22
+ export const ZZZ_FAILURE_CODES = [
23
+ "zzz-payload-invalid",
24
+ "zzz-config-invalid",
25
+ "zzz-invalid-request",
26
+ "zzz-unauthorized",
27
+ "zzz-forbidden",
28
+ "zzz-not-found",
29
+ "zzz-idempotency-conflict",
30
+ "zzz-payload-too-large",
31
+ "zzz-rejected",
32
+ "zzz-rate-limited",
33
+ "zzz-unreachable",
34
+ "zzz-cancelled",
35
+ ...CREDENTIAL_REFUSAL_CODES,
36
+ ];
37
+ export const ZZZ_CREDENTIAL_SPECS = [
38
+ {
39
+ name: ZZZ_TOKEN_NAME,
40
+ kind: "secret",
41
+ label: "ZZZ agent token",
42
+ describe: "an invited zzz.bot principal credential with write scope",
43
+ required: true,
44
+ validate(value) {
45
+ return TOKEN.test(value)
46
+ ? { ok: true }
47
+ : {
48
+ ok: false,
49
+ message: "the ZZZ agent token must be 32 to 256 ASCII letters, digits, underscores, or hyphens",
50
+ };
51
+ },
52
+ },
53
+ ];
54
+ function object(value) {
55
+ return typeof value === "object" && value !== null && !Array.isArray(value)
56
+ ? value
57
+ : null;
58
+ }
59
+ function exactKeys(value, allowed) {
60
+ const extra = Object.keys(value).find((key) => !allowed.includes(key));
61
+ return extra === undefined ? null : extra;
62
+ }
63
+ function boundedString(value, min, max) {
64
+ return typeof value === "string" && value.length >= min && value.length <= max;
65
+ }
66
+ function validReferences(value) {
67
+ if (value === undefined)
68
+ return true;
69
+ if (!Array.isArray(value) || value.length > 20)
70
+ return false;
71
+ return value.every((candidate) => {
72
+ const ref = object(candidate);
73
+ if (ref === null || exactKeys(ref, ["kind", "target", "label", "relationship"]) !== null)
74
+ return false;
75
+ if (!boundedString(ref["target"], 1, 2048) || !boundedString(ref["label"], 1, 120))
76
+ return false;
77
+ if (ref["kind"] !== "external" && ref["kind"] !== "post")
78
+ return false;
79
+ if (!["source", "context", "supersedes"].includes(String(ref["relationship"])))
80
+ return false;
81
+ if (ref["kind"] === "external") {
82
+ try {
83
+ const url = new URL(ref["target"]);
84
+ if (url.protocol !== "http:" && url.protocol !== "https:")
85
+ return false;
86
+ }
87
+ catch {
88
+ return false;
89
+ }
90
+ }
91
+ return true;
92
+ });
93
+ }
94
+ export function validateZzzPayload(value) {
95
+ const input = object(value);
96
+ if (input === null)
97
+ return { ok: false, message: "the payload must be one JSON object" };
98
+ if (input["environment"] !== "production" && input["environment"] !== "preview") {
99
+ return { ok: false, message: "environment must be production or preview" };
100
+ }
101
+ if (input["operation"] !== "create_thread" && input["operation"] !== "create_reply") {
102
+ return { ok: false, message: "operation must be create_thread or create_reply" };
103
+ }
104
+ const common = ["environment", "operation", "body", "metadata", "tags", "references"];
105
+ const allowed = input["operation"] === "create_thread"
106
+ ? [...common, "room_id", "title"]
107
+ : [...common, "thread_id"];
108
+ const extra = exactKeys(input, allowed);
109
+ if (extra !== null)
110
+ return { ok: false, message: `unknown payload field ${JSON.stringify(extra)}` };
111
+ if (!boundedString(input["body"], 1, 65_536))
112
+ return { ok: false, message: "body must contain 1 to 65536 characters" };
113
+ if (input["tags"] !== undefined &&
114
+ (!Array.isArray(input["tags"]) || input["tags"].length > 10 ||
115
+ !input["tags"].every((tag) => boundedString(tag, 1, 40)))) {
116
+ return { ok: false, message: "tags must contain at most 10 strings of 1 to 40 characters" };
117
+ }
118
+ if (!validReferences(input["references"]))
119
+ return { ok: false, message: "references do not match the ZZZ API contract" };
120
+ let path;
121
+ if (input["operation"] === "create_thread") {
122
+ if (!boundedString(input["room_id"], 1, 256) || !boundedString(input["title"], 1, 200)) {
123
+ return { ok: false, message: "create_thread needs a room_id and a title of 1 to 200 characters" };
124
+ }
125
+ path = `/api/v1/rooms/${encodeURIComponent(input["room_id"])}/threads`;
126
+ }
127
+ else {
128
+ if (!boundedString(input["thread_id"], 1, 256))
129
+ return { ok: false, message: "create_reply needs a thread_id" };
130
+ path = `/api/v1/threads/${encodeURIComponent(input["thread_id"])}/posts`;
131
+ }
132
+ const body = {
133
+ ...(input["operation"] === "create_thread" ? { title: input["title"] } : {}),
134
+ body: input["body"],
135
+ ...(input["metadata"] === undefined ? {} : { metadata: input["metadata"] }),
136
+ ...(input["tags"] === undefined ? {} : { tags: input["tags"] }),
137
+ ...(input["references"] === undefined ? {} : { references: input["references"] }),
138
+ };
139
+ if (new TextEncoder().encode(canonicalize(body)).byteLength > MAX_MESSAGE_BYTES) {
140
+ return { ok: false, message: "the canonical ZZZ message exceeds 65536 UTF-8 bytes" };
141
+ }
142
+ return { ok: true, payload: input, path, body };
143
+ }
144
+ function idempotencyKey(actionKey, hash) {
145
+ const bytes = canonicalize({ action_key: actionKey, payload_hash: hash });
146
+ return `approval:${createHash("sha256").update(bytes, "utf8").digest("hex")}`;
147
+ }
148
+ function codeForStatus(status) {
149
+ if (status === 400)
150
+ return "zzz-invalid-request";
151
+ if (status === 401)
152
+ return "zzz-unauthorized";
153
+ if (status === 403)
154
+ return "zzz-forbidden";
155
+ if (status === 404)
156
+ return "zzz-not-found";
157
+ if (status === 409)
158
+ return "zzz-idempotency-conflict";
159
+ if (status === 413)
160
+ return "zzz-payload-too-large";
161
+ if (status === 422)
162
+ return "zzz-rejected";
163
+ if (status === 429)
164
+ return "zzz-rate-limited";
165
+ return "zzz-rejected";
166
+ }
167
+ async function boundedJson(response) {
168
+ const reader = response.body?.getReader();
169
+ if (reader === undefined)
170
+ throw new Error("ZZZ returned no response body");
171
+ const chunks = [];
172
+ let size = 0;
173
+ while (true) {
174
+ const item = await reader.read();
175
+ if (item.done)
176
+ break;
177
+ size += item.value.byteLength;
178
+ if (size > MAX_RESPONSE_BYTES) {
179
+ await reader.cancel();
180
+ throw new Error("ZZZ returned an oversized response");
181
+ }
182
+ chunks.push(item.value);
183
+ }
184
+ const joined = new Uint8Array(size);
185
+ let offset = 0;
186
+ for (const chunk of chunks) {
187
+ joined.set(chunk, offset);
188
+ offset += chunk.byteLength;
189
+ }
190
+ return JSON.parse(new TextDecoder().decode(joined));
191
+ }
192
+ function originFor(environment, options) {
193
+ return options.origins?.[environment] ??
194
+ (environment === "production" ? ZZZ_PRODUCTION_API_BASE : ZZZ_PREVIEW_API_BASE);
195
+ }
196
+ export function zzzAdapter(options = {}) {
197
+ const fetchImpl = options.fetch ?? globalThis.fetch;
198
+ const timeoutMs = options.timeoutMs ?? ZZZ_DEFAULT_TIMEOUT_MS;
199
+ return {
200
+ name: "zzz",
201
+ classes: [ZZZ_CLASS],
202
+ requiredCredentials: [ZZZ_TOKEN_NAME],
203
+ precheck(input) {
204
+ const checked = validateZzzPayload(input.payload);
205
+ return checked.ok
206
+ ? { ok: true }
207
+ : { ok: false, code: "zzz-payload-invalid", message: `${checked.message}. Nothing was sent` };
208
+ },
209
+ async act(input) {
210
+ const checked = validateZzzPayload(input.payload);
211
+ if (!checked.ok)
212
+ return { ok: false, code: "zzz-payload-invalid", message: `${checked.message}. Nothing was sent` };
213
+ const credential = input.credentials.get(ZZZ_TOKEN_NAME);
214
+ if (!credential.ok)
215
+ return { ok: false, code: credential.code, message: credential.message };
216
+ if (!TOKEN.test(credential.value)) {
217
+ return { ok: false, code: "zzz-config-invalid", message: "the vault's ZZZ agent token does not match the service credential shape. Nothing was sent" };
218
+ }
219
+ if (input.signal?.aborted === true) {
220
+ return { ok: false, code: "zzz-cancelled", message: "the ZZZ message was cancelled before the HTTP request. Nothing was sent" };
221
+ }
222
+ const environment = checked.payload.environment;
223
+ const controller = new AbortController();
224
+ const timer = setTimeout(() => controller.abort(), timeoutMs);
225
+ const abort = () => controller.abort();
226
+ input.signal?.addEventListener("abort", abort, { once: true });
227
+ try {
228
+ const response = await fetchImpl(new URL(checked.path, originFor(environment, options)), {
229
+ method: "POST",
230
+ redirect: "error",
231
+ signal: controller.signal,
232
+ headers: {
233
+ Authorization: `Bearer ${credential.value}`,
234
+ "Content-Type": "application/json",
235
+ "Idempotency-Key": idempotencyKey(input.actionKey, payloadHash(input.payload)),
236
+ },
237
+ body: canonicalize(checked.body),
238
+ });
239
+ const definiteRefusal = [400, 401, 403, 404, 409, 413, 422, 429].includes(response.status);
240
+ if (response.status !== 200 && response.status !== 201 && !definiteRefusal) {
241
+ await response.body?.cancel().catch(() => undefined);
242
+ throw new Error(`ZZZ answered an ambiguous HTTP status ${String(response.status)}`);
243
+ }
244
+ if (definiteRefusal) {
245
+ await response.body?.cancel().catch(() => undefined);
246
+ return { ok: false, code: codeForStatus(response.status), message: `ZZZ refused the message with HTTP ${String(response.status)}. No response text was recorded` };
247
+ }
248
+ const answer = await boundedJson(response);
249
+ const parsed = object(answer);
250
+ const expectedPrefix = checked.payload.operation === "create_thread" ? "thr_" : "pst_";
251
+ if (parsed === null || exactKeys(parsed, ["id", "replayed"]) !== null ||
252
+ typeof parsed["id"] !== "string" || !PROVIDER_ID.test(parsed["id"]) ||
253
+ !parsed["id"].startsWith(expectedPrefix) || typeof parsed["replayed"] !== "boolean" ||
254
+ parsed["replayed"] !== (response.status === 200)) {
255
+ throw new Error("ZZZ returned an inconsistent success receipt");
256
+ }
257
+ return {
258
+ ok: true,
259
+ detail: {
260
+ [PROVIDER_REF_DETAIL_KEY]: parsed["id"],
261
+ replayed: parsed["replayed"],
262
+ operation: checked.payload.operation,
263
+ payload_hash: payloadHash(input.payload),
264
+ },
265
+ };
266
+ }
267
+ finally {
268
+ clearTimeout(timer);
269
+ input.signal?.removeEventListener("abort", abort);
270
+ }
271
+ },
272
+ };
273
+ }
274
+ /** Read-only authentication probe. It proves no write scope or room access. */
275
+ export async function probeZzz(token, options = {}) {
276
+ if (!TOKEN.test(token))
277
+ return { ok: false, code: "zzz-config-invalid", message: "the ZZZ agent token does not match the service credential shape" };
278
+ const controller = new AbortController();
279
+ const timer = setTimeout(() => controller.abort(), options.timeoutMs ?? ZZZ_DEFAULT_TIMEOUT_MS);
280
+ try {
281
+ const response = await (options.fetch ?? globalThis.fetch)(new URL("/api/v1/rooms", originFor("production", options)), {
282
+ method: "GET",
283
+ redirect: "error",
284
+ signal: controller.signal,
285
+ headers: { Authorization: `Bearer ${token}` },
286
+ });
287
+ await response.body?.cancel().catch(() => undefined);
288
+ if (response.status === 200)
289
+ return { ok: true };
290
+ return { ok: false, code: codeForStatus(response.status), message: `ZZZ answered HTTP ${String(response.status)}; no response text was recorded` };
291
+ }
292
+ catch {
293
+ return { ok: false, code: "zzz-unreachable", message: "ZZZ could not be reached for the read-only credential check" };
294
+ }
295
+ finally {
296
+ clearTimeout(timer);
297
+ }
298
+ }
299
+ //# sourceMappingURL=zzz.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"zzz.js","sourceRoot":"","sources":["../../../src/adapters/zzz.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,109 @@
1
+ /**
2
+ * Batching: one human gesture over many requests, without losing audit
3
+ * granularity (SPEC.md §10.3, requirement B7).
4
+ *
5
+ * > Channels MAY present multiple pending requests as a batch and collect one
6
+ * > human gesture over the set, and SHOULD for high-volume `record.*` classes.
7
+ * > The log never batches: each granted or rejected request receives its own
8
+ * > `approval.granted` or `approval.rejected` event carrying the batch's channel
9
+ * > delivery id in its payload, so audit granularity survives ergonomic
10
+ * > grouping. A batch MUST NOT mix `manual` classes with differing
11
+ * > payload-display requirements in a way that hides any full payload behind the
12
+ * > fold of another.
13
+ *
14
+ * Two halves, and this module is both: {@link assembleBatch} enforces the
15
+ * forbidden mix *before* anything is delivered, and {@link recordBatchDecisions}
16
+ * records one gate decision per member afterwards.
17
+ *
18
+ * ## The B7 operationalization — FLAGGED FOR HUMAN REVIEW
19
+ *
20
+ * "Hides any full payload behind the fold of another" is a sentence about
21
+ * rendering, and rendering is the one thing the runtime cannot inspect. So B7 is
22
+ * operationalized here as a property of the *batch material* rather than of the
23
+ * pixels:
24
+ *
25
+ * > A batch MUST carry every member's full payload whole. The forbidden mix is
26
+ * > any member whose `fullPayload` is absent or truncated while the batch
27
+ * > contains more than one distinct payload — because with one payload there is
28
+ * > no "another" to hide behind, and with two or more, a member the channel was
29
+ * > not given in full is a member the approver cannot have read.
30
+ *
31
+ * Concretely, {@link assembleBatch} refuses when the batch holds more than one
32
+ * distinct `payload_hash` **and** any member's `fullPayload` is `null` or
33
+ * `truncated`. A single-payload batch (the same bytes requested twice, or one
34
+ * request) is always assemblable, and a multi-payload batch is assemblable
35
+ * exactly when every member arrives whole.
36
+ *
37
+ * What this deliberately does **not** try to be: a judgment about whether a
38
+ * particular channel's layout actually put payload #2 below the fold. That is a
39
+ * per-channel rendering property, and `channels/conformance.ts` checks the
40
+ * observable half of it (every member's full payload text present in the
41
+ * rendering, delineated from the claimed summary). The interpretation to
42
+ * confirm is the reduction of "differing payload-display requirements" to
43
+ * "distinct payload bytes": it is the reading that makes the rule mechanical,
44
+ * and it is stricter than the spec's letter in one direction (two whole payloads
45
+ * are fine only if both are whole) and silent in another (it says nothing about
46
+ * a channel that renders both whole and then collapses one). A human should
47
+ * confirm this is the intended reading before APRV-23/25/26 build against it.
48
+ */
49
+ import type { DecideOptions } from "../core/gate.js";
50
+ import { type ChannelActorOptions, type ChannelBatch, type ChannelDecision, type ChannelRequest, type DecisionOutcome, type DeliveryId } from "./contract.js";
51
+ export { BATCH_DELIVERY_ID_FIELD, BATCH_DELIVERY_NOTE_PREFIX, batchDeliveryIdOf, batchNote, type ChannelBatch, } from "./contract.js";
52
+ /** The one way a batch can be refused (SPEC.md §10.3, B7). */
53
+ export declare const BATCH_REFUSAL_CODE = "batch-forbidden-mix";
54
+ export interface BatchRefusal {
55
+ ok: false;
56
+ code: typeof BATCH_REFUSAL_CODE;
57
+ message: string;
58
+ }
59
+ export type AssembleBatchResult = {
60
+ ok: true;
61
+ batch: ChannelBatch;
62
+ } | BatchRefusal;
63
+ /**
64
+ * Assemble `requests` into a batch, or refuse the forbidden mix.
65
+ *
66
+ * The returned batch carries every member request **whole** — the same
67
+ * {@link ChannelRequest} objects a channel would receive individually, tags and
68
+ * full payloads included. A channel therefore has everything it needs to render
69
+ * each member in full; if it chooses not to, that is a rendering defect the
70
+ * conformance suite catches, not a gap in the material it was handed.
71
+ *
72
+ * `deliveryId` is left unset: it is assigned by the channel at `notify`.
73
+ */
74
+ export declare function assembleBatch(requests: ChannelRequest[]): AssembleBatchResult;
75
+ /** One member's outcome. `token` is held back from the channel, as always. */
76
+ export interface BatchMemberResult {
77
+ action_key: string;
78
+ outcome: DecisionOutcome;
79
+ /** The raw execution token for a successful grant. Runtime-only. */
80
+ token?: string;
81
+ }
82
+ export interface BatchDecisionsResult {
83
+ /** True when every member was recorded. */
84
+ ok: boolean;
85
+ /** One entry per input decision, in input order. */
86
+ results: BatchMemberResult[];
87
+ batchDeliveryId: DeliveryId;
88
+ }
89
+ /**
90
+ * Record one gate decision per batch member.
91
+ *
92
+ * **Unit decisions mean unit outcomes.** The log never batches (SPEC.md §10.3),
93
+ * so this is a loop over `decide()` and not a transaction: each member is
94
+ * checked and appended on its own, each carries the batch delivery id in its
95
+ * payload as the first-class `batch_delivery_id` field (amended SPEC.md §10.3,
96
+ * APRV-38), and a member that refuses does **not** stop the rest. That is
97
+ * deliberate and it is the only coherent semantics available — an "all or
98
+ * nothing" batch would have to un-append events the log forbids un-appending,
99
+ * and abandoning the remaining members because the third one expired would
100
+ * discard a human's answer to the other four. So: partial success is a real
101
+ * outcome, `ok` is false when any member refused, and `results` says exactly
102
+ * which ones landed. A caller that wants atomicity does not want a batch.
103
+ *
104
+ * Ordering: members are recorded in the order given. Each append passes the
105
+ * gate's compare-and-append precondition against the head *it* read, so a
106
+ * concurrent writer refuses one member with `append-failed`/`head-moved`
107
+ * rather than corrupting the set.
108
+ */
109
+ export declare function recordBatchDecisions(logPath: string, decisions: ChannelDecision[], batchDeliveryId: DeliveryId, actorOptions: ChannelActorOptions, gateOptions?: DecideOptions): BatchDecisionsResult;
@@ -0,0 +1,193 @@
1
+ /**
2
+ * The CLI channel (APRV-23) — the zero-config channel, written against the
3
+ * contract in `channels/contract.ts` and nothing else.
4
+ *
5
+ * It is the first implementation of {@link TestableChannel}, and it exists as
6
+ * much to prove the contract is implementable as to be useful: a terminal has no
7
+ * stylesheet, no buttons and no webhook, so everything the contract asks a
8
+ * channel to do has to be done in plain text. If SPEC.md §9's display rule
9
+ * cannot survive a channel this poor, it cannot survive a rich one either.
10
+ *
11
+ * ## The rendering convention (SPEC.md §9)
12
+ *
13
+ * Every line carries a marker in the first column, and the marker is the first
14
+ * thing a reader sees:
15
+ *
16
+ * ```
17
+ * [computed] class communicate.email.external (log)
18
+ * [claimed] summary chase invoice 41 (agent:drafter)
19
+ * ```
20
+ *
21
+ * `[computed]` means the runtime derived the value — from the verified log, the
22
+ * attested policy, the budget evaluator, the payload bytes, or arithmetic on the
23
+ * display instant — and the parenthetical names *which* derivation. `[claimed]`
24
+ * means the party under oversight wrote it, and the parenthetical names that
25
+ * party. The marker is not decoration: it is the difference between "the runtime
26
+ * says this is a manual action" and "an agent says this costs two cents", and a
27
+ * channel that gave them the same weight would be a conformance failure rather
28
+ * than a styling preference.
29
+ *
30
+ * Claimed lines are additionally indented under a `claimed by …` heading, so the
31
+ * split survives a terminal that eats no colour and a reader who skims. There is
32
+ * no bold, no colour and no unicode box drawing anywhere in this file — a marker
33
+ * a `less`, a pipe, a CI log or a screen reader can lose is a marker that was
34
+ * never there.
35
+ *
36
+ * ## The full payload (SPEC.md §10.4)
37
+ *
38
+ * For a manual action the payload is printed verbatim inside an explicitly
39
+ * delimited block:
40
+ *
41
+ * ```
42
+ * --- BEGIN FULL PAYLOAD (bound sha256 <hash>) ---
43
+ * { … }
44
+ * --- END FULL PAYLOAD ---
45
+ * ```
46
+ *
47
+ * The block is never mixed with the claimed summary, and the summary is never
48
+ * printed inside it. `channels/tagging.ts` has already checked those bytes
49
+ * against the recorded binding, so what is inside the delimiters is what the
50
+ * execution token will spend.
51
+ *
52
+ * ## What this file does NOT do
53
+ *
54
+ * It does not read the log, write the log, decide anything, or hold a token.
55
+ * The decision handler is registered by the runtime (`cli/channel.ts`) and its
56
+ * only job is to call {@link recordChannelDecision}. The prompt loop collects a
57
+ * gesture and hands it over; whether that gesture becomes an event is the gate's
58
+ * answer, not this file's.
59
+ *
60
+ * It also does not dispatch (APRV-55). This channel is **one-shot by design**:
61
+ * the runtime derives the queue once, renders it, collects decisions on the
62
+ * requests in front of the operator, and the process ends. There is no cycle in
63
+ * which a newly appended request could arrive, so there is nothing to push —
64
+ * the operator running the verb again is the refresh. Only the long-lived push
65
+ * channel (Telegram) needs a per-cycle send; the long-lived pull channel (web)
66
+ * re-derives per page view.
67
+ */
68
+ import { type PromptLayout } from "../core/prompt-layout.js";
69
+ import type { ChannelBatch, ChannelDecision, ChannelHealth, ChannelRequest, DecisionOutcome, DeliveryId, RenderedRequest, TestableChannel } from "./contract.js";
70
+ /** The narrowest thing this channel needs to write to. `process.stdout` fits. */
71
+ export interface OutputSink {
72
+ write(text: string): unknown;
73
+ }
74
+ /** The narrowest thing this channel needs to read lines from. `process.stdin` fits. */
75
+ export type InputSource = NodeJS.ReadableStream;
76
+ export interface CliChannelOptions {
77
+ /** Where the rendering goes. Defaults to `process.stdout`. */
78
+ output?: OutputSink;
79
+ /** Where the gesture comes from. Defaults to `process.stdin`. */
80
+ input?: InputSource;
81
+ /** Channel name recorded for audit. Defaults to `cli`. */
82
+ name?: string;
83
+ /**
84
+ * Which rows the rendering shows (APRV-218), from `channels.cli.prompt`.
85
+ *
86
+ * Resolved by the verb, which has already loaded the policy; this channel
87
+ * neither reads a policy file nor holds an opinion about what an operator
88
+ * should see. Defaults to {@link CLI_PROMPT_LAYOUT}, so a channel constructed
89
+ * without one renders exactly what it rendered before the key existed.
90
+ */
91
+ layout?: PromptLayout;
92
+ }
93
+ /** The marker prefixes. Exported because the help text and the tests pin them. */
94
+ export declare const COMPUTED_MARKER = "[computed]";
95
+ export declare const CLAIMED_MARKER = "[claimed]";
96
+ /** The full-payload delimiters (SPEC.md §10.4). Pinned by tests. */
97
+ export declare const PAYLOAD_BEGIN = "--- BEGIN FULL PAYLOAD";
98
+ export declare const PAYLOAD_END = "--- END FULL PAYLOAD ---";
99
+ /** One line of the legend, printed above every delivery. */
100
+ export declare const RENDERING_LEGEND: string;
101
+ /** What {@link CliChannel.collectDecision} produced. */
102
+ export type CliCollection = {
103
+ kind: "decided";
104
+ decision: ChannelDecision;
105
+ outcome: DecisionOutcome;
106
+ }
107
+ /** The human declined to answer this one; nothing was reported. */
108
+ | {
109
+ kind: "skipped";
110
+ }
111
+ /** Input ended before an answer arrived; nothing was reported. */
112
+ | {
113
+ kind: "aborted";
114
+ };
115
+ export declare class CliChannel implements TestableChannel {
116
+ readonly name: string;
117
+ private readonly output;
118
+ private readonly input;
119
+ private handler;
120
+ private rendered;
121
+ private reader;
122
+ private counter;
123
+ /** The policy's row layout for this channel (APRV-218). Pure input to the rendering. */
124
+ private readonly layout;
125
+ constructor(options?: CliChannelOptions);
126
+ /**
127
+ * Present a request, or a batch, and return the delivery id.
128
+ *
129
+ * Writes to the output sink and nowhere else: no log, no state, no decision.
130
+ * A batch is rendered member by member — each member carries its own full
131
+ * payload, and folding one behind another is exactly what `channels/batch.ts`
132
+ * refuses upstream.
133
+ */
134
+ notify(request: ChannelRequest | ChannelBatch): DeliveryId;
135
+ onDecision(handler: (decision: ChannelDecision) => DecisionOutcome): void;
136
+ health(): ChannelHealth;
137
+ lastRendered(): RenderedRequest[];
138
+ /**
139
+ * Release the input interface. Safe to call when nothing was ever read.
140
+ *
141
+ * The source is paused as well as closed: a `readline` interface over
142
+ * `process.stdin` leaves the stream flowing, and a process that finished
143
+ * asking would sit there holding the event loop open.
144
+ */
145
+ close(): void;
146
+ /**
147
+ * The prompt loop: `g` grants, `r` rejects, `s` skips.
148
+ *
149
+ * A reject demands a note and re-asks until it gets one — a refusal an agent
150
+ * cannot read is a refusal it will retry. A grant's note is optional; there is
151
+ * nothing to explain about "yes, do the thing I was shown".
152
+ *
153
+ * The gesture is reported to the handler registered by the runtime, and the
154
+ * handler's {@link DecisionOutcome} is returned unchanged, refusals included.
155
+ * Nothing here inspects it, and nothing here retries: a gate refusal is an
156
+ * answer, and re-asking a human who already answered is how double-grants get
157
+ * made.
158
+ */
159
+ collectDecision(actionKey: string, deliveryId: DeliveryId, options?: {
160
+ batchDeliveryId?: DeliveryId;
161
+ }): Promise<CliCollection>;
162
+ /**
163
+ * The checkpoint prompt, in a terminal (APRV-257).
164
+ *
165
+ * The same question the Telegram tap asks, in the channel that has no
166
+ * buttons: the lines the runtime composed, then `s` to sign and `n` to
167
+ * decline. The text is the runtime's and identical on both surfaces, because
168
+ * the thing being consented to is identical and two phrasings of one gesture
169
+ * would be two claims about it.
170
+ *
171
+ * It collects a gesture and nothing else. What signing MEANS — the key, the
172
+ * head, the append — is the runtime's, exactly as a decision is: this channel
173
+ * can no more sign a checkpoint than it can grant a request.
174
+ *
175
+ * End of input is `null`, never a default. A closed pipe has not declined,
176
+ * and it certainly has not signed.
177
+ */
178
+ collectCheckpoint(lines: readonly string[]): Promise<boolean | null>;
179
+ private report;
180
+ /**
181
+ * Ask for a note. Returns `undefined` for "none given" and `null` when input
182
+ * ended — the two are different, and conflating them would let a closed pipe
183
+ * look like a human who chose to say nothing.
184
+ */
185
+ private askNote;
186
+ private readLine;
187
+ /**
188
+ * Build one request's rendering split. This is the same function whose output
189
+ * is written to the terminal — {@link lastRendered} is not a parallel
190
+ * description of the rendering, it *is* the rendering.
191
+ */
192
+ private renderRequest;
193
+ }