@harness-control/protocol 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 (49) hide show
  1. package/LICENSE +202 -0
  2. package/README.md +16 -0
  3. package/dist/bin/conformance.d.ts +3 -0
  4. package/dist/bin/conformance.js +11 -0
  5. package/dist/bin/generate-json-schema.d.ts +3 -0
  6. package/dist/bin/generate-json-schema.js +12 -0
  7. package/dist/conformance.d.ts +42 -0
  8. package/dist/conformance.js +217 -0
  9. package/dist/index.d.ts +6761 -0
  10. package/dist/index.js +1931 -0
  11. package/dist/json-schema.d.ts +19 -0
  12. package/dist/json-schema.js +128 -0
  13. package/dist/pairing.d.ts +59 -0
  14. package/dist/pairing.js +42 -0
  15. package/dist/session-reducer.d.ts +36 -0
  16. package/dist/session-reducer.js +96 -0
  17. package/fixtures/conformance/invalid/arbitrary-event-family.json +13 -0
  18. package/fixtures/conformance/invalid/local-action-lease-binding-mismatch.json +51 -0
  19. package/fixtures/conformance/invalid/local-action-missing-turn-id.json +21 -0
  20. package/fixtures/conformance/invalid/local-action-patch-missing-base-hash.json +53 -0
  21. package/fixtures/conformance/invalid/local-action-shell-missing-approval.json +56 -0
  22. package/fixtures/conformance/invalid/mcp-stdio-attachment.json +27 -0
  23. package/fixtures/conformance/invalid/session-snapshot-unsafe-omission.json +26 -0
  24. package/fixtures/conformance/invalid/terminal-turn-missing-final-output.json +16 -0
  25. package/fixtures/conformance/invalid/unknown-payload-field.json +14 -0
  26. package/fixtures/conformance/invalid/unknown-top-level-field.json +14 -0
  27. package/fixtures/conformance/valid/command-ack.json +11 -0
  28. package/fixtures/conformance/valid/extension-event.json +18 -0
  29. package/fixtures/conformance/valid/host-hello.json +22 -0
  30. package/fixtures/conformance/valid/host-replay-unavailable.json +15 -0
  31. package/fixtures/conformance/valid/local-action-dev-server-start.json +67 -0
  32. package/fixtures/conformance/valid/local-action-dev-server-stop.json +54 -0
  33. package/fixtures/conformance/valid/local-action-error.json +40 -0
  34. package/fixtures/conformance/valid/local-action-filesystem-list.json +54 -0
  35. package/fixtures/conformance/valid/local-action-filesystem-patch.json +55 -0
  36. package/fixtures/conformance/valid/local-action-filesystem-read.json +53 -0
  37. package/fixtures/conformance/valid/local-action-filesystem-write.json +55 -0
  38. package/fixtures/conformance/valid/local-action-git-diff.json +53 -0
  39. package/fixtures/conformance/valid/local-action-git-status.json +53 -0
  40. package/fixtures/conformance/valid/local-action-response.json +49 -0
  41. package/fixtures/conformance/valid/local-action-shell-exec.json +63 -0
  42. package/fixtures/conformance/valid/provider-event.json +18 -0
  43. package/fixtures/conformance/valid/session-snapshot-request.json +9 -0
  44. package/fixtures/conformance/valid/session-snapshot.json +28 -0
  45. package/fixtures/conformance/valid/session-start-with-leases.json +80 -0
  46. package/fixtures/conformance/valid/session-start-with-runner-stdio-profile.json +27 -0
  47. package/fixtures/conformance/valid/turn-completed.json +30 -0
  48. package/package.json +61 -0
  49. package/schemas/hcp-message.schema.json +18667 -0
package/dist/index.js ADDED
@@ -0,0 +1,1931 @@
1
+ import { z } from "zod";
2
+ export const HCP_VERSION = "hcp.v0";
3
+ export const HCP_METADATA_MAX_ENCODED_BYTES = 16 * 1024;
4
+ export const HCP_PAYLOAD_MAX_ENCODED_BYTES = 1024 * 1024;
5
+ export const HCP_MESSAGE_MAX_ENCODED_BYTES = HCP_METADATA_MAX_ENCODED_BYTES + HCP_PAYLOAD_MAX_ENCODED_BYTES + 64 * 1024;
6
+ export const HOST_LIFECYCLE_MESSAGE_TYPES = [
7
+ "host.hello",
8
+ "host.accepted",
9
+ "host.rejected",
10
+ "host.heartbeat",
11
+ "host.capabilities.updated",
12
+ "host.replay.unavailable",
13
+ "host.workspaces.request",
14
+ "host.workspaces.result",
15
+ ];
16
+ export const CONTROL_PLANE_COMMAND_MESSAGE_TYPES = [
17
+ "harness.session.start",
18
+ "harness.session.snapshot.request",
19
+ "harness.turn.send",
20
+ "harness.turn.cancel",
21
+ "harness.session.stop",
22
+ "harness.approval.respond",
23
+ "harness.input.respond",
24
+ "tool_servers.detach",
25
+ ];
26
+ export const COMMAND_ACK_MESSAGE_TYPES = ["hcp.command.ack", "hcp.command.nack"];
27
+ export const LOCAL_ACTION_MESSAGE_TYPES = [
28
+ "local.action.request",
29
+ "local.action.response",
30
+ "local.action.error",
31
+ ];
32
+ export const RUNTIME_EVENT_MESSAGE_TYPES = ["harness.event"];
33
+ export const SESSION_SNAPSHOT_MESSAGE_TYPES = ["harness.session.snapshot"];
34
+ export const KNOWN_HCP_EVENT_TYPES = [
35
+ "session.started",
36
+ "session.configured",
37
+ "session.state.changed",
38
+ "session.exited",
39
+ "thread.started",
40
+ "thread.state.changed",
41
+ "thread.metadata.updated",
42
+ "thread.token_usage.updated",
43
+ "thread.realtime.started",
44
+ "thread.realtime.item_added",
45
+ "thread.realtime.audio_delta",
46
+ "thread.realtime.error",
47
+ "thread.realtime.closed",
48
+ "auth.status",
49
+ "account.updated",
50
+ "account.rate_limits.updated",
51
+ "turn.started",
52
+ "turn.completed",
53
+ "turn.failed",
54
+ "turn.aborted",
55
+ "turn.cancelled",
56
+ "turn.plan.updated",
57
+ "turn.proposed.delta",
58
+ "turn.proposed.completed",
59
+ "turn.diff.updated",
60
+ "item.started",
61
+ "item.updated",
62
+ "item.completed",
63
+ "content.delta",
64
+ "reasoning.delta",
65
+ "command.started",
66
+ "command.completed",
67
+ "local_capability.lease.created",
68
+ "local_capability.lease.revoked",
69
+ "local_capability.lease.expired",
70
+ "local_capability.action.started",
71
+ "local_capability.action.completed",
72
+ "local_capability.action.failed",
73
+ "file_change.started",
74
+ "file_change.completed",
75
+ "mcp_tool.started",
76
+ "mcp_tool.completed",
77
+ "mcp.status.updated",
78
+ "mcp.oauth.completed",
79
+ "approval.requested",
80
+ "approval.resolved",
81
+ "input.requested",
82
+ "input.resolved",
83
+ "request.opened",
84
+ "request.resolved",
85
+ "user_input.requested",
86
+ "user_input.resolved",
87
+ "task.started",
88
+ "task.progress",
89
+ "task.completed",
90
+ "hook.started",
91
+ "hook.progress",
92
+ "hook.completed",
93
+ "tool.progress",
94
+ "tool.summary",
95
+ "model.rerouted",
96
+ "config.warning",
97
+ "deprecation.notice",
98
+ "files.persisted",
99
+ "workspace.preflight.completed",
100
+ "usage.updated",
101
+ "runtime.warning",
102
+ "runtime.error",
103
+ ];
104
+ export const LOCAL_ACTION_TYPES = [
105
+ "local.filesystem.read",
106
+ "local.filesystem.list",
107
+ "local.filesystem.write",
108
+ "local.filesystem.patch",
109
+ "local.git.status",
110
+ "local.git.diff",
111
+ "local.shell.exec",
112
+ "local.dev_server.start",
113
+ "local.dev_server.stop",
114
+ ];
115
+ const nonEmptyStringSchema = z.string().min(1);
116
+ const timestampSchema = z.string().datetime({ offset: true });
117
+ const metadataSchema = z.record(z.string(), z.unknown());
118
+ const unknownRecordSchema = z.record(z.string(), z.unknown());
119
+ const stringRecordSchema = z.record(z.string(), z.string());
120
+ const harnessOptionValueSchema = z.union([z.string(), z.boolean(), z.number()]);
121
+ const streamableHttpUrlSchema = z.string().url().refine((value) => {
122
+ try {
123
+ const url = new URL(value);
124
+ return url.protocol === "http:" || url.protocol === "https:";
125
+ }
126
+ catch (error) {
127
+ if (error instanceof TypeError) {
128
+ return false;
129
+ }
130
+ throw error;
131
+ }
132
+ }, { message: "Streamable HTTP MCP attachment URLs must use http or https." });
133
+ export const hcpVersionSchema = z.literal(HCP_VERSION);
134
+ export const hcpErrorSchema = z
135
+ .object({
136
+ code: nonEmptyStringSchema,
137
+ message: nonEmptyStringSchema,
138
+ retryable: z.boolean(),
139
+ details: unknownRecordSchema.optional(),
140
+ })
141
+ .strict();
142
+ export const hcpCommandAckPayloadSchema = z
143
+ .object({
144
+ command_id: nonEmptyStringSchema,
145
+ accepted_at: timestampSchema,
146
+ duplicate: z.boolean(),
147
+ })
148
+ .strict();
149
+ export const hcpCommandNackPayloadSchema = z
150
+ .object({
151
+ command_id: nonEmptyStringSchema,
152
+ rejected_at: timestampSchema,
153
+ error: hcpErrorSchema,
154
+ })
155
+ .strict();
156
+ export const hcpAckPayloadSchema = hcpCommandAckPayloadSchema;
157
+ export const hcpNackPayloadSchema = hcpCommandNackPayloadSchema;
158
+ export const hcpHostResumeCursorSchema = z
159
+ .object({
160
+ sessions: z
161
+ .array(z
162
+ .object({
163
+ session_id: nonEmptyStringSchema,
164
+ last_event_sequence: z.number().int().nonnegative(),
165
+ })
166
+ .strict())
167
+ .default([]),
168
+ })
169
+ .strict();
170
+ export const hcpHostRetainedEventRangesSchema = z
171
+ .object({
172
+ sessions: z
173
+ .array(z
174
+ .object({
175
+ session_id: nonEmptyStringSchema,
176
+ first_event_sequence: z.number().int().positive(),
177
+ last_event_sequence: z.number().int().positive(),
178
+ })
179
+ .strict()
180
+ .refine((range) => range.first_event_sequence <= range.last_event_sequence, {
181
+ message: "Retained event range must not end before it starts.",
182
+ }))
183
+ .default([]),
184
+ })
185
+ .strict();
186
+ export const hcpHostHelloPayloadSchema = z
187
+ .object({
188
+ runner_id: nonEmptyStringSchema,
189
+ host_id: nonEmptyStringSchema,
190
+ runner_version: nonEmptyStringSchema,
191
+ supported_protocol_versions: z.array(hcpVersionSchema).min(1),
192
+ capabilities: z.array(nonEmptyStringSchema),
193
+ retained_events: hcpHostRetainedEventRangesSchema.optional(),
194
+ })
195
+ .strict();
196
+ export const hcpHostAcceptedPayloadSchema = z
197
+ .object({
198
+ protocol_version: hcpVersionSchema,
199
+ heartbeat_interval_seconds: z.number().int().positive(),
200
+ resume: hcpHostResumeCursorSchema.optional(),
201
+ })
202
+ .strict();
203
+ export const hcpHostRejectedPayloadSchema = z
204
+ .object({
205
+ reason: nonEmptyStringSchema,
206
+ supported_protocol_versions: z.array(hcpVersionSchema).optional(),
207
+ })
208
+ .strict();
209
+ export const hcpHostHeartbeatPayloadSchema = z
210
+ .object({
211
+ host_id: nonEmptyStringSchema,
212
+ status: z.enum(["online", "degraded", "draining"]),
213
+ active_sessions: z.number().int().nonnegative(),
214
+ })
215
+ .strict();
216
+ export const localCapabilitySnapshotSchema = z
217
+ .object({
218
+ id: nonEmptyStringSchema,
219
+ status: z.enum(["available", "unavailable", "disabled", "unknown"]),
220
+ scopes: z.array(nonEmptyStringSchema),
221
+ approval_required: z.boolean(),
222
+ message: nonEmptyStringSchema.optional(),
223
+ })
224
+ .strict();
225
+ export const providerAuthSnapshotSchema = z
226
+ .object({
227
+ status: z.enum(["authenticated", "unauthenticated", "unknown"]),
228
+ type: nonEmptyStringSchema.optional(),
229
+ label: nonEmptyStringSchema.optional(),
230
+ email: nonEmptyStringSchema.optional(),
231
+ })
232
+ .strict();
233
+ export const harnessOptionDescriptorSchema = z
234
+ .object({
235
+ id: nonEmptyStringSchema,
236
+ label: nonEmptyStringSchema,
237
+ type: z.enum(["select", "boolean", "number", "string"]),
238
+ values: z
239
+ .array(z
240
+ .object({
241
+ value: z.string(),
242
+ label: nonEmptyStringSchema,
243
+ })
244
+ .strict())
245
+ .optional(),
246
+ default_value: harnessOptionValueSchema.optional(),
247
+ current_value: harnessOptionValueSchema.optional(),
248
+ prompt_injected_values: z.array(z.string()).optional(),
249
+ })
250
+ .strict();
251
+ export const harnessModelSchema = z
252
+ .object({
253
+ id: nonEmptyStringSchema,
254
+ label: nonEmptyStringSchema,
255
+ is_default: z.boolean().optional(),
256
+ capabilities: z
257
+ .object({
258
+ option_descriptors: z.array(harnessOptionDescriptorSchema),
259
+ })
260
+ .strict(),
261
+ })
262
+ .strict();
263
+ export const harnessProviderSnapshotSchema = z
264
+ .object({
265
+ execution_capabilities: z.object({
266
+ streaming: z.boolean(),
267
+ multi_turn: z.boolean(),
268
+ session_continuation: z.boolean(),
269
+ sandbox_modes: z.array(z.enum(["read_only", "workspace_write", "danger_full_access"])),
270
+ approval_policies: z.array(z.enum(["ask", "auto_edits", "full_access"])),
271
+ }).strict().optional(),
272
+ provider_instance_id: nonEmptyStringSchema,
273
+ driver_kind: nonEmptyStringSchema,
274
+ display_name: nonEmptyStringSchema.optional(),
275
+ accent_color: nonEmptyStringSchema.optional(),
276
+ enabled: z.boolean(),
277
+ installed: z.boolean(),
278
+ version: nonEmptyStringSchema.optional(),
279
+ status: z.enum(["ready", "unavailable", "unauthenticated", "disabled", "error", "unknown"]),
280
+ availability: z.enum(["available", "unavailable"]),
281
+ message: nonEmptyStringSchema.optional(),
282
+ checked_at: timestampSchema.optional(),
283
+ continuation_group_key: nonEmptyStringSchema.optional(),
284
+ auth: providerAuthSnapshotSchema.optional(),
285
+ models: z.array(harnessModelSchema),
286
+ hidden_models: z.array(z.string()).optional(),
287
+ model_order: z.array(z.string()).optional(),
288
+ favorite_models: z.array(z.string()).optional(),
289
+ local_capabilities: z.array(nonEmptyStringSchema).optional(),
290
+ version_advisory: z
291
+ .object({
292
+ level: z.enum(["info", "warning", "blocking"]),
293
+ message: nonEmptyStringSchema,
294
+ })
295
+ .strict()
296
+ .nullable()
297
+ .optional(),
298
+ update_state: z
299
+ .object({
300
+ available: z.boolean(),
301
+ latest_version: nonEmptyStringSchema.optional(),
302
+ command: nonEmptyStringSchema.optional(),
303
+ })
304
+ .strict()
305
+ .nullable()
306
+ .optional(),
307
+ })
308
+ .strict();
309
+ export const hcpWorkspaceSchema = z
310
+ .object({
311
+ id: nonEmptyStringSchema,
312
+ path: nonEmptyStringSchema,
313
+ git_remote: nonEmptyStringSchema.optional(),
314
+ display_name: z.string().trim().min(1).max(100).optional(),
315
+ })
316
+ .strict();
317
+ export const hcpMcpStdioProfileSnapshotSchema = z
318
+ .object({
319
+ id: nonEmptyStringSchema,
320
+ provider_instance_ids: z.array(nonEmptyStringSchema),
321
+ allowed_tools: z.array(nonEmptyStringSchema).optional(),
322
+ denied_tools: z.array(nonEmptyStringSchema).optional(),
323
+ })
324
+ .strict();
325
+ export const hcpWorkspaceManagementSchema = z.object({
326
+ revision: z.string().min(1).max(100),
327
+ allowed_roots: z.array(z.string().min(1).max(4096)).max(32),
328
+ }).strict();
329
+ export const hcpWorkspaceOperationSchema = z.discriminatedUnion("kind", [
330
+ z.object({ kind: z.literal("list") }).strict(),
331
+ z.object({ kind: z.literal("add"), path: z.string().min(1).max(4096), display_name: z.string().trim().min(1).max(100) }).strict(),
332
+ z.object({ kind: z.literal("rename"), id: z.string().min(1).max(200), display_name: z.string().trim().min(1).max(100) }).strict(),
333
+ z.object({ kind: z.literal("remove"), id: z.string().min(1).max(200) }).strict(),
334
+ ]);
335
+ export const hcpWorkspacesRequestPayloadSchema = z.object({
336
+ expected_revision: z.string().min(1).max(100),
337
+ expires_at: timestampSchema,
338
+ operation: hcpWorkspaceOperationSchema,
339
+ }).strict();
340
+ export const hcpWorkspacesResultPayloadSchema = z.object({
341
+ request_id: nonEmptyStringSchema,
342
+ outcome: z.discriminatedUnion("kind", [
343
+ z.object({ kind: z.literal("success") }).strict(),
344
+ z.object({ kind: z.literal("error"), message: z.string().min(1).max(1000) }).strict(),
345
+ ]),
346
+ management: hcpWorkspaceManagementSchema,
347
+ workspaces: z.array(hcpWorkspaceSchema).max(128),
348
+ }).strict();
349
+ export const hcpHostCapabilitiesUpdatedPayloadSchema = z
350
+ .object({
351
+ providers: z.array(harnessProviderSnapshotSchema),
352
+ local_capabilities: z.array(localCapabilitySnapshotSchema),
353
+ workspaces: z.array(hcpWorkspaceSchema),
354
+ workspace_management: hcpWorkspaceManagementSchema.optional(),
355
+ mcp_stdio_profiles: z.array(hcpMcpStdioProfileSnapshotSchema).optional(),
356
+ })
357
+ .strict();
358
+ export const hcpHostReplayUnavailablePayloadSchema = z
359
+ .object({
360
+ session_id: nonEmptyStringSchema,
361
+ requested_after_sequence: z.number().int().nonnegative(),
362
+ reason: z.enum(["no_retained_events", "cursor_outside_retention"]),
363
+ retained_range: z
364
+ .object({
365
+ first_event_sequence: z.number().int().positive(),
366
+ last_event_sequence: z.number().int().positive(),
367
+ })
368
+ .strict()
369
+ .optional(),
370
+ })
371
+ .strict();
372
+ export const harnessProviderReferenceSchema = z
373
+ .object({
374
+ execution_host_id: nonEmptyStringSchema,
375
+ provider_instance_id: nonEmptyStringSchema,
376
+ driver_kind: nonEmptyStringSchema,
377
+ continuation_group_key: nonEmptyStringSchema.optional(),
378
+ })
379
+ .strict();
380
+ export const harnessModelSelectionSchema = z
381
+ .object({
382
+ model: nonEmptyStringSchema,
383
+ options: z
384
+ .array(z
385
+ .object({
386
+ id: nonEmptyStringSchema,
387
+ value: harnessOptionValueSchema,
388
+ })
389
+ .strict())
390
+ .optional(),
391
+ })
392
+ .strict();
393
+ export const workspacePreflightSchema = z
394
+ .object({
395
+ workspace_id: nonEmptyStringSchema,
396
+ expected_git_remote: nonEmptyStringSchema.optional(),
397
+ expected_branch: nonEmptyStringSchema.optional(),
398
+ allow_dirty_worktree: z.boolean().optional(),
399
+ required_paths: z.array(nonEmptyStringSchema).optional(),
400
+ })
401
+ .strict();
402
+ export const workspacePreflightCompletedSchema = z
403
+ .object({
404
+ workspace_id: nonEmptyStringSchema,
405
+ cwd: nonEmptyStringSchema,
406
+ branch: nonEmptyStringSchema.optional(),
407
+ commit: nonEmptyStringSchema.optional(),
408
+ dirty: z.boolean().optional(),
409
+ remote: nonEmptyStringSchema.optional(),
410
+ result: z.enum(["passed", "failed", "warning"]),
411
+ message: nonEmptyStringSchema.optional(),
412
+ })
413
+ .strict();
414
+ export const commandPolicySchema = z
415
+ .object({
416
+ allowed_executables: z.array(nonEmptyStringSchema).optional(),
417
+ denied_executables: z.array(nonEmptyStringSchema).optional(),
418
+ argv_patterns: z.array(nonEmptyStringSchema).optional(),
419
+ cwd_policy: z.literal("selected_workspace_only"),
420
+ env_policy: z.enum(["minimal", "allowlisted"]),
421
+ allow_shell: z.boolean(),
422
+ timeout_seconds: z.number().int().positive(),
423
+ network_policy: z.enum(["inherit", "disabled", "allowlisted"]),
424
+ })
425
+ .strict();
426
+ export const localCapabilityGrantSchema = z
427
+ .object({
428
+ id: nonEmptyStringSchema,
429
+ scopes: z.array(nonEmptyStringSchema),
430
+ approval_policy: z.enum(["ask", "auto_edits", "full_access"]).optional(),
431
+ command_policy: commandPolicySchema.optional(),
432
+ max_calls: z.number().int().positive().optional(),
433
+ })
434
+ .strict();
435
+ export const localCapabilityLeaseSchema = z
436
+ .object({
437
+ lease_id: nonEmptyStringSchema,
438
+ org_id: nonEmptyStringSchema,
439
+ actor_id: nonEmptyStringSchema.optional(),
440
+ workflow_id: nonEmptyStringSchema,
441
+ run_id: nonEmptyStringSchema,
442
+ node_id: nonEmptyStringSchema,
443
+ hcp_session_id: nonEmptyStringSchema,
444
+ execution_host_id: nonEmptyStringSchema,
445
+ provider_instance_id: nonEmptyStringSchema,
446
+ workspace_id: nonEmptyStringSchema,
447
+ issued_at: timestampSchema,
448
+ expires_at: timestampSchema,
449
+ policy_version: nonEmptyStringSchema,
450
+ capabilities: z.array(localCapabilityGrantSchema),
451
+ })
452
+ .strict();
453
+ export const mcpProofOfPossessionSchema = z
454
+ .object({
455
+ scheme: z.literal("runner_signed_request"),
456
+ key_id: nonEmptyStringSchema,
457
+ required_headers: z.array(nonEmptyStringSchema).min(1),
458
+ })
459
+ .strict();
460
+ export const streamableHttpMcpServerAttachmentSchema = z
461
+ .object({
462
+ name: nonEmptyStringSchema,
463
+ transport: z.literal("streamable_http"),
464
+ url: streamableHttpUrlSchema,
465
+ headers: stringRecordSchema,
466
+ lease_id: nonEmptyStringSchema,
467
+ proof_of_possession: mcpProofOfPossessionSchema,
468
+ expires_at: timestampSchema.optional(),
469
+ allowed_tools: z.array(nonEmptyStringSchema).optional(),
470
+ denied_tools: z.array(nonEmptyStringSchema).optional(),
471
+ })
472
+ .strict();
473
+ export const runnerStdioMcpProfileAttachmentSchema = z
474
+ .object({
475
+ name: nonEmptyStringSchema,
476
+ transport: z.literal("runner_stdio_profile"),
477
+ profile_id: nonEmptyStringSchema,
478
+ allowed_tools: z.array(nonEmptyStringSchema).optional(),
479
+ denied_tools: z.array(nonEmptyStringSchema).optional(),
480
+ })
481
+ .strict();
482
+ export const mcpServerAttachmentSchema = z.discriminatedUnion("transport", [
483
+ streamableHttpMcpServerAttachmentSchema,
484
+ runnerStdioMcpProfileAttachmentSchema,
485
+ ]);
486
+ export const hcpSessionStartPayloadSchema = z
487
+ .object({
488
+ session_id: nonEmptyStringSchema,
489
+ workspace_id: nonEmptyStringSchema,
490
+ provider_instance_id: nonEmptyStringSchema,
491
+ driver_kind: nonEmptyStringSchema,
492
+ continuation_group_key: nonEmptyStringSchema.optional(),
493
+ cwd: nonEmptyStringSchema,
494
+ sandbox_mode: z.enum(["read_only", "workspace_write", "danger_full_access"]),
495
+ approval_policy: z.enum(["ask", "auto_edits", "full_access"]),
496
+ continue_session: z.boolean(),
497
+ model_selection: harnessModelSelectionSchema,
498
+ workspace_preflight: workspacePreflightSchema.optional(),
499
+ local_capability_lease: localCapabilityLeaseSchema.optional(),
500
+ mcp_servers: z.array(mcpServerAttachmentSchema),
501
+ })
502
+ .strict();
503
+ export const hcpSessionSnapshotRequestPayloadSchema = z
504
+ .object({
505
+ session_id: nonEmptyStringSchema,
506
+ })
507
+ .strict();
508
+ export const hcpTurnSendPayloadSchema = z
509
+ .object({
510
+ session_id: nonEmptyStringSchema,
511
+ turn_id: nonEmptyStringSchema,
512
+ input: z.string(),
513
+ model_selection: harnessModelSelectionSchema.optional(),
514
+ })
515
+ .strict();
516
+ export const hcpTurnCancelPayloadSchema = z
517
+ .object({
518
+ session_id: nonEmptyStringSchema,
519
+ turn_id: nonEmptyStringSchema,
520
+ reason: nonEmptyStringSchema.optional(),
521
+ })
522
+ .strict();
523
+ export const hcpSessionStopPayloadSchema = z
524
+ .object({
525
+ session_id: nonEmptyStringSchema,
526
+ reason: nonEmptyStringSchema.optional(),
527
+ })
528
+ .strict();
529
+ export const hcpApprovalResponsePayloadSchema = z
530
+ .object({
531
+ request_id: nonEmptyStringSchema,
532
+ session_id: nonEmptyStringSchema,
533
+ turn_id: nonEmptyStringSchema,
534
+ action_hash: nonEmptyStringSchema,
535
+ decision: z.enum(["accept", "accept_for_session", "decline", "cancel"]),
536
+ actor_id: nonEmptyStringSchema,
537
+ })
538
+ .strict();
539
+ export const hcpInputResponsePayloadSchema = z
540
+ .object({
541
+ request_id: nonEmptyStringSchema,
542
+ session_id: nonEmptyStringSchema,
543
+ turn_id: nonEmptyStringSchema,
544
+ actor_id: nonEmptyStringSchema,
545
+ value: z.unknown().optional(),
546
+ cancelled: z.boolean().optional(),
547
+ })
548
+ .strict();
549
+ export const toolServersDetachPayloadSchema = z
550
+ .object({
551
+ session_id: nonEmptyStringSchema,
552
+ names: z.array(nonEmptyStringSchema).min(1),
553
+ reason: nonEmptyStringSchema.optional(),
554
+ })
555
+ .strict();
556
+ const localActionProtocolCapabilityIdSchema = z.enum(["filesystem", "git", "shell", "dev_server"]);
557
+ const localActionTypeSchema = z.enum(LOCAL_ACTION_TYPES);
558
+ const localActionErrorCodeSchema = z.enum([
559
+ "local_capability_lease_missing",
560
+ "local_capability_lease_expired",
561
+ "local_capability_lease_revoked",
562
+ "local_capability_session_mismatch",
563
+ "local_capability_workspace_mismatch",
564
+ "local_capability_provider_mismatch",
565
+ "local_capability_scope_not_granted",
566
+ "local_capability_sandbox_denied",
567
+ "local_capability_approval_required",
568
+ "local_capability_approval_mismatch",
569
+ "local_capability_path_denied",
570
+ "local_capability_expected_hash_mismatch",
571
+ "local_capability_output_limit_exceeded",
572
+ "local_capability_timeout",
573
+ "local_capability_cancelled",
574
+ "local_capability_command_denied",
575
+ "local_capability_process_failed",
576
+ "local_capability_dev_server_exists",
577
+ "local_capability_dev_server_not_found",
578
+ "local_capability_action_failed",
579
+ ]);
580
+ const localActionAttributionSchema = z
581
+ .object({
582
+ session_id: nonEmptyStringSchema,
583
+ turn_id: nonEmptyStringSchema,
584
+ workspace_id: nonEmptyStringSchema,
585
+ provider_instance_id: nonEmptyStringSchema,
586
+ run_id: nonEmptyStringSchema,
587
+ })
588
+ .strict();
589
+ const localActionLeaseBindingSchema = z
590
+ .object({
591
+ lease_id: nonEmptyStringSchema,
592
+ capability_id: localActionProtocolCapabilityIdSchema,
593
+ scope: nonEmptyStringSchema,
594
+ run_id: nonEmptyStringSchema,
595
+ hcp_session_id: nonEmptyStringSchema,
596
+ execution_host_id: nonEmptyStringSchema,
597
+ provider_instance_id: nonEmptyStringSchema,
598
+ workspace_id: nonEmptyStringSchema,
599
+ expires_at: timestampSchema.optional(),
600
+ })
601
+ .strict();
602
+ const localFilesystemReadLeaseBindingSchema = localActionLeaseBindingSchema.extend({
603
+ capability_id: z.literal("filesystem"),
604
+ scope: z.literal("workspace_read"),
605
+ });
606
+ const localFilesystemWriteLeaseBindingSchema = localActionLeaseBindingSchema.extend({
607
+ capability_id: z.literal("filesystem"),
608
+ scope: z.literal("workspace_write"),
609
+ });
610
+ const localGitReadLeaseBindingSchema = localActionLeaseBindingSchema.extend({
611
+ capability_id: z.literal("git"),
612
+ scope: z.literal("workspace_read"),
613
+ });
614
+ const localShellLeaseBindingSchema = localActionLeaseBindingSchema.extend({
615
+ capability_id: z.literal("shell"),
616
+ scope: z.literal("workspace"),
617
+ });
618
+ const localDevServerLeaseBindingSchema = localActionLeaseBindingSchema.extend({
619
+ capability_id: z.literal("dev_server"),
620
+ scope: z.literal("workspace"),
621
+ });
622
+ const localActionSandboxRequirementsSchema = z
623
+ .object({
624
+ mode: z.enum(["read_only", "workspace_write", "danger_full_access"]),
625
+ workspace_root: nonEmptyStringSchema,
626
+ cwd: nonEmptyStringSchema,
627
+ requires_workspace_containment: z.literal(true),
628
+ })
629
+ .strict();
630
+ const localActionOutputLimitsSchema = z
631
+ .object({
632
+ content_bytes: z.number().int().positive().optional(),
633
+ entries: z.number().int().positive().optional(),
634
+ status_bytes: z.number().int().positive().optional(),
635
+ diff_bytes: z.number().int().positive().optional(),
636
+ stdout_bytes: z.number().int().positive().optional(),
637
+ stderr_bytes: z.number().int().positive().optional(),
638
+ })
639
+ .strict();
640
+ const localFilesystemReadOutputLimitsSchema = localActionOutputLimitsSchema.extend({
641
+ content_bytes: z.number().int().positive(),
642
+ });
643
+ const localFilesystemListOutputLimitsSchema = localActionOutputLimitsSchema.extend({
644
+ entries: z.number().int().positive(),
645
+ });
646
+ const localGitStatusOutputLimitsSchema = localActionOutputLimitsSchema.extend({
647
+ status_bytes: z.number().int().positive(),
648
+ });
649
+ const localGitDiffOutputLimitsSchema = localActionOutputLimitsSchema.extend({
650
+ diff_bytes: z.number().int().positive(),
651
+ });
652
+ const localShellOutputLimitsSchema = localActionOutputLimitsSchema.extend({
653
+ stdout_bytes: z.number().int().positive(),
654
+ stderr_bytes: z.number().int().positive(),
655
+ });
656
+ const localActionCancellationSchema = z
657
+ .object({
658
+ cancellable: z.boolean(),
659
+ timeout_ms: z.number().int().positive().optional(),
660
+ token: nonEmptyStringSchema.optional(),
661
+ })
662
+ .strict();
663
+ const localActionApprovalBindingSchema = z.discriminatedUnion("status", [
664
+ z
665
+ .object({
666
+ status: z.literal("not_required"),
667
+ })
668
+ .strict(),
669
+ z
670
+ .object({
671
+ status: z.literal("approved"),
672
+ request_id: nonEmptyStringSchema,
673
+ action_hash: nonEmptyStringSchema,
674
+ decision: z.enum(["accept", "accept_for_session"]),
675
+ actor_id: nonEmptyStringSchema,
676
+ approved_at: timestampSchema,
677
+ })
678
+ .strict(),
679
+ ]);
680
+ const localActionApprovedBindingSchema = z
681
+ .object({
682
+ status: z.literal("approved"),
683
+ request_id: nonEmptyStringSchema,
684
+ action_hash: nonEmptyStringSchema,
685
+ decision: z.enum(["accept", "accept_for_session"]),
686
+ actor_id: nonEmptyStringSchema,
687
+ approved_at: timestampSchema,
688
+ })
689
+ .strict();
690
+ const localActionAuditMappingSchema = z
691
+ .object({
692
+ started_event_type: z.literal("local_capability.action.started"),
693
+ completed_event_type: z.literal("local_capability.action.completed"),
694
+ failed_event_type: z.literal("local_capability.action.failed"),
695
+ })
696
+ .strict();
697
+ const localActionAuditEventRefSchema = z
698
+ .object({
699
+ event_type: z.enum([
700
+ "local_capability.action.started",
701
+ "local_capability.action.completed",
702
+ "local_capability.action.failed",
703
+ ]),
704
+ sequence: z.number().int().positive().optional(),
705
+ })
706
+ .strict();
707
+ const localActionStartedAuditEventRefSchema = localActionAuditEventRefSchema.extend({
708
+ event_type: z.literal("local_capability.action.started"),
709
+ });
710
+ const localActionCompletedAuditEventRefSchema = localActionAuditEventRefSchema.extend({
711
+ event_type: z.literal("local_capability.action.completed"),
712
+ });
713
+ const localActionFailedAuditEventRefSchema = localActionAuditEventRefSchema.extend({
714
+ event_type: z.literal("local_capability.action.failed"),
715
+ });
716
+ const localActionResponseAuditEventsSchema = z
717
+ .object({
718
+ started: localActionStartedAuditEventRefSchema.optional(),
719
+ completed: localActionCompletedAuditEventRefSchema,
720
+ })
721
+ .strict();
722
+ const localActionErrorAuditEventsSchema = z
723
+ .object({
724
+ started: localActionStartedAuditEventRefSchema.optional(),
725
+ failed: localActionFailedAuditEventRefSchema,
726
+ })
727
+ .strict();
728
+ const localFilesystemReadInputSchema = z
729
+ .object({
730
+ path: nonEmptyStringSchema,
731
+ encoding: z.enum(["utf8", "base64"]).optional(),
732
+ range: z
733
+ .object({
734
+ start: z.number().int().nonnegative().optional(),
735
+ length: z.number().int().positive().optional(),
736
+ })
737
+ .strict()
738
+ .optional(),
739
+ })
740
+ .strict();
741
+ const localFilesystemListInputSchema = z
742
+ .object({
743
+ path: nonEmptyStringSchema,
744
+ recursive: z.boolean().optional(),
745
+ include_hidden: z.boolean().optional(),
746
+ max_depth: z.number().int().positive().optional(),
747
+ })
748
+ .strict();
749
+ const localFilesystemWriteInputSchema = z
750
+ .object({
751
+ path: nonEmptyStringSchema,
752
+ content: z.string(),
753
+ encoding: z.enum(["utf8", "base64"]).optional(),
754
+ mode: z.enum(["create", "overwrite"]),
755
+ create_parents: z.boolean(),
756
+ expected_base_hash: nonEmptyStringSchema.optional(),
757
+ })
758
+ .strict()
759
+ .superRefine((input, context) => {
760
+ if (input.mode === "overwrite" && input.expected_base_hash === undefined) {
761
+ context.addIssue({
762
+ code: "custom",
763
+ path: ["expected_base_hash"],
764
+ message: "Filesystem overwrite requests must bind an expected base hash.",
765
+ });
766
+ }
767
+ });
768
+ const localFilesystemPatchInputSchema = z
769
+ .object({
770
+ path: nonEmptyStringSchema,
771
+ expected_base_hash: nonEmptyStringSchema,
772
+ patch: z
773
+ .object({
774
+ format: z.literal("unified_diff"),
775
+ content: nonEmptyStringSchema,
776
+ })
777
+ .strict(),
778
+ create_if_missing: z.boolean().optional(),
779
+ })
780
+ .strict();
781
+ const localGitStatusInputSchema = z
782
+ .object({
783
+ porcelain_version: z.enum(["v1", "v2"]),
784
+ include_branch: z.boolean().optional(),
785
+ })
786
+ .strict();
787
+ const localGitDiffInputSchema = z
788
+ .object({
789
+ paths: z.array(nonEmptyStringSchema).optional(),
790
+ staged: z.boolean().optional(),
791
+ base_ref: nonEmptyStringSchema.optional(),
792
+ })
793
+ .strict();
794
+ const localShellExecInputSchema = z
795
+ .object({
796
+ executable: nonEmptyStringSchema,
797
+ argv: z.array(z.string()),
798
+ cwd: nonEmptyStringSchema,
799
+ use_shell: z.boolean(),
800
+ env: stringRecordSchema.optional(),
801
+ stdin: z.string().optional(),
802
+ })
803
+ .strict();
804
+ const localDevServerStartInputSchema = z
805
+ .object({
806
+ server_id: nonEmptyStringSchema,
807
+ executable: nonEmptyStringSchema,
808
+ argv: z.array(z.string()),
809
+ cwd: nonEmptyStringSchema,
810
+ host: z.enum(["127.0.0.1", "localhost"]),
811
+ port: z.number().int().min(1).max(65_535),
812
+ use_shell: z.boolean(),
813
+ env: stringRecordSchema.optional(),
814
+ readiness: z
815
+ .object({
816
+ url: nonEmptyStringSchema.optional(),
817
+ timeout_ms: z.number().int().positive(),
818
+ })
819
+ .strict()
820
+ .optional(),
821
+ })
822
+ .strict();
823
+ const localDevServerStopInputSchema = z
824
+ .object({
825
+ server_id: nonEmptyStringSchema,
826
+ signal: z.enum(["SIGTERM", "SIGKILL"]).optional(),
827
+ timeout_ms: z.number().int().positive().optional(),
828
+ })
829
+ .strict();
830
+ const localActionRequestSharedShape = {
831
+ request_id: nonEmptyStringSchema,
832
+ issued_at: timestampSchema,
833
+ attribution: localActionAttributionSchema,
834
+ lease: localActionLeaseBindingSchema,
835
+ sandbox: localActionSandboxRequirementsSchema,
836
+ approval: localActionApprovalBindingSchema,
837
+ output_limits: localActionOutputLimitsSchema,
838
+ cancellation: localActionCancellationSchema,
839
+ audit: localActionAuditMappingSchema,
840
+ };
841
+ export const localFilesystemReadRequestPayloadSchema = z
842
+ .object({
843
+ ...localActionRequestSharedShape,
844
+ action: z.literal("local.filesystem.read"),
845
+ lease: localFilesystemReadLeaseBindingSchema,
846
+ output_limits: localFilesystemReadOutputLimitsSchema,
847
+ input: localFilesystemReadInputSchema,
848
+ })
849
+ .strict();
850
+ export const localFilesystemListRequestPayloadSchema = z
851
+ .object({
852
+ ...localActionRequestSharedShape,
853
+ action: z.literal("local.filesystem.list"),
854
+ lease: localFilesystemReadLeaseBindingSchema,
855
+ output_limits: localFilesystemListOutputLimitsSchema,
856
+ input: localFilesystemListInputSchema,
857
+ })
858
+ .strict();
859
+ export const localFilesystemWriteRequestPayloadSchema = z
860
+ .object({
861
+ ...localActionRequestSharedShape,
862
+ action: z.literal("local.filesystem.write"),
863
+ lease: localFilesystemWriteLeaseBindingSchema,
864
+ input: localFilesystemWriteInputSchema,
865
+ })
866
+ .strict();
867
+ export const localFilesystemPatchRequestPayloadSchema = z
868
+ .object({
869
+ ...localActionRequestSharedShape,
870
+ action: z.literal("local.filesystem.patch"),
871
+ lease: localFilesystemWriteLeaseBindingSchema,
872
+ input: localFilesystemPatchInputSchema,
873
+ })
874
+ .strict();
875
+ export const localGitStatusRequestPayloadSchema = z
876
+ .object({
877
+ ...localActionRequestSharedShape,
878
+ action: z.literal("local.git.status"),
879
+ lease: localGitReadLeaseBindingSchema,
880
+ output_limits: localGitStatusOutputLimitsSchema,
881
+ input: localGitStatusInputSchema,
882
+ })
883
+ .strict();
884
+ export const localGitDiffRequestPayloadSchema = z
885
+ .object({
886
+ ...localActionRequestSharedShape,
887
+ action: z.literal("local.git.diff"),
888
+ lease: localGitReadLeaseBindingSchema,
889
+ output_limits: localGitDiffOutputLimitsSchema,
890
+ input: localGitDiffInputSchema,
891
+ })
892
+ .strict();
893
+ export const localShellExecRequestPayloadSchema = z
894
+ .object({
895
+ ...localActionRequestSharedShape,
896
+ action: z.literal("local.shell.exec"),
897
+ lease: localShellLeaseBindingSchema,
898
+ approval: localActionApprovedBindingSchema,
899
+ output_limits: localShellOutputLimitsSchema,
900
+ input: localShellExecInputSchema,
901
+ })
902
+ .strict();
903
+ export const localDevServerStartRequestPayloadSchema = z
904
+ .object({
905
+ ...localActionRequestSharedShape,
906
+ action: z.literal("local.dev_server.start"),
907
+ lease: localDevServerLeaseBindingSchema,
908
+ approval: localActionApprovedBindingSchema,
909
+ input: localDevServerStartInputSchema,
910
+ })
911
+ .strict();
912
+ export const localDevServerStopRequestPayloadSchema = z
913
+ .object({
914
+ ...localActionRequestSharedShape,
915
+ action: z.literal("local.dev_server.stop"),
916
+ lease: localDevServerLeaseBindingSchema,
917
+ input: localDevServerStopInputSchema,
918
+ })
919
+ .strict();
920
+ export const localActionRequestPayloadSchema = z
921
+ .discriminatedUnion("action", [
922
+ localFilesystemReadRequestPayloadSchema,
923
+ localFilesystemListRequestPayloadSchema,
924
+ localFilesystemWriteRequestPayloadSchema,
925
+ localFilesystemPatchRequestPayloadSchema,
926
+ localGitStatusRequestPayloadSchema,
927
+ localGitDiffRequestPayloadSchema,
928
+ localShellExecRequestPayloadSchema,
929
+ localDevServerStartRequestPayloadSchema,
930
+ localDevServerStopRequestPayloadSchema,
931
+ ])
932
+ .superRefine(refineLocalActionContract);
933
+ const localFilesystemReadOutputSchema = z
934
+ .object({
935
+ path: nonEmptyStringSchema,
936
+ content: z.string(),
937
+ encoding: z.enum(["utf8", "base64"]),
938
+ hash: nonEmptyStringSchema,
939
+ truncated: z.boolean().optional(),
940
+ })
941
+ .strict();
942
+ const localFilesystemListOutputSchema = z
943
+ .object({
944
+ path: nonEmptyStringSchema,
945
+ entries: z.array(z
946
+ .object({
947
+ name: nonEmptyStringSchema,
948
+ type: z.enum(["file", "directory", "other"]),
949
+ })
950
+ .strict()),
951
+ truncated: z.boolean().optional(),
952
+ })
953
+ .strict();
954
+ const localFilesystemWriteOutputSchema = z
955
+ .object({
956
+ path: nonEmptyStringSchema,
957
+ bytes_written: z.number().int().nonnegative(),
958
+ new_hash: nonEmptyStringSchema,
959
+ })
960
+ .strict();
961
+ const localFilesystemPatchOutputSchema = z
962
+ .object({
963
+ path: nonEmptyStringSchema,
964
+ changed: z.boolean(),
965
+ new_hash: nonEmptyStringSchema,
966
+ })
967
+ .strict();
968
+ const localGitStatusOutputSchema = z
969
+ .object({
970
+ porcelain: z.string(),
971
+ branch: nonEmptyStringSchema.optional(),
972
+ truncated: z.boolean().optional(),
973
+ })
974
+ .strict();
975
+ const localGitDiffOutputSchema = z
976
+ .object({
977
+ diff: z.string(),
978
+ truncated: z.boolean().optional(),
979
+ })
980
+ .strict();
981
+ const localShellExecOutputSchema = z
982
+ .object({
983
+ executable: nonEmptyStringSchema,
984
+ argv: z.array(z.string()),
985
+ cwd: nonEmptyStringSchema,
986
+ exit_code: z.number().int().nullable(),
987
+ signal: z.string().nullable().optional(),
988
+ stdout: z.string(),
989
+ stderr: z.string(),
990
+ timed_out: z.boolean(),
991
+ stdout_truncated: z.boolean().optional(),
992
+ stderr_truncated: z.boolean().optional(),
993
+ })
994
+ .strict();
995
+ const localDevServerStartOutputSchema = z
996
+ .object({
997
+ server_id: nonEmptyStringSchema,
998
+ pid: z.number().int().positive(),
999
+ host: nonEmptyStringSchema,
1000
+ port: z.number().int().min(1).max(65_535),
1001
+ cwd: nonEmptyStringSchema,
1002
+ started_at: timestampSchema,
1003
+ url: nonEmptyStringSchema.optional(),
1004
+ })
1005
+ .strict();
1006
+ const localDevServerStopOutputSchema = z
1007
+ .object({
1008
+ server_id: nonEmptyStringSchema,
1009
+ stopped_at: timestampSchema,
1010
+ })
1011
+ .strict();
1012
+ const localActionResponseSharedShape = {
1013
+ request_id: nonEmptyStringSchema,
1014
+ status: z.literal("completed"),
1015
+ completed_at: timestampSchema,
1016
+ attribution: localActionAttributionSchema,
1017
+ lease: localActionLeaseBindingSchema,
1018
+ audit_events: localActionResponseAuditEventsSchema,
1019
+ };
1020
+ export const localActionResponsePayloadSchema = z
1021
+ .discriminatedUnion("action", [
1022
+ z
1023
+ .object({
1024
+ ...localActionResponseSharedShape,
1025
+ action: z.literal("local.filesystem.read"),
1026
+ lease: localFilesystemReadLeaseBindingSchema,
1027
+ output: localFilesystemReadOutputSchema,
1028
+ })
1029
+ .strict(),
1030
+ z
1031
+ .object({
1032
+ ...localActionResponseSharedShape,
1033
+ action: z.literal("local.filesystem.list"),
1034
+ lease: localFilesystemReadLeaseBindingSchema,
1035
+ output: localFilesystemListOutputSchema,
1036
+ })
1037
+ .strict(),
1038
+ z
1039
+ .object({
1040
+ ...localActionResponseSharedShape,
1041
+ action: z.literal("local.filesystem.write"),
1042
+ lease: localFilesystemWriteLeaseBindingSchema,
1043
+ output: localFilesystemWriteOutputSchema,
1044
+ })
1045
+ .strict(),
1046
+ z
1047
+ .object({
1048
+ ...localActionResponseSharedShape,
1049
+ action: z.literal("local.filesystem.patch"),
1050
+ lease: localFilesystemWriteLeaseBindingSchema,
1051
+ output: localFilesystemPatchOutputSchema,
1052
+ })
1053
+ .strict(),
1054
+ z
1055
+ .object({
1056
+ ...localActionResponseSharedShape,
1057
+ action: z.literal("local.git.status"),
1058
+ lease: localGitReadLeaseBindingSchema,
1059
+ output: localGitStatusOutputSchema,
1060
+ })
1061
+ .strict(),
1062
+ z
1063
+ .object({
1064
+ ...localActionResponseSharedShape,
1065
+ action: z.literal("local.git.diff"),
1066
+ lease: localGitReadLeaseBindingSchema,
1067
+ output: localGitDiffOutputSchema,
1068
+ })
1069
+ .strict(),
1070
+ z
1071
+ .object({
1072
+ ...localActionResponseSharedShape,
1073
+ action: z.literal("local.shell.exec"),
1074
+ lease: localShellLeaseBindingSchema,
1075
+ output: localShellExecOutputSchema,
1076
+ })
1077
+ .strict(),
1078
+ z
1079
+ .object({
1080
+ ...localActionResponseSharedShape,
1081
+ action: z.literal("local.dev_server.start"),
1082
+ lease: localDevServerLeaseBindingSchema,
1083
+ output: localDevServerStartOutputSchema,
1084
+ })
1085
+ .strict(),
1086
+ z
1087
+ .object({
1088
+ ...localActionResponseSharedShape,
1089
+ action: z.literal("local.dev_server.stop"),
1090
+ lease: localDevServerLeaseBindingSchema,
1091
+ output: localDevServerStopOutputSchema,
1092
+ })
1093
+ .strict(),
1094
+ ])
1095
+ .superRefine(refineLocalActionContract);
1096
+ export const localActionErrorSchema = z
1097
+ .object({
1098
+ code: localActionErrorCodeSchema,
1099
+ message: nonEmptyStringSchema,
1100
+ retryable: z.boolean(),
1101
+ details: unknownRecordSchema.optional(),
1102
+ })
1103
+ .strict();
1104
+ export const localActionErrorPayloadSchema = z
1105
+ .object({
1106
+ request_id: nonEmptyStringSchema,
1107
+ action: localActionTypeSchema,
1108
+ status: z.enum(["failed", "cancelled", "timed_out"]),
1109
+ failed_at: timestampSchema,
1110
+ attribution: localActionAttributionSchema,
1111
+ lease: localActionLeaseBindingSchema.optional(),
1112
+ error: localActionErrorSchema,
1113
+ audit_events: localActionErrorAuditEventsSchema,
1114
+ })
1115
+ .strict()
1116
+ .superRefine(refineLocalActionErrorContract);
1117
+ function refineLocalActionContract(payload, context) {
1118
+ if (payload.attribution.session_id !== payload.lease.hcp_session_id) {
1119
+ addLocalActionIssue(context, ["lease", "hcp_session_id"], "Local action lease session must match request attribution.");
1120
+ }
1121
+ if (payload.attribution.workspace_id !== payload.lease.workspace_id) {
1122
+ addLocalActionIssue(context, ["lease", "workspace_id"], "Local action lease workspace must match request attribution.");
1123
+ }
1124
+ if (payload.attribution.provider_instance_id !== payload.lease.provider_instance_id) {
1125
+ addLocalActionIssue(context, ["lease", "provider_instance_id"], "Local action lease provider must match request attribution.");
1126
+ }
1127
+ if (payload.attribution.run_id !== payload.lease.run_id) {
1128
+ addLocalActionIssue(context, ["lease", "run_id"], "Local action lease run must match request attribution.");
1129
+ }
1130
+ const expectedBinding = localActionExpectedBinding(payload.action);
1131
+ if (payload.lease.capability_id !== expectedBinding.capabilityId) {
1132
+ addLocalActionIssue(context, ["lease", "capability_id"], `Action '${payload.action}' must use the ${expectedBinding.capabilityId} capability.`);
1133
+ }
1134
+ if (payload.lease.scope !== expectedBinding.scope) {
1135
+ addLocalActionIssue(context, ["lease", "scope"], `Action '${payload.action}' must use the ${expectedBinding.scope} scope.`);
1136
+ }
1137
+ if (payload.sandbox !== undefined && !payload.sandbox.requires_workspace_containment) {
1138
+ addLocalActionIssue(context, ["sandbox", "requires_workspace_containment"], "Local actions must require workspace containment.");
1139
+ }
1140
+ if (payload.approval !== undefined && localActionRequiresApproval(payload.action) && payload.approval.status !== "approved") {
1141
+ addLocalActionIssue(context, ["approval"], `Action '${payload.action}' requires an approved action hash binding.`);
1142
+ }
1143
+ if (payload.output_limits !== undefined) {
1144
+ refineLocalActionOutputLimits(payload.action, payload.output_limits, context);
1145
+ }
1146
+ }
1147
+ function refineLocalActionErrorContract(payload, context) {
1148
+ if (localActionErrorMayHaveRejectedBinding(payload.error.code)) {
1149
+ return;
1150
+ }
1151
+ if (payload.lease === undefined) {
1152
+ addLocalActionIssue(context, ["lease"], `Error code '${payload.error.code}' requires a validated lease binding.`);
1153
+ return;
1154
+ }
1155
+ refineLocalActionContract({
1156
+ action: payload.action,
1157
+ attribution: payload.attribution,
1158
+ lease: payload.lease,
1159
+ }, context);
1160
+ }
1161
+ function addLocalActionIssue(context, path, message) {
1162
+ context.addIssue({
1163
+ code: "custom",
1164
+ path,
1165
+ message,
1166
+ });
1167
+ }
1168
+ function localActionErrorMayHaveRejectedBinding(code) {
1169
+ switch (code) {
1170
+ case "local_capability_lease_missing":
1171
+ case "local_capability_lease_expired":
1172
+ case "local_capability_lease_revoked":
1173
+ case "local_capability_session_mismatch":
1174
+ case "local_capability_workspace_mismatch":
1175
+ case "local_capability_provider_mismatch":
1176
+ case "local_capability_scope_not_granted":
1177
+ return true;
1178
+ case "local_capability_sandbox_denied":
1179
+ case "local_capability_approval_required":
1180
+ case "local_capability_approval_mismatch":
1181
+ case "local_capability_path_denied":
1182
+ case "local_capability_expected_hash_mismatch":
1183
+ case "local_capability_output_limit_exceeded":
1184
+ case "local_capability_timeout":
1185
+ case "local_capability_cancelled":
1186
+ case "local_capability_command_denied":
1187
+ case "local_capability_process_failed":
1188
+ case "local_capability_dev_server_exists":
1189
+ case "local_capability_dev_server_not_found":
1190
+ case "local_capability_action_failed":
1191
+ return false;
1192
+ }
1193
+ }
1194
+ function localActionExpectedBinding(action) {
1195
+ switch (action) {
1196
+ case "local.filesystem.read":
1197
+ case "local.filesystem.list":
1198
+ return { capabilityId: "filesystem", scope: "workspace_read" };
1199
+ case "local.filesystem.write":
1200
+ case "local.filesystem.patch":
1201
+ return { capabilityId: "filesystem", scope: "workspace_write" };
1202
+ case "local.git.status":
1203
+ case "local.git.diff":
1204
+ return { capabilityId: "git", scope: "workspace_read" };
1205
+ case "local.shell.exec":
1206
+ return { capabilityId: "shell", scope: "workspace" };
1207
+ case "local.dev_server.start":
1208
+ case "local.dev_server.stop":
1209
+ return { capabilityId: "dev_server", scope: "workspace" };
1210
+ }
1211
+ }
1212
+ function localActionRequiresApproval(action) {
1213
+ return action === "local.shell.exec" || action === "local.dev_server.start";
1214
+ }
1215
+ function refineLocalActionOutputLimits(action, outputLimits, context) {
1216
+ switch (action) {
1217
+ case "local.filesystem.read":
1218
+ requireLocalActionOutputLimit(outputLimits.content_bytes, "content_bytes", action, context);
1219
+ return;
1220
+ case "local.filesystem.list":
1221
+ requireLocalActionOutputLimit(outputLimits.entries, "entries", action, context);
1222
+ return;
1223
+ case "local.git.diff":
1224
+ requireLocalActionOutputLimit(outputLimits.diff_bytes, "diff_bytes", action, context);
1225
+ return;
1226
+ case "local.git.status":
1227
+ requireLocalActionOutputLimit(outputLimits.status_bytes, "status_bytes", action, context);
1228
+ return;
1229
+ case "local.shell.exec":
1230
+ requireLocalActionOutputLimit(outputLimits.stdout_bytes, "stdout_bytes", action, context);
1231
+ requireLocalActionOutputLimit(outputLimits.stderr_bytes, "stderr_bytes", action, context);
1232
+ return;
1233
+ case "local.filesystem.write":
1234
+ case "local.filesystem.patch":
1235
+ case "local.dev_server.start":
1236
+ case "local.dev_server.stop":
1237
+ return;
1238
+ }
1239
+ }
1240
+ function requireLocalActionOutputLimit(value, field, action, context) {
1241
+ if (value === undefined) {
1242
+ addLocalActionIssue(context, ["output_limits", field], `Action '${action}' requires output limit '${field}'.`);
1243
+ }
1244
+ }
1245
+ export const harnessUsageSnapshotSchema = z
1246
+ .object({
1247
+ input_tokens: z.number().int().nonnegative().optional(),
1248
+ output_tokens: z.number().int().nonnegative().optional(),
1249
+ total_tokens: z.number().int().nonnegative().optional(),
1250
+ cost_usd: z.number().nonnegative().optional(),
1251
+ })
1252
+ .strict();
1253
+ export const harnessTurnFinalOutputSchema = z
1254
+ .object({
1255
+ final_text: z.string().optional(),
1256
+ structured_output: z.unknown().optional(),
1257
+ diff_summary: z.string().optional(),
1258
+ changed_files: z
1259
+ .array(z
1260
+ .object({
1261
+ path: nonEmptyStringSchema,
1262
+ change_type: z.enum(["added", "modified", "deleted", "renamed"]),
1263
+ })
1264
+ .strict())
1265
+ .optional(),
1266
+ artifact_refs: z
1267
+ .array(z
1268
+ .object({
1269
+ id: nonEmptyStringSchema,
1270
+ kind: z.enum(["diff", "file", "log", "image", "other"]),
1271
+ label: nonEmptyStringSchema.optional(),
1272
+ size_bytes: z.number().int().nonnegative().optional(),
1273
+ })
1274
+ .strict())
1275
+ .optional(),
1276
+ usage: harnessUsageSnapshotSchema.optional(),
1277
+ exit_reason: nonEmptyStringSchema.optional(),
1278
+ })
1279
+ .strict();
1280
+ export const hcpExtensionEventDataSchema = z
1281
+ .object({
1282
+ summary: z.string().optional(),
1283
+ fields: unknownRecordSchema.optional(),
1284
+ })
1285
+ .strict();
1286
+ export const hcpKnownEventDataSchema = z
1287
+ .object({
1288
+ summary: z.string().optional(),
1289
+ message: z.string().optional(),
1290
+ details: unknownRecordSchema.optional(),
1291
+ })
1292
+ .strict();
1293
+ export const hcpRawDiagnosticPayloadSchema = z
1294
+ .object({
1295
+ source: nonEmptyStringSchema,
1296
+ payload: unknownRecordSchema,
1297
+ })
1298
+ .strict();
1299
+ const sessionEventDataSchema = z
1300
+ .object({
1301
+ provider_instance_id: nonEmptyStringSchema.optional(),
1302
+ driver_kind: nonEmptyStringSchema.optional(),
1303
+ workspace_id: nonEmptyStringSchema.optional(),
1304
+ cwd: nonEmptyStringSchema.optional(),
1305
+ sandbox_mode: z.enum(["read_only", "workspace_write", "danger_full_access"]).optional(),
1306
+ state: nonEmptyStringSchema.optional(),
1307
+ reason: z.string().optional(),
1308
+ exit_code: z.number().int().optional(),
1309
+ model_selection: harnessModelSelectionSchema.optional(),
1310
+ mcp_server_count: z.number().int().nonnegative().optional(),
1311
+ local_capabilities: z.array(nonEmptyStringSchema).optional(),
1312
+ message: z.string().optional(),
1313
+ })
1314
+ .strict();
1315
+ const threadEventDataSchema = z
1316
+ .object({
1317
+ thread_id: nonEmptyStringSchema.optional(),
1318
+ state: nonEmptyStringSchema.optional(),
1319
+ metadata: unknownRecordSchema.optional(),
1320
+ usage: harnessUsageSnapshotSchema.optional(),
1321
+ item: z.unknown().optional(),
1322
+ audio_delta: z.string().optional(),
1323
+ error: hcpErrorSchema.optional(),
1324
+ })
1325
+ .strict();
1326
+ const accountEventDataSchema = z
1327
+ .object({
1328
+ provider_instance_id: nonEmptyStringSchema.optional(),
1329
+ status: nonEmptyStringSchema.optional(),
1330
+ auth: providerAuthSnapshotSchema.optional(),
1331
+ account: unknownRecordSchema.optional(),
1332
+ rate_limits: unknownRecordSchema.optional(),
1333
+ message: z.string().optional(),
1334
+ })
1335
+ .strict();
1336
+ const turnLifecycleEventDataSchema = z
1337
+ .object({
1338
+ turn_id: nonEmptyStringSchema.optional(),
1339
+ provider_instance_id: nonEmptyStringSchema.optional(),
1340
+ input_length: z.number().int().nonnegative().optional(),
1341
+ model_selection: harnessModelSelectionSchema.optional(),
1342
+ status: nonEmptyStringSchema.optional(),
1343
+ plan: z.unknown().optional(),
1344
+ delta: z.string().optional(),
1345
+ diff_summary: z.string().optional(),
1346
+ error: hcpErrorSchema.optional(),
1347
+ })
1348
+ .strict();
1349
+ const itemEventDataSchema = z
1350
+ .object({
1351
+ item_id: nonEmptyStringSchema.optional(),
1352
+ item_type: nonEmptyStringSchema.optional(),
1353
+ status: nonEmptyStringSchema.optional(),
1354
+ content: z.unknown().optional(),
1355
+ summary: z.string().optional(),
1356
+ })
1357
+ .strict();
1358
+ const textDeltaEventDataSchema = z
1359
+ .object({
1360
+ stream_kind: nonEmptyStringSchema.optional(),
1361
+ delta: z.string(),
1362
+ })
1363
+ .strict();
1364
+ const commandEventDataSchema = z
1365
+ .object({
1366
+ command_id: nonEmptyStringSchema.optional(),
1367
+ command: z.string().optional(),
1368
+ argv: z.array(z.string()).optional(),
1369
+ cwd: nonEmptyStringSchema.optional(),
1370
+ status: nonEmptyStringSchema.optional(),
1371
+ exit_code: z.number().int().optional(),
1372
+ duration_ms: z.number().nonnegative().optional(),
1373
+ output: z.unknown().optional(),
1374
+ error: hcpErrorSchema.optional(),
1375
+ })
1376
+ .strict();
1377
+ const localCapabilityLeaseEventDataSchema = z
1378
+ .object({
1379
+ lease_id: nonEmptyStringSchema,
1380
+ workspace_id: nonEmptyStringSchema,
1381
+ provider_instance_id: nonEmptyStringSchema,
1382
+ status: z.enum(["created", "started", "revoked", "expired"]),
1383
+ capability_ids: z.array(nonEmptyStringSchema).optional(),
1384
+ reason: z.string().optional(),
1385
+ })
1386
+ .strict();
1387
+ const localCapabilityActionEventDataSchema = z
1388
+ .object({
1389
+ lease_id: nonEmptyStringSchema,
1390
+ run_id: nonEmptyStringSchema,
1391
+ workspace_id: nonEmptyStringSchema,
1392
+ provider_instance_id: nonEmptyStringSchema,
1393
+ capability_id: nonEmptyStringSchema,
1394
+ action: nonEmptyStringSchema,
1395
+ status: z.enum(["started", "completed", "failed"]),
1396
+ duration_ms: z.number().nonnegative().optional(),
1397
+ input: z.unknown().optional(),
1398
+ output: z.unknown().optional(),
1399
+ error: hcpErrorSchema.optional(),
1400
+ })
1401
+ .strict();
1402
+ const mcpToolEventDataSchema = z
1403
+ .object({
1404
+ server_name: nonEmptyStringSchema.optional(),
1405
+ attachment: nonEmptyStringSchema.optional(),
1406
+ tool_name: nonEmptyStringSchema,
1407
+ status: z.enum(["started", "completed", "failed"]).optional(),
1408
+ input_summary: z.unknown().optional(),
1409
+ output_summary: z.unknown().optional(),
1410
+ arguments: z.unknown().optional(),
1411
+ result: z.unknown().optional(),
1412
+ duration_ms: z.number().nonnegative().optional(),
1413
+ error: hcpErrorSchema.optional(),
1414
+ })
1415
+ .strict();
1416
+ const mcpStatusEventDataSchema = z
1417
+ .object({
1418
+ server_name: nonEmptyStringSchema.optional(),
1419
+ attachment: nonEmptyStringSchema.optional(),
1420
+ status: nonEmptyStringSchema.optional(),
1421
+ message: z.string().optional(),
1422
+ oauth_state: nonEmptyStringSchema.optional(),
1423
+ })
1424
+ .strict();
1425
+ const approvalRequestedEventDataSchema = z
1426
+ .object({
1427
+ request_id: nonEmptyStringSchema,
1428
+ session_id: nonEmptyStringSchema,
1429
+ turn_id: nonEmptyStringSchema,
1430
+ workspace_id: nonEmptyStringSchema,
1431
+ provider_instance_id: nonEmptyStringSchema,
1432
+ driver_kind: nonEmptyStringSchema,
1433
+ request_type: z.enum(["command", "file_read", "file_change", "mcp_tool", "other"]),
1434
+ risk_class: z.enum(["low", "medium", "high"]),
1435
+ action: z.unknown(),
1436
+ action_hash: nonEmptyStringSchema,
1437
+ allowed_decisions: z.array(z.enum(["accept", "accept_for_session", "decline", "cancel"])).min(1),
1438
+ expires_at: timestampSchema,
1439
+ display: z
1440
+ .object({
1441
+ title: nonEmptyStringSchema,
1442
+ detail: z.string().optional(),
1443
+ })
1444
+ .strict(),
1445
+ })
1446
+ .strict();
1447
+ const approvalResolvedEventDataSchema = z
1448
+ .object({
1449
+ request_id: nonEmptyStringSchema,
1450
+ session_id: nonEmptyStringSchema,
1451
+ turn_id: nonEmptyStringSchema,
1452
+ action_hash: nonEmptyStringSchema,
1453
+ decision: z.enum(["accept", "accept_for_session", "decline", "cancel"]),
1454
+ actor_id: nonEmptyStringSchema,
1455
+ resolved_at: timestampSchema.optional(),
1456
+ })
1457
+ .strict();
1458
+ const inputRequestedEventDataSchema = z
1459
+ .object({
1460
+ request_id: nonEmptyStringSchema,
1461
+ session_id: nonEmptyStringSchema,
1462
+ turn_id: nonEmptyStringSchema,
1463
+ prompt: z.string(),
1464
+ input_kind: z.enum(["text", "choice", "multi_choice", "form"]),
1465
+ choices: z
1466
+ .array(z
1467
+ .object({
1468
+ id: nonEmptyStringSchema,
1469
+ label: nonEmptyStringSchema,
1470
+ description: z.string().optional(),
1471
+ })
1472
+ .strict())
1473
+ .optional(),
1474
+ required: z.boolean(),
1475
+ expires_at: timestampSchema.optional(),
1476
+ redaction: z.enum(["none", "secret"]),
1477
+ })
1478
+ .strict();
1479
+ const inputResolvedEventDataSchema = z
1480
+ .object({
1481
+ request_id: nonEmptyStringSchema,
1482
+ session_id: nonEmptyStringSchema,
1483
+ turn_id: nonEmptyStringSchema,
1484
+ actor_id: nonEmptyStringSchema.optional(),
1485
+ cancelled: z.boolean().optional(),
1486
+ value: z.unknown().optional(),
1487
+ resolved_at: timestampSchema.optional(),
1488
+ })
1489
+ .strict();
1490
+ const requestEventDataSchema = z
1491
+ .object({
1492
+ request_id: nonEmptyStringSchema.optional(),
1493
+ session_id: nonEmptyStringSchema.optional(),
1494
+ turn_id: nonEmptyStringSchema.optional(),
1495
+ request_type: nonEmptyStringSchema.optional(),
1496
+ status: nonEmptyStringSchema.optional(),
1497
+ summary: z.string().optional(),
1498
+ resolved_at: timestampSchema.optional(),
1499
+ })
1500
+ .strict();
1501
+ const taskEventDataSchema = z
1502
+ .object({
1503
+ task_id: nonEmptyStringSchema.optional(),
1504
+ status: nonEmptyStringSchema.optional(),
1505
+ summary: z.string().optional(),
1506
+ progress: z.number().min(0).max(1).optional(),
1507
+ output: z.unknown().optional(),
1508
+ error: hcpErrorSchema.optional(),
1509
+ })
1510
+ .strict();
1511
+ const hookEventDataSchema = z
1512
+ .object({
1513
+ hook_id: nonEmptyStringSchema.optional(),
1514
+ name: nonEmptyStringSchema.optional(),
1515
+ status: nonEmptyStringSchema.optional(),
1516
+ summary: z.string().optional(),
1517
+ progress: z.number().min(0).max(1).optional(),
1518
+ output: z.unknown().optional(),
1519
+ error: hcpErrorSchema.optional(),
1520
+ })
1521
+ .strict();
1522
+ const toolEventDataSchema = z
1523
+ .object({
1524
+ tool_name: nonEmptyStringSchema.optional(),
1525
+ status: nonEmptyStringSchema.optional(),
1526
+ summary: z.string().optional(),
1527
+ progress: z.number().min(0).max(1).optional(),
1528
+ })
1529
+ .strict();
1530
+ const modelReroutedEventDataSchema = z
1531
+ .object({
1532
+ from_model: nonEmptyStringSchema.optional(),
1533
+ to_model: nonEmptyStringSchema.optional(),
1534
+ reason: z.string().optional(),
1535
+ })
1536
+ .strict();
1537
+ const filesPersistedEventDataSchema = z
1538
+ .object({
1539
+ artifact_refs: harnessTurnFinalOutputSchema.shape.artifact_refs.optional(),
1540
+ changed_files: harnessTurnFinalOutputSchema.shape.changed_files.optional(),
1541
+ })
1542
+ .strict();
1543
+ const runtimeDiagnosticEventDataSchema = z
1544
+ .object({
1545
+ code: nonEmptyStringSchema.optional(),
1546
+ message: z.string().optional(),
1547
+ summary: z.string().optional(),
1548
+ details: unknownRecordSchema.optional(),
1549
+ event: nonEmptyStringSchema.optional(),
1550
+ attachment: nonEmptyStringSchema.optional(),
1551
+ url: nonEmptyStringSchema.optional(),
1552
+ headers: stringRecordSchema.optional(),
1553
+ })
1554
+ .strict();
1555
+ const turnTerminalEventDataSchema = z
1556
+ .object({
1557
+ status: nonEmptyStringSchema.optional(),
1558
+ final_output: harnessTurnFinalOutputSchema,
1559
+ error: hcpErrorSchema.optional(),
1560
+ })
1561
+ .strict();
1562
+ function schemaForKnownEventType(eventType) {
1563
+ if (eventType.startsWith("local_capability.lease.")) {
1564
+ return localCapabilityLeaseEventDataSchema;
1565
+ }
1566
+ if (eventType.startsWith("local_capability.action.")) {
1567
+ return localCapabilityActionEventDataSchema;
1568
+ }
1569
+ if (eventType.startsWith("mcp_tool.")) {
1570
+ return mcpToolEventDataSchema;
1571
+ }
1572
+ if (eventType.startsWith("mcp.")) {
1573
+ return mcpStatusEventDataSchema;
1574
+ }
1575
+ if (eventType.startsWith("session.")) {
1576
+ return sessionEventDataSchema;
1577
+ }
1578
+ if (eventType.startsWith("thread.")) {
1579
+ return threadEventDataSchema;
1580
+ }
1581
+ if (eventType.startsWith("account.") || eventType === "auth.status") {
1582
+ return accountEventDataSchema;
1583
+ }
1584
+ if (eventType === "workspace.preflight.completed") {
1585
+ return workspacePreflightCompletedSchema;
1586
+ }
1587
+ if (eventType === "runtime.warning" || eventType === "runtime.error") {
1588
+ return runtimeDiagnosticEventDataSchema;
1589
+ }
1590
+ if (eventType === "turn.completed" ||
1591
+ eventType === "turn.failed" ||
1592
+ eventType === "turn.aborted" ||
1593
+ eventType === "turn.cancelled") {
1594
+ return turnTerminalEventDataSchema;
1595
+ }
1596
+ if (eventType.startsWith("turn.")) {
1597
+ return turnLifecycleEventDataSchema;
1598
+ }
1599
+ if (eventType.startsWith("item.")) {
1600
+ return itemEventDataSchema;
1601
+ }
1602
+ if (eventType === "content.delta" || eventType === "reasoning.delta") {
1603
+ return textDeltaEventDataSchema;
1604
+ }
1605
+ if (eventType.startsWith("command.") || eventType.startsWith("file_change.")) {
1606
+ return commandEventDataSchema;
1607
+ }
1608
+ if (eventType === "approval.requested") {
1609
+ return approvalRequestedEventDataSchema;
1610
+ }
1611
+ if (eventType === "approval.resolved") {
1612
+ return approvalResolvedEventDataSchema;
1613
+ }
1614
+ if (eventType === "input.requested" || eventType === "user_input.requested") {
1615
+ return inputRequestedEventDataSchema;
1616
+ }
1617
+ if (eventType === "input.resolved" || eventType === "user_input.resolved") {
1618
+ return inputResolvedEventDataSchema;
1619
+ }
1620
+ if (eventType.startsWith("request.")) {
1621
+ return requestEventDataSchema;
1622
+ }
1623
+ if (eventType.startsWith("task.")) {
1624
+ return taskEventDataSchema;
1625
+ }
1626
+ if (eventType.startsWith("hook.")) {
1627
+ return hookEventDataSchema;
1628
+ }
1629
+ if (eventType.startsWith("tool.")) {
1630
+ return toolEventDataSchema;
1631
+ }
1632
+ if (eventType === "model.rerouted") {
1633
+ return modelReroutedEventDataSchema;
1634
+ }
1635
+ if (eventType === "files.persisted") {
1636
+ return filesPersistedEventDataSchema;
1637
+ }
1638
+ if (eventType === "usage.updated") {
1639
+ return harnessUsageSnapshotSchema;
1640
+ }
1641
+ if (eventType === "config.warning" || eventType === "deprecation.notice") {
1642
+ return runtimeDiagnosticEventDataSchema;
1643
+ }
1644
+ return hcpKnownEventDataSchema;
1645
+ }
1646
+ export const knownHcpEventDataSchemas = Object.freeze(Object.fromEntries(KNOWN_HCP_EVENT_TYPES.map((eventType) => [
1647
+ eventType,
1648
+ schemaForKnownEventType(eventType),
1649
+ ])));
1650
+ export function isKnownHcpEventType(value) {
1651
+ return KNOWN_HCP_EVENT_TYPES.includes(value);
1652
+ }
1653
+ export function isHcpEventType(value) {
1654
+ return isKnownHcpEventType(value) || value.startsWith("provider.") || value.startsWith("extension.");
1655
+ }
1656
+ function enforceEnvelopeSizeLimits(envelope, context) {
1657
+ const payloadBytes = encodedJsonByteLength(envelope.payload);
1658
+ if (payloadBytes > HCP_PAYLOAD_MAX_ENCODED_BYTES) {
1659
+ context.addIssue({
1660
+ code: "custom",
1661
+ path: ["payload"],
1662
+ message: `HCP payload exceeds ${HCP_PAYLOAD_MAX_ENCODED_BYTES} encoded bytes.`,
1663
+ });
1664
+ }
1665
+ if (envelope.metadata !== undefined) {
1666
+ const metadataBytes = encodedJsonByteLength(envelope.metadata);
1667
+ if (metadataBytes > HCP_METADATA_MAX_ENCODED_BYTES) {
1668
+ context.addIssue({
1669
+ code: "custom",
1670
+ path: ["metadata"],
1671
+ message: `HCP metadata exceeds ${HCP_METADATA_MAX_ENCODED_BYTES} encoded bytes.`,
1672
+ });
1673
+ }
1674
+ }
1675
+ }
1676
+ function encodedJsonByteLength(value) {
1677
+ return new TextEncoder().encode(JSON.stringify(value) ?? "null").byteLength;
1678
+ }
1679
+ export const hcpEventTypeSchema = z.string().refine(isHcpEventType, {
1680
+ message: "Event type must be a known HCP event, provider.* event, or extension.* event.",
1681
+ });
1682
+ export const hcpHarnessEventPayloadSchema = z
1683
+ .object({
1684
+ session_id: nonEmptyStringSchema,
1685
+ turn_id: nonEmptyStringSchema.optional(),
1686
+ sequence: z.number().int().positive(),
1687
+ event_type: hcpEventTypeSchema,
1688
+ created_at: timestampSchema,
1689
+ data: z.unknown(),
1690
+ raw: hcpRawDiagnosticPayloadSchema.optional(),
1691
+ })
1692
+ .strict()
1693
+ .superRefine((payload, context) => {
1694
+ const eventType = payload.event_type;
1695
+ const dataSchema = isKnownHcpEventType(eventType)
1696
+ ? knownHcpEventDataSchemas[eventType]
1697
+ : hcpExtensionEventDataSchema;
1698
+ const dataResult = dataSchema.safeParse(payload.data);
1699
+ if (!dataResult.success) {
1700
+ for (const issue of dataResult.error.issues) {
1701
+ context.addIssue({
1702
+ ...issue,
1703
+ path: ["data", ...issue.path],
1704
+ });
1705
+ }
1706
+ }
1707
+ if (eventType.startsWith("local_capability.action.") && payload.turn_id === undefined) {
1708
+ context.addIssue({
1709
+ code: "custom",
1710
+ path: ["turn_id"],
1711
+ message: "Local capability action events must include turn_id for attribution.",
1712
+ });
1713
+ }
1714
+ });
1715
+ const hcpSessionSnapshotTombstoneSchema = z
1716
+ .object({
1717
+ entity_type: z.enum(["session", "turn", "item"]),
1718
+ entity_id: nonEmptyStringSchema,
1719
+ deleted_at: timestampSchema,
1720
+ })
1721
+ .strict();
1722
+ const hcpSessionSnapshotBaseShape = {
1723
+ command_id: nonEmptyStringSchema,
1724
+ session_id: nonEmptyStringSchema,
1725
+ generated_at: timestampSchema,
1726
+ through_sequence: z.number().int().positive(),
1727
+ events: z.array(hcpHarnessEventPayloadSchema).min(1),
1728
+ tombstones: z.array(hcpSessionSnapshotTombstoneSchema),
1729
+ };
1730
+ export const hcpSessionSnapshotPayloadSchema = z
1731
+ .discriminatedUnion("completeness", [
1732
+ z
1733
+ .object({
1734
+ ...hcpSessionSnapshotBaseShape,
1735
+ completeness: z.literal("complete"),
1736
+ omission_semantics: z.literal("replace"),
1737
+ from_sequence: z.literal(1),
1738
+ })
1739
+ .strict(),
1740
+ z
1741
+ .object({
1742
+ ...hcpSessionSnapshotBaseShape,
1743
+ completeness: z.literal("partial"),
1744
+ omission_semantics: z.literal("preserve"),
1745
+ reason: z.enum(["retention_gap", "size_limit"]),
1746
+ from_sequence: z.number().int().positive(),
1747
+ })
1748
+ .strict(),
1749
+ ])
1750
+ .superRefine((snapshot, context) => {
1751
+ if (snapshot.through_sequence < snapshot.from_sequence) {
1752
+ context.addIssue({
1753
+ code: "custom",
1754
+ path: ["through_sequence"],
1755
+ message: "Snapshot range must not end before it starts.",
1756
+ });
1757
+ }
1758
+ for (let index = 0; index < snapshot.events.length; index += 1) {
1759
+ const event = snapshot.events[index];
1760
+ const expectedSequence = snapshot.from_sequence + index;
1761
+ if (event?.session_id !== snapshot.session_id) {
1762
+ context.addIssue({
1763
+ code: "custom",
1764
+ path: ["events", index, "session_id"],
1765
+ message: "Snapshot events must belong to the requested session.",
1766
+ });
1767
+ }
1768
+ if (event?.sequence !== expectedSequence) {
1769
+ context.addIssue({
1770
+ code: "custom",
1771
+ path: ["events", index, "sequence"],
1772
+ message: "Snapshot events must form one contiguous sequence.",
1773
+ });
1774
+ }
1775
+ }
1776
+ if (snapshot.events.at(-1)?.sequence !== snapshot.through_sequence) {
1777
+ context.addIssue({
1778
+ code: "custom",
1779
+ path: ["through_sequence"],
1780
+ message: "Snapshot through_sequence must equal the final event sequence.",
1781
+ });
1782
+ }
1783
+ });
1784
+ export const hcpEnvelopeSchema = z
1785
+ .object({
1786
+ id: nonEmptyStringSchema,
1787
+ type: nonEmptyStringSchema,
1788
+ version: hcpVersionSchema,
1789
+ sent_at: timestampSchema,
1790
+ payload: z.unknown(),
1791
+ metadata: metadataSchema.optional(),
1792
+ })
1793
+ .strict()
1794
+ .superRefine(enforceEnvelopeSizeLimits);
1795
+ export function hcpTypedEnvelopeSchema(type, payloadSchema) {
1796
+ return z
1797
+ .object({
1798
+ id: nonEmptyStringSchema,
1799
+ type: z.literal(type),
1800
+ version: hcpVersionSchema,
1801
+ sent_at: timestampSchema,
1802
+ payload: payloadSchema,
1803
+ metadata: metadataSchema.optional(),
1804
+ })
1805
+ .strict()
1806
+ .superRefine(enforceEnvelopeSizeLimits);
1807
+ }
1808
+ export const hcpCommandAckMessageSchema = hcpTypedEnvelopeSchema("hcp.command.ack", hcpCommandAckPayloadSchema);
1809
+ export const hcpCommandNackMessageSchema = hcpTypedEnvelopeSchema("hcp.command.nack", hcpCommandNackPayloadSchema);
1810
+ export const hcpAckMessageSchema = hcpCommandAckMessageSchema;
1811
+ export const hcpNackMessageSchema = hcpCommandNackMessageSchema;
1812
+ export const hcpHostHelloMessageSchema = hcpTypedEnvelopeSchema("host.hello", hcpHostHelloPayloadSchema);
1813
+ export const hcpHostAcceptedMessageSchema = hcpTypedEnvelopeSchema("host.accepted", hcpHostAcceptedPayloadSchema);
1814
+ export const hcpHostRejectedMessageSchema = hcpTypedEnvelopeSchema("host.rejected", hcpHostRejectedPayloadSchema);
1815
+ export const hcpHostHeartbeatMessageSchema = hcpTypedEnvelopeSchema("host.heartbeat", hcpHostHeartbeatPayloadSchema);
1816
+ export const hcpHostCapabilitiesUpdatedMessageSchema = hcpTypedEnvelopeSchema("host.capabilities.updated", hcpHostCapabilitiesUpdatedPayloadSchema);
1817
+ export const hcpHostReplayUnavailableMessageSchema = hcpTypedEnvelopeSchema("host.replay.unavailable", hcpHostReplayUnavailablePayloadSchema);
1818
+ export const hcpSessionStartMessageSchema = hcpTypedEnvelopeSchema("harness.session.start", hcpSessionStartPayloadSchema);
1819
+ export const hcpSessionSnapshotRequestMessageSchema = hcpTypedEnvelopeSchema("harness.session.snapshot.request", hcpSessionSnapshotRequestPayloadSchema);
1820
+ export const hcpSessionSnapshotMessageSchema = hcpTypedEnvelopeSchema("harness.session.snapshot", hcpSessionSnapshotPayloadSchema);
1821
+ export const hcpTurnSendMessageSchema = hcpTypedEnvelopeSchema("harness.turn.send", hcpTurnSendPayloadSchema);
1822
+ export const hcpTurnCancelMessageSchema = hcpTypedEnvelopeSchema("harness.turn.cancel", hcpTurnCancelPayloadSchema);
1823
+ export const hcpSessionStopMessageSchema = hcpTypedEnvelopeSchema("harness.session.stop", hcpSessionStopPayloadSchema);
1824
+ export const hcpApprovalRespondMessageSchema = hcpTypedEnvelopeSchema("harness.approval.respond", hcpApprovalResponsePayloadSchema);
1825
+ export const hcpInputRespondMessageSchema = hcpTypedEnvelopeSchema("harness.input.respond", hcpInputResponsePayloadSchema);
1826
+ export const toolServersDetachMessageSchema = hcpTypedEnvelopeSchema("tool_servers.detach", toolServersDetachPayloadSchema);
1827
+ export const localActionRequestMessageSchema = hcpTypedEnvelopeSchema("local.action.request", localActionRequestPayloadSchema);
1828
+ export const localActionResponseMessageSchema = hcpTypedEnvelopeSchema("local.action.response", localActionResponsePayloadSchema);
1829
+ export const localActionErrorMessageSchema = hcpTypedEnvelopeSchema("local.action.error", localActionErrorPayloadSchema);
1830
+ export const hcpHarnessEventMessageSchema = hcpTypedEnvelopeSchema("harness.event", hcpHarnessEventPayloadSchema);
1831
+ export const hcpWorkspacesRequestMessageSchema = hcpTypedEnvelopeSchema("host.workspaces.request", hcpWorkspacesRequestPayloadSchema);
1832
+ export const hcpWorkspacesResultMessageSchema = hcpTypedEnvelopeSchema("host.workspaces.result", hcpWorkspacesResultPayloadSchema);
1833
+ export const hcpMessageSchema = z.discriminatedUnion("type", [
1834
+ hcpWorkspacesRequestMessageSchema,
1835
+ hcpWorkspacesResultMessageSchema,
1836
+ hcpCommandAckMessageSchema,
1837
+ hcpCommandNackMessageSchema,
1838
+ hcpHostHelloMessageSchema,
1839
+ hcpHostAcceptedMessageSchema,
1840
+ hcpHostRejectedMessageSchema,
1841
+ hcpHostHeartbeatMessageSchema,
1842
+ hcpHostCapabilitiesUpdatedMessageSchema,
1843
+ hcpHostReplayUnavailableMessageSchema,
1844
+ hcpSessionStartMessageSchema,
1845
+ hcpSessionSnapshotRequestMessageSchema,
1846
+ hcpSessionSnapshotMessageSchema,
1847
+ hcpTurnSendMessageSchema,
1848
+ hcpTurnCancelMessageSchema,
1849
+ hcpSessionStopMessageSchema,
1850
+ hcpApprovalRespondMessageSchema,
1851
+ hcpInputRespondMessageSchema,
1852
+ toolServersDetachMessageSchema,
1853
+ localActionRequestMessageSchema,
1854
+ localActionResponseMessageSchema,
1855
+ localActionErrorMessageSchema,
1856
+ hcpHarnessEventMessageSchema,
1857
+ ]);
1858
+ export function parseHcpEnvelope(input) {
1859
+ return hcpEnvelopeSchema.parse(input);
1860
+ }
1861
+ export function parseHcpMessage(input) {
1862
+ return hcpMessageSchema.parse(input);
1863
+ }
1864
+ export function parseJsonHcpMessage(input) {
1865
+ const parsed = JSON.parse(input);
1866
+ return parseHcpMessage(parsed);
1867
+ }
1868
+ export function createHcpEnvelope(type, payload, metadata) {
1869
+ return {
1870
+ id: crypto.randomUUID(),
1871
+ type,
1872
+ version: HCP_VERSION,
1873
+ sent_at: new Date().toISOString(),
1874
+ payload,
1875
+ ...(metadata ? { metadata } : {}),
1876
+ };
1877
+ }
1878
+ export function parseHcpHostHelloPayload(input) {
1879
+ return hcpHostHelloPayloadSchema.parse(input);
1880
+ }
1881
+ export function parseHcpHostAcceptedPayload(input) {
1882
+ return hcpHostAcceptedPayloadSchema.parse(input);
1883
+ }
1884
+ export function parseHcpHostRejectedPayload(input) {
1885
+ return hcpHostRejectedPayloadSchema.parse(input);
1886
+ }
1887
+ export function parseHcpHostHeartbeatPayload(input) {
1888
+ return hcpHostHeartbeatPayloadSchema.parse(input);
1889
+ }
1890
+ export function parseHcpHostCapabilitiesUpdatedPayload(input) {
1891
+ return hcpHostCapabilitiesUpdatedPayloadSchema.parse(input);
1892
+ }
1893
+ export function parseHcpHostReplayUnavailablePayload(input) {
1894
+ return hcpHostReplayUnavailablePayloadSchema.parse(input);
1895
+ }
1896
+ export function parseHarnessProviderSnapshot(input) {
1897
+ return harnessProviderSnapshotSchema.parse(input);
1898
+ }
1899
+ export function parseLocalCapabilityLease(input) {
1900
+ return localCapabilityLeaseSchema.parse(input);
1901
+ }
1902
+ export function parseMcpServerAttachment(input) {
1903
+ return mcpServerAttachmentSchema.parse(input);
1904
+ }
1905
+ export function parseHcpSessionStartPayload(input) {
1906
+ return hcpSessionStartPayloadSchema.parse(input);
1907
+ }
1908
+ export function parseHcpSessionSnapshotRequestPayload(input) {
1909
+ return hcpSessionSnapshotRequestPayloadSchema.parse(input);
1910
+ }
1911
+ export function parseHcpSessionSnapshotPayload(input) {
1912
+ return hcpSessionSnapshotPayloadSchema.parse(input);
1913
+ }
1914
+ export function parseHcpTurnSendPayload(input) {
1915
+ return hcpTurnSendPayloadSchema.parse(input);
1916
+ }
1917
+ export function parseLocalActionRequestPayload(input) {
1918
+ return localActionRequestPayloadSchema.parse(input);
1919
+ }
1920
+ export function parseLocalActionResponsePayload(input) {
1921
+ return localActionResponsePayloadSchema.parse(input);
1922
+ }
1923
+ export function parseLocalActionErrorPayload(input) {
1924
+ return localActionErrorPayloadSchema.parse(input);
1925
+ }
1926
+ export function parseHcpHarnessEventPayload(input) {
1927
+ return hcpHarnessEventPayloadSchema.parse(input);
1928
+ }
1929
+ export { HcpSessionEventReducer, } from "./session-reducer.js";
1930
+ export * from "./pairing.js";
1931
+ //# sourceMappingURL=index.js.map