@fusionkit/plane 0.1.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 (52) hide show
  1. package/dist/auth.d.ts +18 -0
  2. package/dist/auth.js +46 -0
  3. package/dist/claim-token-service.d.ts +23 -0
  4. package/dist/claim-token-service.js +54 -0
  5. package/dist/contract-service.d.ts +14 -0
  6. package/dist/contract-service.js +39 -0
  7. package/dist/domain-errors.d.ts +13 -0
  8. package/dist/domain-errors.js +31 -0
  9. package/dist/idp.d.ts +26 -0
  10. package/dist/idp.js +24 -0
  11. package/dist/index.d.ts +35 -0
  12. package/dist/index.js +21 -0
  13. package/dist/keys.d.ts +60 -0
  14. package/dist/keys.js +132 -0
  15. package/dist/logging.d.ts +21 -0
  16. package/dist/logging.js +42 -0
  17. package/dist/plane.d.ts +167 -0
  18. package/dist/plane.js +606 -0
  19. package/dist/policy.d.ts +23 -0
  20. package/dist/policy.js +92 -0
  21. package/dist/ratelimit.d.ts +40 -0
  22. package/dist/ratelimit.js +94 -0
  23. package/dist/receipt-service.d.ts +16 -0
  24. package/dist/receipt-service.js +17 -0
  25. package/dist/retention.d.ts +33 -0
  26. package/dist/retention.js +123 -0
  27. package/dist/run-lifecycle.d.ts +2 -0
  28. package/dist/run-lifecycle.js +19 -0
  29. package/dist/secrets.d.ts +25 -0
  30. package/dist/secrets.js +73 -0
  31. package/dist/server.d.ts +38 -0
  32. package/dist/server.js +418 -0
  33. package/dist/sqlite-store.d.ts +53 -0
  34. package/dist/sqlite-store.js +401 -0
  35. package/dist/store.d.ts +107 -0
  36. package/dist/store.js +9 -0
  37. package/dist/test/api.test.d.ts +1 -0
  38. package/dist/test/api.test.js +179 -0
  39. package/dist/test/hardening.test.d.ts +1 -0
  40. package/dist/test/hardening.test.js +259 -0
  41. package/dist/test/policy.test.d.ts +1 -0
  42. package/dist/test/policy.test.js +78 -0
  43. package/dist/test/server-hardening.test.d.ts +1 -0
  44. package/dist/test/server-hardening.test.js +192 -0
  45. package/dist/test/ui-parity.test.d.ts +1 -0
  46. package/dist/test/ui-parity.test.js +28 -0
  47. package/dist/validation.d.ts +326 -0
  48. package/dist/validation.js +178 -0
  49. package/package.json +34 -0
  50. package/ui/app.css +276 -0
  51. package/ui/app.js +483 -0
  52. package/ui/index.html +65 -0
@@ -0,0 +1,192 @@
1
+ import assert from "node:assert/strict";
2
+ import { mkdtempSync, rmSync } from "node:fs";
3
+ import { tmpdir } from "node:os";
4
+ import { join } from "node:path";
5
+ import { after, before, test } from "node:test";
6
+ import { generateEd25519KeyPair } from "@fusionkit/protocol";
7
+ import { generateMasterKeyHex, masterKeyFromMaterial } from "../keys.js";
8
+ import { Plane } from "../plane.js";
9
+ import { defaultPolicy } from "../policy.js";
10
+ import { SecretStore } from "../secrets.js";
11
+ import { startPlaneServer } from "../server.js";
12
+ const ADMIN = "srv-admin";
13
+ let dir;
14
+ let plane;
15
+ let server;
16
+ let baseUrl;
17
+ let requesterToken;
18
+ function manifest() {
19
+ return {
20
+ version: "warrant.manifest.v1",
21
+ baseRef: "0".repeat(40),
22
+ bundleHash: "1".repeat(64),
23
+ untrackedFiles: [],
24
+ deniedPatterns: [],
25
+ deniedPaths: []
26
+ };
27
+ }
28
+ function runBody() {
29
+ return {
30
+ requestedBy: { kind: "human", id: "tester" },
31
+ agentKind: "mock",
32
+ prompt: "server hardening",
33
+ pool: "default",
34
+ secretNames: [],
35
+ workspace: manifest(),
36
+ network: { defaultDeny: true, allowHosts: [] },
37
+ budget: {},
38
+ disclosure: "minimal-context"
39
+ };
40
+ }
41
+ async function http(method, path, options = {}) {
42
+ const headers = {};
43
+ if (options.token)
44
+ headers.authorization = `Bearer ${options.token}`;
45
+ if (options.body !== undefined || options.rawBody !== undefined) {
46
+ headers["content-type"] = "application/json";
47
+ }
48
+ const response = await fetch(`${baseUrl}${path}`, {
49
+ method,
50
+ headers,
51
+ body: options.rawBody ??
52
+ (options.body === undefined ? undefined : JSON.stringify(options.body))
53
+ });
54
+ const text = await response.text();
55
+ return {
56
+ status: response.status,
57
+ body: text.length > 0 ? JSON.parse(text) : undefined
58
+ };
59
+ }
60
+ before(async () => {
61
+ dir = mkdtempSync(join(tmpdir(), "warrant-srv-"));
62
+ const keys = generateEd25519KeyPair();
63
+ plane = new Plane({
64
+ dataDir: dir,
65
+ policy: defaultPolicy(),
66
+ planePrivateKeyPem: keys.privateKeyPem,
67
+ planePublicKeyPem: keys.publicKeyPem,
68
+ adminToken: ADMIN,
69
+ enrollToken: "srv-enroll",
70
+ secretStore: new SecretStore(join(dir, "secrets.enc"), masterKeyFromMaterial(generateMasterKeyHex()))
71
+ });
72
+ requesterToken = plane.issuePrincipal("ci", "requester").token;
73
+ const started = await startPlaneServer(plane, { port: 0 });
74
+ server = started.server;
75
+ baseUrl = `http://127.0.0.1:${started.port}`;
76
+ });
77
+ after(() => {
78
+ server.close(() => undefined);
79
+ plane.close();
80
+ rmSync(dir, { recursive: true, force: true });
81
+ });
82
+ test("readiness and health probes", async () => {
83
+ assert.equal((await http("GET", "/v1/health")).status, 200);
84
+ const ready = await http("GET", "/v1/ready");
85
+ assert.equal(ready.status, 200);
86
+ assert.deepEqual(ready.body, { ready: true });
87
+ });
88
+ test("auth distinguishes 401 (no/invalid token) from 403 (wrong role)", async () => {
89
+ assert.equal((await http("GET", "/v1/runs")).status, 401);
90
+ assert.equal((await http("GET", "/v1/runs", { token: "bogus" })).status, 401);
91
+ // requester may read/create runs but not list runners or manage principals.
92
+ assert.equal((await http("GET", "/v1/runs", { token: requesterToken })).status, 200);
93
+ assert.equal((await http("GET", "/v1/runners", { token: requesterToken })).status, 403);
94
+ assert.equal((await http("GET", "/v1/principals", { token: requesterToken })).status, 403);
95
+ assert.equal((await http("GET", "/v1/principals", { token: ADMIN })).status, 200);
96
+ });
97
+ test("malformed JSON and schema violations return structured 400s", async () => {
98
+ const malformed = await http("POST", "/v1/runs", {
99
+ token: ADMIN,
100
+ rawBody: "{not json"
101
+ });
102
+ assert.equal(malformed.status, 400);
103
+ const missingRequest = await http("POST", "/v1/runs", {
104
+ token: ADMIN,
105
+ body: {}
106
+ });
107
+ assert.equal(missingRequest.status, 400);
108
+ assert.ok(Array.isArray(missingRequest.body.issues));
109
+ const badEnum = await http("POST", "/v1/runs", {
110
+ token: ADMIN,
111
+ body: { request: { ...runBody(), disclosure: "nonsense" } }
112
+ });
113
+ assert.equal(badEnum.status, 400);
114
+ const badHash = await http("POST", "/v1/runs", {
115
+ token: ADMIN,
116
+ body: {
117
+ request: {
118
+ ...runBody(),
119
+ workspace: { ...manifest(), bundleHash: "not-a-hash" }
120
+ }
121
+ }
122
+ });
123
+ assert.equal(badHash.status, 400);
124
+ });
125
+ test("valid run request is accepted and listed", async () => {
126
+ const created = await http("POST", "/v1/runs", {
127
+ token: ADMIN,
128
+ body: { request: runBody() }
129
+ });
130
+ assert.equal(created.status, 200);
131
+ const list = await http("GET", "/v1/runs", { token: ADMIN });
132
+ assert.equal(list.status, 200);
133
+ });
134
+ test("admin can mint and use a single-use enroll token over HTTP", async () => {
135
+ const issued = await http("POST", "/v1/enroll-tokens", { token: ADMIN });
136
+ assert.equal(issued.status, 200);
137
+ const token = issued.body.token;
138
+ const enroll = await http("POST", "/v1/runners/enroll", {
139
+ body: {
140
+ enrollToken: token,
141
+ publicKeyPem: generateEd25519KeyPair().publicKeyPem,
142
+ pool: "default"
143
+ }
144
+ });
145
+ assert.equal(enroll.status, 200);
146
+ // Reuse is rejected.
147
+ const reuse = await http("POST", "/v1/runners/enroll", {
148
+ body: {
149
+ enrollToken: token,
150
+ publicKeyPem: generateEd25519KeyPair().publicKeyPem,
151
+ pool: "default"
152
+ }
153
+ });
154
+ assert.equal(reuse.status, 400);
155
+ });
156
+ test("rate limiting trips after the burst is exhausted", async () => {
157
+ // A dedicated server with a tiny bucket so the limit trips deterministically
158
+ // without starving the other tests sharing the main server.
159
+ const tinyDir = mkdtempSync(join(tmpdir(), "warrant-rl-"));
160
+ const keys = generateEd25519KeyPair();
161
+ const tinyPlane = new Plane({
162
+ dataDir: tinyDir,
163
+ policy: defaultPolicy(),
164
+ planePrivateKeyPem: keys.privateKeyPem,
165
+ planePublicKeyPem: keys.publicKeyPem,
166
+ adminToken: "rl-admin",
167
+ enrollToken: "rl-enroll",
168
+ secretStore: new SecretStore(join(tinyDir, "secrets.enc"), masterKeyFromMaterial(generateMasterKeyHex()))
169
+ });
170
+ const started = await startPlaneServer(tinyPlane, {
171
+ port: 0,
172
+ rateLimit: { ratePerSec: 1, burst: 3, authFailureLimit: 100, authFailureWindowMs: 1000 }
173
+ });
174
+ const tinyUrl = `http://127.0.0.1:${started.port}`;
175
+ try {
176
+ const statuses = [];
177
+ for (let i = 0; i < 6; i++) {
178
+ const res = await fetch(`${tinyUrl}/v1/runs`, {
179
+ headers: { authorization: "Bearer rl-admin" }
180
+ });
181
+ statuses.push(res.status);
182
+ await res.arrayBuffer();
183
+ }
184
+ assert.ok(statuses.includes(200), "the first requests within the burst succeed");
185
+ assert.ok(statuses.includes(429), "later requests are rate limited");
186
+ }
187
+ finally {
188
+ await new Promise((resolve) => started.server.close(() => resolve()));
189
+ tinyPlane.close();
190
+ rmSync(tinyDir, { recursive: true, force: true });
191
+ }
192
+ });
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,28 @@
1
+ import assert from "node:assert/strict";
2
+ import { readFileSync } from "node:fs";
3
+ import { dirname, join } from "node:path";
4
+ import { fileURLToPath } from "node:url";
5
+ import { test } from "node:test";
6
+ import { RUN_EVENT_TYPES } from "@fusionkit/protocol";
7
+ /**
8
+ * The control panel is deliberately dependency-free, so it carries its own
9
+ * copy of the event-summary switch instead of importing the protocol's
10
+ * `summarizeRunEvent`. This test is the drift guard the copy pays for: the
11
+ * UI must name exactly the run-event types the protocol vocabulary declares
12
+ * (which is itself completeness-checked against the `RunEvent` union at
13
+ * compile time). Adding an event type without teaching the panel about it
14
+ * fails here, not silently in a browser's default branch.
15
+ */
16
+ const APP_JS = join(dirname(fileURLToPath(import.meta.url)), "..", "..", "ui", "app.js");
17
+ test("the control panel's eventSummary covers exactly the protocol's run-event types", () => {
18
+ const source = readFileSync(APP_JS, "utf8");
19
+ const start = source.indexOf("function eventSummary(");
20
+ assert.ok(start >= 0, "ui/app.js must define eventSummary");
21
+ const end = source.indexOf("function ", start + 1);
22
+ const body = source.slice(start, end === -1 ? undefined : end);
23
+ const seen = new Set();
24
+ for (const match of body.matchAll(/case "([a-z.]+)":/g)) {
25
+ seen.add(match[1]);
26
+ }
27
+ assert.deepEqual([...seen].sort(), [...RUN_EVENT_TYPES].sort(), "ui eventSummary switch must handle exactly the protocol's RunEvent types");
28
+ });
@@ -0,0 +1,326 @@
1
+ import { z } from "zod";
2
+ export declare const runRequestSchema: z.ZodObject<{
3
+ requestedBy: z.ZodObject<{
4
+ kind: z.ZodEnum<{
5
+ human: "human";
6
+ service: "service";
7
+ }>;
8
+ id: z.ZodString;
9
+ }, z.core.$strip>;
10
+ agentKind: z.ZodString;
11
+ agentVersion: z.ZodOptional<z.ZodString>;
12
+ prompt: z.ZodString;
13
+ pool: z.ZodPipe<z.ZodString, z.ZodTransform<string, string>>;
14
+ secretNames: z.ZodArray<z.ZodPipe<z.ZodString, z.ZodTransform<string, string>>>;
15
+ workspace: z.ZodObject<{
16
+ version: z.ZodLiteral<"warrant.manifest.v1">;
17
+ baseRef: z.ZodString;
18
+ bundleHash: z.ZodString;
19
+ dirtyDiffHash: z.ZodOptional<z.ZodString>;
20
+ untrackedFiles: z.ZodArray<z.ZodObject<{
21
+ path: z.ZodPipe<z.ZodString, z.ZodTransform<string, string>>;
22
+ hash: z.ZodString;
23
+ bytes: z.ZodNumber;
24
+ }, z.core.$strip>>;
25
+ deniedPatterns: z.ZodArray<z.ZodString>;
26
+ deniedPaths: z.ZodArray<z.ZodPipe<z.ZodString, z.ZodTransform<string, string>>>;
27
+ }, z.core.$strip>;
28
+ network: z.ZodObject<{
29
+ defaultDeny: z.ZodBoolean;
30
+ allowHosts: z.ZodArray<z.ZodPipe<z.ZodString, z.ZodTransform<string, string>>>;
31
+ }, z.core.$strip>;
32
+ budget: z.ZodObject<{
33
+ maxSpendUsd: z.ZodOptional<z.ZodNumber>;
34
+ maxDurationMin: z.ZodOptional<z.ZodNumber>;
35
+ }, z.core.$strip>;
36
+ disclosure: z.ZodEnum<{
37
+ none: "none";
38
+ "metadata-only": "metadata-only";
39
+ redacted: "redacted";
40
+ "minimal-context": "minimal-context";
41
+ full: "full";
42
+ }>;
43
+ execution: z.ZodOptional<z.ZodDiscriminatedUnion<[z.ZodObject<{
44
+ kind: z.ZodLiteral<"shell">;
45
+ script: z.ZodString;
46
+ shell: z.ZodOptional<z.ZodEnum<{
47
+ sh: "sh";
48
+ bash: "bash";
49
+ }>>;
50
+ cwd: z.ZodOptional<z.ZodPipe<z.ZodString, z.ZodTransform<string, string>>>;
51
+ timeoutMs: z.ZodOptional<z.ZodNumber>;
52
+ env: z.ZodOptional<z.ZodObject<{
53
+ inherit: z.ZodOptional<z.ZodArray<z.ZodString>>;
54
+ secrets: z.ZodOptional<z.ZodArray<z.ZodObject<{
55
+ env: z.ZodPipe<z.ZodString, z.ZodTransform<string, string>>;
56
+ secretName: z.ZodPipe<z.ZodString, z.ZodTransform<string, string>>;
57
+ }, z.core.$strip>>>;
58
+ vars: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
59
+ egressProxy: z.ZodOptional<z.ZodBoolean>;
60
+ }, z.core.$strict>>;
61
+ log: z.ZodOptional<z.ZodObject<{
62
+ stdout: z.ZodLiteral<"capture">;
63
+ stderr: z.ZodEnum<{
64
+ capture: "capture";
65
+ merge: "merge";
66
+ }>;
67
+ maxBytes: z.ZodOptional<z.ZodNumber>;
68
+ }, z.core.$strict>>;
69
+ }, z.core.$strict>, z.ZodObject<{
70
+ kind: z.ZodLiteral<"argv">;
71
+ command: z.ZodString;
72
+ args: z.ZodArray<z.ZodString>;
73
+ cwd: z.ZodOptional<z.ZodPipe<z.ZodString, z.ZodTransform<string, string>>>;
74
+ timeoutMs: z.ZodOptional<z.ZodNumber>;
75
+ env: z.ZodOptional<z.ZodObject<{
76
+ inherit: z.ZodOptional<z.ZodArray<z.ZodString>>;
77
+ secrets: z.ZodOptional<z.ZodArray<z.ZodObject<{
78
+ env: z.ZodPipe<z.ZodString, z.ZodTransform<string, string>>;
79
+ secretName: z.ZodPipe<z.ZodString, z.ZodTransform<string, string>>;
80
+ }, z.core.$strip>>>;
81
+ vars: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
82
+ egressProxy: z.ZodOptional<z.ZodBoolean>;
83
+ }, z.core.$strict>>;
84
+ log: z.ZodOptional<z.ZodObject<{
85
+ stdout: z.ZodLiteral<"capture">;
86
+ stderr: z.ZodEnum<{
87
+ capture: "capture";
88
+ merge: "merge";
89
+ }>;
90
+ maxBytes: z.ZodOptional<z.ZodNumber>;
91
+ }, z.core.$strict>>;
92
+ }, z.core.$strict>, z.ZodObject<{
93
+ kind: z.ZodLiteral<"agent">;
94
+ agent: z.ZodObject<{
95
+ kind: z.ZodEnum<{
96
+ "claude-code": "claude-code";
97
+ codex: "codex";
98
+ pi: "pi";
99
+ mock: "mock";
100
+ command: "command";
101
+ }>;
102
+ version: z.ZodOptional<z.ZodString>;
103
+ }, z.core.$strict>;
104
+ prompt: z.ZodString;
105
+ timeoutMs: z.ZodOptional<z.ZodNumber>;
106
+ env: z.ZodOptional<z.ZodObject<{
107
+ inherit: z.ZodOptional<z.ZodArray<z.ZodString>>;
108
+ secrets: z.ZodOptional<z.ZodArray<z.ZodObject<{
109
+ env: z.ZodPipe<z.ZodString, z.ZodTransform<string, string>>;
110
+ secretName: z.ZodPipe<z.ZodString, z.ZodTransform<string, string>>;
111
+ }, z.core.$strip>>>;
112
+ vars: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
113
+ egressProxy: z.ZodOptional<z.ZodBoolean>;
114
+ }, z.core.$strict>>;
115
+ log: z.ZodOptional<z.ZodObject<{
116
+ stdout: z.ZodLiteral<"capture">;
117
+ stderr: z.ZodEnum<{
118
+ capture: "capture";
119
+ merge: "merge";
120
+ }>;
121
+ maxBytes: z.ZodOptional<z.ZodNumber>;
122
+ }, z.core.$strict>>;
123
+ }, z.core.$strict>], "kind">>;
124
+ isolation: z.ZodOptional<z.ZodEnum<{
125
+ process: "process";
126
+ hermetic: "hermetic";
127
+ "vercel-sandbox": "vercel-sandbox";
128
+ }>>;
129
+ continuation: z.ZodOptional<z.ZodObject<{
130
+ envelopeHash: z.ZodString;
131
+ checkpointId: z.ZodString;
132
+ tier: z.ZodEnum<{
133
+ workspace: "workspace";
134
+ semantic: "semantic";
135
+ }>;
136
+ }, z.core.$strip>>;
137
+ }, z.core.$strip>;
138
+ export declare const createRunBodySchema: z.ZodObject<{
139
+ dryRun: z.ZodOptional<z.ZodBoolean>;
140
+ request: z.ZodObject<{
141
+ requestedBy: z.ZodObject<{
142
+ kind: z.ZodEnum<{
143
+ human: "human";
144
+ service: "service";
145
+ }>;
146
+ id: z.ZodString;
147
+ }, z.core.$strip>;
148
+ agentKind: z.ZodString;
149
+ agentVersion: z.ZodOptional<z.ZodString>;
150
+ prompt: z.ZodString;
151
+ pool: z.ZodPipe<z.ZodString, z.ZodTransform<string, string>>;
152
+ secretNames: z.ZodArray<z.ZodPipe<z.ZodString, z.ZodTransform<string, string>>>;
153
+ workspace: z.ZodObject<{
154
+ version: z.ZodLiteral<"warrant.manifest.v1">;
155
+ baseRef: z.ZodString;
156
+ bundleHash: z.ZodString;
157
+ dirtyDiffHash: z.ZodOptional<z.ZodString>;
158
+ untrackedFiles: z.ZodArray<z.ZodObject<{
159
+ path: z.ZodPipe<z.ZodString, z.ZodTransform<string, string>>;
160
+ hash: z.ZodString;
161
+ bytes: z.ZodNumber;
162
+ }, z.core.$strip>>;
163
+ deniedPatterns: z.ZodArray<z.ZodString>;
164
+ deniedPaths: z.ZodArray<z.ZodPipe<z.ZodString, z.ZodTransform<string, string>>>;
165
+ }, z.core.$strip>;
166
+ network: z.ZodObject<{
167
+ defaultDeny: z.ZodBoolean;
168
+ allowHosts: z.ZodArray<z.ZodPipe<z.ZodString, z.ZodTransform<string, string>>>;
169
+ }, z.core.$strip>;
170
+ budget: z.ZodObject<{
171
+ maxSpendUsd: z.ZodOptional<z.ZodNumber>;
172
+ maxDurationMin: z.ZodOptional<z.ZodNumber>;
173
+ }, z.core.$strip>;
174
+ disclosure: z.ZodEnum<{
175
+ none: "none";
176
+ "metadata-only": "metadata-only";
177
+ redacted: "redacted";
178
+ "minimal-context": "minimal-context";
179
+ full: "full";
180
+ }>;
181
+ execution: z.ZodOptional<z.ZodDiscriminatedUnion<[z.ZodObject<{
182
+ kind: z.ZodLiteral<"shell">;
183
+ script: z.ZodString;
184
+ shell: z.ZodOptional<z.ZodEnum<{
185
+ sh: "sh";
186
+ bash: "bash";
187
+ }>>;
188
+ cwd: z.ZodOptional<z.ZodPipe<z.ZodString, z.ZodTransform<string, string>>>;
189
+ timeoutMs: z.ZodOptional<z.ZodNumber>;
190
+ env: z.ZodOptional<z.ZodObject<{
191
+ inherit: z.ZodOptional<z.ZodArray<z.ZodString>>;
192
+ secrets: z.ZodOptional<z.ZodArray<z.ZodObject<{
193
+ env: z.ZodPipe<z.ZodString, z.ZodTransform<string, string>>;
194
+ secretName: z.ZodPipe<z.ZodString, z.ZodTransform<string, string>>;
195
+ }, z.core.$strip>>>;
196
+ vars: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
197
+ egressProxy: z.ZodOptional<z.ZodBoolean>;
198
+ }, z.core.$strict>>;
199
+ log: z.ZodOptional<z.ZodObject<{
200
+ stdout: z.ZodLiteral<"capture">;
201
+ stderr: z.ZodEnum<{
202
+ capture: "capture";
203
+ merge: "merge";
204
+ }>;
205
+ maxBytes: z.ZodOptional<z.ZodNumber>;
206
+ }, z.core.$strict>>;
207
+ }, z.core.$strict>, z.ZodObject<{
208
+ kind: z.ZodLiteral<"argv">;
209
+ command: z.ZodString;
210
+ args: z.ZodArray<z.ZodString>;
211
+ cwd: z.ZodOptional<z.ZodPipe<z.ZodString, z.ZodTransform<string, string>>>;
212
+ timeoutMs: z.ZodOptional<z.ZodNumber>;
213
+ env: z.ZodOptional<z.ZodObject<{
214
+ inherit: z.ZodOptional<z.ZodArray<z.ZodString>>;
215
+ secrets: z.ZodOptional<z.ZodArray<z.ZodObject<{
216
+ env: z.ZodPipe<z.ZodString, z.ZodTransform<string, string>>;
217
+ secretName: z.ZodPipe<z.ZodString, z.ZodTransform<string, string>>;
218
+ }, z.core.$strip>>>;
219
+ vars: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
220
+ egressProxy: z.ZodOptional<z.ZodBoolean>;
221
+ }, z.core.$strict>>;
222
+ log: z.ZodOptional<z.ZodObject<{
223
+ stdout: z.ZodLiteral<"capture">;
224
+ stderr: z.ZodEnum<{
225
+ capture: "capture";
226
+ merge: "merge";
227
+ }>;
228
+ maxBytes: z.ZodOptional<z.ZodNumber>;
229
+ }, z.core.$strict>>;
230
+ }, z.core.$strict>, z.ZodObject<{
231
+ kind: z.ZodLiteral<"agent">;
232
+ agent: z.ZodObject<{
233
+ kind: z.ZodEnum<{
234
+ "claude-code": "claude-code";
235
+ codex: "codex";
236
+ pi: "pi";
237
+ mock: "mock";
238
+ command: "command";
239
+ }>;
240
+ version: z.ZodOptional<z.ZodString>;
241
+ }, z.core.$strict>;
242
+ prompt: z.ZodString;
243
+ timeoutMs: z.ZodOptional<z.ZodNumber>;
244
+ env: z.ZodOptional<z.ZodObject<{
245
+ inherit: z.ZodOptional<z.ZodArray<z.ZodString>>;
246
+ secrets: z.ZodOptional<z.ZodArray<z.ZodObject<{
247
+ env: z.ZodPipe<z.ZodString, z.ZodTransform<string, string>>;
248
+ secretName: z.ZodPipe<z.ZodString, z.ZodTransform<string, string>>;
249
+ }, z.core.$strip>>>;
250
+ vars: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
251
+ egressProxy: z.ZodOptional<z.ZodBoolean>;
252
+ }, z.core.$strict>>;
253
+ log: z.ZodOptional<z.ZodObject<{
254
+ stdout: z.ZodLiteral<"capture">;
255
+ stderr: z.ZodEnum<{
256
+ capture: "capture";
257
+ merge: "merge";
258
+ }>;
259
+ maxBytes: z.ZodOptional<z.ZodNumber>;
260
+ }, z.core.$strict>>;
261
+ }, z.core.$strict>], "kind">>;
262
+ isolation: z.ZodOptional<z.ZodEnum<{
263
+ process: "process";
264
+ hermetic: "hermetic";
265
+ "vercel-sandbox": "vercel-sandbox";
266
+ }>>;
267
+ continuation: z.ZodOptional<z.ZodObject<{
268
+ envelopeHash: z.ZodString;
269
+ checkpointId: z.ZodString;
270
+ tier: z.ZodEnum<{
271
+ workspace: "workspace";
272
+ semantic: "semantic";
273
+ }>;
274
+ }, z.core.$strip>>;
275
+ }, z.core.$strip>;
276
+ }, z.core.$strip>;
277
+ export declare const enrollBodySchema: z.ZodObject<{
278
+ enrollToken: z.ZodString;
279
+ publicKeyPem: z.ZodString;
280
+ pool: z.ZodPipe<z.ZodString, z.ZodTransform<string, string>>;
281
+ }, z.core.$strip>;
282
+ export declare const claimBodySchema: z.ZodObject<{
283
+ runnerToken: z.ZodString;
284
+ pool: z.ZodPipe<z.ZodString, z.ZodTransform<string, string>>;
285
+ }, z.core.$strip>;
286
+ export declare const approveBodySchema: z.ZodObject<{
287
+ actor: z.ZodOptional<z.ZodObject<{
288
+ kind: z.ZodEnum<{
289
+ human: "human";
290
+ service: "service";
291
+ }>;
292
+ id: z.ZodString;
293
+ }, z.core.$strip>>;
294
+ idpToken: z.ZodOptional<z.ZodString>;
295
+ }, z.core.$strip>;
296
+ export declare const cancelBodySchema: z.ZodObject<{
297
+ actor: z.ZodOptional<z.ZodObject<{
298
+ kind: z.ZodEnum<{
299
+ human: "human";
300
+ service: "service";
301
+ }>;
302
+ id: z.ZodString;
303
+ }, z.core.$strip>>;
304
+ }, z.core.$strip>;
305
+ export declare const eventsBodySchema: z.ZodObject<{
306
+ claimToken: z.ZodString;
307
+ events: z.ZodArray<z.ZodUnknown>;
308
+ }, z.core.$strip>;
309
+ export declare const completeBodySchema: z.ZodObject<{
310
+ claimToken: z.ZodString;
311
+ receipt: z.ZodUnknown;
312
+ }, z.core.$strip>;
313
+ export declare const issuePrincipalBodySchema: z.ZodObject<{
314
+ name: z.ZodString;
315
+ role: z.ZodEnum<{
316
+ admin: "admin";
317
+ requester: "requester";
318
+ approver: "approver";
319
+ enroller: "enroller";
320
+ }>;
321
+ }, z.core.$strip>;
322
+ export declare class ValidationError extends Error {
323
+ readonly issues: string[];
324
+ constructor(issues: string[]);
325
+ }
326
+ export declare function parseBody<T>(schema: z.ZodType<T>, raw: unknown): T;