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.
- package/README.md +584 -553
- package/SPEC.md +42 -13
- package/dist/src/adapters/agentmail.d.ts +426 -0
- package/dist/src/adapters/agentmail.js +2 -2
- package/dist/src/adapters/conformance.d.ts +149 -0
- package/dist/src/adapters/contract.d.ts +628 -0
- package/dist/src/adapters/contract.js +110 -16
- package/dist/src/adapters/contract.js.map +1 -1
- package/dist/src/adapters/email.d.ts +324 -0
- package/dist/src/adapters/env-passphrase.d.ts +93 -0
- package/dist/src/adapters/public.d.ts +11 -0
- package/dist/src/adapters/public.js +11 -0
- package/dist/src/adapters/public.js.map +1 -0
- package/dist/src/adapters/registry.d.ts +59 -0
- package/dist/src/adapters/registry.js +2 -1
- package/dist/src/adapters/registry.js.map +1 -1
- package/dist/src/adapters/smtp.d.ts +213 -0
- package/dist/src/adapters/vault-provider.d.ts +114 -0
- package/dist/src/adapters/vault-provider.js +3 -3
- package/dist/src/adapters/zzz.d.ts +66 -0
- package/dist/src/adapters/zzz.js +299 -0
- package/dist/src/adapters/zzz.js.map +1 -0
- package/dist/src/channels/batch.d.ts +109 -0
- package/dist/src/channels/cli.d.ts +193 -0
- package/dist/src/channels/conformance.d.ts +92 -0
- package/dist/src/channels/contract.d.ts +623 -0
- package/dist/src/channels/payload-view.d.ts +35 -0
- package/dist/src/channels/render-queue.d.ts +149 -0
- package/dist/src/channels/tagging.d.ts +196 -0
- package/dist/src/channels/telegram.d.ts +1832 -0
- package/dist/src/channels/web.d.ts +341 -0
- package/dist/src/cli/adapter.d.ts +90 -0
- package/dist/src/cli/adapter.js +25 -15
- package/dist/src/cli/adapter.js.map +1 -1
- package/dist/src/cli/amend.d.ts +59 -0
- package/dist/src/cli/args.d.ts +43 -0
- package/dist/src/cli/attest.d.ts +41 -0
- package/dist/src/cli/audit-card.d.ts +62 -0
- package/dist/src/cli/audit.d.ts +59 -0
- package/dist/src/cli/channel-telegram.d.ts +806 -0
- package/dist/src/cli/channel-web.d.ts +131 -0
- package/dist/src/cli/channel.d.ts +71 -0
- package/dist/src/cli/checkpoint-tap.d.ts +169 -0
- package/dist/src/cli/codex.d.ts +2 -0
- package/dist/src/cli/codex.js +172 -0
- package/dist/src/cli/codex.js.map +1 -0
- package/dist/src/cli/coverage.d.ts +61 -0
- package/dist/src/cli/daemon.d.ts +120 -0
- package/dist/src/cli/doctor.d.ts +129 -0
- package/dist/src/cli/doctor.js +119 -5
- package/dist/src/cli/doctor.js.map +1 -1
- package/dist/src/cli/env.d.ts +65 -0
- package/dist/src/cli/execute.d.ts +202 -0
- package/dist/src/cli/exit-codes.d.ts +73 -0
- package/dist/src/cli/feedback.d.ts +60 -0
- package/dist/src/cli/gate-window.d.ts +40 -0
- package/dist/src/cli/gate.d.ts +68 -0
- package/dist/src/cli/git-scope.d.ts +190 -0
- package/dist/src/cli/gloss-attach.d.ts +85 -0
- package/dist/src/cli/gloss-codex-child.d.ts +9 -0
- package/dist/src/cli/gloss-codex.d.ts +24 -0
- package/dist/src/cli/gloss-options.d.ts +42 -0
- package/dist/src/cli/gloss.d.ts +265 -0
- package/dist/src/cli/help.d.ts +103 -0
- package/dist/src/cli/help.js +173 -51
- package/dist/src/cli/help.js.map +1 -1
- package/dist/src/cli/hook-codex.d.ts +78 -0
- package/dist/src/cli/hook-codex.js +167 -0
- package/dist/src/cli/hook-codex.js.map +1 -0
- package/dist/src/cli/hook.d.ts +331 -0
- package/dist/src/cli/hook.js +186 -80
- package/dist/src/cli/hook.js.map +1 -1
- package/dist/src/cli/import.d.ts +35 -0
- package/dist/src/cli/init.d.ts +84 -0
- package/dist/src/cli/init.js +2 -2
- package/dist/src/cli/init.js.map +1 -1
- package/dist/src/cli/instructions.d.ts +23 -0
- package/dist/src/cli/journal.d.ts +41 -0
- package/dist/src/cli/log-advance.d.ts +287 -0
- package/dist/src/cli/log-advance.js +102 -11
- package/dist/src/cli/log-advance.js.map +1 -1
- package/dist/src/cli/log-anchor.d.ts +176 -0
- package/dist/src/cli/log-checkpoint.d.ts +22 -0
- package/dist/src/cli/log-sync.d.ts +243 -0
- package/dist/src/cli/log-verbs.d.ts +16 -0
- package/dist/src/cli/log-verbs.js +7 -1
- package/dist/src/cli/log-verbs.js.map +1 -1
- package/dist/src/cli/long-help.d.ts +70 -0
- package/dist/src/cli/main.d.ts +77 -0
- package/dist/src/cli/main.js +155 -5
- package/dist/src/cli/main.js.map +1 -1
- package/dist/src/cli/mcp.d.ts +52 -0
- package/dist/src/cli/paths.d.ts +56 -0
- package/dist/src/cli/payload.d.ts +58 -0
- package/dist/src/cli/policy.d.ts +43 -0
- package/dist/src/cli/preflight.d.ts +363 -0
- package/dist/src/cli/preflight.js +294 -7
- package/dist/src/cli/preflight.js.map +1 -1
- package/dist/src/cli/progress.d.ts +78 -0
- package/dist/src/cli/prompt.d.ts +209 -0
- package/dist/src/cli/quickstart.d.ts +46 -0
- package/dist/src/cli/quickstart.js +297 -0
- package/dist/src/cli/quickstart.js.map +1 -0
- package/dist/src/cli/records.d.ts +34 -0
- package/dist/src/cli/render.d.ts +22 -0
- package/dist/src/cli/sandbox.d.ts +51 -0
- package/dist/src/cli/scaffold.d.ts +79 -0
- package/dist/src/cli/setup-adapter.d.ts +137 -0
- package/dist/src/cli/setup-adapter.js +38 -4
- package/dist/src/cli/setup-adapter.js.map +1 -1
- package/dist/src/cli/setup-channel.d.ts +117 -0
- package/dist/src/cli/setup-checkpoint.d.ts +57 -0
- package/dist/src/cli/setup-common.d.ts +275 -0
- package/dist/src/cli/setup-flow.d.ts +287 -0
- package/dist/src/cli/setup-service.d.ts +96 -0
- package/dist/src/cli/setup.d.ts +202 -0
- package/dist/src/cli/style.d.ts +320 -0
- package/dist/src/cli/token.d.ts +39 -0
- package/dist/src/cli/up.d.ts +155 -0
- package/dist/src/cli/up.js +4 -2
- package/dist/src/cli/up.js.map +1 -1
- package/dist/src/cli/usage.d.ts +37 -0
- package/dist/src/cli/values.d.ts +40 -0
- package/dist/src/cli/vault.d.ts +59 -0
- package/dist/src/cli/vault.js +2 -2
- package/dist/src/cli/vault.js.map +1 -1
- package/dist/src/cli/verb-registry.d.ts +76 -0
- package/dist/src/cli/verb-registry.js +176 -8
- package/dist/src/cli/verb-registry.js.map +1 -1
- package/dist/src/cli/wordmark.d.ts +31 -0
- package/dist/src/cli/wordmark.js +2 -2
- package/dist/src/codex/doctor.d.ts +13 -0
- package/dist/src/codex/doctor.js +41 -0
- package/dist/src/codex/doctor.js.map +1 -0
- package/dist/src/codex/manifest.d.ts +49 -0
- package/dist/src/codex/manifest.js +103 -0
- package/dist/src/codex/manifest.js.map +1 -0
- package/dist/src/codex/templates.d.ts +41 -0
- package/dist/src/codex/templates.js +319 -0
- package/dist/src/codex/templates.js.map +1 -0
- package/dist/src/codex/trust.d.ts +19 -0
- package/dist/src/codex/trust.js +183 -0
- package/dist/src/codex/trust.js.map +1 -0
- package/dist/src/codex/workspace-plan.d.ts +131 -0
- package/dist/src/codex/workspace-plan.js +561 -0
- package/dist/src/codex/workspace-plan.js.map +1 -0
- package/dist/src/core/actor.d.ts +2 -0
- package/dist/src/core/actor.js +5 -0
- package/dist/src/core/actor.js.map +1 -0
- package/dist/src/core/advance-cycle.d.ts +170 -0
- package/dist/src/core/agents-md.d.ts +276 -0
- package/dist/src/core/apply-patch.d.ts +49 -0
- package/dist/src/core/apply-patch.js +266 -0
- package/dist/src/core/apply-patch.js.map +1 -0
- package/dist/src/core/attest.d.ts +420 -0
- package/dist/src/core/attest.js +13 -1
- package/dist/src/core/attest.js.map +1 -1
- package/dist/src/core/audit.d.ts +492 -0
- package/dist/src/core/budgets.d.ts +238 -0
- package/dist/src/core/checkpoint.d.ts +500 -0
- package/dist/src/core/child-env.d.ts +88 -0
- package/dist/src/core/clock.d.ts +52 -0
- package/dist/src/core/command-class.d.ts +543 -0
- package/dist/src/core/command-class.js +43 -8
- package/dist/src/core/command-class.js.map +1 -1
- package/dist/src/core/coverage-sources/adapter.d.ts +40 -0
- package/dist/src/core/coverage-sources/gh.d.ts +48 -0
- package/dist/src/core/coverage-sources/git.d.ts +101 -0
- package/dist/src/core/coverage.d.ts +217 -0
- package/dist/src/core/credential-spec.d.ts +72 -0
- package/dist/src/core/dark-session.d.ts +331 -0
- package/dist/src/core/decision-refusal.d.ts +185 -0
- package/dist/src/core/env-file.d.ts +450 -0
- package/dist/src/core/execute.d.ts +858 -0
- package/dist/src/core/execute.js +44 -6
- package/dist/src/core/execute.js.map +1 -1
- package/dist/src/core/frontmatter.d.ts +78 -0
- package/dist/src/core/gate-window.d.ts +312 -0
- package/dist/src/core/gate.d.ts +1364 -0
- package/dist/src/core/gate.js +68 -13
- package/dist/src/core/gate.js.map +1 -1
- package/dist/src/core/git-run.d.ts +73 -0
- package/dist/src/core/harness-version.d.ts +157 -0
- package/dist/src/core/harness-version.js +2 -1
- package/dist/src/core/harness-version.js.map +1 -1
- package/dist/src/core/harness-wait.d.ts +55 -0
- package/dist/src/core/head-retry.d.ts +107 -0
- package/dist/src/core/instance.d.ts +253 -0
- package/dist/src/core/intake-limits.d.ts +247 -0
- package/dist/src/core/jcs.d.ts +52 -0
- package/dist/src/core/journal.d.ts +144 -0
- package/dist/src/core/live-draw.d.ts +436 -0
- package/dist/src/core/log-reconcile.d.ts +89 -0
- package/dist/src/core/log-subscribe.d.ts +36 -0
- package/dist/src/core/log-subscribe.js +162 -0
- package/dist/src/core/log-subscribe.js.map +1 -0
- package/dist/src/core/log.d.ts +278 -0
- package/dist/src/core/loop.d.ts +274 -0
- package/dist/src/core/loop.js +11 -0
- package/dist/src/core/loop.js.map +1 -1
- package/dist/src/core/md-fence.d.ts +41 -0
- package/dist/src/core/money.d.ts +147 -0
- package/dist/src/core/payload-census.d.ts +74 -0
- package/dist/src/core/payload-store.d.ts +175 -0
- package/dist/src/core/payload.d.ts +71 -0
- package/dist/src/core/policy-diff.d.ts +292 -0
- package/dist/src/core/policy-diff.js +27 -4
- package/dist/src/core/policy-diff.js.map +1 -1
- package/dist/src/core/policy-expectations.d.ts +199 -0
- package/dist/src/core/policy-explain.d.ts +150 -0
- package/dist/src/core/policy-explain.js +31 -3
- package/dist/src/core/policy-explain.js.map +1 -1
- package/dist/src/core/policy-load.d.ts +527 -0
- package/dist/src/core/policy-load.js +15 -3
- package/dist/src/core/policy-load.js.map +1 -1
- package/dist/src/core/policy-match.d.ts +281 -0
- package/dist/src/core/policy-match.js +20 -9
- package/dist/src/core/policy-match.js.map +1 -1
- package/dist/src/core/policy-proposal.d.ts +265 -0
- package/dist/src/core/prompt-layout.d.ts +221 -0
- package/dist/src/core/protected-path-guard.d.ts +453 -0
- package/dist/src/core/protected-path-guard.js +514 -35
- package/dist/src/core/protected-path-guard.js.map +1 -1
- package/dist/src/core/registration.d.ts +25 -0
- package/dist/src/core/reindex.d.ts +99 -0
- package/dist/src/core/sampler.d.ts +313 -0
- package/dist/src/core/sandbox.d.ts +290 -0
- package/dist/src/core/seal.d.ts +165 -0
- package/dist/src/core/state.d.ts +505 -0
- package/dist/src/core/task-file.d.ts +185 -0
- package/dist/src/core/telegram-config.d.ts +93 -0
- package/dist/src/core/token.d.ts +409 -0
- package/dist/src/core/token.js +21 -38
- package/dist/src/core/token.js.map +1 -1
- package/dist/src/core/validate.d.ts +138 -0
- package/dist/src/core/values.d.ts +137 -0
- package/dist/src/core/vault.d.ts +291 -0
- package/dist/src/core/verified-snapshot.d.ts +204 -0
- package/dist/src/core/verify.d.ts +336 -0
- package/dist/src/core/version.d.ts +8 -0
- package/dist/src/core/wysiwys.d.ts +370 -0
- package/dist/src/daemon/advance-child.d.ts +39 -0
- package/dist/src/daemon/advance.d.ts +466 -0
- package/dist/src/daemon/audit.d.ts +87 -0
- package/dist/src/daemon/daemon.d.ts +1180 -0
- package/dist/src/daemon/dark-session.d.ts +64 -0
- package/dist/src/daemon/draw-child.d.ts +36 -0
- package/dist/src/daemon/draw.d.ts +154 -0
- package/dist/src/daemon/git-evidence.d.ts +173 -0
- package/dist/src/daemon/git-evidence.js +1 -1
- package/dist/src/daemon/projection.d.ts +180 -0
- package/dist/src/daemon/prune.d.ts +207 -0
- package/dist/src/mcp/http.d.ts +113 -0
- package/dist/src/mcp/server.d.ts +265 -0
- package/dist/src/mcp/server.js +9 -1
- package/dist/src/mcp/server.js.map +1 -1
- package/docs/adapter-api.md +106 -0
- package/docs/cli-reference.md +389 -36
- package/docs/codex-enforced-session.md +30 -0
- package/package.json +12 -2
- package/schema/codex-instance.schema.json +82 -0
- package/schema/event.schema.json +2 -1
- package/schema/fixtures/codex-instance/invalid/unpinned-codex-version.json +40 -0
- package/schema/fixtures/codex-instance/valid/canonical.json +40 -0
- package/schema/policy.schema.json +21 -1
- package/templates/codex/README.md +9 -0
|
@@ -0,0 +1,628 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The adapter contract (SPEC.md §4, §6.2, §10.4, §11).
|
|
3
|
+
*
|
|
4
|
+
* An **adapter** is a side-effect executor: the thing that actually sends the
|
|
5
|
+
* email, writes the calendar entry, moves the file. SPEC.md §10.4 makes it the
|
|
6
|
+
* hard boundary of the whole system: credentials reach an adapter only inside
|
|
7
|
+
* a runtime-authorized execution window.
|
|
8
|
+
*
|
|
9
|
+
* That boundary describes a *sequence*, not a property of any one function:
|
|
10
|
+
* recompute the payload hash, verify the applicable authority and consume a
|
|
11
|
+
* token where required, record that the execution started, act, record how it
|
|
12
|
+
* ended. An adapter that owned that
|
|
13
|
+
* sequence could skip a step — and the step it would skip is whichever one was
|
|
14
|
+
* inconvenient the week the adapter was written. So the sequence lives here,
|
|
15
|
+
* once, and an adapter implements exactly one method:
|
|
16
|
+
*
|
|
17
|
+
* ```ts
|
|
18
|
+
* act(input: ActInput): Promise<ActOutcome> | ActOutcome
|
|
19
|
+
* ```
|
|
20
|
+
*
|
|
21
|
+
* {@link executeThroughAdapter} owns everything around that call. It is not a
|
|
22
|
+
* helper an adapter may choose; it is the only door, in the same sense that
|
|
23
|
+
* `core/token.ts`'s `consumeToken` is the only sanctioned way to append a
|
|
24
|
+
* manual `execution.started`.
|
|
25
|
+
*
|
|
26
|
+
* ## The five things the contract does that an adapter therefore cannot skip
|
|
27
|
+
*
|
|
28
|
+
* 1. **Recompute the hash.** Amended §10.4: "Adapters and `approval run` MUST
|
|
29
|
+
* recompute the hash of the payload they are about to execute and MUST
|
|
30
|
+
* refuse, with a distinct machine-readable reason (`payload-mismatch`), when
|
|
31
|
+
* it differs from the hash the grant recorded." The contract hashes
|
|
32
|
+
* `request.payload` with `core/payload.ts` — the same canonicalizer the log
|
|
33
|
+
* uses — and hands the digest to the token spend. An adapter is never asked
|
|
34
|
+
* what its payload hashes to, because an executor that could *state* its
|
|
35
|
+
* hash could state the approved one while holding different bytes.
|
|
36
|
+
* 2. **Check the class before touching the log.** An adapter declares the
|
|
37
|
+
* classes it serves. An adapter asked to execute an action declared under
|
|
38
|
+
* some other class is refused `adapter-class-mismatch` with the log
|
|
39
|
+
* untouched: the declaration is read from `task.registered` (the log, not the
|
|
40
|
+
* caller's claim), and nothing is appended, because nothing happened.
|
|
41
|
+
* 3. **Start before acting.** {@link startExecution} appends `execution.started`
|
|
42
|
+
* *before* `act` is called, and a refusal there means `act` is never called
|
|
43
|
+
* at all. A log that recorded an execution only once it succeeded could not
|
|
44
|
+
* tell you about the one that did not.
|
|
45
|
+
* 3b. **Resolve declared credentials before spending the token** (APRV-169). An
|
|
46
|
+
* adapter names the credentials it cannot act without, and the contract
|
|
47
|
+
* resolves them before `startExecution`. A missing one refuses
|
|
48
|
+
* `credential-unavailable` with the log untouched and the grant intact,
|
|
49
|
+
* because a configuration fault must not consume a human's single-use
|
|
50
|
+
* authority. The side effect's own ordering is unchanged: the token is still
|
|
51
|
+
* consumed and `execution.started` still appended before `act` runs.
|
|
52
|
+
* 3c. **Ask the adapter what it can learn before the spend** (APRV-276). An
|
|
53
|
+
* adapter MAY implement {@link Adapter.precheck}, and the contract calls it
|
|
54
|
+
* after the credentials resolve and before the token is consumed. It is the
|
|
55
|
+
* home of one specific refusal: the condition that makes the side effect
|
|
56
|
+
* impossible, that this runtime can learn without attempting it, and that
|
|
57
|
+
* would otherwise cost a human's single-use grant to discover. AgentMail's
|
|
58
|
+
* drift check is the worked case. A refusal appends nothing, spends nothing,
|
|
59
|
+
* and returns `adapter-precheck-refused`. It does not replace the same check
|
|
60
|
+
* inside `act`: the far side can move in between, and the check that binds
|
|
61
|
+
* the bytes actually sent is the later one.
|
|
62
|
+
* 4. **Scope the credentials.** The provider handed to `act` is a wrapper that
|
|
63
|
+
* closes when `act` returns. Inside the verified execution window it answers;
|
|
64
|
+
* outside it, every `get` refuses `credential-window-closed`. An adapter that
|
|
65
|
+
* stashes the provider and reads it later gets a refusal rather than a
|
|
66
|
+
* secret, so the execution window is a mechanism instead of an intention.
|
|
67
|
+
* 5. **Redact.** Every string the contract is about to return is scanned for
|
|
68
|
+
* each credential value the provider handed out during the window, and hits
|
|
69
|
+
* are replaced with {@link REDACTION_PLACEHOLDER} and counted. SPEC.md §11.1
|
|
70
|
+
* invariant 3 ("raw secrets never appear in the log") is the reason adapters
|
|
71
|
+
* exist; here it is a mechanical check rather than a convention. Note what
|
|
72
|
+
* reaches the log from an adapter: one bounded field. Since APRV-251 a
|
|
73
|
+
* completion may carry `provider_ref`, the identifier the provider files the
|
|
74
|
+
* effect under, and the sweep runs BEFORE that record is appended so the id
|
|
75
|
+
* is scanned exactly as the rest of the detail is. Everything else in the
|
|
76
|
+
* adapter's own vocabulary rides in the returned result, which is scanned
|
|
77
|
+
* before it is handed back.
|
|
78
|
+
*
|
|
79
|
+
* ## What is deliberately not here
|
|
80
|
+
*
|
|
81
|
+
* No vault. {@link CredentialProvider} is the seam a real vault implements
|
|
82
|
+
* (APRV-68); this module ships {@link inMemoryCredentials} for tests and
|
|
83
|
+
* {@link NO_CREDENTIALS}, which refuses everything, as the default. A runtime
|
|
84
|
+
* that wires no provider therefore fails closed: an adapter that needs a secret
|
|
85
|
+
* to act cannot act.
|
|
86
|
+
*
|
|
87
|
+
* No token verification, consumption, or append logic. Those are
|
|
88
|
+
* `core/token.ts` and `core/execute.ts`, called here and reimplemented nowhere.
|
|
89
|
+
*
|
|
90
|
+
* ## Two callers, one core path
|
|
91
|
+
*
|
|
92
|
+
* `approval run` (`src/cli/execute.ts`) is the other caller of the same core
|
|
93
|
+
* path: a command is an adapter whose `act` is `spawnSync`, whose payload is
|
|
94
|
+
* §6.2's `{argv, cwd}`, and whose credentials are the ambient environment. It
|
|
95
|
+
* calls `startExecution` and `finishExecution` directly rather than through this
|
|
96
|
+
* module, because its stdio, exit-code transparency, and `--` argv split are CLI
|
|
97
|
+
* concerns with nothing to do with adapters. The two callers share the core
|
|
98
|
+
* verbs, not this wrapper; anything that must hold for both belongs in
|
|
99
|
+
* `core/execute.ts`, and a rule added here alone protects adapters only.
|
|
100
|
+
*
|
|
101
|
+
* Deterministic and total: no clock of its own (it forwards
|
|
102
|
+
* {@link ExecuteOptions.clock}), no randomness, and nothing here throws — an
|
|
103
|
+
* adapter that throws is caught and recorded as a failed execution.
|
|
104
|
+
*/
|
|
105
|
+
import { type ExecuteOptions, type ExecuteRefusal, type ProviderRef } from "../core/execute.js";
|
|
106
|
+
import { type GateOptions } from "../core/gate.js";
|
|
107
|
+
import type { ObservationWindow, ObservedEffect } from "../core/coverage.js";
|
|
108
|
+
import { type Autonomy } from "../core/policy-load.js";
|
|
109
|
+
/**
|
|
110
|
+
* A value RFC 8785 can canonicalize, which is exactly what a payload may be.
|
|
111
|
+
*
|
|
112
|
+
* The bound bytes are the ones a human saw in a channel and the ones
|
|
113
|
+
* `core/payload.ts` hashed, so the payload type is the JSON type: a payload
|
|
114
|
+
* carrying a function, a cycle, or a `NaN` has no canonical serialization and
|
|
115
|
+
* therefore no binding. Such a value is refused {@link "payload-unhashable"}
|
|
116
|
+
* rather than executed against a digest nobody can reproduce.
|
|
117
|
+
*/
|
|
118
|
+
export type JsonValue = null | boolean | number | string | JsonValue[] | {
|
|
119
|
+
[key: string]: JsonValue;
|
|
120
|
+
};
|
|
121
|
+
/**
|
|
122
|
+
* Why a credential was not handed over. Frozen union, per SPEC.md §11.1(6).
|
|
123
|
+
*
|
|
124
|
+
* The three are distinguished because they call for three different responses:
|
|
125
|
+
* fix the configuration, ask a human, or fix the adapter.
|
|
126
|
+
*/
|
|
127
|
+
export declare const CREDENTIAL_REFUSAL_CODES: readonly [
|
|
128
|
+
/** No such credential is configured. The repair is configuration. */
|
|
129
|
+
"credential-unavailable",
|
|
130
|
+
/** The provider knows it and declined: policy, a locked vault, a human's no. */
|
|
131
|
+
"credential-refused",
|
|
132
|
+
/**
|
|
133
|
+
* The verified execution window has closed: `act` has already returned, and the
|
|
134
|
+
* provider it was handed is no longer live. Distinct from the two above
|
|
135
|
+
* because nothing is wrong with the credential or the configuration — the
|
|
136
|
+
* adapter asked at the wrong time, which is a defect in the adapter and is
|
|
137
|
+
* reported as one.
|
|
138
|
+
*/
|
|
139
|
+
"credential-window-closed"];
|
|
140
|
+
export type CredentialRefusalCode = (typeof CREDENTIAL_REFUSAL_CODES)[number];
|
|
141
|
+
export type CredentialResult = {
|
|
142
|
+
ok: true;
|
|
143
|
+
value: string;
|
|
144
|
+
} | {
|
|
145
|
+
ok: false;
|
|
146
|
+
code: CredentialRefusalCode;
|
|
147
|
+
message: string;
|
|
148
|
+
};
|
|
149
|
+
/**
|
|
150
|
+
* The seam between an adapter and the secrets it needs (SPEC.md §10.4: adapters
|
|
151
|
+
* "hold the actual credentials in an encrypted vault").
|
|
152
|
+
*
|
|
153
|
+
* Synchronous and total: `get` never throws and never blocks, because it is
|
|
154
|
+
* called from inside a window the contract holds open and an adapter awaiting a
|
|
155
|
+
* human inside that window would hold an execution open with no outcome. A
|
|
156
|
+
* provider that must prompt should prompt before the execution starts and
|
|
157
|
+
* answer from what it learned.
|
|
158
|
+
*/
|
|
159
|
+
export interface CredentialProvider {
|
|
160
|
+
get(name: string): CredentialResult;
|
|
161
|
+
/**
|
|
162
|
+
* Told, by the contract and by nothing else, that a token has been consumed
|
|
163
|
+
* for this action and that the credential window is open (APRV-168). Called
|
|
164
|
+
* with `null` when the window closes.
|
|
165
|
+
*
|
|
166
|
+
* Optional, and a provider that ignores it behaves exactly as it always did.
|
|
167
|
+
* It exists so a provider can offer a capability that is only defensible
|
|
168
|
+
* inside a granted window, and it is safe to publish as a method because the
|
|
169
|
+
* argument cannot be forged: see {@link ExecutionGrant}.
|
|
170
|
+
*/
|
|
171
|
+
grant?(grant: ExecutionGrant | null): void;
|
|
172
|
+
}
|
|
173
|
+
/**
|
|
174
|
+
* The brand that makes {@link ExecutionGrant} unforgeable outside this module.
|
|
175
|
+
*
|
|
176
|
+
* NOT exported. A `unique symbol` that no other module can name is a property
|
|
177
|
+
* no other module can write, so an object satisfying {@link ExecutionGrant} can
|
|
178
|
+
* be constructed here and nowhere else. This is the structural half of
|
|
179
|
+
* APRV-168's boundary: a capability keyed to a value only the contract can mint
|
|
180
|
+
* is reachable only from the contract's own execution path.
|
|
181
|
+
*/
|
|
182
|
+
declare const EXECUTION_GRANT_BRAND: unique symbol;
|
|
183
|
+
/**
|
|
184
|
+
* Evidence, handed to a {@link CredentialProvider}, that this execution is
|
|
185
|
+
* inside a verified window (APRV-168).
|
|
186
|
+
*
|
|
187
|
+
* The contract mints one after {@link startExecution} returns, and drops it the
|
|
188
|
+
* moment `act` does. It carries no secret and grants no read by itself; what it
|
|
189
|
+
* asserts is WHEN, and on the manual path also WHAT: `tokenSha256` is the digest
|
|
190
|
+
* of the single-use token that was actually spent, present only when a token was
|
|
191
|
+
* actually spent, so a provider can insist on a human's grant rather than merely
|
|
192
|
+
* on being inside some execution.
|
|
193
|
+
*/
|
|
194
|
+
export interface ExecutionGrant {
|
|
195
|
+
readonly [EXECUTION_GRANT_BRAND]: true;
|
|
196
|
+
/**
|
|
197
|
+
* Where in the sequence this window is.
|
|
198
|
+
*
|
|
199
|
+
* - **`presented`** — the caller holds a token whose digest matches the one
|
|
200
|
+
* the log's `approval.granted` recorded for this action, and the contract is
|
|
201
|
+
* about to resolve the adapter's declared credentials (APRV-169). Minted
|
|
202
|
+
* only on that digest match, so it is proof a human granted THIS action and
|
|
203
|
+
* the caller has the token that grant minted. It is not full verification:
|
|
204
|
+
* TTL, revocation and the single-use check are `core/token.ts`'s, and they
|
|
205
|
+
* run in `startExecution` before anything is spent.
|
|
206
|
+
* - **`consumed`** — the token has been spent, `execution.started` is on the
|
|
207
|
+
* log, and `act` is running.
|
|
208
|
+
*
|
|
209
|
+
* A capability that must not exist before a human decided may look at this;
|
|
210
|
+
* one that must not exist before the token is BURNED reads `tokenSha256`.
|
|
211
|
+
*/
|
|
212
|
+
readonly phase: "presented" | "consumed";
|
|
213
|
+
/** The action this window belongs to. */
|
|
214
|
+
readonly actionKey: string;
|
|
215
|
+
/** The seq of the `execution.started` that opened it. `null` before it. */
|
|
216
|
+
readonly startedSeq: number | null;
|
|
217
|
+
/** How the action was admitted. `null` until `startExecution` has answered. */
|
|
218
|
+
readonly autonomy: Autonomy | null;
|
|
219
|
+
/**
|
|
220
|
+
* The digest of the token that was consumed, on the manual path only. Absent
|
|
221
|
+
* before the spend, and absent after it for a `supervised` or `autonomous`
|
|
222
|
+
* execution, which no human was asked about.
|
|
223
|
+
*/
|
|
224
|
+
readonly tokenSha256?: string;
|
|
225
|
+
}
|
|
226
|
+
/** The default: no vault is wired, so nothing is handed out. Fails closed. */
|
|
227
|
+
export declare const NO_CREDENTIALS: CredentialProvider;
|
|
228
|
+
/**
|
|
229
|
+
* A provider over a literal map. **Tests and fixtures only** — it holds secrets
|
|
230
|
+
* in process memory in the clear, which is precisely what the vault (APRV-68)
|
|
231
|
+
* exists to stop doing.
|
|
232
|
+
*/
|
|
233
|
+
export declare function inMemoryCredentials(entries: Readonly<Record<string, string>>): CredentialProvider;
|
|
234
|
+
/** What a redacted credential value is replaced with. */
|
|
235
|
+
export declare const REDACTION_PLACEHOLDER = "[redacted]";
|
|
236
|
+
/** A string with every known secret replaced, and how many replacements ran. */
|
|
237
|
+
export interface Redaction {
|
|
238
|
+
text: string;
|
|
239
|
+
hits: number;
|
|
240
|
+
}
|
|
241
|
+
/**
|
|
242
|
+
* Replace every occurrence of every secret in `text`.
|
|
243
|
+
*
|
|
244
|
+
* Empty secrets are skipped, because "replace every occurrence of the empty
|
|
245
|
+
* string" redacts a document into nothing and would hide the very message a
|
|
246
|
+
* reader needs. Everything else is replaced literally (no regex, no escaping
|
|
247
|
+
* question), including a secret that appears as a substring of a longer word:
|
|
248
|
+
* over-redaction is the safe direction, and a credential that happens to be a
|
|
249
|
+
* common word is a credential problem, not a scanner problem.
|
|
250
|
+
*/
|
|
251
|
+
export declare function redactSecrets(text: string, secrets: Iterable<string>): Redaction;
|
|
252
|
+
/** Does `text` contain any of `secrets`? The assertion form of the guard. */
|
|
253
|
+
export declare function containsSecret(text: string, secrets: Iterable<string>): boolean;
|
|
254
|
+
/** A JSON value with every string (key or value) redacted. */
|
|
255
|
+
export interface RedactedJson {
|
|
256
|
+
value: JsonValue;
|
|
257
|
+
hits: number;
|
|
258
|
+
}
|
|
259
|
+
/**
|
|
260
|
+
* Walk `value` and redact every string in it, keys included.
|
|
261
|
+
*
|
|
262
|
+
* Keys are scanned as well as values because a leak does not care which side of
|
|
263
|
+
* the colon it lands on: `{"sk-live-…": "used"}` publishes the secret exactly as
|
|
264
|
+
* effectively as the other arrangement.
|
|
265
|
+
*/
|
|
266
|
+
export declare function redactJson(value: JsonValue, secrets: Iterable<string>): RedactedJson;
|
|
267
|
+
/** Everything an adapter is given, and nothing else. */
|
|
268
|
+
export interface ActInput {
|
|
269
|
+
/** The action's idempotency key (SPEC.md §7), for the adapter's own logging. */
|
|
270
|
+
actionKey: string;
|
|
271
|
+
/**
|
|
272
|
+
* The bytes the grant or registered declaration bound. The contract has
|
|
273
|
+
* already hashed this value and checked that digest against the applicable
|
|
274
|
+
* authority, so an adapter acting on exactly this value is acting on bound bytes. An
|
|
275
|
+
* adapter that reaches past it for "the current version" of anything has left
|
|
276
|
+
* the binding behind.
|
|
277
|
+
*/
|
|
278
|
+
payload: JsonValue;
|
|
279
|
+
/** Live only until `act` returns. See {@link scopeCredentials}. */
|
|
280
|
+
credentials: CredentialProvider;
|
|
281
|
+
/** Cancellation, when the caller supplied one. */
|
|
282
|
+
signal?: AbortSignal;
|
|
283
|
+
}
|
|
284
|
+
/**
|
|
285
|
+
* What the adapter reports.
|
|
286
|
+
*
|
|
287
|
+
* The failure vocabulary is the adapter's own: `code` is a free string, because
|
|
288
|
+
* this repository cannot enumerate the ways an SMTP server, a calendar API, or
|
|
289
|
+
* a payments processor says no, and forcing those into a fixed union would
|
|
290
|
+
* either lie about them or freeze on the first adapter written. What is NOT
|
|
291
|
+
* negotiable is that neither `code`, `message`, nor `detail` may carry a
|
|
292
|
+
* credential; the contract scans all three before returning them.
|
|
293
|
+
*/
|
|
294
|
+
export type ActOutcome = {
|
|
295
|
+
ok: true;
|
|
296
|
+
detail?: JsonValue;
|
|
297
|
+
} | {
|
|
298
|
+
ok: false;
|
|
299
|
+
code: string;
|
|
300
|
+
message: string;
|
|
301
|
+
};
|
|
302
|
+
/**
|
|
303
|
+
* The one key by which a success `detail` NAMES the provider's own identifier
|
|
304
|
+
* for the effect (APRV-251, SPEC.md §8).
|
|
305
|
+
*
|
|
306
|
+
* An adapter that wants its effect joinable by id puts a short printable string
|
|
307
|
+
* at the top level of its detail under this key, beside whatever else its
|
|
308
|
+
* receipt says. Everything after that is the contract's: the value passes the
|
|
309
|
+
* redaction sweep with the rest of the detail, the adapter half of the record
|
|
310
|
+
* is this runtime's own knowledge of which adapter it called, and the record is
|
|
311
|
+
* written by {@link finishExecution}.
|
|
312
|
+
*
|
|
313
|
+
* ONE conventional key rather than a guess across `message_id`, `sid`, `id` and
|
|
314
|
+
* whatever the next provider calls it. A contract that guessed would sooner or
|
|
315
|
+
* later lift the wrong field of some receipt onto a permanent log, and an
|
|
316
|
+
* adapter that says nothing under this key is treated as naming no reference,
|
|
317
|
+
* which is the pre-amendment behaviour and always valid.
|
|
318
|
+
*/
|
|
319
|
+
export declare const PROVIDER_REF_DETAIL_KEY = "provider_ref";
|
|
320
|
+
/**
|
|
321
|
+
* The reference to record for this call, or `null` for none.
|
|
322
|
+
*
|
|
323
|
+
* Given BOTH the raw detail the adapter returned and the redacted copy about to
|
|
324
|
+
* be handed back, because the interesting case is the one where they differ. A
|
|
325
|
+
* lifted id whose bytes the redaction sweep touched is dropped rather than
|
|
326
|
+
* recorded: `[redacted]` matches no provider's record, and writing it would put
|
|
327
|
+
* a value in the join column that reads exactly like one that means something.
|
|
328
|
+
* The credential itself never reaches the log either way, since what would be
|
|
329
|
+
* written is the redacted copy.
|
|
330
|
+
*
|
|
331
|
+
* Everything else it declines is declined for the same reason the schema would
|
|
332
|
+
* reject it (an absent key, a value that is not a string, a string that is
|
|
333
|
+
* empty, too long, or carries a space or a control character). Declining here
|
|
334
|
+
* rather than at the append is deliberate: a record the write boundary rejects
|
|
335
|
+
* would leave a side effect that already happened with no outcome in the log,
|
|
336
|
+
* and a completion carrying no reference is the better failure.
|
|
337
|
+
*/
|
|
338
|
+
export declare function providerRefFor(adapterName: string, rawDetail: JsonValue | undefined, redactedDetail: JsonValue): ProviderRef | null;
|
|
339
|
+
/**
|
|
340
|
+
* Everything an adapter is given for {@link Adapter.precheck}, and nothing else
|
|
341
|
+
* (APRV-276).
|
|
342
|
+
*
|
|
343
|
+
* Shaped like {@link ActInput} and deliberately a separate type, because one
|
|
344
|
+
* sentence of `ActInput`'s contract does not hold here: the token has NOT been
|
|
345
|
+
* spent. What has happened is narrower and is exactly what a pre-spend check
|
|
346
|
+
* may rely on — the payload has been hashed and IS the one the log binds this
|
|
347
|
+
* action to (the grant's `payload_hash` on the manual path, the registered
|
|
348
|
+
* declaration's off it; bytes that are anything else never reach a precheck,
|
|
349
|
+
* see {@link logBindsPayload}), the class has been read from the verified log,
|
|
350
|
+
* and the declared credentials have resolved inside APRV-168's
|
|
351
|
+
* `presented`-phase grant, minted only when the caller's token matches the
|
|
352
|
+
* digest the human's grant recorded. Whether that token may still be SPENT is
|
|
353
|
+
* `core/token.ts`'s question and is asked after this returns.
|
|
354
|
+
*/
|
|
355
|
+
export interface PrecheckInput {
|
|
356
|
+
/** The action's idempotency key (SPEC.md §7), for the adapter's own logging. */
|
|
357
|
+
actionKey: string;
|
|
358
|
+
/**
|
|
359
|
+
* The bytes the grant or registered declaration bound, hashed by the contract already. The same
|
|
360
|
+
* value `act` will be handed: a precheck that read some other version of the
|
|
361
|
+
* payload would be checking bytes nobody is about to execute.
|
|
362
|
+
*/
|
|
363
|
+
payload: JsonValue;
|
|
364
|
+
/** Live only until `precheck` returns, exactly as `act`'s is. */
|
|
365
|
+
credentials: CredentialProvider;
|
|
366
|
+
/** Cancellation, when the caller supplied one. */
|
|
367
|
+
signal?: AbortSignal;
|
|
368
|
+
}
|
|
369
|
+
/**
|
|
370
|
+
* What a precheck reports: may this execution be attempted at all?
|
|
371
|
+
*
|
|
372
|
+
* `ok: true` says nothing more than "I found no reason to refuse before the
|
|
373
|
+
* spend". It is never a promise about the send, and it authorizes nothing:
|
|
374
|
+
* every check an adapter performs here it still performs inside `act`, where
|
|
375
|
+
* the window is the binding one.
|
|
376
|
+
*
|
|
377
|
+
* The failure vocabulary is the adapter's own, for {@link ActOutcome}'s reason,
|
|
378
|
+
* and `code` and `message` are scanned for credentials exactly as `act`'s are.
|
|
379
|
+
*/
|
|
380
|
+
export type PrecheckOutcome = {
|
|
381
|
+
ok: true;
|
|
382
|
+
} | {
|
|
383
|
+
ok: false;
|
|
384
|
+
code: string;
|
|
385
|
+
message: string;
|
|
386
|
+
};
|
|
387
|
+
/**
|
|
388
|
+
* A side-effect executor (SPEC.md §4: "an email sender, calendar writer … that
|
|
389
|
+
* holds credentials and refuses to act without a valid token").
|
|
390
|
+
*
|
|
391
|
+
* The refusal in that sentence is structural here: an adapter has no way to act
|
|
392
|
+
* *except* by being handed an {@link ActInput}, and only
|
|
393
|
+
* {@link executeThroughAdapter} builds one, only after the token was verified
|
|
394
|
+
* and consumed.
|
|
395
|
+
*
|
|
396
|
+
* `classes` lists the side-effect classes (SPEC.md §7) this adapter serves,
|
|
397
|
+
* matched exactly against the class the `task.registered` record declared.
|
|
398
|
+
* Exactly, not by glob: patterns are the policy's language for deciding
|
|
399
|
+
* autonomy, and an adapter that claimed `communicate.*` would be asserting
|
|
400
|
+
* competence over classes that do not exist yet.
|
|
401
|
+
*/
|
|
402
|
+
export interface Adapter {
|
|
403
|
+
/** Stable identifier: `email`, `gcal`, `mock-email`. Recorded in results. */
|
|
404
|
+
name: string;
|
|
405
|
+
/** The declared classes this adapter serves, matched exactly. */
|
|
406
|
+
classes: readonly string[];
|
|
407
|
+
/**
|
|
408
|
+
* The credential names without which `act` cannot even be attempted (APRV-169).
|
|
409
|
+
*
|
|
410
|
+
* Declared here rather than discovered inside `act`, because the contract
|
|
411
|
+
* resolves them BEFORE it consumes the token: a credential this runtime cannot
|
|
412
|
+
* reach is a configuration fault, and a configuration fault must not spend the
|
|
413
|
+
* single-use authority a human granted. An adapter that names nothing keeps
|
|
414
|
+
* exactly the behaviour it had, and one that names an OPTIONAL credential here
|
|
415
|
+
* turns an optional value into a required one, so the list holds only the
|
|
416
|
+
* values whose absence makes the action impossible.
|
|
417
|
+
*
|
|
418
|
+
* Names, never values: the contract asks the provider for each of them and
|
|
419
|
+
* keeps none of what comes back.
|
|
420
|
+
*/
|
|
421
|
+
requiredCredentials?: readonly string[];
|
|
422
|
+
/**
|
|
423
|
+
* Everything this adapter can find out BEFORE the token is spent (APRV-276).
|
|
424
|
+
*
|
|
425
|
+
* Optional, and an adapter that omits it behaves exactly as it always did.
|
|
426
|
+
* It exists for one class of refusal: the condition that makes a send
|
|
427
|
+
* impossible is knowable before the spend, is not the caller's fault, and
|
|
428
|
+
* costs a human another tap when a spent token is the price of discovering
|
|
429
|
+
* it. The worked case is AgentMail's drift check. A draft is server-side
|
|
430
|
+
* mutable state, so a grant binds the bytes fetched at request time and the
|
|
431
|
+
* adapter compares them against the live draft before it sends; performing
|
|
432
|
+
* that comparison after the spend meant an edited draft refused correctly and
|
|
433
|
+
* burned the grant, and restoring the approved text could not send under the
|
|
434
|
+
* token the human had already given (the APRV-224 e2e, 2026-09-06).
|
|
435
|
+
*
|
|
436
|
+
* Three rules bind an implementation:
|
|
437
|
+
*
|
|
438
|
+
* - **Read-only.** It performs no write of any kind against the far side. It
|
|
439
|
+
* runs on the strength of a token that has not been verified for spending,
|
|
440
|
+
* so a precheck that could send would be a side effect outside the window.
|
|
441
|
+
* - **It never stands in for a check inside `act`.** Whatever it verifies,
|
|
442
|
+
* `act` verifies again inside the consumed-token window. The far side can
|
|
443
|
+
* move between the two, and the check that binds the bytes actually sent is
|
|
444
|
+
* the later one; this one exists to protect the grant, not to license
|
|
445
|
+
* skipping it.
|
|
446
|
+
* - **Refusing is free and passing is not a promise.** A refusal appends
|
|
447
|
+
* nothing and spends nothing ({@link "adapter-precheck-refused"}), so an
|
|
448
|
+
* adapter should refuse here whenever it can, and a `true` says only that
|
|
449
|
+
* nothing was found — never that the send will succeed.
|
|
450
|
+
*
|
|
451
|
+
* The credential window is the pre-token one APRV-169 opens for
|
|
452
|
+
* {@link requiredCredentials}, with APRV-168's `presented`-phase grant live:
|
|
453
|
+
* on the manual path it is minted only when the caller's token matches the
|
|
454
|
+
* digest the human's grant recorded, so a vault read here answers to a
|
|
455
|
+
* human's decision like every other.
|
|
456
|
+
*/
|
|
457
|
+
precheck?(input: PrecheckInput): Promise<PrecheckOutcome> | PrecheckOutcome;
|
|
458
|
+
act(input: ActInput): Promise<ActOutcome> | ActOutcome;
|
|
459
|
+
/**
|
|
460
|
+
* What this adapter's PROVIDER recorded happening in `window` (APRV-245).
|
|
461
|
+
*
|
|
462
|
+
* Optional, and an adapter that omits it behaves exactly as it always did.
|
|
463
|
+
* It exists because MCP use is voluntary: an agent can route an action through
|
|
464
|
+
* the gate, or it can act. What keeps the arrangement honest is that a side
|
|
465
|
+
* effect leaves a witness this project does not write, and for an adapter-
|
|
466
|
+
* backed class the witness is the provider's own record of what it did.
|
|
467
|
+
* `approval coverage` reads that record back and joins it against the verified
|
|
468
|
+
* log, so an effect with no matching record is visible as a gap.
|
|
469
|
+
*
|
|
470
|
+
* Four rules bind an implementation, and they are the mirror of {@link grant}'s:
|
|
471
|
+
*
|
|
472
|
+
* - **Read-only.** It performs no write of any kind against the far side. A
|
|
473
|
+
* coverage report that could send is a report nobody dares to run.
|
|
474
|
+
* - **No token.** It is called OUTSIDE any grant window, by a reporting verb,
|
|
475
|
+
* with a provider the caller built for the purpose. There is no
|
|
476
|
+
* {@link ExecutionGrant} in scope and none is needed: reading what already
|
|
477
|
+
* happened authorizes nothing.
|
|
478
|
+
* - **The caller redacts.** Whatever the far side says may be quoted back, so
|
|
479
|
+
* the caller runs every returned `detail` through {@link redactSecrets} with
|
|
480
|
+
* the secrets the adapter's own configuration reader reported. An
|
|
481
|
+
* implementation scrubs its strings as well; two passes are cheap and a leak
|
|
482
|
+
* is not (SPEC.md §11.1 invariant 3).
|
|
483
|
+
* - **No message content.** A detail line names an effect for a person to
|
|
484
|
+
* recognize (a subject, a recipient count, an id) and never a body: the
|
|
485
|
+
* report is read by somebody who did not approve the message.
|
|
486
|
+
*
|
|
487
|
+
* Every returned effect carries a class this adapter serves, so a class the
|
|
488
|
+
* adapter never handles cannot arrive dressed as an effect it observed.
|
|
489
|
+
*/
|
|
490
|
+
observe?(window: ObservationWindow, credentials: CredentialProvider): Promise<readonly ObservedEffect[]>;
|
|
491
|
+
}
|
|
492
|
+
/**
|
|
493
|
+
* Everything {@link executeThroughAdapter} can refuse. Frozen public API, per
|
|
494
|
+
* SPEC.md §11.1(6), and a strict superset of {@link EXECUTE_REFUSAL_CODES}:
|
|
495
|
+
* every core refusal surfaces verbatim rather than being collapsed into an
|
|
496
|
+
* adapter-flavoured one, because `token-consumed`, `payload-mismatch` and
|
|
497
|
+
* `budget-exceeded` call for three different responses whether the caller is an
|
|
498
|
+
* adapter or `approval run`.
|
|
499
|
+
*/
|
|
500
|
+
export declare const ADAPTER_REFUSAL_CODES: readonly ["actor-invalid", "action-not-registered", "class-human-only", "token-required", "loop-escalated", "policy-not-attested", "policy-drift", "already-executed", "budget-exceeded", "not-started", "already-finished", "not-granted", "token-mismatch", "token-consumed", "token-expired", "token-revoked", "harness-executed", "payload-mismatch", "actor-not-human", "execution-delegated", "execution-indeterminate", "not-indeterminate", "already-reconciled", "dangling-stdin-not-tty", "dangling-declined", "log-unreadable", "log-torn-tail", "log-corrupt", "append-failed", "not-registered", "duplicate-request", "queue-full", "rate-limited", "payload-hash-required", "token-delivery-unavailable", "payload-store-failed", "adapter-class-mismatch", "payload-unhashable", "adapter-failed", "adapter-act-threw", "credential-unavailable", "adapter-precheck-refused"];
|
|
501
|
+
export type AdapterRefusalCode = (typeof ADAPTER_REFUSAL_CODES)[number];
|
|
502
|
+
/** Every adapter-path failure is one of these. Nothing here throws. */
|
|
503
|
+
export interface AdapterRefusal {
|
|
504
|
+
ok: false;
|
|
505
|
+
code: AdapterRefusalCode;
|
|
506
|
+
message: string;
|
|
507
|
+
/** The adapter this was routed to. */
|
|
508
|
+
adapter: string;
|
|
509
|
+
action_key: string;
|
|
510
|
+
/** Did `act` actually run? `false` means no side effect was attempted. */
|
|
511
|
+
acted: boolean;
|
|
512
|
+
/** The `execution.started` seq, when one was appended before the failure. */
|
|
513
|
+
started_seq?: number;
|
|
514
|
+
/**
|
|
515
|
+
* The outcome event appended, when one was: `execution.failed` for an
|
|
516
|
+
* attempt that provably did not commit, `execution.indeterminate` for one
|
|
517
|
+
* whose outcome nobody knows (APRV-120).
|
|
518
|
+
*/
|
|
519
|
+
outcome?: "execution.failed" | "execution.indeterminate";
|
|
520
|
+
outcome_seq?: number;
|
|
521
|
+
exit_code?: number;
|
|
522
|
+
/** The adapter's own failure code, when `code` is `adapter-failed`. */
|
|
523
|
+
adapter_code?: string;
|
|
524
|
+
/** The underlying core refusal, verbatim, when the refusal came from core. */
|
|
525
|
+
execute?: ExecuteRefusal;
|
|
526
|
+
/** How many credential values the redaction guard replaced on this path. */
|
|
527
|
+
redactions: number;
|
|
528
|
+
}
|
|
529
|
+
/** A completed execution: `act` reported success and the log says so. */
|
|
530
|
+
export interface AdapterExecuteSuccess {
|
|
531
|
+
ok: true;
|
|
532
|
+
adapter: string;
|
|
533
|
+
action_key: string;
|
|
534
|
+
task: string;
|
|
535
|
+
class: string;
|
|
536
|
+
autonomy: Autonomy;
|
|
537
|
+
/** The digest the contract recomputed and the token spend checked. */
|
|
538
|
+
payload_hash: string;
|
|
539
|
+
started_seq: number;
|
|
540
|
+
outcome: "execution.completed";
|
|
541
|
+
outcome_seq: number;
|
|
542
|
+
/** Always 0 here; present so success and failure read alike to a consumer. */
|
|
543
|
+
exit_code: number;
|
|
544
|
+
/** The adapter's own detail, after redaction. */
|
|
545
|
+
detail?: JsonValue;
|
|
546
|
+
/**
|
|
547
|
+
* The reference the log now carries for this effect, when one was recorded
|
|
548
|
+
* (APRV-251). Absent when the adapter's detail named none, or named one the
|
|
549
|
+
* contract declined to write; see {@link providerRefFor}.
|
|
550
|
+
*/
|
|
551
|
+
provider_ref?: ProviderRef;
|
|
552
|
+
redactions: number;
|
|
553
|
+
}
|
|
554
|
+
export type AdapterExecuteResult = AdapterExecuteSuccess | AdapterRefusal;
|
|
555
|
+
/** What the contract asks an adapter to execute. */
|
|
556
|
+
export interface AdapterExecuteRequest {
|
|
557
|
+
logPath: string;
|
|
558
|
+
actionKey: string;
|
|
559
|
+
/** The concrete bytes. The contract hashes these; nobody states the hash. */
|
|
560
|
+
payload: JsonValue;
|
|
561
|
+
/** `human:<id>` or `agent:<id>`; the event schema is the authority on shape. */
|
|
562
|
+
actor: string;
|
|
563
|
+
}
|
|
564
|
+
/**
|
|
565
|
+
* {@link ExecuteOptions} plus the two things only the adapter path has.
|
|
566
|
+
*
|
|
567
|
+
* `presentedPayloadHash` is inherited and deliberately ignored: the contract
|
|
568
|
+
* computes it from {@link AdapterExecuteRequest.payload}, and honoring a
|
|
569
|
+
* caller-supplied digest would reintroduce exactly the "tell me what you are
|
|
570
|
+
* running" hole that content binding closes.
|
|
571
|
+
*/
|
|
572
|
+
export interface AdapterExecuteOptions extends ExecuteOptions {
|
|
573
|
+
/** The vault seam. Absent means {@link NO_CREDENTIALS}: nothing is handed out. */
|
|
574
|
+
credentials?: CredentialProvider;
|
|
575
|
+
/** Forwarded to `act` for cancellation. */
|
|
576
|
+
signal?: AbortSignal;
|
|
577
|
+
/** Test/embedded seams for supervised-live request intake. CLI callers omit it. */
|
|
578
|
+
liveIntake?: Pick<GateOptions, "env" | "drawAsk">;
|
|
579
|
+
}
|
|
580
|
+
/**
|
|
581
|
+
* Execute one approved action through `adapter`, and own every step around the
|
|
582
|
+
* adapter's own.
|
|
583
|
+
*
|
|
584
|
+
* The order, and why it is this order:
|
|
585
|
+
*
|
|
586
|
+
* 1. **Hash the payload.** Before any log read, because a payload with no
|
|
587
|
+
* canonical form has nothing to check and nothing to execute.
|
|
588
|
+
* 2. **Read the declaration** from the verified log and check the class. Both
|
|
589
|
+
* before `startExecution`, so a misrouted action leaves the log exactly as it
|
|
590
|
+
* found it. (The log is read twice on this path — once here, once inside
|
|
591
|
+
* `startExecution`, which reads for itself and compare-and-appends against
|
|
592
|
+
* the head it read. That is not redundancy to remove: a routing check that
|
|
593
|
+
* handed its records to core would be core trusting a caller's snapshot.)
|
|
594
|
+
* 3. **Resolve the declared credentials** (APRV-169), in a window of their own
|
|
595
|
+
* that closes at once. A name the provider cannot answer refuses
|
|
596
|
+
* `credential-unavailable` here, with the log untouched and the token
|
|
597
|
+
* unspent, so a missing secret costs no authority and the same token works
|
|
598
|
+
* once the secret appears. An adapter declaring none skips this entirely.
|
|
599
|
+
* 3b. **The adapter's own pre-token check** (APRV-276), in a window of its own,
|
|
600
|
+
* on the same presented-phase grant. Whatever it refuses is refused with the
|
|
601
|
+
* log untouched and the token unspent, so a condition the runtime could
|
|
602
|
+
* learn without attempting the side effect costs no authority to discover.
|
|
603
|
+
* An adapter implementing none skips this entirely, and so does a payload
|
|
604
|
+
* the log does not bind this action to: step 4 owns that refusal.
|
|
605
|
+
* 4. **`startExecution`**, which on the manual path verifies and consumes the
|
|
606
|
+
* token, refuses `payload-mismatch` against the digest from step 1, and
|
|
607
|
+
* appends `execution.started`. Any refusal here returns with `acted: false`;
|
|
608
|
+
* `act` is not called, so no side effect was attempted.
|
|
609
|
+
* 5. **`act`**, inside a credential window that closes the moment it returns.
|
|
610
|
+
* 6. **The outcome event**, and WHICH one depends on where things went wrong
|
|
611
|
+
* (APRV-120). `act` returning success is `execution.completed`; `act`
|
|
612
|
+
* returning a failure is `execution.failed`, because the provider answered
|
|
613
|
+
* and the answer was no; a throw on the way INTO `act` is `execution.failed`
|
|
614
|
+
* too, because nothing was attempted; and a throw from inside `act` is
|
|
615
|
+
* `execution.indeterminate`, because the provider may or may not have
|
|
616
|
+
* committed and this runtime cannot tell. The boundary is the invocation
|
|
617
|
+
* itself, not a judgment about the error.
|
|
618
|
+
*
|
|
619
|
+
* A refusal from step 6 is returned with `started_seq` set and the log left
|
|
620
|
+
* holding a dangling execution — which is the honest state, since the side
|
|
621
|
+
* effect did happen and its outcome could not be recorded. `approval status`
|
|
622
|
+
* reports it and `approval execution resolve` is how a human closes it. An
|
|
623
|
+
* indeterminate outcome is not that: it IS recorded, the consumption stays
|
|
624
|
+
* burned, a retry is refused, and `approval execution reconcile` is how a
|
|
625
|
+
* person resolves it from the relying party's own evidence.
|
|
626
|
+
*/
|
|
627
|
+
export declare function executeThroughAdapter(adapter: Adapter, request: AdapterExecuteRequest, options?: AdapterExecuteOptions): Promise<AdapterExecuteResult>;
|
|
628
|
+
export {};
|