approval-md 0.2.0 → 0.3.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 +63 -24
- package/SPEC.md +57 -11
- package/dist/src/channels/contract.d.ts +34 -1
- package/dist/src/channels/contract.js +200 -7
- package/dist/src/channels/contract.js.map +1 -1
- package/dist/src/channels/telegram.d.ts +123 -11
- package/dist/src/channels/telegram.js +218 -23
- package/dist/src/channels/telegram.js.map +1 -1
- package/dist/src/channels/web.d.ts +9 -0
- package/dist/src/channels/web.js +17 -0
- package/dist/src/channels/web.js.map +1 -1
- package/dist/src/cli/amend.js +214 -30
- package/dist/src/cli/amend.js.map +1 -1
- package/dist/src/cli/attest.d.ts +9 -0
- package/dist/src/cli/attest.js +134 -7
- package/dist/src/cli/attest.js.map +1 -1
- package/dist/src/cli/channel-telegram.d.ts +99 -26
- package/dist/src/cli/channel-telegram.js +311 -13
- package/dist/src/cli/channel-telegram.js.map +1 -1
- package/dist/src/cli/channel.d.ts +9 -0
- package/dist/src/cli/channel.js +9 -0
- package/dist/src/cli/channel.js.map +1 -1
- package/dist/src/cli/codex-bridge.d.ts +819 -0
- package/dist/src/cli/codex-bridge.js +1607 -0
- package/dist/src/cli/codex-bridge.js.map +1 -0
- package/dist/src/cli/codex.d.ts +1 -1
- package/dist/src/cli/codex.js +304 -7
- package/dist/src/cli/codex.js.map +1 -1
- package/dist/src/cli/daemon.js +4 -1
- package/dist/src/cli/daemon.js.map +1 -1
- package/dist/src/cli/doctor.js +467 -12
- package/dist/src/cli/doctor.js.map +1 -1
- package/dist/src/cli/execute.js +25 -2
- package/dist/src/cli/execute.js.map +1 -1
- package/dist/src/cli/help.d.ts +6 -2
- package/dist/src/cli/help.js +165 -60
- package/dist/src/cli/help.js.map +1 -1
- package/dist/src/cli/hook-codex.d.ts +49 -1
- package/dist/src/cli/hook-codex.js +60 -1
- package/dist/src/cli/hook-codex.js.map +1 -1
- package/dist/src/cli/hook.d.ts +459 -3
- package/dist/src/cli/hook.js +1062 -114
- package/dist/src/cli/hook.js.map +1 -1
- package/dist/src/cli/import.js +1 -1
- package/dist/src/cli/import.js.map +1 -1
- package/dist/src/cli/main.js +5 -3
- package/dist/src/cli/main.js.map +1 -1
- package/dist/src/cli/policy-apply.d.ts +195 -0
- package/dist/src/cli/policy-apply.js +573 -0
- package/dist/src/cli/policy-apply.js.map +1 -0
- package/dist/src/cli/policy.js +14 -1
- package/dist/src/cli/policy.js.map +1 -1
- package/dist/src/cli/preflight.d.ts +151 -13
- package/dist/src/cli/preflight.js +398 -41
- package/dist/src/cli/preflight.js.map +1 -1
- package/dist/src/cli/sandbox.js +17 -1
- package/dist/src/cli/sandbox.js.map +1 -1
- package/dist/src/cli/scaffold.d.ts +1 -1
- package/dist/src/cli/scaffold.js +1 -1
- package/dist/src/cli/setup-channel.d.ts +9 -0
- package/dist/src/cli/setup-channel.js +28 -1
- package/dist/src/cli/setup-channel.js.map +1 -1
- package/dist/src/cli/setup-common.d.ts +3 -1
- package/dist/src/cli/setup-common.js +3 -2
- package/dist/src/cli/setup-common.js.map +1 -1
- package/dist/src/cli/setup.d.ts +2 -0
- package/dist/src/cli/setup.js +94 -2
- package/dist/src/cli/setup.js.map +1 -1
- package/dist/src/cli/up.js +115 -51
- package/dist/src/cli/up.js.map +1 -1
- package/dist/src/cli/values.js +3 -4
- package/dist/src/cli/values.js.map +1 -1
- package/dist/src/cli/verb-registry.js +174 -9
- package/dist/src/cli/verb-registry.js.map +1 -1
- package/dist/src/cli/wordmark.d.ts +2 -2
- package/dist/src/cli/wordmark.js +2 -2
- package/dist/src/codex/broker.d.ts +229 -0
- package/dist/src/codex/broker.js +548 -0
- package/dist/src/codex/broker.js.map +1 -0
- package/dist/src/codex/runner.d.ts +178 -0
- package/dist/src/codex/runner.js +231 -0
- package/dist/src/codex/runner.js.map +1 -0
- package/dist/src/codex/serve.d.ts +56 -0
- package/dist/src/codex/serve.js +98 -0
- package/dist/src/codex/serve.js.map +1 -0
- package/dist/src/codex/workspace-commit.d.ts +219 -0
- package/dist/src/codex/workspace-commit.js +549 -0
- package/dist/src/codex/workspace-commit.js.map +1 -0
- package/dist/src/core/advance-cycle.d.ts +51 -0
- package/dist/src/core/advance-cycle.js +66 -2
- package/dist/src/core/advance-cycle.js.map +1 -1
- package/dist/src/core/agents-md.d.ts +20 -18
- package/dist/src/core/agents-md.js +33 -31
- package/dist/src/core/agents-md.js.map +1 -1
- package/dist/src/core/attest.d.ts +215 -0
- package/dist/src/core/attest.js +317 -7
- package/dist/src/core/attest.js.map +1 -1
- package/dist/src/core/audit.d.ts +18 -0
- package/dist/src/core/audit.js +13 -0
- package/dist/src/core/audit.js.map +1 -1
- package/dist/src/core/channel-owner.d.ts +213 -0
- package/dist/src/core/channel-owner.js +358 -0
- package/dist/src/core/channel-owner.js.map +1 -0
- package/dist/src/core/command-class.d.ts +154 -0
- package/dist/src/core/command-class.js +673 -20
- package/dist/src/core/command-class.js.map +1 -1
- package/dist/src/core/commit-guard.d.ts +272 -0
- package/dist/src/core/commit-guard.js +424 -0
- package/dist/src/core/commit-guard.js.map +1 -0
- package/dist/src/core/daemon-actor.d.ts +45 -0
- package/dist/src/core/daemon-actor.js +54 -0
- package/dist/src/core/daemon-actor.js.map +1 -0
- package/dist/src/core/dark-session.d.ts +109 -8
- package/dist/src/core/dark-session.js +266 -82
- package/dist/src/core/dark-session.js.map +1 -1
- package/dist/src/core/decision-refusal.d.ts +23 -2
- package/dist/src/core/decision-refusal.js +24 -2
- package/dist/src/core/decision-refusal.js.map +1 -1
- package/dist/src/core/env-file.d.ts +5 -0
- package/dist/src/core/env-file.js +60 -1
- package/dist/src/core/env-file.js.map +1 -1
- package/dist/src/core/execute.d.ts +15 -2
- package/dist/src/core/execute.js +15 -2
- package/dist/src/core/execute.js.map +1 -1
- package/dist/src/core/gate.d.ts +86 -1
- package/dist/src/core/gate.js +81 -1
- package/dist/src/core/gate.js.map +1 -1
- package/dist/src/core/gesture-refusal.d.ts +166 -0
- package/dist/src/core/gesture-refusal.js +188 -0
- package/dist/src/core/gesture-refusal.js.map +1 -0
- package/dist/src/core/harness-version.d.ts +1 -1
- package/dist/src/core/harness-version.js +3 -1
- package/dist/src/core/harness-version.js.map +1 -1
- package/dist/src/core/instance.d.ts +59 -2
- package/dist/src/core/instance.js +113 -0
- package/dist/src/core/instance.js.map +1 -1
- package/dist/src/core/log.d.ts +39 -1
- package/dist/src/core/log.js.map +1 -1
- package/dist/src/core/policy-explain.d.ts +10 -0
- package/dist/src/core/policy-explain.js +32 -0
- package/dist/src/core/policy-explain.js.map +1 -1
- package/dist/src/core/policy-load.d.ts +41 -1
- package/dist/src/core/policy-load.js +21 -3
- package/dist/src/core/policy-load.js.map +1 -1
- package/dist/src/core/policy-match.d.ts +43 -0
- package/dist/src/core/policy-match.js +52 -0
- package/dist/src/core/policy-match.js.map +1 -1
- package/dist/src/core/policy-proposal.d.ts +52 -0
- package/dist/src/core/policy-proposal.js +102 -2
- package/dist/src/core/policy-proposal.js.map +1 -1
- package/dist/src/core/protected-path-guard.d.ts +117 -4
- package/dist/src/core/protected-path-guard.js +362 -48
- package/dist/src/core/protected-path-guard.js.map +1 -1
- package/dist/src/core/question-preempted.d.ts +141 -0
- package/dist/src/core/question-preempted.js +152 -0
- package/dist/src/core/question-preempted.js.map +1 -0
- package/dist/src/core/read-scope.d.ts +172 -0
- package/dist/src/core/read-scope.js +252 -0
- package/dist/src/core/read-scope.js.map +1 -0
- package/dist/src/core/sandbox.d.ts +81 -0
- package/dist/src/core/sandbox.js +190 -1
- package/dist/src/core/sandbox.js.map +1 -1
- package/dist/src/core/sender-identity.d.ts +476 -0
- package/dist/src/core/sender-identity.js +572 -0
- package/dist/src/core/sender-identity.js.map +1 -0
- package/dist/src/core/shlex.d.ts +102 -0
- package/dist/src/core/shlex.js +159 -0
- package/dist/src/core/shlex.js.map +1 -0
- package/dist/src/core/values.d.ts +18 -8
- package/dist/src/core/values.js +36 -1
- package/dist/src/core/values.js.map +1 -1
- package/dist/src/daemon/advance.d.ts +10 -0
- package/dist/src/daemon/advance.js +25 -4
- package/dist/src/daemon/advance.js.map +1 -1
- package/dist/src/daemon/daemon.js +9 -0
- package/dist/src/daemon/daemon.js.map +1 -1
- package/dist/src/daemon/git-evidence.d.ts +2 -2
- package/dist/src/daemon/git-evidence.js +1 -1
- package/dist/src/mcp/server.js +8 -0
- package/dist/src/mcp/server.js.map +1 -1
- package/docs/cli-reference.md +932 -32
- package/docs/codex-enforced-session.md +75 -2
- package/docs/codex-workspace-broker.md +118 -0
- package/package.json +3 -1
- package/schema/event.schema.json +538 -9
- package/schema/fixtures/event/invalid/approval-granted-sender-hashed-false.json +20 -0
- package/schema/fixtures/event/invalid/approval-granted-sender-hashed-raw-id.json +20 -0
- package/schema/fixtures/event/invalid/audit-gesture-refused-human-actor.json +16 -0
- package/schema/fixtures/event/invalid/audit-gesture-refused-no-actor-no-sender.json +15 -0
- package/schema/fixtures/event/invalid/audit-gesture-refused-unknown-gesture.json +16 -0
- package/schema/fixtures/event/invalid/audit-question-preempted-agent-actor.json +16 -0
- package/schema/fixtures/event/invalid/audit-question-preempted-no-question-id.json +16 -0
- package/schema/fixtures/event/invalid/audit-question-preempted-unknown-source.json +15 -0
- package/schema/fixtures/event/invalid/gate-path-signed-off-absolute-path.json +14 -0
- package/schema/fixtures/event/invalid/gate-path-signed-off-agent-actor.json +14 -0
- package/schema/fixtures/event/invalid/gate-path-signed-off-missing-path.json +13 -0
- package/schema/fixtures/event/valid/approval-granted-sender-hashed.json +20 -0
- package/schema/fixtures/event/valid/audit-gesture-refused-review-note.json +21 -0
- package/schema/fixtures/event/valid/audit-gesture-refused-sender-key-unavailable.json +19 -0
- package/schema/fixtures/event/valid/audit-gesture-refused.json +19 -0
- package/schema/fixtures/event/valid/audit-question-preempted-no-verdict.json +16 -0
- package/schema/fixtures/event/valid/audit-question-preempted.json +20 -0
- package/schema/fixtures/event/valid/gate-path-signed-off.json +14 -0
- package/schema/fixtures/event/valid/harness-kind-claude-code.json +23 -0
- package/schema/fixtures/event/valid/harness-kind-codex.json +23 -0
- package/schema/fixtures/event/valid/harness-kind-cursor.json +23 -0
- package/schema/fixtures/event/valid/harness-kind-grok.json +23 -0
- package/schema/fixtures/event/valid/harness-kind-muse.json +23 -0
- package/schema/fixtures/policy/invalid/senders-half-keyed.json +20 -0
- package/schema/fixtures/policy/valid/canonical.json +1 -1
- package/schema/fixtures/policy/valid/senders-keyed.json +24 -0
- package/schema/fixtures/policy-md/valid/canonical.md +1 -1
- package/schema/fixtures/policy-md/valid/with-values.md +5 -7
- package/schema/fixtures/values/invalid/class-shaped.json +1 -1
- package/schema/fixtures/values/invalid/duplicate-entry.json +1 -1
- package/schema/fixtures/values/invalid/non-string-item.json +1 -1
- package/schema/fixtures/values/invalid/over-cap.json +1 -1
- package/schema/fixtures/values/invalid/unknown-key.json +1 -1
- package/schema/fixtures/values/invalid/version-float.json +1 -0
- package/schema/fixtures/values/invalid/version-integer.json +1 -0
- package/schema/fixtures/values/invalid/version-wrong-string.json +1 -0
- package/schema/fixtures/values/valid/empty-lists.json +2 -3
- package/schema/fixtures/values/valid/full.json +5 -7
- package/schema/fixtures/values/valid/minimal.json +1 -1
- package/schema/fixtures/values-md/invalid/schema-invalid.md +5 -3
- package/schema/fixtures/values-md/invalid/two-blocks.md +3 -3
- package/schema/fixtures/values-md/invalid/unterminated.md +2 -2
- package/schema/fixtures/values-md/invalid/version-1.md +69 -0
- package/schema/fixtures/values-md/invalid/version-unquoted.md +64 -0
- package/schema/fixtures/values-md/invalid/yaml-error.md +2 -2
- package/schema/fixtures/values-md/valid/absent.md +1 -1
- package/schema/fixtures/values-md/valid/with-values.md +5 -7
- package/schema/policy.schema.json +54 -2
- package/schema/values.schema.json +7 -11
- package/schema/fixtures/values/invalid/version-string.json +0 -1
|
@@ -0,0 +1,229 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The policy-bound Codex workspace change broker (APRV-325.2).
|
|
3
|
+
*
|
|
4
|
+
* APRV-325.1 shipped preparation, APRV-325.2.1 shipped the read-only planner,
|
|
5
|
+
* and this module is the thing both were for: the ONLY way a change reaches a
|
|
6
|
+
* canonical workspace in a constrained Codex session. It is deliberately not a
|
|
7
|
+
* mode of `src/mcp/server.ts`. That server publishes the whole agent verb
|
|
8
|
+
* catalog, including `run`, and a broker that lived inside it would be one
|
|
9
|
+
* unchecked flag away from the surface it exists to replace.
|
|
10
|
+
*
|
|
11
|
+
* ## What the caller may say, and what it may not
|
|
12
|
+
*
|
|
13
|
+
* A caller supplies exactly two things: a bounded list of typed operations, and
|
|
14
|
+
* the SHA-256 it believes the policy currently has. Everything else — the
|
|
15
|
+
* acting identity, the workspace root, the policy file, the log, the schema
|
|
16
|
+
* directory, the classes, the reversibility, the sandbox posture — comes from
|
|
17
|
+
* the installation manifest, which lives under a root-owned install root that
|
|
18
|
+
* no agent principal can write (`codex/manifest.ts`, `codex/trust.ts`).
|
|
19
|
+
* {@link parseBrokerInput} refuses an unknown key rather than ignoring it, so a
|
|
20
|
+
* caller that tries to name its own actor is told no instead of being quietly
|
|
21
|
+
* overridden, and {@link BROKER_TOOLS} is a POSITIVE allowlist of one: a name
|
|
22
|
+
* not on it is refused whether or not any surface advertised it.
|
|
23
|
+
*
|
|
24
|
+
* ## One action per class, never collapsed
|
|
25
|
+
*
|
|
26
|
+
* The planner returns one action leg per distinct path class, and this module
|
|
27
|
+
* registers, requests, starts and closes each of them separately. Collapsing
|
|
28
|
+
* four classes into one "workspace write" would lose exactly what the policy
|
|
29
|
+
* is for: the class is what the operator's roster, budget and autonomy are
|
|
30
|
+
* keyed to, and an action that reports a cheaper class than it performs is the
|
|
31
|
+
* self-reporting SPEC.md §11.1 invariant 4 forbids.
|
|
32
|
+
*
|
|
33
|
+
* ## The order, and why every step of it is load-bearing
|
|
34
|
+
*
|
|
35
|
+
* Read policy once and hash those exact bytes → check attestation against
|
|
36
|
+
* VERIFIED records → refuse if the caller's expected digest differs → plan →
|
|
37
|
+
* register the legs → authorize EVERY leg (policy, or a real grant token) →
|
|
38
|
+
* start EVERY leg → take custody → revalidate the plan UNDER custody → commit
|
|
39
|
+
* durably → read the workspace back → close every leg with what the reading
|
|
40
|
+
* said.
|
|
41
|
+
*
|
|
42
|
+
* Two of those orderings are the hard-won ones from the 2026-09-09 handover.
|
|
43
|
+
* **Every leg starts before any byte moves**, so a leg that refuses at start
|
|
44
|
+
* leaves a workspace that is untouched by construction rather than by cleanup;
|
|
45
|
+
* the already-started legs are closed `execution.failed` and the filesystem was
|
|
46
|
+
* never entered. And **revalidation happens under custody**, after the last
|
|
47
|
+
* start, because a revalidation that precedes the lock proves only what was
|
|
48
|
+
* true before another writer could act.
|
|
49
|
+
*
|
|
50
|
+
* ## Outcomes are read, not remembered
|
|
51
|
+
*
|
|
52
|
+
* `codex/workspace-commit.ts` classifies the workspace by reading it back
|
|
53
|
+
* against the journal. All-after closes every leg `execution.completed`;
|
|
54
|
+
* all-before closes every leg `execution.failed`; anything else — a partial
|
|
55
|
+
* apply, a failed rollback, an endpoint that could not be read — closes every
|
|
56
|
+
* leg `execution.indeterminate` with reason `workspace-commit-unknown`, the
|
|
57
|
+
* reason this task added to SPEC.md §8's closed set. Nothing here converts an
|
|
58
|
+
* indeterminate outcome into either of the others; that stays human-owned
|
|
59
|
+
* (`approval execution reconcile`).
|
|
60
|
+
*/
|
|
61
|
+
import type { ClockOptions } from "../core/clock.js";
|
|
62
|
+
import type { AppendOptions } from "../core/log.js";
|
|
63
|
+
import type { CodexInstanceManifest } from "./manifest.js";
|
|
64
|
+
import { type CustodyReport, type WorkspaceState } from "./workspace-commit.js";
|
|
65
|
+
export declare const BROKER_VERSION: "approval.codex.broker.v1";
|
|
66
|
+
/**
|
|
67
|
+
* The positive server-side tool allowlist: one name, and nothing is reachable
|
|
68
|
+
* by any other.
|
|
69
|
+
*
|
|
70
|
+
* A deny list would have to name every verb the runtime grows next; this names
|
|
71
|
+
* the one a constrained Codex session may call, so anything added tomorrow is
|
|
72
|
+
* unreachable here until somebody decides otherwise. Fail closed, SPEC.md §11.
|
|
73
|
+
*/
|
|
74
|
+
export declare const BROKER_TOOLS: ReadonlySet<string>;
|
|
75
|
+
/** The indeterminate reason a mixed or unreadable commit records (SPEC.md §8). */
|
|
76
|
+
export declare const WORKSPACE_COMMIT_UNKNOWN: "workspace-commit-unknown";
|
|
77
|
+
/**
|
|
78
|
+
* Everything the broker is, derived from the manifest and from nothing a caller
|
|
79
|
+
* said. Constructed by {@link brokerInstallation}; there is no other maker.
|
|
80
|
+
*/
|
|
81
|
+
export interface BrokerInstallation {
|
|
82
|
+
instanceId: string;
|
|
83
|
+
/** `agent:codex-<instance_id>`, fixed by the installation. */
|
|
84
|
+
actor: string;
|
|
85
|
+
/** The canonical workspace root, absolute and normalized. */
|
|
86
|
+
root: string;
|
|
87
|
+
policyPath: string;
|
|
88
|
+
logPath: string;
|
|
89
|
+
}
|
|
90
|
+
/** Derive the fixed context from a validated instance manifest. */
|
|
91
|
+
export declare function brokerInstallation(manifest: CodexInstanceManifest): BrokerInstallation;
|
|
92
|
+
/** The whole of what a caller may say. */
|
|
93
|
+
export interface BrokerInput {
|
|
94
|
+
operations: unknown;
|
|
95
|
+
expected_policy_sha256: string;
|
|
96
|
+
}
|
|
97
|
+
export type BrokerInputResult = {
|
|
98
|
+
ok: true;
|
|
99
|
+
input: BrokerInput;
|
|
100
|
+
} | {
|
|
101
|
+
ok: false;
|
|
102
|
+
message: string;
|
|
103
|
+
};
|
|
104
|
+
/**
|
|
105
|
+
* Accept `{operations, expected_policy_sha256}` and refuse everything else.
|
|
106
|
+
*
|
|
107
|
+
* An unknown key is a refusal rather than a silent drop for the reason the MCP
|
|
108
|
+
* server refuses `--as`: a caller that named an actor, a root, a class or a
|
|
109
|
+
* token meant something by it, and the something they meant is not available
|
|
110
|
+
* here. Being told so is the only way they learn that.
|
|
111
|
+
*/
|
|
112
|
+
export declare function parseBrokerInput(value: unknown): BrokerInputResult;
|
|
113
|
+
/**
|
|
114
|
+
* Every way the broker can say no. Frozen public API in the sense SPEC.md
|
|
115
|
+
* §11.1 invariant 6 means: each fires for exactly one condition, they are
|
|
116
|
+
* distinct from one another, and `tests/codex-broker.test.ts` pins the union.
|
|
117
|
+
*/
|
|
118
|
+
export declare const BROKER_REFUSAL_CODES: readonly [
|
|
119
|
+
/** The tool name is not on {@link BROKER_TOOLS}. */
|
|
120
|
+
"tool-not-allowed",
|
|
121
|
+
/** The caller's object is not `{operations, expected_policy_sha256}`. */
|
|
122
|
+
"input-invalid",
|
|
123
|
+
/** The workspace root is not an absolute normalized path. */
|
|
124
|
+
"installation-invalid",
|
|
125
|
+
/** The log could not be read, is torn, or does not verify. */
|
|
126
|
+
"log-unavailable",
|
|
127
|
+
/** The policy file could not be read or parsed. */
|
|
128
|
+
"policy-unavailable",
|
|
129
|
+
/** The live policy bytes are not the attested ones. */
|
|
130
|
+
"policy-not-attested",
|
|
131
|
+
/** The caller's expected digest is not the live attested digest. */
|
|
132
|
+
"attestation-drift",
|
|
133
|
+
/** An endpoint names the broker's own reserved transaction paths. */
|
|
134
|
+
"reserved-path",
|
|
135
|
+
/** A replace whose after-image equals its preimage: nothing to approve. */
|
|
136
|
+
"no-op-operation",
|
|
137
|
+
/** The planner refused. `detail` carries its own code verbatim. */
|
|
138
|
+
"plan-refused",
|
|
139
|
+
/** The log already declares this task or key under different bytes. */
|
|
140
|
+
"replay",
|
|
141
|
+
/** Registration refused for any other gate reason. */
|
|
142
|
+
"register-refused",
|
|
143
|
+
/** Intake refused for any gate reason. */
|
|
144
|
+
"request-refused",
|
|
145
|
+
/** A leg needs a human's grant and no token for it was presented. */
|
|
146
|
+
"approval-required",
|
|
147
|
+
/** A leg's `execution.started` refused. Nothing was written to the workspace. */
|
|
148
|
+
"start-refused",
|
|
149
|
+
/** Another transaction holds the workspace lock. */
|
|
150
|
+
"custody-contended",
|
|
151
|
+
/** The lock or staging directory could not be created. */
|
|
152
|
+
"custody-unavailable",
|
|
153
|
+
/** The installation requires OS-exclusive custody and the host cannot prove it. */
|
|
154
|
+
"custody-insufficient",
|
|
155
|
+
/** The plan no longer validates against the workspace under custody. */
|
|
156
|
+
"workspace-drift",
|
|
157
|
+
/** Staging failed; the workspace is untouched by construction. */
|
|
158
|
+
"stage-failed",
|
|
159
|
+
/** The commit was attempted and did not take. Every leg is `execution.failed`. */
|
|
160
|
+
"commit-not-applied",
|
|
161
|
+
/** The commit was attempted and nobody knows. Every leg is indeterminate. */
|
|
162
|
+
"commit-unknown"];
|
|
163
|
+
export type BrokerRefusalCode = (typeof BROKER_REFUSAL_CODES)[number];
|
|
164
|
+
export interface BrokerRefusal {
|
|
165
|
+
ok: false;
|
|
166
|
+
code: BrokerRefusalCode;
|
|
167
|
+
message: string;
|
|
168
|
+
/** The underlying layer's own code, when this refusal wraps one. */
|
|
169
|
+
detail?: string;
|
|
170
|
+
/** The action keys a human must decide, when `code` is `approval-required`. */
|
|
171
|
+
pending?: readonly string[];
|
|
172
|
+
/** Present once a commit was attempted: what reading the workspace proved. */
|
|
173
|
+
state?: WorkspaceState;
|
|
174
|
+
}
|
|
175
|
+
export interface BrokerOptions extends ClockOptions {
|
|
176
|
+
/**
|
|
177
|
+
* Grant tokens, keyed by CLASS, for the legs whose policy resolves manual.
|
|
178
|
+
*
|
|
179
|
+
* Keyed by class rather than by action key because the class is the thing a
|
|
180
|
+
* human decided about and the key is derived; a caller cannot use this map to
|
|
181
|
+
* reach a leg it did not register, because every key is recomputed here.
|
|
182
|
+
*/
|
|
183
|
+
tokens?: Readonly<Record<string, string>>;
|
|
184
|
+
/**
|
|
185
|
+
* Refuse unless the host proves OS-exclusive write custody (APRV-325.3 sets
|
|
186
|
+
* it). Absent, the broker still REPORTS which custody it got: the claim never
|
|
187
|
+
* silently softens, only the refusal is optional.
|
|
188
|
+
*/
|
|
189
|
+
requireExclusiveCustody?: boolean;
|
|
190
|
+
schemaDir?: string;
|
|
191
|
+
append?: AppendOptions;
|
|
192
|
+
/** Forwarded verbatim to the commit's test seam. See `CommitOptions.onStep`. */
|
|
193
|
+
onStep?: (step: number) => void;
|
|
194
|
+
/** Test seam: called once after the last start and before custody is taken. */
|
|
195
|
+
afterStart?: () => void;
|
|
196
|
+
}
|
|
197
|
+
/** One class's leg through the gate. */
|
|
198
|
+
export interface BrokerLeg {
|
|
199
|
+
class: string;
|
|
200
|
+
actionKey: string;
|
|
201
|
+
/** How it was authorized: `policy` (no token exists) or `token` (a real grant). */
|
|
202
|
+
mode: "policy" | "token";
|
|
203
|
+
}
|
|
204
|
+
export interface BrokerSuccess {
|
|
205
|
+
ok: true;
|
|
206
|
+
version: typeof BROKER_VERSION;
|
|
207
|
+
task: string;
|
|
208
|
+
payload_hash: string;
|
|
209
|
+
policy_sha256: string;
|
|
210
|
+
legs: readonly BrokerLeg[];
|
|
211
|
+
custody: CustodyReport;
|
|
212
|
+
/** Always `"after"`: a success is a workspace that was read back as applied. */
|
|
213
|
+
state: "after";
|
|
214
|
+
}
|
|
215
|
+
export type BrokerResult = BrokerSuccess | BrokerRefusal;
|
|
216
|
+
/** The task id one proposal's bytes always produce. Deterministic, so a replay collides. */
|
|
217
|
+
export declare function brokerTaskId(instanceId: string, payloadHash: string): string;
|
|
218
|
+
/** The action key one class's leg always produces under that task. */
|
|
219
|
+
export declare function brokerActionKey(task: string, cls: string): string;
|
|
220
|
+
/**
|
|
221
|
+
* Apply one bounded typed proposal to the canonical workspace, or say exactly
|
|
222
|
+
* why not.
|
|
223
|
+
*
|
|
224
|
+
* `tool` is checked against {@link BROKER_TOOLS} first, before the input is
|
|
225
|
+
* even parsed: a surface that published nothing still refuses a name it does
|
|
226
|
+
* not serve, which is the defence in depth `src/mcp/server.ts` keeps for
|
|
227
|
+
* `mcp-guest-restricted`.
|
|
228
|
+
*/
|
|
229
|
+
export declare function applyWorkspaceChange(tool: string, installation: BrokerInstallation, rawInput: unknown, options?: BrokerOptions): BrokerResult;
|