@vm0/runner 2.3.1 → 2.4.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 (2) hide show
  1. package/index.js +1909 -683
  2. package/package.json +1 -1
package/index.js CHANGED
@@ -4816,25 +4816,143 @@ var apiErrorSchema = z3.object({
4816
4816
  });
4817
4817
 
4818
4818
  // ../../packages/core/src/contracts/composes.ts
4819
+ import { z as z5 } from "zod";
4820
+
4821
+ // ../../packages/core/src/contracts/runners.ts
4819
4822
  import { z as z4 } from "zod";
4820
4823
  var c = initContract();
4821
- var composeVersionQuerySchema = z4.preprocess(
4824
+ var firewallRuleSchema = z4.object({
4825
+ domain: z4.string().optional(),
4826
+ ip: z4.string().optional(),
4827
+ /** Terminal rule - value is the action (ALLOW or DENY) */
4828
+ final: z4.enum(["ALLOW", "DENY"]).optional(),
4829
+ /** Action for domain/ip rules */
4830
+ action: z4.enum(["ALLOW", "DENY"]).optional()
4831
+ });
4832
+ var experimentalFirewallSchema = z4.object({
4833
+ enabled: z4.boolean(),
4834
+ rules: z4.array(firewallRuleSchema).optional(),
4835
+ experimental_mitm: z4.boolean().optional(),
4836
+ experimental_seal_secrets: z4.boolean().optional()
4837
+ });
4838
+ var runnerGroupSchema = z4.string().regex(
4839
+ /^[a-z0-9-]+\/[a-z0-9-]+$/,
4840
+ "Runner group must be in scope/name format (e.g., acme/production)"
4841
+ );
4842
+ var jobSchema = z4.object({
4843
+ runId: z4.string().uuid(),
4844
+ prompt: z4.string(),
4845
+ agentComposeVersionId: z4.string(),
4846
+ vars: z4.record(z4.string(), z4.string()).nullable(),
4847
+ secretNames: z4.array(z4.string()).nullable(),
4848
+ checkpointId: z4.string().uuid().nullable()
4849
+ });
4850
+ var runnersPollContract = c.router({
4851
+ poll: {
4852
+ method: "POST",
4853
+ path: "/api/runners/poll",
4854
+ body: z4.object({
4855
+ group: runnerGroupSchema
4856
+ }),
4857
+ responses: {
4858
+ 200: z4.object({
4859
+ job: jobSchema.nullable()
4860
+ }),
4861
+ 400: apiErrorSchema,
4862
+ 401: apiErrorSchema,
4863
+ 500: apiErrorSchema
4864
+ },
4865
+ summary: "Poll for pending jobs (long-polling with 30s timeout)"
4866
+ }
4867
+ });
4868
+ var storageEntrySchema = z4.object({
4869
+ mountPath: z4.string(),
4870
+ archiveUrl: z4.string().nullable()
4871
+ });
4872
+ var artifactEntrySchema = z4.object({
4873
+ mountPath: z4.string(),
4874
+ archiveUrl: z4.string().nullable(),
4875
+ vasStorageName: z4.string(),
4876
+ vasVersionId: z4.string()
4877
+ });
4878
+ var storageManifestSchema = z4.object({
4879
+ storages: z4.array(storageEntrySchema),
4880
+ artifact: artifactEntrySchema.nullable()
4881
+ });
4882
+ var resumeSessionSchema = z4.object({
4883
+ sessionId: z4.string(),
4884
+ sessionHistory: z4.string()
4885
+ });
4886
+ var storedExecutionContextSchema = z4.object({
4887
+ workingDir: z4.string(),
4888
+ storageManifest: storageManifestSchema.nullable(),
4889
+ environment: z4.record(z4.string(), z4.string()).nullable(),
4890
+ resumeSession: resumeSessionSchema.nullable(),
4891
+ encryptedSecrets: z4.string().nullable(),
4892
+ // AES-256-GCM encrypted secrets
4893
+ cliAgentType: z4.string(),
4894
+ experimentalFirewall: experimentalFirewallSchema.optional()
4895
+ });
4896
+ var executionContextSchema = z4.object({
4897
+ runId: z4.string().uuid(),
4898
+ prompt: z4.string(),
4899
+ agentComposeVersionId: z4.string(),
4900
+ vars: z4.record(z4.string(), z4.string()).nullable(),
4901
+ secretNames: z4.array(z4.string()).nullable(),
4902
+ checkpointId: z4.string().uuid().nullable(),
4903
+ sandboxToken: z4.string(),
4904
+ // New fields for E2B parity:
4905
+ workingDir: z4.string(),
4906
+ storageManifest: storageManifestSchema.nullable(),
4907
+ environment: z4.record(z4.string(), z4.string()).nullable(),
4908
+ resumeSession: resumeSessionSchema.nullable(),
4909
+ secretValues: z4.array(z4.string()).nullable(),
4910
+ cliAgentType: z4.string(),
4911
+ // Experimental firewall configuration
4912
+ experimentalFirewall: experimentalFirewallSchema.optional()
4913
+ });
4914
+ var runnersJobClaimContract = c.router({
4915
+ claim: {
4916
+ method: "POST",
4917
+ path: "/api/runners/jobs/:id/claim",
4918
+ pathParams: z4.object({
4919
+ id: z4.string().uuid()
4920
+ }),
4921
+ body: z4.object({}),
4922
+ responses: {
4923
+ 200: executionContextSchema,
4924
+ 400: apiErrorSchema,
4925
+ 401: apiErrorSchema,
4926
+ 403: apiErrorSchema,
4927
+ // Job does not belong to user
4928
+ 404: apiErrorSchema,
4929
+ 409: apiErrorSchema,
4930
+ // Already claimed
4931
+ 500: apiErrorSchema
4932
+ },
4933
+ summary: "Claim a pending job for execution"
4934
+ }
4935
+ });
4936
+
4937
+ // ../../packages/core/src/contracts/composes.ts
4938
+ var c2 = initContract();
4939
+ var composeVersionQuerySchema = z5.preprocess(
4822
4940
  (val) => val === void 0 || val === null ? void 0 : String(val),
4823
- z4.string().min(1, "Missing version query parameter").regex(
4941
+ z5.string().min(1, "Missing version query parameter").regex(
4824
4942
  /^[a-f0-9]{8,64}$|^latest$/i,
4825
4943
  "Version must be 8-64 hex characters or 'latest'"
4826
4944
  )
4827
4945
  );
4828
- var agentNameSchema = z4.string().min(3, "Agent name must be at least 3 characters").max(64, "Agent name must be 64 characters or less").regex(
4946
+ var agentNameSchema = z5.string().min(3, "Agent name must be at least 3 characters").max(64, "Agent name must be 64 characters or less").regex(
4829
4947
  /^[a-zA-Z0-9][a-zA-Z0-9-]{1,62}[a-zA-Z0-9]$/,
4830
4948
  "Agent name must start and end with letter or number, and contain only letters, numbers, and hyphens"
4831
4949
  );
4832
- var volumeConfigSchema = z4.object({
4833
- name: z4.string().min(1, "Volume name is required"),
4834
- version: z4.string().min(1, "Volume version is required")
4950
+ var volumeConfigSchema = z5.object({
4951
+ name: z5.string().min(1, "Volume name is required"),
4952
+ version: z5.string().min(1, "Volume version is required")
4835
4953
  });
4836
4954
  var SUPPORTED_APPS = ["github"];
4837
- var appStringSchema = z4.string().regex(
4955
+ var appStringSchema = z5.string().regex(
4838
4956
  /^[a-z]+(:(?:latest|dev))?$/,
4839
4957
  "App must be in format 'app' or 'app:tag' (e.g., 'github', 'github:dev')"
4840
4958
  ).refine(
@@ -4844,74 +4962,80 @@ var appStringSchema = z4.string().regex(
4844
4962
  },
4845
4963
  `Unsupported app. Supported apps: ${SUPPORTED_APPS.join(", ")}`
4846
4964
  );
4847
- var agentDefinitionSchema = z4.object({
4848
- description: z4.string().optional(),
4965
+ var agentDefinitionSchema = z5.object({
4966
+ description: z5.string().optional(),
4849
4967
  /**
4850
4968
  * @deprecated Use `apps` field instead for pre-installed tools.
4851
4969
  * This field will be removed in a future version.
4852
4970
  */
4853
- image: z4.string().optional(),
4854
- provider: z4.string().min(1, "Provider is required"),
4971
+ image: z5.string().optional(),
4972
+ provider: z5.string().min(1, "Provider is required"),
4855
4973
  /**
4856
4974
  * Array of pre-installed apps/tools for the agent environment.
4857
4975
  * Format: "app" or "app:tag" (e.g., "github", "github:dev", "github:latest")
4858
4976
  * Default tag is "latest" if not specified.
4859
4977
  * Currently supported apps: "github" (includes GitHub CLI)
4860
4978
  */
4861
- apps: z4.array(appStringSchema).optional(),
4862
- volumes: z4.array(z4.string()).optional(),
4863
- working_dir: z4.string().optional(),
4979
+ apps: z5.array(appStringSchema).optional(),
4980
+ volumes: z5.array(z5.string()).optional(),
4981
+ working_dir: z5.string().optional(),
4864
4982
  // Optional when provider supports auto-config
4865
- environment: z4.record(z4.string(), z4.string()).optional(),
4983
+ environment: z5.record(z5.string(), z5.string()).optional(),
4866
4984
  /**
4867
4985
  * Enable network security mode for secrets.
4868
4986
  * When true, secrets are encrypted into proxy tokens and all traffic
4869
4987
  * is routed through mitmproxy -> VM0 Proxy for decryption.
4870
4988
  * Default: false (plaintext secrets in env vars)
4871
4989
  */
4872
- experimental_network_security: z4.boolean().optional().default(false),
4990
+ experimental_network_security: z5.boolean().optional().default(false),
4873
4991
  /**
4874
4992
  * Path to instructions file (e.g., AGENTS.md).
4875
4993
  * Auto-uploaded as volume and mounted at /home/user/.claude/CLAUDE.md
4876
4994
  */
4877
- instructions: z4.string().optional(),
4995
+ instructions: z5.string().optional(),
4878
4996
  /**
4879
4997
  * Array of GitHub tree URLs for agent skills.
4880
4998
  * Each skill is auto-downloaded and mounted at /home/user/.claude/skills/{skillName}/
4881
4999
  */
4882
- skills: z4.array(z4.string()).optional(),
5000
+ skills: z5.array(z5.string()).optional(),
4883
5001
  /**
4884
5002
  * Route this agent to a self-hosted runner instead of E2B.
4885
5003
  * When specified, runs will be queued for the specified runner group.
4886
5004
  */
4887
- experimental_runner: z4.object({
4888
- group: z4.string().regex(
5005
+ experimental_runner: z5.object({
5006
+ group: z5.string().regex(
4889
5007
  /^[a-z0-9-]+\/[a-z0-9-]+$/,
4890
5008
  "Runner group must be in scope/name format (e.g., acme/production)"
4891
5009
  )
4892
- }).optional()
5010
+ }).optional(),
5011
+ /**
5012
+ * Experimental firewall configuration for network egress control.
5013
+ * Requires experimental_runner to be configured.
5014
+ * When enabled, filters outbound traffic by domain/IP rules.
5015
+ */
5016
+ experimental_firewall: experimentalFirewallSchema.optional()
4893
5017
  });
4894
- var agentComposeContentSchema = z4.object({
4895
- version: z4.string().min(1, "Version is required"),
4896
- agents: z4.record(z4.string(), agentDefinitionSchema),
4897
- volumes: z4.record(z4.string(), volumeConfigSchema).optional()
5018
+ var agentComposeContentSchema = z5.object({
5019
+ version: z5.string().min(1, "Version is required"),
5020
+ agents: z5.record(z5.string(), agentDefinitionSchema),
5021
+ volumes: z5.record(z5.string(), volumeConfigSchema).optional()
4898
5022
  });
4899
- var composeResponseSchema = z4.object({
4900
- id: z4.string(),
4901
- name: z4.string(),
4902
- headVersionId: z4.string().nullable(),
5023
+ var composeResponseSchema = z5.object({
5024
+ id: z5.string(),
5025
+ name: z5.string(),
5026
+ headVersionId: z5.string().nullable(),
4903
5027
  content: agentComposeContentSchema.nullable(),
4904
- createdAt: z4.string(),
4905
- updatedAt: z4.string()
5028
+ createdAt: z5.string(),
5029
+ updatedAt: z5.string()
4906
5030
  });
4907
- var createComposeResponseSchema = z4.object({
4908
- composeId: z4.string(),
4909
- name: z4.string(),
4910
- versionId: z4.string(),
4911
- action: z4.enum(["created", "existing"]),
4912
- updatedAt: z4.string()
5031
+ var createComposeResponseSchema = z5.object({
5032
+ composeId: z5.string(),
5033
+ name: z5.string(),
5034
+ versionId: z5.string(),
5035
+ action: z5.enum(["created", "existing"]),
5036
+ updatedAt: z5.string()
4913
5037
  });
4914
- var composesMainContract = c.router({
5038
+ var composesMainContract = c2.router({
4915
5039
  /**
4916
5040
  * GET /api/agent/composes?name={name}&scope={scope}
4917
5041
  * Get agent compose by name with HEAD version content
@@ -4920,9 +5044,9 @@ var composesMainContract = c.router({
4920
5044
  getByName: {
4921
5045
  method: "GET",
4922
5046
  path: "/api/agent/composes",
4923
- query: z4.object({
4924
- name: z4.string().min(1, "Missing name query parameter"),
4925
- scope: z4.string().optional()
5047
+ query: z5.object({
5048
+ name: z5.string().min(1, "Missing name query parameter"),
5049
+ scope: z5.string().optional()
4926
5050
  }),
4927
5051
  responses: {
4928
5052
  200: composeResponseSchema,
@@ -4941,7 +5065,7 @@ var composesMainContract = c.router({
4941
5065
  create: {
4942
5066
  method: "POST",
4943
5067
  path: "/api/agent/composes",
4944
- body: z4.object({
5068
+ body: z5.object({
4945
5069
  content: agentComposeContentSchema
4946
5070
  }),
4947
5071
  responses: {
@@ -4953,7 +5077,7 @@ var composesMainContract = c.router({
4953
5077
  summary: "Create or update agent compose version"
4954
5078
  }
4955
5079
  });
4956
- var composesByIdContract = c.router({
5080
+ var composesByIdContract = c2.router({
4957
5081
  /**
4958
5082
  * GET /api/agent/composes/:id
4959
5083
  * Get agent compose by ID with HEAD version content
@@ -4961,8 +5085,8 @@ var composesByIdContract = c.router({
4961
5085
  getById: {
4962
5086
  method: "GET",
4963
5087
  path: "/api/agent/composes/:id",
4964
- pathParams: z4.object({
4965
- id: z4.string().min(1, "Compose ID is required")
5088
+ pathParams: z5.object({
5089
+ id: z5.string().min(1, "Compose ID is required")
4966
5090
  }),
4967
5091
  responses: {
4968
5092
  200: composeResponseSchema,
@@ -4972,7 +5096,7 @@ var composesByIdContract = c.router({
4972
5096
  summary: "Get agent compose by ID"
4973
5097
  }
4974
5098
  });
4975
- var composesVersionsContract = c.router({
5099
+ var composesVersionsContract = c2.router({
4976
5100
  /**
4977
5101
  * GET /api/agent/composes/versions?composeId={id}&version={hash|tag}
4978
5102
  * Resolve a version specifier to a full version ID
@@ -4980,14 +5104,14 @@ var composesVersionsContract = c.router({
4980
5104
  resolveVersion: {
4981
5105
  method: "GET",
4982
5106
  path: "/api/agent/composes/versions",
4983
- query: z4.object({
4984
- composeId: z4.string().min(1, "Missing composeId query parameter"),
5107
+ query: z5.object({
5108
+ composeId: z5.string().min(1, "Missing composeId query parameter"),
4985
5109
  version: composeVersionQuerySchema
4986
5110
  }),
4987
5111
  responses: {
4988
- 200: z4.object({
4989
- versionId: z4.string(),
4990
- tag: z4.string().optional()
5112
+ 200: z5.object({
5113
+ versionId: z5.string(),
5114
+ tag: z5.string().optional()
4991
5115
  }),
4992
5116
  400: apiErrorSchema,
4993
5117
  401: apiErrorSchema,
@@ -4996,85 +5120,112 @@ var composesVersionsContract = c.router({
4996
5120
  summary: "Resolve version specifier to full version ID"
4997
5121
  }
4998
5122
  });
5123
+ var composeListItemSchema = z5.object({
5124
+ name: z5.string(),
5125
+ headVersionId: z5.string().nullable(),
5126
+ updatedAt: z5.string()
5127
+ });
5128
+ var composesListContract = c2.router({
5129
+ /**
5130
+ * GET /api/agent/composes/list?scope={scope}
5131
+ * List all agent composes for a scope
5132
+ * If scope is not provided, uses the authenticated user's default scope
5133
+ */
5134
+ list: {
5135
+ method: "GET",
5136
+ path: "/api/agent/composes/list",
5137
+ query: z5.object({
5138
+ scope: z5.string().optional()
5139
+ }),
5140
+ responses: {
5141
+ 200: z5.object({
5142
+ composes: z5.array(composeListItemSchema)
5143
+ }),
5144
+ 400: apiErrorSchema,
5145
+ 401: apiErrorSchema
5146
+ },
5147
+ summary: "List all agent composes for a scope"
5148
+ }
5149
+ });
4999
5150
 
5000
5151
  // ../../packages/core/src/contracts/runs.ts
5001
- import { z as z5 } from "zod";
5002
- var c2 = initContract();
5003
- var runStatusSchema = z5.enum([
5152
+ import { z as z6 } from "zod";
5153
+ var c3 = initContract();
5154
+ var runStatusSchema = z6.enum([
5004
5155
  "pending",
5005
5156
  "running",
5006
5157
  "completed",
5007
5158
  "failed",
5008
5159
  "timeout"
5009
5160
  ]);
5010
- var unifiedRunRequestSchema = z5.object({
5161
+ var unifiedRunRequestSchema = z6.object({
5011
5162
  // High-level shortcuts (mutually exclusive with each other)
5012
- checkpointId: z5.string().optional(),
5013
- sessionId: z5.string().optional(),
5163
+ checkpointId: z6.string().optional(),
5164
+ sessionId: z6.string().optional(),
5014
5165
  // Base parameters (can be used directly or overridden after shortcut expansion)
5015
- agentComposeId: z5.string().optional(),
5016
- agentComposeVersionId: z5.string().optional(),
5017
- conversationId: z5.string().optional(),
5018
- artifactName: z5.string().optional(),
5019
- artifactVersion: z5.string().optional(),
5020
- vars: z5.record(z5.string(), z5.string()).optional(),
5021
- secrets: z5.record(z5.string(), z5.string()).optional(),
5022
- volumeVersions: z5.record(z5.string(), z5.string()).optional(),
5166
+ agentComposeId: z6.string().optional(),
5167
+ agentComposeVersionId: z6.string().optional(),
5168
+ conversationId: z6.string().optional(),
5169
+ artifactName: z6.string().optional(),
5170
+ artifactVersion: z6.string().optional(),
5171
+ vars: z6.record(z6.string(), z6.string()).optional(),
5172
+ secrets: z6.record(z6.string(), z6.string()).optional(),
5173
+ volumeVersions: z6.record(z6.string(), z6.string()).optional(),
5023
5174
  // Required
5024
- prompt: z5.string().min(1, "Missing prompt")
5175
+ prompt: z6.string().min(1, "Missing prompt")
5025
5176
  });
5026
- var createRunResponseSchema = z5.object({
5027
- runId: z5.string(),
5177
+ var createRunResponseSchema = z6.object({
5178
+ runId: z6.string(),
5028
5179
  status: runStatusSchema,
5029
- sandboxId: z5.string().optional(),
5030
- output: z5.string().optional(),
5031
- error: z5.string().optional(),
5032
- executionTimeMs: z5.number().optional(),
5033
- createdAt: z5.string()
5034
- });
5035
- var getRunResponseSchema = z5.object({
5036
- runId: z5.string(),
5037
- agentComposeVersionId: z5.string(),
5180
+ sandboxId: z6.string().optional(),
5181
+ output: z6.string().optional(),
5182
+ error: z6.string().optional(),
5183
+ executionTimeMs: z6.number().optional(),
5184
+ createdAt: z6.string()
5185
+ });
5186
+ var getRunResponseSchema = z6.object({
5187
+ runId: z6.string(),
5188
+ agentComposeVersionId: z6.string(),
5038
5189
  status: runStatusSchema,
5039
- prompt: z5.string(),
5040
- vars: z5.record(z5.string(), z5.string()).optional(),
5041
- sandboxId: z5.string().optional(),
5042
- result: z5.object({
5043
- output: z5.string(),
5044
- executionTimeMs: z5.number()
5190
+ prompt: z6.string(),
5191
+ vars: z6.record(z6.string(), z6.string()).optional(),
5192
+ sandboxId: z6.string().optional(),
5193
+ result: z6.object({
5194
+ output: z6.string(),
5195
+ executionTimeMs: z6.number()
5045
5196
  }).optional(),
5046
- error: z5.string().optional(),
5047
- createdAt: z5.string(),
5048
- startedAt: z5.string().optional(),
5049
- completedAt: z5.string().optional()
5050
- });
5051
- var runEventSchema = z5.object({
5052
- sequenceNumber: z5.number(),
5053
- eventType: z5.string(),
5054
- eventData: z5.unknown(),
5055
- createdAt: z5.string()
5056
- });
5057
- var runResultSchema = z5.object({
5058
- checkpointId: z5.string(),
5059
- agentSessionId: z5.string(),
5060
- conversationId: z5.string(),
5061
- artifact: z5.record(z5.string(), z5.string()).optional(),
5197
+ error: z6.string().optional(),
5198
+ createdAt: z6.string(),
5199
+ startedAt: z6.string().optional(),
5200
+ completedAt: z6.string().optional()
5201
+ });
5202
+ var runEventSchema = z6.object({
5203
+ sequenceNumber: z6.number(),
5204
+ eventType: z6.string(),
5205
+ eventData: z6.unknown(),
5206
+ createdAt: z6.string()
5207
+ });
5208
+ var runResultSchema = z6.object({
5209
+ checkpointId: z6.string(),
5210
+ agentSessionId: z6.string(),
5211
+ conversationId: z6.string(),
5212
+ artifact: z6.record(z6.string(), z6.string()).optional(),
5062
5213
  // optional when run has no artifact
5063
- volumes: z5.record(z5.string(), z5.string()).optional()
5214
+ volumes: z6.record(z6.string(), z6.string()).optional()
5064
5215
  });
5065
- var runStateSchema = z5.object({
5216
+ var runStateSchema = z6.object({
5066
5217
  status: runStatusSchema,
5067
5218
  result: runResultSchema.optional(),
5068
- error: z5.string().optional()
5219
+ error: z6.string().optional()
5069
5220
  });
5070
- var eventsResponseSchema = z5.object({
5071
- events: z5.array(runEventSchema),
5072
- hasMore: z5.boolean(),
5073
- nextSequence: z5.number(),
5221
+ var eventsResponseSchema = z6.object({
5222
+ events: z6.array(runEventSchema),
5223
+ hasMore: z6.boolean(),
5224
+ nextSequence: z6.number(),
5074
5225
  run: runStateSchema,
5075
- provider: z5.string()
5226
+ provider: z6.string()
5076
5227
  });
5077
- var runsMainContract = c2.router({
5228
+ var runsMainContract = c3.router({
5078
5229
  /**
5079
5230
  * POST /api/agent/runs
5080
5231
  * Create and execute a new agent run
@@ -5092,7 +5243,7 @@ var runsMainContract = c2.router({
5092
5243
  summary: "Create and execute agent run"
5093
5244
  }
5094
5245
  });
5095
- var runsByIdContract = c2.router({
5246
+ var runsByIdContract = c3.router({
5096
5247
  /**
5097
5248
  * GET /api/agent/runs/:id
5098
5249
  * Get agent run status and results
@@ -5100,8 +5251,8 @@ var runsByIdContract = c2.router({
5100
5251
  getById: {
5101
5252
  method: "GET",
5102
5253
  path: "/api/agent/runs/:id",
5103
- pathParams: z5.object({
5104
- id: z5.string().min(1, "Run ID is required")
5254
+ pathParams: z6.object({
5255
+ id: z6.string().min(1, "Run ID is required")
5105
5256
  }),
5106
5257
  responses: {
5107
5258
  200: getRunResponseSchema,
@@ -5112,7 +5263,7 @@ var runsByIdContract = c2.router({
5112
5263
  summary: "Get agent run by ID"
5113
5264
  }
5114
5265
  });
5115
- var runEventsContract = c2.router({
5266
+ var runEventsContract = c3.router({
5116
5267
  /**
5117
5268
  * GET /api/agent/runs/:id/events
5118
5269
  * Poll for agent run events with pagination
@@ -5120,12 +5271,12 @@ var runEventsContract = c2.router({
5120
5271
  getEvents: {
5121
5272
  method: "GET",
5122
5273
  path: "/api/agent/runs/:id/events",
5123
- pathParams: z5.object({
5124
- id: z5.string().min(1, "Run ID is required")
5274
+ pathParams: z6.object({
5275
+ id: z6.string().min(1, "Run ID is required")
5125
5276
  }),
5126
- query: z5.object({
5127
- since: z5.coerce.number().default(0),
5128
- limit: z5.coerce.number().default(100)
5277
+ query: z6.object({
5278
+ since: z6.coerce.number().default(0),
5279
+ limit: z6.coerce.number().default(100)
5129
5280
  }),
5130
5281
  responses: {
5131
5282
  200: eventsResponseSchema,
@@ -5135,45 +5286,45 @@ var runEventsContract = c2.router({
5135
5286
  summary: "Get agent run events"
5136
5287
  }
5137
5288
  });
5138
- var telemetryMetricSchema = z5.object({
5139
- ts: z5.string(),
5140
- cpu: z5.number(),
5141
- mem_used: z5.number(),
5142
- mem_total: z5.number(),
5143
- disk_used: z5.number(),
5144
- disk_total: z5.number()
5145
- });
5146
- var systemLogResponseSchema = z5.object({
5147
- systemLog: z5.string(),
5148
- hasMore: z5.boolean()
5149
- });
5150
- var metricsResponseSchema = z5.object({
5151
- metrics: z5.array(telemetryMetricSchema),
5152
- hasMore: z5.boolean()
5153
- });
5154
- var agentEventsResponseSchema = z5.object({
5155
- events: z5.array(runEventSchema),
5156
- hasMore: z5.boolean(),
5157
- provider: z5.string()
5158
- });
5159
- var networkLogEntrySchema = z5.object({
5160
- timestamp: z5.string(),
5161
- method: z5.string(),
5162
- url: z5.string(),
5163
- status: z5.number(),
5164
- latency_ms: z5.number(),
5165
- request_size: z5.number(),
5166
- response_size: z5.number()
5167
- });
5168
- var networkLogsResponseSchema = z5.object({
5169
- networkLogs: z5.array(networkLogEntrySchema),
5170
- hasMore: z5.boolean()
5171
- });
5172
- var telemetryResponseSchema = z5.object({
5173
- systemLog: z5.string(),
5174
- metrics: z5.array(telemetryMetricSchema)
5175
- });
5176
- var runTelemetryContract = c2.router({
5289
+ var telemetryMetricSchema = z6.object({
5290
+ ts: z6.string(),
5291
+ cpu: z6.number(),
5292
+ mem_used: z6.number(),
5293
+ mem_total: z6.number(),
5294
+ disk_used: z6.number(),
5295
+ disk_total: z6.number()
5296
+ });
5297
+ var systemLogResponseSchema = z6.object({
5298
+ systemLog: z6.string(),
5299
+ hasMore: z6.boolean()
5300
+ });
5301
+ var metricsResponseSchema = z6.object({
5302
+ metrics: z6.array(telemetryMetricSchema),
5303
+ hasMore: z6.boolean()
5304
+ });
5305
+ var agentEventsResponseSchema = z6.object({
5306
+ events: z6.array(runEventSchema),
5307
+ hasMore: z6.boolean(),
5308
+ provider: z6.string()
5309
+ });
5310
+ var networkLogEntrySchema = z6.object({
5311
+ timestamp: z6.string(),
5312
+ method: z6.string(),
5313
+ url: z6.string(),
5314
+ status: z6.number(),
5315
+ latency_ms: z6.number(),
5316
+ request_size: z6.number(),
5317
+ response_size: z6.number()
5318
+ });
5319
+ var networkLogsResponseSchema = z6.object({
5320
+ networkLogs: z6.array(networkLogEntrySchema),
5321
+ hasMore: z6.boolean()
5322
+ });
5323
+ var telemetryResponseSchema = z6.object({
5324
+ systemLog: z6.string(),
5325
+ metrics: z6.array(telemetryMetricSchema)
5326
+ });
5327
+ var runTelemetryContract = c3.router({
5177
5328
  /**
5178
5329
  * GET /api/agent/runs/:id/telemetry
5179
5330
  * Get aggregated telemetry data for a run (legacy combined format)
@@ -5181,8 +5332,8 @@ var runTelemetryContract = c2.router({
5181
5332
  getTelemetry: {
5182
5333
  method: "GET",
5183
5334
  path: "/api/agent/runs/:id/telemetry",
5184
- pathParams: z5.object({
5185
- id: z5.string().min(1, "Run ID is required")
5335
+ pathParams: z6.object({
5336
+ id: z6.string().min(1, "Run ID is required")
5186
5337
  }),
5187
5338
  responses: {
5188
5339
  200: telemetryResponseSchema,
@@ -5192,7 +5343,7 @@ var runTelemetryContract = c2.router({
5192
5343
  summary: "Get run telemetry data"
5193
5344
  }
5194
5345
  });
5195
- var runSystemLogContract = c2.router({
5346
+ var runSystemLogContract = c3.router({
5196
5347
  /**
5197
5348
  * GET /api/agent/runs/:id/telemetry/system-log
5198
5349
  * Get system log with pagination
@@ -5200,13 +5351,13 @@ var runSystemLogContract = c2.router({
5200
5351
  getSystemLog: {
5201
5352
  method: "GET",
5202
5353
  path: "/api/agent/runs/:id/telemetry/system-log",
5203
- pathParams: z5.object({
5204
- id: z5.string().min(1, "Run ID is required")
5354
+ pathParams: z6.object({
5355
+ id: z6.string().min(1, "Run ID is required")
5205
5356
  }),
5206
- query: z5.object({
5207
- since: z5.coerce.number().optional(),
5208
- limit: z5.coerce.number().min(1).max(100).default(5),
5209
- order: z5.enum(["asc", "desc"]).default("desc")
5357
+ query: z6.object({
5358
+ since: z6.coerce.number().optional(),
5359
+ limit: z6.coerce.number().min(1).max(100).default(5),
5360
+ order: z6.enum(["asc", "desc"]).default("desc")
5210
5361
  }),
5211
5362
  responses: {
5212
5363
  200: systemLogResponseSchema,
@@ -5216,7 +5367,7 @@ var runSystemLogContract = c2.router({
5216
5367
  summary: "Get system log with pagination"
5217
5368
  }
5218
5369
  });
5219
- var runMetricsContract = c2.router({
5370
+ var runMetricsContract = c3.router({
5220
5371
  /**
5221
5372
  * GET /api/agent/runs/:id/telemetry/metrics
5222
5373
  * Get metrics with pagination
@@ -5224,13 +5375,13 @@ var runMetricsContract = c2.router({
5224
5375
  getMetrics: {
5225
5376
  method: "GET",
5226
5377
  path: "/api/agent/runs/:id/telemetry/metrics",
5227
- pathParams: z5.object({
5228
- id: z5.string().min(1, "Run ID is required")
5378
+ pathParams: z6.object({
5379
+ id: z6.string().min(1, "Run ID is required")
5229
5380
  }),
5230
- query: z5.object({
5231
- since: z5.coerce.number().optional(),
5232
- limit: z5.coerce.number().min(1).max(100).default(5),
5233
- order: z5.enum(["asc", "desc"]).default("desc")
5381
+ query: z6.object({
5382
+ since: z6.coerce.number().optional(),
5383
+ limit: z6.coerce.number().min(1).max(100).default(5),
5384
+ order: z6.enum(["asc", "desc"]).default("desc")
5234
5385
  }),
5235
5386
  responses: {
5236
5387
  200: metricsResponseSchema,
@@ -5240,7 +5391,7 @@ var runMetricsContract = c2.router({
5240
5391
  summary: "Get metrics with pagination"
5241
5392
  }
5242
5393
  });
5243
- var runAgentEventsContract = c2.router({
5394
+ var runAgentEventsContract = c3.router({
5244
5395
  /**
5245
5396
  * GET /api/agent/runs/:id/telemetry/agent
5246
5397
  * Get agent events with pagination (for vm0 logs default)
@@ -5248,13 +5399,13 @@ var runAgentEventsContract = c2.router({
5248
5399
  getAgentEvents: {
5249
5400
  method: "GET",
5250
5401
  path: "/api/agent/runs/:id/telemetry/agent",
5251
- pathParams: z5.object({
5252
- id: z5.string().min(1, "Run ID is required")
5402
+ pathParams: z6.object({
5403
+ id: z6.string().min(1, "Run ID is required")
5253
5404
  }),
5254
- query: z5.object({
5255
- since: z5.coerce.number().optional(),
5256
- limit: z5.coerce.number().min(1).max(100).default(5),
5257
- order: z5.enum(["asc", "desc"]).default("desc")
5405
+ query: z6.object({
5406
+ since: z6.coerce.number().optional(),
5407
+ limit: z6.coerce.number().min(1).max(100).default(5),
5408
+ order: z6.enum(["asc", "desc"]).default("desc")
5258
5409
  }),
5259
5410
  responses: {
5260
5411
  200: agentEventsResponseSchema,
@@ -5264,7 +5415,7 @@ var runAgentEventsContract = c2.router({
5264
5415
  summary: "Get agent events with pagination"
5265
5416
  }
5266
5417
  });
5267
- var runNetworkLogsContract = c2.router({
5418
+ var runNetworkLogsContract = c3.router({
5268
5419
  /**
5269
5420
  * GET /api/agent/runs/:id/telemetry/network
5270
5421
  * Get network logs with pagination (for vm0 logs --network)
@@ -5272,13 +5423,13 @@ var runNetworkLogsContract = c2.router({
5272
5423
  getNetworkLogs: {
5273
5424
  method: "GET",
5274
5425
  path: "/api/agent/runs/:id/telemetry/network",
5275
- pathParams: z5.object({
5276
- id: z5.string().min(1, "Run ID is required")
5426
+ pathParams: z6.object({
5427
+ id: z6.string().min(1, "Run ID is required")
5277
5428
  }),
5278
- query: z5.object({
5279
- since: z5.coerce.number().optional(),
5280
- limit: z5.coerce.number().min(1).max(100).default(5),
5281
- order: z5.enum(["asc", "desc"]).default("desc")
5429
+ query: z6.object({
5430
+ since: z6.coerce.number().optional(),
5431
+ limit: z6.coerce.number().min(1).max(100).default(5),
5432
+ order: z6.enum(["asc", "desc"]).default("desc")
5282
5433
  }),
5283
5434
  responses: {
5284
5435
  200: networkLogsResponseSchema,
@@ -5290,22 +5441,22 @@ var runNetworkLogsContract = c2.router({
5290
5441
  });
5291
5442
 
5292
5443
  // ../../packages/core/src/contracts/storages.ts
5293
- import { z as z6 } from "zod";
5294
- var c3 = initContract();
5295
- var storageTypeSchema = z6.enum(["volume", "artifact"]);
5296
- var versionQuerySchema = z6.preprocess(
5444
+ import { z as z7 } from "zod";
5445
+ var c4 = initContract();
5446
+ var storageTypeSchema = z7.enum(["volume", "artifact"]);
5447
+ var versionQuerySchema = z7.preprocess(
5297
5448
  (val) => val === void 0 || val === null ? void 0 : String(val),
5298
- z6.string().regex(/^[a-f0-9]{8,64}$/i, "Version must be 8-64 hex characters").optional()
5449
+ z7.string().regex(/^[a-f0-9]{8,64}$/i, "Version must be 8-64 hex characters").optional()
5299
5450
  );
5300
- var uploadStorageResponseSchema = z6.object({
5301
- name: z6.string(),
5302
- versionId: z6.string(),
5303
- size: z6.number(),
5304
- fileCount: z6.number(),
5451
+ var uploadStorageResponseSchema = z7.object({
5452
+ name: z7.string(),
5453
+ versionId: z7.string(),
5454
+ size: z7.number(),
5455
+ fileCount: z7.number(),
5305
5456
  type: storageTypeSchema,
5306
- deduplicated: z6.boolean()
5457
+ deduplicated: z7.boolean()
5307
5458
  });
5308
- var storagesContract = c3.router({
5459
+ var storagesContract = c4.router({
5309
5460
  /**
5310
5461
  * POST /api/storages
5311
5462
  * Upload a storage (tar.gz file)
@@ -5321,7 +5472,7 @@ var storagesContract = c3.router({
5321
5472
  method: "POST",
5322
5473
  path: "/api/storages",
5323
5474
  contentType: "multipart/form-data",
5324
- body: c3.type(),
5475
+ body: c4.type(),
5325
5476
  responses: {
5326
5477
  200: uploadStorageResponseSchema,
5327
5478
  400: apiErrorSchema,
@@ -5343,15 +5494,15 @@ var storagesContract = c3.router({
5343
5494
  download: {
5344
5495
  method: "GET",
5345
5496
  path: "/api/storages",
5346
- query: z6.object({
5347
- name: z6.string().min(1, "Storage name is required"),
5497
+ query: z7.object({
5498
+ name: z7.string().min(1, "Storage name is required"),
5348
5499
  version: versionQuerySchema
5349
5500
  }),
5350
5501
  responses: {
5351
5502
  // Binary response - actual handling done at route level
5352
- 200: c3.otherResponse({
5503
+ 200: c4.otherResponse({
5353
5504
  contentType: "application/gzip",
5354
- body: c3.type()
5505
+ body: c4.type()
5355
5506
  }),
5356
5507
  400: apiErrorSchema,
5357
5508
  401: apiErrorSchema,
@@ -5361,40 +5512,40 @@ var storagesContract = c3.router({
5361
5512
  summary: "Download storage archive"
5362
5513
  }
5363
5514
  });
5364
- var fileEntryWithHashSchema = z6.object({
5365
- path: z6.string().min(1, "File path is required"),
5366
- hash: z6.string().length(64, "Hash must be SHA-256 (64 hex chars)"),
5367
- size: z6.number().int().min(0, "Size must be non-negative")
5515
+ var fileEntryWithHashSchema = z7.object({
5516
+ path: z7.string().min(1, "File path is required"),
5517
+ hash: z7.string().length(64, "Hash must be SHA-256 (64 hex chars)"),
5518
+ size: z7.number().int().min(0, "Size must be non-negative")
5368
5519
  });
5369
- var storageChangesSchema = z6.object({
5370
- added: z6.array(z6.string()),
5371
- modified: z6.array(z6.string()),
5372
- deleted: z6.array(z6.string())
5520
+ var storageChangesSchema = z7.object({
5521
+ added: z7.array(z7.string()),
5522
+ modified: z7.array(z7.string()),
5523
+ deleted: z7.array(z7.string())
5373
5524
  });
5374
- var presignedUploadSchema = z6.object({
5375
- key: z6.string(),
5376
- presignedUrl: z6.string().url()
5525
+ var presignedUploadSchema = z7.object({
5526
+ key: z7.string(),
5527
+ presignedUrl: z7.string().url()
5377
5528
  });
5378
- var storagesPrepareContract = c3.router({
5529
+ var storagesPrepareContract = c4.router({
5379
5530
  prepare: {
5380
5531
  method: "POST",
5381
5532
  path: "/api/storages/prepare",
5382
- body: z6.object({
5383
- storageName: z6.string().min(1, "Storage name is required"),
5533
+ body: z7.object({
5534
+ storageName: z7.string().min(1, "Storage name is required"),
5384
5535
  storageType: storageTypeSchema,
5385
- files: z6.array(fileEntryWithHashSchema),
5386
- force: z6.boolean().optional(),
5387
- runId: z6.string().optional(),
5536
+ files: z7.array(fileEntryWithHashSchema),
5537
+ force: z7.boolean().optional(),
5538
+ runId: z7.string().optional(),
5388
5539
  // For sandbox auth
5389
- baseVersion: z6.string().optional(),
5540
+ baseVersion: z7.string().optional(),
5390
5541
  // For incremental uploads
5391
5542
  changes: storageChangesSchema.optional()
5392
5543
  }),
5393
5544
  responses: {
5394
- 200: z6.object({
5395
- versionId: z6.string(),
5396
- existing: z6.boolean(),
5397
- uploads: z6.object({
5545
+ 200: z7.object({
5546
+ versionId: z7.string(),
5547
+ existing: z7.boolean(),
5548
+ uploads: z7.object({
5398
5549
  archive: presignedUploadSchema,
5399
5550
  manifest: presignedUploadSchema
5400
5551
  }).optional()
@@ -5407,26 +5558,26 @@ var storagesPrepareContract = c3.router({
5407
5558
  summary: "Prepare for direct S3 upload"
5408
5559
  }
5409
5560
  });
5410
- var storagesCommitContract = c3.router({
5561
+ var storagesCommitContract = c4.router({
5411
5562
  commit: {
5412
5563
  method: "POST",
5413
5564
  path: "/api/storages/commit",
5414
- body: z6.object({
5415
- storageName: z6.string().min(1, "Storage name is required"),
5565
+ body: z7.object({
5566
+ storageName: z7.string().min(1, "Storage name is required"),
5416
5567
  storageType: storageTypeSchema,
5417
- versionId: z6.string().min(1, "Version ID is required"),
5418
- files: z6.array(fileEntryWithHashSchema),
5419
- runId: z6.string().optional(),
5420
- message: z6.string().optional()
5568
+ versionId: z7.string().min(1, "Version ID is required"),
5569
+ files: z7.array(fileEntryWithHashSchema),
5570
+ runId: z7.string().optional(),
5571
+ message: z7.string().optional()
5421
5572
  }),
5422
5573
  responses: {
5423
- 200: z6.object({
5424
- success: z6.literal(true),
5425
- versionId: z6.string(),
5426
- storageName: z6.string(),
5427
- size: z6.number(),
5428
- fileCount: z6.number(),
5429
- deduplicated: z6.boolean().optional()
5574
+ 200: z7.object({
5575
+ success: z7.literal(true),
5576
+ versionId: z7.string(),
5577
+ storageName: z7.string(),
5578
+ size: z7.number(),
5579
+ fileCount: z7.number(),
5580
+ deduplicated: z7.boolean().optional()
5430
5581
  }),
5431
5582
  400: apiErrorSchema,
5432
5583
  401: apiErrorSchema,
@@ -5438,30 +5589,30 @@ var storagesCommitContract = c3.router({
5438
5589
  summary: "Commit uploaded storage"
5439
5590
  }
5440
5591
  });
5441
- var storagesDownloadContract = c3.router({
5592
+ var storagesDownloadContract = c4.router({
5442
5593
  download: {
5443
5594
  method: "GET",
5444
5595
  path: "/api/storages/download",
5445
- query: z6.object({
5446
- name: z6.string().min(1, "Storage name is required"),
5596
+ query: z7.object({
5597
+ name: z7.string().min(1, "Storage name is required"),
5447
5598
  type: storageTypeSchema,
5448
5599
  version: versionQuerySchema
5449
5600
  }),
5450
5601
  responses: {
5451
5602
  // Normal response with presigned URL
5452
- 200: z6.union([
5453
- z6.object({
5454
- url: z6.string().url(),
5455
- versionId: z6.string(),
5456
- fileCount: z6.number(),
5457
- size: z6.number()
5603
+ 200: z7.union([
5604
+ z7.object({
5605
+ url: z7.string().url(),
5606
+ versionId: z7.string(),
5607
+ fileCount: z7.number(),
5608
+ size: z7.number()
5458
5609
  }),
5459
5610
  // Empty artifact response
5460
- z6.object({
5461
- empty: z6.literal(true),
5462
- versionId: z6.string(),
5463
- fileCount: z6.literal(0),
5464
- size: z6.literal(0)
5611
+ z7.object({
5612
+ empty: z7.literal(true),
5613
+ versionId: z7.string(),
5614
+ fileCount: z7.literal(0),
5615
+ size: z7.literal(0)
5465
5616
  })
5466
5617
  ]),
5467
5618
  400: apiErrorSchema,
@@ -5472,20 +5623,20 @@ var storagesDownloadContract = c3.router({
5472
5623
  summary: "Get presigned download URL"
5473
5624
  }
5474
5625
  });
5475
- var storagesListContract = c3.router({
5626
+ var storagesListContract = c4.router({
5476
5627
  list: {
5477
5628
  method: "GET",
5478
5629
  path: "/api/storages/list",
5479
- query: z6.object({
5630
+ query: z7.object({
5480
5631
  type: storageTypeSchema
5481
5632
  }),
5482
5633
  responses: {
5483
- 200: z6.array(
5484
- z6.object({
5485
- name: z6.string(),
5486
- size: z6.number(),
5487
- fileCount: z6.number(),
5488
- updatedAt: z6.string()
5634
+ 200: z7.array(
5635
+ z7.object({
5636
+ name: z7.string(),
5637
+ size: z7.number(),
5638
+ fileCount: z7.number(),
5639
+ updatedAt: z7.string()
5489
5640
  })
5490
5641
  ),
5491
5642
  401: apiErrorSchema,
@@ -5496,20 +5647,20 @@ var storagesListContract = c3.router({
5496
5647
  });
5497
5648
 
5498
5649
  // ../../packages/core/src/contracts/webhooks.ts
5499
- import { z as z7 } from "zod";
5500
- var c4 = initContract();
5501
- var agentEventSchema = z7.object({
5502
- type: z7.string(),
5503
- sequenceNumber: z7.number().int().positive()
5650
+ import { z as z8 } from "zod";
5651
+ var c5 = initContract();
5652
+ var agentEventSchema = z8.object({
5653
+ type: z8.string(),
5654
+ sequenceNumber: z8.number().int().positive()
5504
5655
  }).passthrough();
5505
- var artifactSnapshotSchema = z7.object({
5506
- artifactName: z7.string(),
5507
- artifactVersion: z7.string()
5656
+ var artifactSnapshotSchema = z8.object({
5657
+ artifactName: z8.string(),
5658
+ artifactVersion: z8.string()
5508
5659
  });
5509
- var volumeVersionsSnapshotSchema = z7.object({
5510
- versions: z7.record(z7.string(), z7.string())
5660
+ var volumeVersionsSnapshotSchema = z8.object({
5661
+ versions: z8.record(z8.string(), z8.string())
5511
5662
  });
5512
- var webhookEventsContract = c4.router({
5663
+ var webhookEventsContract = c5.router({
5513
5664
  /**
5514
5665
  * POST /api/webhooks/agent/events
5515
5666
  * Receive agent events from E2B sandbox
@@ -5517,15 +5668,15 @@ var webhookEventsContract = c4.router({
5517
5668
  send: {
5518
5669
  method: "POST",
5519
5670
  path: "/api/webhooks/agent/events",
5520
- body: z7.object({
5521
- runId: z7.string().min(1, "runId is required"),
5522
- events: z7.array(agentEventSchema).min(1, "events array cannot be empty")
5671
+ body: z8.object({
5672
+ runId: z8.string().min(1, "runId is required"),
5673
+ events: z8.array(agentEventSchema).min(1, "events array cannot be empty")
5523
5674
  }),
5524
5675
  responses: {
5525
- 200: z7.object({
5526
- received: z7.number(),
5527
- firstSequence: z7.number(),
5528
- lastSequence: z7.number()
5676
+ 200: z8.object({
5677
+ received: z8.number(),
5678
+ firstSequence: z8.number(),
5679
+ lastSequence: z8.number()
5529
5680
  }),
5530
5681
  400: apiErrorSchema,
5531
5682
  401: apiErrorSchema,
@@ -5535,7 +5686,7 @@ var webhookEventsContract = c4.router({
5535
5686
  summary: "Receive agent events from sandbox"
5536
5687
  }
5537
5688
  });
5538
- var webhookCompleteContract = c4.router({
5689
+ var webhookCompleteContract = c5.router({
5539
5690
  /**
5540
5691
  * POST /api/webhooks/agent/complete
5541
5692
  * Handle agent run completion (success or failure)
@@ -5543,15 +5694,15 @@ var webhookCompleteContract = c4.router({
5543
5694
  complete: {
5544
5695
  method: "POST",
5545
5696
  path: "/api/webhooks/agent/complete",
5546
- body: z7.object({
5547
- runId: z7.string().min(1, "runId is required"),
5548
- exitCode: z7.number(),
5549
- error: z7.string().optional()
5697
+ body: z8.object({
5698
+ runId: z8.string().min(1, "runId is required"),
5699
+ exitCode: z8.number(),
5700
+ error: z8.string().optional()
5550
5701
  }),
5551
5702
  responses: {
5552
- 200: z7.object({
5553
- success: z7.boolean(),
5554
- status: z7.enum(["completed", "failed"])
5703
+ 200: z8.object({
5704
+ success: z8.boolean(),
5705
+ status: z8.enum(["completed", "failed"])
5555
5706
  }),
5556
5707
  400: apiErrorSchema,
5557
5708
  401: apiErrorSchema,
@@ -5561,7 +5712,7 @@ var webhookCompleteContract = c4.router({
5561
5712
  summary: "Handle agent run completion"
5562
5713
  }
5563
5714
  });
5564
- var webhookCheckpointsContract = c4.router({
5715
+ var webhookCheckpointsContract = c5.router({
5565
5716
  /**
5566
5717
  * POST /api/webhooks/agent/checkpoints
5567
5718
  * Create checkpoint for completed agent run
@@ -5569,21 +5720,21 @@ var webhookCheckpointsContract = c4.router({
5569
5720
  create: {
5570
5721
  method: "POST",
5571
5722
  path: "/api/webhooks/agent/checkpoints",
5572
- body: z7.object({
5573
- runId: z7.string().min(1, "runId is required"),
5574
- cliAgentType: z7.string().min(1, "cliAgentType is required"),
5575
- cliAgentSessionId: z7.string().min(1, "cliAgentSessionId is required"),
5576
- cliAgentSessionHistory: z7.string().min(1, "cliAgentSessionHistory is required"),
5723
+ body: z8.object({
5724
+ runId: z8.string().min(1, "runId is required"),
5725
+ cliAgentType: z8.string().min(1, "cliAgentType is required"),
5726
+ cliAgentSessionId: z8.string().min(1, "cliAgentSessionId is required"),
5727
+ cliAgentSessionHistory: z8.string().min(1, "cliAgentSessionHistory is required"),
5577
5728
  artifactSnapshot: artifactSnapshotSchema.optional(),
5578
5729
  volumeVersionsSnapshot: volumeVersionsSnapshotSchema.optional()
5579
5730
  }),
5580
5731
  responses: {
5581
- 200: z7.object({
5582
- checkpointId: z7.string(),
5583
- agentSessionId: z7.string(),
5584
- conversationId: z7.string(),
5732
+ 200: z8.object({
5733
+ checkpointId: z8.string(),
5734
+ agentSessionId: z8.string(),
5735
+ conversationId: z8.string(),
5585
5736
  artifact: artifactSnapshotSchema.optional(),
5586
- volumes: z7.record(z7.string(), z7.string()).optional()
5737
+ volumes: z8.record(z8.string(), z8.string()).optional()
5587
5738
  }),
5588
5739
  400: apiErrorSchema,
5589
5740
  401: apiErrorSchema,
@@ -5593,7 +5744,7 @@ var webhookCheckpointsContract = c4.router({
5593
5744
  summary: "Create checkpoint for agent run"
5594
5745
  }
5595
5746
  });
5596
- var webhookHeartbeatContract = c4.router({
5747
+ var webhookHeartbeatContract = c5.router({
5597
5748
  /**
5598
5749
  * POST /api/webhooks/agent/heartbeat
5599
5750
  * Receive heartbeat signals from E2B sandbox
@@ -5601,12 +5752,12 @@ var webhookHeartbeatContract = c4.router({
5601
5752
  send: {
5602
5753
  method: "POST",
5603
5754
  path: "/api/webhooks/agent/heartbeat",
5604
- body: z7.object({
5605
- runId: z7.string().min(1, "runId is required")
5755
+ body: z8.object({
5756
+ runId: z8.string().min(1, "runId is required")
5606
5757
  }),
5607
5758
  responses: {
5608
- 200: z7.object({
5609
- ok: z7.boolean()
5759
+ 200: z8.object({
5760
+ ok: z8.boolean()
5610
5761
  }),
5611
5762
  400: apiErrorSchema,
5612
5763
  401: apiErrorSchema,
@@ -5616,7 +5767,7 @@ var webhookHeartbeatContract = c4.router({
5616
5767
  summary: "Receive heartbeat from sandbox"
5617
5768
  }
5618
5769
  });
5619
- var webhookStoragesContract = c4.router({
5770
+ var webhookStoragesContract = c5.router({
5620
5771
  /**
5621
5772
  * POST /api/webhooks/agent/storages
5622
5773
  * Create a new version of a storage from sandbox
@@ -5631,13 +5782,13 @@ var webhookStoragesContract = c4.router({
5631
5782
  method: "POST",
5632
5783
  path: "/api/webhooks/agent/storages",
5633
5784
  contentType: "multipart/form-data",
5634
- body: c4.type(),
5785
+ body: c5.type(),
5635
5786
  responses: {
5636
- 200: z7.object({
5637
- versionId: z7.string(),
5638
- storageName: z7.string(),
5639
- size: z7.number(),
5640
- fileCount: z7.number()
5787
+ 200: z8.object({
5788
+ versionId: z8.string(),
5789
+ storageName: z8.string(),
5790
+ size: z8.number(),
5791
+ fileCount: z8.number()
5641
5792
  }),
5642
5793
  400: apiErrorSchema,
5643
5794
  401: apiErrorSchema,
@@ -5647,7 +5798,7 @@ var webhookStoragesContract = c4.router({
5647
5798
  summary: "Upload storage version from sandbox"
5648
5799
  }
5649
5800
  });
5650
- var webhookStoragesIncrementalContract = c4.router({
5801
+ var webhookStoragesIncrementalContract = c5.router({
5651
5802
  /**
5652
5803
  * POST /api/webhooks/agent/storages/incremental
5653
5804
  * Create a new version using incremental upload
@@ -5664,19 +5815,19 @@ var webhookStoragesIncrementalContract = c4.router({
5664
5815
  method: "POST",
5665
5816
  path: "/api/webhooks/agent/storages/incremental",
5666
5817
  contentType: "multipart/form-data",
5667
- body: c4.type(),
5818
+ body: c5.type(),
5668
5819
  responses: {
5669
- 200: z7.object({
5670
- versionId: z7.string(),
5671
- storageName: z7.string(),
5672
- size: z7.number(),
5673
- fileCount: z7.number(),
5674
- incrementalStats: z7.object({
5675
- addedFiles: z7.number(),
5676
- modifiedFiles: z7.number(),
5677
- deletedFiles: z7.number(),
5678
- unchangedFiles: z7.number(),
5679
- bytesUploaded: z7.number()
5820
+ 200: z8.object({
5821
+ versionId: z8.string(),
5822
+ storageName: z8.string(),
5823
+ size: z8.number(),
5824
+ fileCount: z8.number(),
5825
+ incrementalStats: z8.object({
5826
+ addedFiles: z8.number(),
5827
+ modifiedFiles: z8.number(),
5828
+ deletedFiles: z8.number(),
5829
+ unchangedFiles: z8.number(),
5830
+ bytesUploaded: z8.number()
5680
5831
  }).optional()
5681
5832
  }),
5682
5833
  400: apiErrorSchema,
@@ -5687,24 +5838,24 @@ var webhookStoragesIncrementalContract = c4.router({
5687
5838
  summary: "Upload storage version incrementally from sandbox"
5688
5839
  }
5689
5840
  });
5690
- var metricDataSchema = z7.object({
5691
- ts: z7.string(),
5692
- cpu: z7.number(),
5693
- mem_used: z7.number(),
5694
- mem_total: z7.number(),
5695
- disk_used: z7.number(),
5696
- disk_total: z7.number()
5697
- });
5698
- var networkLogSchema = z7.object({
5699
- timestamp: z7.string(),
5700
- method: z7.string(),
5701
- url: z7.string(),
5702
- status: z7.number(),
5703
- latency_ms: z7.number(),
5704
- request_size: z7.number(),
5705
- response_size: z7.number()
5706
- });
5707
- var webhookTelemetryContract = c4.router({
5841
+ var metricDataSchema = z8.object({
5842
+ ts: z8.string(),
5843
+ cpu: z8.number(),
5844
+ mem_used: z8.number(),
5845
+ mem_total: z8.number(),
5846
+ disk_used: z8.number(),
5847
+ disk_total: z8.number()
5848
+ });
5849
+ var networkLogSchema = z8.object({
5850
+ timestamp: z8.string(),
5851
+ method: z8.string(),
5852
+ url: z8.string(),
5853
+ status: z8.number(),
5854
+ latency_ms: z8.number(),
5855
+ request_size: z8.number(),
5856
+ response_size: z8.number()
5857
+ });
5858
+ var webhookTelemetryContract = c5.router({
5708
5859
  /**
5709
5860
  * POST /api/webhooks/agent/telemetry
5710
5861
  * Receive telemetry data (system log, metrics, and network logs) from sandbox
@@ -5712,16 +5863,16 @@ var webhookTelemetryContract = c4.router({
5712
5863
  send: {
5713
5864
  method: "POST",
5714
5865
  path: "/api/webhooks/agent/telemetry",
5715
- body: z7.object({
5716
- runId: z7.string().min(1, "runId is required"),
5717
- systemLog: z7.string().optional(),
5718
- metrics: z7.array(metricDataSchema).optional(),
5719
- networkLogs: z7.array(networkLogSchema).optional()
5866
+ body: z8.object({
5867
+ runId: z8.string().min(1, "runId is required"),
5868
+ systemLog: z8.string().optional(),
5869
+ metrics: z8.array(metricDataSchema).optional(),
5870
+ networkLogs: z8.array(networkLogSchema).optional()
5720
5871
  }),
5721
5872
  responses: {
5722
- 200: z7.object({
5723
- success: z7.boolean(),
5724
- id: z7.string()
5873
+ 200: z8.object({
5874
+ success: z8.boolean(),
5875
+ id: z8.string()
5725
5876
  }),
5726
5877
  400: apiErrorSchema,
5727
5878
  401: apiErrorSchema,
@@ -5731,25 +5882,25 @@ var webhookTelemetryContract = c4.router({
5731
5882
  summary: "Receive telemetry data from sandbox"
5732
5883
  }
5733
5884
  });
5734
- var webhookStoragesPrepareContract = c4.router({
5885
+ var webhookStoragesPrepareContract = c5.router({
5735
5886
  prepare: {
5736
5887
  method: "POST",
5737
5888
  path: "/api/webhooks/agent/storages/prepare",
5738
- body: z7.object({
5739
- runId: z7.string().min(1, "runId is required"),
5889
+ body: z8.object({
5890
+ runId: z8.string().min(1, "runId is required"),
5740
5891
  // Required for webhook auth
5741
- storageName: z7.string().min(1, "Storage name is required"),
5892
+ storageName: z8.string().min(1, "Storage name is required"),
5742
5893
  storageType: storageTypeSchema,
5743
- files: z7.array(fileEntryWithHashSchema),
5744
- force: z7.boolean().optional(),
5745
- baseVersion: z7.string().optional(),
5894
+ files: z8.array(fileEntryWithHashSchema),
5895
+ force: z8.boolean().optional(),
5896
+ baseVersion: z8.string().optional(),
5746
5897
  changes: storageChangesSchema.optional()
5747
5898
  }),
5748
5899
  responses: {
5749
- 200: z7.object({
5750
- versionId: z7.string(),
5751
- existing: z7.boolean(),
5752
- uploads: z7.object({
5900
+ 200: z8.object({
5901
+ versionId: z8.string(),
5902
+ existing: z8.boolean(),
5903
+ uploads: z8.object({
5753
5904
  archive: presignedUploadSchema,
5754
5905
  manifest: presignedUploadSchema
5755
5906
  }).optional()
@@ -5762,27 +5913,27 @@ var webhookStoragesPrepareContract = c4.router({
5762
5913
  summary: "Prepare for direct S3 upload from sandbox"
5763
5914
  }
5764
5915
  });
5765
- var webhookStoragesCommitContract = c4.router({
5916
+ var webhookStoragesCommitContract = c5.router({
5766
5917
  commit: {
5767
5918
  method: "POST",
5768
5919
  path: "/api/webhooks/agent/storages/commit",
5769
- body: z7.object({
5770
- runId: z7.string().min(1, "runId is required"),
5920
+ body: z8.object({
5921
+ runId: z8.string().min(1, "runId is required"),
5771
5922
  // Required for webhook auth
5772
- storageName: z7.string().min(1, "Storage name is required"),
5923
+ storageName: z8.string().min(1, "Storage name is required"),
5773
5924
  storageType: storageTypeSchema,
5774
- versionId: z7.string().min(1, "Version ID is required"),
5775
- files: z7.array(fileEntryWithHashSchema),
5776
- message: z7.string().optional()
5925
+ versionId: z8.string().min(1, "Version ID is required"),
5926
+ files: z8.array(fileEntryWithHashSchema),
5927
+ message: z8.string().optional()
5777
5928
  }),
5778
5929
  responses: {
5779
- 200: z7.object({
5780
- success: z7.literal(true),
5781
- versionId: z7.string(),
5782
- storageName: z7.string(),
5783
- size: z7.number(),
5784
- fileCount: z7.number(),
5785
- deduplicated: z7.boolean().optional()
5930
+ 200: z8.object({
5931
+ success: z8.literal(true),
5932
+ versionId: z8.string(),
5933
+ storageName: z8.string(),
5934
+ size: z8.number(),
5935
+ fileCount: z8.number(),
5936
+ deduplicated: z8.boolean().optional()
5786
5937
  }),
5787
5938
  400: apiErrorSchema,
5788
5939
  401: apiErrorSchema,
@@ -5796,13 +5947,13 @@ var webhookStoragesCommitContract = c4.router({
5796
5947
  });
5797
5948
 
5798
5949
  // ../../packages/core/src/contracts/cli-auth.ts
5799
- import { z as z8 } from "zod";
5800
- var c5 = initContract();
5801
- var oauthErrorSchema = z8.object({
5802
- error: z8.string(),
5803
- error_description: z8.string()
5950
+ import { z as z9 } from "zod";
5951
+ var c6 = initContract();
5952
+ var oauthErrorSchema = z9.object({
5953
+ error: z9.string(),
5954
+ error_description: z9.string()
5804
5955
  });
5805
- var cliAuthDeviceContract = c5.router({
5956
+ var cliAuthDeviceContract = c6.router({
5806
5957
  /**
5807
5958
  * POST /api/cli/auth/device
5808
5959
  * Initiate device authorization flow
@@ -5810,21 +5961,21 @@ var cliAuthDeviceContract = c5.router({
5810
5961
  create: {
5811
5962
  method: "POST",
5812
5963
  path: "/api/cli/auth/device",
5813
- body: z8.object({}).optional(),
5964
+ body: z9.object({}).optional(),
5814
5965
  responses: {
5815
- 200: z8.object({
5816
- device_code: z8.string(),
5817
- user_code: z8.string(),
5818
- verification_url: z8.string(),
5819
- expires_in: z8.number(),
5820
- interval: z8.number()
5966
+ 200: z9.object({
5967
+ device_code: z9.string(),
5968
+ user_code: z9.string(),
5969
+ verification_url: z9.string(),
5970
+ expires_in: z9.number(),
5971
+ interval: z9.number()
5821
5972
  }),
5822
5973
  500: oauthErrorSchema
5823
5974
  },
5824
5975
  summary: "Initiate device authorization flow"
5825
5976
  }
5826
5977
  });
5827
- var cliAuthTokenContract = c5.router({
5978
+ var cliAuthTokenContract = c6.router({
5828
5979
  /**
5829
5980
  * POST /api/cli/auth/token
5830
5981
  * Exchange device code for access token
@@ -5832,16 +5983,16 @@ var cliAuthTokenContract = c5.router({
5832
5983
  exchange: {
5833
5984
  method: "POST",
5834
5985
  path: "/api/cli/auth/token",
5835
- body: z8.object({
5836
- device_code: z8.string().min(1, "device_code is required")
5986
+ body: z9.object({
5987
+ device_code: z9.string().min(1, "device_code is required")
5837
5988
  }),
5838
5989
  responses: {
5839
5990
  // Success - token issued
5840
- 200: z8.object({
5841
- access_token: z8.string(),
5842
- refresh_token: z8.string(),
5843
- token_type: z8.literal("Bearer"),
5844
- expires_in: z8.number()
5991
+ 200: z9.object({
5992
+ access_token: z9.string(),
5993
+ refresh_token: z9.string(),
5994
+ token_type: z9.literal("Bearer"),
5995
+ expires_in: z9.number()
5845
5996
  }),
5846
5997
  // Authorization pending
5847
5998
  202: oauthErrorSchema,
@@ -5854,9 +6005,9 @@ var cliAuthTokenContract = c5.router({
5854
6005
  });
5855
6006
 
5856
6007
  // ../../packages/core/src/contracts/auth.ts
5857
- import { z as z9 } from "zod";
5858
- var c6 = initContract();
5859
- var authContract = c6.router({
6008
+ import { z as z10 } from "zod";
6009
+ var c7 = initContract();
6010
+ var authContract = c7.router({
5860
6011
  /**
5861
6012
  * GET /api/auth/me
5862
6013
  * Get current user information
@@ -5865,9 +6016,9 @@ var authContract = c6.router({
5865
6016
  method: "GET",
5866
6017
  path: "/api/auth/me",
5867
6018
  responses: {
5868
- 200: z9.object({
5869
- userId: z9.string(),
5870
- email: z9.string()
6019
+ 200: z10.object({
6020
+ userId: z10.string(),
6021
+ email: z10.string()
5871
6022
  }),
5872
6023
  401: apiErrorSchema,
5873
6024
  404: apiErrorSchema,
@@ -5878,20 +6029,20 @@ var authContract = c6.router({
5878
6029
  });
5879
6030
 
5880
6031
  // ../../packages/core/src/contracts/cron.ts
5881
- import { z as z10 } from "zod";
5882
- var c7 = initContract();
5883
- var cleanupResultSchema = z10.object({
5884
- runId: z10.string(),
5885
- sandboxId: z10.string().nullable(),
5886
- status: z10.enum(["cleaned", "error"]),
5887
- error: z10.string().optional()
5888
- });
5889
- var cleanupResponseSchema = z10.object({
5890
- cleaned: z10.number(),
5891
- errors: z10.number(),
5892
- results: z10.array(cleanupResultSchema)
5893
- });
5894
- var cronCleanupSandboxesContract = c7.router({
6032
+ import { z as z11 } from "zod";
6033
+ var c8 = initContract();
6034
+ var cleanupResultSchema = z11.object({
6035
+ runId: z11.string(),
6036
+ sandboxId: z11.string().nullable(),
6037
+ status: z11.enum(["cleaned", "error"]),
6038
+ error: z11.string().optional()
6039
+ });
6040
+ var cleanupResponseSchema = z11.object({
6041
+ cleaned: z11.number(),
6042
+ errors: z11.number(),
6043
+ results: z11.array(cleanupResultSchema)
6044
+ });
6045
+ var cronCleanupSandboxesContract = c8.router({
5895
6046
  /**
5896
6047
  * GET /api/cron/cleanup-sandboxes
5897
6048
  * Cron job to cleanup sandboxes that have stopped sending heartbeats
@@ -5900,286 +6051,1100 @@ var cronCleanupSandboxesContract = c7.router({
5900
6051
  method: "GET",
5901
6052
  path: "/api/cron/cleanup-sandboxes",
5902
6053
  responses: {
5903
- 200: cleanupResponseSchema,
5904
- 401: apiErrorSchema,
5905
- 500: apiErrorSchema
6054
+ 200: cleanupResponseSchema,
6055
+ 401: apiErrorSchema,
6056
+ 500: apiErrorSchema
6057
+ },
6058
+ summary: "Cleanup expired sandboxes"
6059
+ }
6060
+ });
6061
+
6062
+ // ../../packages/core/src/contracts/proxy.ts
6063
+ import { z as z12 } from "zod";
6064
+ var proxyErrorSchema = z12.object({
6065
+ error: z12.object({
6066
+ message: z12.string(),
6067
+ code: z12.enum([
6068
+ "UNAUTHORIZED",
6069
+ "BAD_REQUEST",
6070
+ "BAD_GATEWAY",
6071
+ "INTERNAL_ERROR"
6072
+ ]),
6073
+ targetUrl: z12.string().optional()
6074
+ })
6075
+ });
6076
+
6077
+ // ../../packages/core/src/contracts/scopes.ts
6078
+ import { z as z13 } from "zod";
6079
+ var c9 = initContract();
6080
+ var scopeTypeSchema = z13.enum(["personal", "organization", "system"]);
6081
+ var scopeSlugSchema = z13.string().min(3, "Scope slug must be at least 3 characters").max(64, "Scope slug must be at most 64 characters").regex(
6082
+ /^[a-z0-9][a-z0-9-]*[a-z0-9]$|^[a-z0-9]{1,2}$/,
6083
+ "Scope slug must contain only lowercase letters, numbers, and hyphens, and must start and end with an alphanumeric character"
6084
+ ).refine(
6085
+ (slug) => !slug.startsWith("vm0"),
6086
+ "Scope slug cannot start with 'vm0' (reserved)"
6087
+ ).transform((s) => s.toLowerCase());
6088
+ var scopeResponseSchema = z13.object({
6089
+ id: z13.string().uuid(),
6090
+ slug: z13.string(),
6091
+ type: scopeTypeSchema,
6092
+ displayName: z13.string().nullable(),
6093
+ createdAt: z13.string(),
6094
+ updatedAt: z13.string()
6095
+ });
6096
+ var createScopeRequestSchema = z13.object({
6097
+ slug: scopeSlugSchema,
6098
+ displayName: z13.string().max(128).optional()
6099
+ });
6100
+ var updateScopeRequestSchema = z13.object({
6101
+ slug: scopeSlugSchema,
6102
+ force: z13.boolean().optional().default(false)
6103
+ });
6104
+ var scopeContract = c9.router({
6105
+ /**
6106
+ * GET /api/scope
6107
+ * Get current user's scope
6108
+ */
6109
+ get: {
6110
+ method: "GET",
6111
+ path: "/api/scope",
6112
+ responses: {
6113
+ 200: scopeResponseSchema,
6114
+ 401: apiErrorSchema,
6115
+ 404: apiErrorSchema,
6116
+ 500: apiErrorSchema
6117
+ },
6118
+ summary: "Get current user's scope"
6119
+ },
6120
+ /**
6121
+ * POST /api/scope
6122
+ * Create user's scope
6123
+ */
6124
+ create: {
6125
+ method: "POST",
6126
+ path: "/api/scope",
6127
+ body: createScopeRequestSchema,
6128
+ responses: {
6129
+ 201: scopeResponseSchema,
6130
+ 400: apiErrorSchema,
6131
+ 401: apiErrorSchema,
6132
+ 409: apiErrorSchema,
6133
+ 500: apiErrorSchema
6134
+ },
6135
+ summary: "Create user's scope"
6136
+ },
6137
+ /**
6138
+ * PUT /api/scope
6139
+ * Update user's scope slug
6140
+ */
6141
+ update: {
6142
+ method: "PUT",
6143
+ path: "/api/scope",
6144
+ body: updateScopeRequestSchema,
6145
+ responses: {
6146
+ 200: scopeResponseSchema,
6147
+ 400: apiErrorSchema,
6148
+ 401: apiErrorSchema,
6149
+ 403: apiErrorSchema,
6150
+ 404: apiErrorSchema,
6151
+ 409: apiErrorSchema,
6152
+ 500: apiErrorSchema
6153
+ },
6154
+ summary: "Update user's scope slug"
6155
+ }
6156
+ });
6157
+
6158
+ // ../../packages/core/src/contracts/sessions.ts
6159
+ import { z as z14 } from "zod";
6160
+ var c10 = initContract();
6161
+ var sessionResponseSchema = z14.object({
6162
+ id: z14.string(),
6163
+ agentComposeId: z14.string(),
6164
+ agentComposeVersionId: z14.string().nullable(),
6165
+ conversationId: z14.string().nullable(),
6166
+ artifactName: z14.string().nullable(),
6167
+ vars: z14.record(z14.string(), z14.string()).nullable(),
6168
+ secretNames: z14.array(z14.string()).nullable(),
6169
+ volumeVersions: z14.record(z14.string(), z14.string()).nullable(),
6170
+ createdAt: z14.string(),
6171
+ updatedAt: z14.string()
6172
+ });
6173
+ var agentComposeSnapshotSchema = z14.object({
6174
+ agentComposeVersionId: z14.string(),
6175
+ vars: z14.record(z14.string(), z14.string()).optional(),
6176
+ secretNames: z14.array(z14.string()).optional()
6177
+ });
6178
+ var artifactSnapshotSchema2 = z14.object({
6179
+ artifactName: z14.string(),
6180
+ artifactVersion: z14.string()
6181
+ });
6182
+ var volumeVersionsSnapshotSchema2 = z14.object({
6183
+ versions: z14.record(z14.string(), z14.string())
6184
+ });
6185
+ var checkpointResponseSchema = z14.object({
6186
+ id: z14.string(),
6187
+ runId: z14.string(),
6188
+ conversationId: z14.string(),
6189
+ agentComposeSnapshot: agentComposeSnapshotSchema,
6190
+ artifactSnapshot: artifactSnapshotSchema2.nullable(),
6191
+ volumeVersionsSnapshot: volumeVersionsSnapshotSchema2.nullable(),
6192
+ createdAt: z14.string()
6193
+ });
6194
+ var sessionsByIdContract = c10.router({
6195
+ /**
6196
+ * GET /api/agent/sessions/:id
6197
+ * Get session by ID
6198
+ */
6199
+ getById: {
6200
+ method: "GET",
6201
+ path: "/api/agent/sessions/:id",
6202
+ pathParams: z14.object({
6203
+ id: z14.string().min(1, "Session ID is required")
6204
+ }),
6205
+ responses: {
6206
+ 200: sessionResponseSchema,
6207
+ 401: apiErrorSchema,
6208
+ 403: apiErrorSchema,
6209
+ 404: apiErrorSchema
6210
+ },
6211
+ summary: "Get session by ID"
6212
+ }
6213
+ });
6214
+ var checkpointsByIdContract = c10.router({
6215
+ /**
6216
+ * GET /api/agent/checkpoints/:id
6217
+ * Get checkpoint by ID
6218
+ */
6219
+ getById: {
6220
+ method: "GET",
6221
+ path: "/api/agent/checkpoints/:id",
6222
+ pathParams: z14.object({
6223
+ id: z14.string().min(1, "Checkpoint ID is required")
6224
+ }),
6225
+ responses: {
6226
+ 200: checkpointResponseSchema,
6227
+ 401: apiErrorSchema,
6228
+ 403: apiErrorSchema,
6229
+ 404: apiErrorSchema
6230
+ },
6231
+ summary: "Get checkpoint by ID"
6232
+ }
6233
+ });
6234
+
6235
+ // ../../packages/core/src/contracts/public/common.ts
6236
+ import { z as z15 } from "zod";
6237
+ var publicApiErrorTypeSchema = z15.enum([
6238
+ "api_error",
6239
+ // Internal server error (5xx)
6240
+ "invalid_request_error",
6241
+ // Bad parameters (400)
6242
+ "authentication_error",
6243
+ // Auth failure (401)
6244
+ "not_found_error",
6245
+ // Resource missing (404)
6246
+ "conflict_error"
6247
+ // Resource conflict (409)
6248
+ ]);
6249
+ var publicApiErrorSchema = z15.object({
6250
+ error: z15.object({
6251
+ type: publicApiErrorTypeSchema,
6252
+ code: z15.string(),
6253
+ message: z15.string(),
6254
+ param: z15.string().optional(),
6255
+ doc_url: z15.string().url().optional()
6256
+ })
6257
+ });
6258
+ var paginationSchema = z15.object({
6259
+ has_more: z15.boolean(),
6260
+ next_cursor: z15.string().nullable()
6261
+ });
6262
+ function createPaginatedResponseSchema(dataSchema) {
6263
+ return z15.object({
6264
+ data: z15.array(dataSchema),
6265
+ pagination: paginationSchema
6266
+ });
6267
+ }
6268
+ var listQuerySchema = z15.object({
6269
+ cursor: z15.string().optional(),
6270
+ limit: z15.coerce.number().min(1).max(100).default(20)
6271
+ });
6272
+ var requestIdSchema = z15.string().uuid();
6273
+ var timestampSchema = z15.string().datetime();
6274
+
6275
+ // ../../packages/core/src/contracts/public/agents.ts
6276
+ import { z as z16 } from "zod";
6277
+ var c11 = initContract();
6278
+ var publicAgentSchema = z16.object({
6279
+ id: z16.string(),
6280
+ name: z16.string(),
6281
+ current_version_id: z16.string().nullable(),
6282
+ created_at: timestampSchema,
6283
+ updated_at: timestampSchema
6284
+ });
6285
+ var agentVersionSchema = z16.object({
6286
+ id: z16.string(),
6287
+ agent_id: z16.string(),
6288
+ version_number: z16.number(),
6289
+ config: z16.unknown(),
6290
+ // Agent YAML configuration
6291
+ created_at: timestampSchema
6292
+ });
6293
+ var publicAgentDetailSchema = publicAgentSchema.extend({
6294
+ config: z16.unknown().optional()
6295
+ });
6296
+ var paginatedAgentsSchema = createPaginatedResponseSchema(publicAgentSchema);
6297
+ var paginatedAgentVersionsSchema = createPaginatedResponseSchema(agentVersionSchema);
6298
+ var createAgentRequestSchema = z16.object({
6299
+ name: z16.string().min(1).max(100).regex(
6300
+ /^[a-z0-9][a-z0-9-]*[a-z0-9]$|^[a-z0-9]$/,
6301
+ "Name must be lowercase alphanumeric with hyphens, not starting or ending with hyphen"
6302
+ ),
6303
+ config: z16.unknown()
6304
+ // Agent YAML configuration
6305
+ });
6306
+ var updateAgentRequestSchema = z16.object({
6307
+ config: z16.unknown()
6308
+ // New agent configuration (creates new version)
6309
+ });
6310
+ var agentListQuerySchema = listQuerySchema.extend({
6311
+ name: z16.string().optional()
6312
+ });
6313
+ var publicAgentsListContract = c11.router({
6314
+ list: {
6315
+ method: "GET",
6316
+ path: "/v1/agents",
6317
+ query: agentListQuerySchema,
6318
+ responses: {
6319
+ 200: paginatedAgentsSchema,
6320
+ 401: publicApiErrorSchema,
6321
+ 500: publicApiErrorSchema
6322
+ },
6323
+ summary: "List agents",
6324
+ description: "List all agents in the current scope with pagination. Use the `name` query parameter to filter by agent name."
6325
+ },
6326
+ create: {
6327
+ method: "POST",
6328
+ path: "/v1/agents",
6329
+ body: createAgentRequestSchema,
6330
+ responses: {
6331
+ 201: publicAgentDetailSchema,
6332
+ 400: publicApiErrorSchema,
6333
+ 401: publicApiErrorSchema,
6334
+ 409: publicApiErrorSchema,
6335
+ 500: publicApiErrorSchema
6336
+ },
6337
+ summary: "Create agent",
6338
+ description: "Create a new agent with the given configuration"
6339
+ }
6340
+ });
6341
+ var publicAgentByIdContract = c11.router({
6342
+ get: {
6343
+ method: "GET",
6344
+ path: "/v1/agents/:id",
6345
+ pathParams: z16.object({
6346
+ id: z16.string().min(1, "Agent ID is required")
6347
+ }),
6348
+ responses: {
6349
+ 200: publicAgentDetailSchema,
6350
+ 401: publicApiErrorSchema,
6351
+ 404: publicApiErrorSchema,
6352
+ 500: publicApiErrorSchema
6353
+ },
6354
+ summary: "Get agent",
6355
+ description: "Get agent details by ID"
6356
+ },
6357
+ update: {
6358
+ method: "PUT",
6359
+ path: "/v1/agents/:id",
6360
+ pathParams: z16.object({
6361
+ id: z16.string().min(1, "Agent ID is required")
6362
+ }),
6363
+ body: updateAgentRequestSchema,
6364
+ responses: {
6365
+ 200: publicAgentDetailSchema,
6366
+ 400: publicApiErrorSchema,
6367
+ 401: publicApiErrorSchema,
6368
+ 404: publicApiErrorSchema,
6369
+ 500: publicApiErrorSchema
6370
+ },
6371
+ summary: "Update agent",
6372
+ description: "Update agent configuration. Creates a new version if config changes."
6373
+ },
6374
+ delete: {
6375
+ method: "DELETE",
6376
+ path: "/v1/agents/:id",
6377
+ pathParams: z16.object({
6378
+ id: z16.string().min(1, "Agent ID is required")
6379
+ }),
6380
+ body: z16.undefined(),
6381
+ responses: {
6382
+ 204: z16.undefined(),
6383
+ 401: publicApiErrorSchema,
6384
+ 404: publicApiErrorSchema,
6385
+ 500: publicApiErrorSchema
6386
+ },
6387
+ summary: "Delete agent",
6388
+ description: "Archive an agent (soft delete)"
6389
+ }
6390
+ });
6391
+ var publicAgentVersionsContract = c11.router({
6392
+ list: {
6393
+ method: "GET",
6394
+ path: "/v1/agents/:id/versions",
6395
+ pathParams: z16.object({
6396
+ id: z16.string().min(1, "Agent ID is required")
6397
+ }),
6398
+ query: listQuerySchema,
6399
+ responses: {
6400
+ 200: paginatedAgentVersionsSchema,
6401
+ 401: publicApiErrorSchema,
6402
+ 404: publicApiErrorSchema,
6403
+ 500: publicApiErrorSchema
6404
+ },
6405
+ summary: "List agent versions",
6406
+ description: "List all versions of an agent with pagination"
6407
+ }
6408
+ });
6409
+
6410
+ // ../../packages/core/src/contracts/public/runs.ts
6411
+ import { z as z17 } from "zod";
6412
+ var c12 = initContract();
6413
+ var publicRunStatusSchema = z17.enum([
6414
+ "pending",
6415
+ "running",
6416
+ "completed",
6417
+ "failed",
6418
+ "timeout",
6419
+ "cancelled"
6420
+ ]);
6421
+ var publicRunSchema = z17.object({
6422
+ id: z17.string(),
6423
+ agent_id: z17.string(),
6424
+ agent_name: z17.string(),
6425
+ status: publicRunStatusSchema,
6426
+ prompt: z17.string(),
6427
+ created_at: timestampSchema,
6428
+ started_at: timestampSchema.nullable(),
6429
+ completed_at: timestampSchema.nullable()
6430
+ });
6431
+ var publicRunDetailSchema = publicRunSchema.extend({
6432
+ output: z17.string().nullable(),
6433
+ error: z17.string().nullable(),
6434
+ execution_time_ms: z17.number().nullable(),
6435
+ checkpoint_id: z17.string().nullable(),
6436
+ session_id: z17.string().nullable(),
6437
+ artifacts: z17.record(z17.string(), z17.string()).optional(),
6438
+ volumes: z17.record(z17.string(), z17.string()).optional()
6439
+ });
6440
+ var paginatedRunsSchema = createPaginatedResponseSchema(publicRunSchema);
6441
+ var createRunRequestSchema = z17.object({
6442
+ // Agent identification (one of: agent, agent_id, session_id, checkpoint_id)
6443
+ agent: z17.string().optional(),
6444
+ // Agent name
6445
+ agent_id: z17.string().optional(),
6446
+ // Agent ID
6447
+ agent_version: z17.string().optional(),
6448
+ // Version specifier (e.g., "latest", "v1", specific ID)
6449
+ // Continue session
6450
+ session_id: z17.string().optional(),
6451
+ // Resume from checkpoint
6452
+ checkpoint_id: z17.string().optional(),
6453
+ // Required
6454
+ prompt: z17.string().min(1, "Prompt is required"),
6455
+ // Optional configuration
6456
+ variables: z17.record(z17.string(), z17.string()).optional(),
6457
+ secrets: z17.record(z17.string(), z17.string()).optional(),
6458
+ artifacts: z17.record(z17.string(), z17.string()).optional(),
6459
+ // artifact_name -> version
6460
+ volumes: z17.record(z17.string(), z17.string()).optional()
6461
+ // volume_name -> version
6462
+ });
6463
+ var runListQuerySchema = listQuerySchema.extend({
6464
+ agent_id: z17.string().optional(),
6465
+ status: publicRunStatusSchema.optional(),
6466
+ since: timestampSchema.optional()
6467
+ });
6468
+ var publicRunsListContract = c12.router({
6469
+ list: {
6470
+ method: "GET",
6471
+ path: "/v1/runs",
6472
+ query: runListQuerySchema,
6473
+ responses: {
6474
+ 200: paginatedRunsSchema,
6475
+ 401: publicApiErrorSchema,
6476
+ 500: publicApiErrorSchema
6477
+ },
6478
+ summary: "List runs",
6479
+ description: "List runs with optional filtering by agent, status, and time"
6480
+ },
6481
+ create: {
6482
+ method: "POST",
6483
+ path: "/v1/runs",
6484
+ body: createRunRequestSchema,
6485
+ responses: {
6486
+ 202: publicRunDetailSchema,
6487
+ // Async operation
6488
+ 400: publicApiErrorSchema,
6489
+ 401: publicApiErrorSchema,
6490
+ 404: publicApiErrorSchema,
6491
+ 500: publicApiErrorSchema
6492
+ },
6493
+ summary: "Create run",
6494
+ description: "Create and execute a new agent run. Returns 202 Accepted as runs execute asynchronously."
6495
+ }
6496
+ });
6497
+ var publicRunByIdContract = c12.router({
6498
+ get: {
6499
+ method: "GET",
6500
+ path: "/v1/runs/:id",
6501
+ pathParams: z17.object({
6502
+ id: z17.string().min(1, "Run ID is required")
6503
+ }),
6504
+ responses: {
6505
+ 200: publicRunDetailSchema,
6506
+ 401: publicApiErrorSchema,
6507
+ 404: publicApiErrorSchema,
6508
+ 500: publicApiErrorSchema
6509
+ },
6510
+ summary: "Get run",
6511
+ description: "Get run details by ID"
6512
+ }
6513
+ });
6514
+ var publicRunCancelContract = c12.router({
6515
+ cancel: {
6516
+ method: "POST",
6517
+ path: "/v1/runs/:id/cancel",
6518
+ pathParams: z17.object({
6519
+ id: z17.string().min(1, "Run ID is required")
6520
+ }),
6521
+ body: z17.undefined(),
6522
+ responses: {
6523
+ 200: publicRunDetailSchema,
6524
+ 400: publicApiErrorSchema,
6525
+ // Run not in cancellable state
6526
+ 401: publicApiErrorSchema,
6527
+ 404: publicApiErrorSchema,
6528
+ 500: publicApiErrorSchema
6529
+ },
6530
+ summary: "Cancel run",
6531
+ description: "Cancel a pending or running execution"
6532
+ }
6533
+ });
6534
+ var logEntrySchema = z17.object({
6535
+ timestamp: timestampSchema,
6536
+ type: z17.enum(["agent", "system", "network"]),
6537
+ level: z17.enum(["debug", "info", "warn", "error"]),
6538
+ message: z17.string(),
6539
+ metadata: z17.record(z17.string(), z17.unknown()).optional()
6540
+ });
6541
+ var paginatedLogsSchema = createPaginatedResponseSchema(logEntrySchema);
6542
+ var logsQuerySchema = listQuerySchema.extend({
6543
+ type: z17.enum(["agent", "system", "network", "all"]).default("all"),
6544
+ since: timestampSchema.optional(),
6545
+ until: timestampSchema.optional(),
6546
+ order: z17.enum(["asc", "desc"]).default("asc")
6547
+ });
6548
+ var publicRunLogsContract = c12.router({
6549
+ getLogs: {
6550
+ method: "GET",
6551
+ path: "/v1/runs/:id/logs",
6552
+ pathParams: z17.object({
6553
+ id: z17.string().min(1, "Run ID is required")
6554
+ }),
6555
+ query: logsQuerySchema,
6556
+ responses: {
6557
+ 200: paginatedLogsSchema,
6558
+ 401: publicApiErrorSchema,
6559
+ 404: publicApiErrorSchema,
6560
+ 500: publicApiErrorSchema
6561
+ },
6562
+ summary: "Get run logs",
6563
+ description: "Get unified logs for a run. Combines agent, system, and network logs."
6564
+ }
6565
+ });
6566
+ var metricPointSchema = z17.object({
6567
+ timestamp: timestampSchema,
6568
+ cpu_percent: z17.number(),
6569
+ memory_used_mb: z17.number(),
6570
+ memory_total_mb: z17.number(),
6571
+ disk_used_mb: z17.number(),
6572
+ disk_total_mb: z17.number()
6573
+ });
6574
+ var metricsSummarySchema = z17.object({
6575
+ avg_cpu_percent: z17.number(),
6576
+ max_memory_used_mb: z17.number(),
6577
+ total_duration_ms: z17.number().nullable()
6578
+ });
6579
+ var metricsResponseSchema2 = z17.object({
6580
+ data: z17.array(metricPointSchema),
6581
+ summary: metricsSummarySchema
6582
+ });
6583
+ var publicRunMetricsContract = c12.router({
6584
+ getMetrics: {
6585
+ method: "GET",
6586
+ path: "/v1/runs/:id/metrics",
6587
+ pathParams: z17.object({
6588
+ id: z17.string().min(1, "Run ID is required")
6589
+ }),
6590
+ responses: {
6591
+ 200: metricsResponseSchema2,
6592
+ 401: publicApiErrorSchema,
6593
+ 404: publicApiErrorSchema,
6594
+ 500: publicApiErrorSchema
6595
+ },
6596
+ summary: "Get run metrics",
6597
+ description: "Get CPU, memory, and disk metrics for a run"
6598
+ }
6599
+ });
6600
+ var sseEventTypeSchema = z17.enum([
6601
+ "status",
6602
+ // Run status change
6603
+ "output",
6604
+ // Agent output
6605
+ "error",
6606
+ // Error occurred
6607
+ "complete",
6608
+ // Run completed
6609
+ "heartbeat"
6610
+ // Keep-alive
6611
+ ]);
6612
+ var sseEventSchema = z17.object({
6613
+ event: sseEventTypeSchema,
6614
+ data: z17.unknown(),
6615
+ id: z17.string().optional()
6616
+ // For Last-Event-ID reconnection
6617
+ });
6618
+ var publicRunEventsContract = c12.router({
6619
+ streamEvents: {
6620
+ method: "GET",
6621
+ path: "/v1/runs/:id/events",
6622
+ pathParams: z17.object({
6623
+ id: z17.string().min(1, "Run ID is required")
6624
+ }),
6625
+ query: z17.object({
6626
+ last_event_id: z17.string().optional()
6627
+ // For reconnection
6628
+ }),
6629
+ responses: {
6630
+ 200: z17.any(),
6631
+ // SSE stream - actual content is text/event-stream
6632
+ 401: publicApiErrorSchema,
6633
+ 404: publicApiErrorSchema,
6634
+ 500: publicApiErrorSchema
6635
+ },
6636
+ summary: "Stream run events",
6637
+ description: "Stream real-time events for a run using Server-Sent Events (SSE). Set Accept: text/event-stream header."
6638
+ }
6639
+ });
6640
+
6641
+ // ../../packages/core/src/contracts/public/artifacts.ts
6642
+ import { z as z18 } from "zod";
6643
+ var c13 = initContract();
6644
+ var publicArtifactSchema = z18.object({
6645
+ id: z18.string(),
6646
+ name: z18.string(),
6647
+ current_version_id: z18.string().nullable(),
6648
+ size: z18.number(),
6649
+ // Total size in bytes
6650
+ file_count: z18.number(),
6651
+ created_at: timestampSchema,
6652
+ updated_at: timestampSchema
6653
+ });
6654
+ var artifactVersionSchema = z18.object({
6655
+ id: z18.string(),
6656
+ // SHA-256 content hash
6657
+ artifact_id: z18.string(),
6658
+ size: z18.number(),
6659
+ // Size in bytes
6660
+ file_count: z18.number(),
6661
+ message: z18.string().nullable(),
6662
+ // Optional commit message
6663
+ created_by: z18.string(),
6664
+ created_at: timestampSchema
6665
+ });
6666
+ var publicArtifactDetailSchema = publicArtifactSchema.extend({
6667
+ current_version: artifactVersionSchema.nullable()
6668
+ });
6669
+ var paginatedArtifactsSchema = createPaginatedResponseSchema(publicArtifactSchema);
6670
+ var paginatedArtifactVersionsSchema = createPaginatedResponseSchema(
6671
+ artifactVersionSchema
6672
+ );
6673
+ var createArtifactRequestSchema = z18.object({
6674
+ name: z18.string().min(1).max(100).regex(
6675
+ /^[a-z0-9][a-z0-9-]*[a-z0-9]$|^[a-z0-9]$/,
6676
+ "Name must be lowercase alphanumeric with hyphens, not starting or ending with hyphen"
6677
+ )
6678
+ });
6679
+ var fileEntrySchema = z18.object({
6680
+ path: z18.string(),
6681
+ size: z18.number(),
6682
+ hash: z18.string().optional()
6683
+ // SHA-256 hash of file content
6684
+ });
6685
+ var prepareUploadRequestSchema = z18.object({
6686
+ files: z18.array(fileEntrySchema),
6687
+ message: z18.string().optional()
6688
+ // Optional commit message
6689
+ });
6690
+ var presignedUploadSchema2 = z18.object({
6691
+ path: z18.string(),
6692
+ upload_url: z18.string(),
6693
+ // Presigned S3 URL
6694
+ upload_id: z18.string()
6695
+ // For multi-part uploads
6696
+ });
6697
+ var prepareUploadResponseSchema = z18.object({
6698
+ upload_session_id: z18.string(),
6699
+ files: z18.array(presignedUploadSchema2),
6700
+ expires_at: timestampSchema
6701
+ });
6702
+ var commitUploadRequestSchema = z18.object({
6703
+ upload_session_id: z18.string(),
6704
+ message: z18.string().optional()
6705
+ });
6706
+ var downloadResponseSchema = z18.object({
6707
+ version_id: z18.string(),
6708
+ files: z18.array(
6709
+ z18.object({
6710
+ path: z18.string(),
6711
+ size: z18.number(),
6712
+ download_url: z18.string()
6713
+ // Presigned S3 URL
6714
+ })
6715
+ ),
6716
+ expires_at: timestampSchema
6717
+ });
6718
+ var publicArtifactsListContract = c13.router({
6719
+ list: {
6720
+ method: "GET",
6721
+ path: "/v1/artifacts",
6722
+ query: listQuerySchema,
6723
+ responses: {
6724
+ 200: paginatedArtifactsSchema,
6725
+ 401: publicApiErrorSchema,
6726
+ 500: publicApiErrorSchema
6727
+ },
6728
+ summary: "List artifacts",
6729
+ description: "List all artifacts in the current scope with pagination"
6730
+ },
6731
+ create: {
6732
+ method: "POST",
6733
+ path: "/v1/artifacts",
6734
+ body: createArtifactRequestSchema,
6735
+ responses: {
6736
+ 201: publicArtifactDetailSchema,
6737
+ 400: publicApiErrorSchema,
6738
+ 401: publicApiErrorSchema,
6739
+ 409: publicApiErrorSchema,
6740
+ 500: publicApiErrorSchema
6741
+ },
6742
+ summary: "Create artifact",
6743
+ description: "Create a new empty artifact container"
6744
+ }
6745
+ });
6746
+ var publicArtifactByIdContract = c13.router({
6747
+ get: {
6748
+ method: "GET",
6749
+ path: "/v1/artifacts/:id",
6750
+ pathParams: z18.object({
6751
+ id: z18.string().min(1, "Artifact ID is required")
6752
+ }),
6753
+ responses: {
6754
+ 200: publicArtifactDetailSchema,
6755
+ 401: publicApiErrorSchema,
6756
+ 404: publicApiErrorSchema,
6757
+ 500: publicApiErrorSchema
6758
+ },
6759
+ summary: "Get artifact",
6760
+ description: "Get artifact details by ID"
6761
+ },
6762
+ delete: {
6763
+ method: "DELETE",
6764
+ path: "/v1/artifacts/:id",
6765
+ pathParams: z18.object({
6766
+ id: z18.string().min(1, "Artifact ID is required")
6767
+ }),
6768
+ body: z18.undefined(),
6769
+ responses: {
6770
+ 204: z18.undefined(),
6771
+ 401: publicApiErrorSchema,
6772
+ 404: publicApiErrorSchema,
6773
+ 500: publicApiErrorSchema
6774
+ },
6775
+ summary: "Delete artifact",
6776
+ description: "Delete an artifact and all its versions"
6777
+ }
6778
+ });
6779
+ var publicArtifactVersionsContract = c13.router({
6780
+ list: {
6781
+ method: "GET",
6782
+ path: "/v1/artifacts/:id/versions",
6783
+ pathParams: z18.object({
6784
+ id: z18.string().min(1, "Artifact ID is required")
6785
+ }),
6786
+ query: listQuerySchema,
6787
+ responses: {
6788
+ 200: paginatedArtifactVersionsSchema,
6789
+ 401: publicApiErrorSchema,
6790
+ 404: publicApiErrorSchema,
6791
+ 500: publicApiErrorSchema
6792
+ },
6793
+ summary: "List artifact versions",
6794
+ description: "List all versions of an artifact with pagination"
6795
+ }
6796
+ });
6797
+ var publicArtifactUploadContract = c13.router({
6798
+ prepareUpload: {
6799
+ method: "POST",
6800
+ path: "/v1/artifacts/:id/upload",
6801
+ pathParams: z18.object({
6802
+ id: z18.string().min(1, "Artifact ID is required")
6803
+ }),
6804
+ body: prepareUploadRequestSchema,
6805
+ responses: {
6806
+ 200: prepareUploadResponseSchema,
6807
+ 400: publicApiErrorSchema,
6808
+ 401: publicApiErrorSchema,
6809
+ 404: publicApiErrorSchema,
6810
+ 500: publicApiErrorSchema
6811
+ },
6812
+ summary: "Prepare artifact upload",
6813
+ description: "Get presigned URLs for direct S3 upload. Returns upload URLs for each file."
6814
+ }
6815
+ });
6816
+ var publicArtifactCommitContract = c13.router({
6817
+ commitUpload: {
6818
+ method: "POST",
6819
+ path: "/v1/artifacts/:id/commit",
6820
+ pathParams: z18.object({
6821
+ id: z18.string().min(1, "Artifact ID is required")
6822
+ }),
6823
+ body: commitUploadRequestSchema,
6824
+ responses: {
6825
+ 200: artifactVersionSchema,
6826
+ 400: publicApiErrorSchema,
6827
+ 401: publicApiErrorSchema,
6828
+ 404: publicApiErrorSchema,
6829
+ 500: publicApiErrorSchema
6830
+ },
6831
+ summary: "Commit artifact upload",
6832
+ description: "Finalize an upload session and create a new artifact version."
6833
+ }
6834
+ });
6835
+ var publicArtifactDownloadContract = c13.router({
6836
+ download: {
6837
+ method: "GET",
6838
+ path: "/v1/artifacts/:id/download",
6839
+ pathParams: z18.object({
6840
+ id: z18.string().min(1, "Artifact ID is required")
6841
+ }),
6842
+ query: z18.object({
6843
+ version_id: z18.string().optional()
6844
+ // Defaults to current version
6845
+ }),
6846
+ responses: {
6847
+ 200: downloadResponseSchema,
6848
+ 401: publicApiErrorSchema,
6849
+ 404: publicApiErrorSchema,
6850
+ 500: publicApiErrorSchema
5906
6851
  },
5907
- summary: "Cleanup expired sandboxes"
6852
+ summary: "Download artifact",
6853
+ description: "Get presigned URLs for downloading artifact files. Defaults to current version."
5908
6854
  }
5909
6855
  });
5910
6856
 
5911
- // ../../packages/core/src/contracts/proxy.ts
5912
- import { z as z11 } from "zod";
5913
- var proxyErrorSchema = z11.object({
5914
- error: z11.object({
5915
- message: z11.string(),
5916
- code: z11.enum([
5917
- "UNAUTHORIZED",
5918
- "BAD_REQUEST",
5919
- "BAD_GATEWAY",
5920
- "INTERNAL_ERROR"
5921
- ]),
5922
- targetUrl: z11.string().optional()
5923
- })
6857
+ // ../../packages/core/src/contracts/public/volumes.ts
6858
+ import { z as z19 } from "zod";
6859
+ var c14 = initContract();
6860
+ var publicVolumeSchema = z19.object({
6861
+ id: z19.string(),
6862
+ name: z19.string(),
6863
+ current_version_id: z19.string().nullable(),
6864
+ size: z19.number(),
6865
+ // Total size in bytes
6866
+ file_count: z19.number(),
6867
+ created_at: timestampSchema,
6868
+ updated_at: timestampSchema
5924
6869
  });
5925
-
5926
- // ../../packages/core/src/contracts/scopes.ts
5927
- import { z as z12 } from "zod";
5928
- var c8 = initContract();
5929
- var scopeTypeSchema = z12.enum(["personal", "organization", "system"]);
5930
- var scopeSlugSchema = z12.string().min(3, "Scope slug must be at least 3 characters").max(64, "Scope slug must be at most 64 characters").regex(
5931
- /^[a-z0-9][a-z0-9-]*[a-z0-9]$|^[a-z0-9]{1,2}$/,
5932
- "Scope slug must contain only lowercase letters, numbers, and hyphens, and must start and end with an alphanumeric character"
5933
- ).refine(
5934
- (slug) => !slug.startsWith("vm0"),
5935
- "Scope slug cannot start with 'vm0' (reserved)"
5936
- ).transform((s) => s.toLowerCase());
5937
- var scopeResponseSchema = z12.object({
5938
- id: z12.string().uuid(),
5939
- slug: z12.string(),
5940
- type: scopeTypeSchema,
5941
- displayName: z12.string().nullable(),
5942
- createdAt: z12.string(),
5943
- updatedAt: z12.string()
6870
+ var volumeVersionSchema = z19.object({
6871
+ id: z19.string(),
6872
+ // SHA-256 content hash
6873
+ volume_id: z19.string(),
6874
+ size: z19.number(),
6875
+ // Size in bytes
6876
+ file_count: z19.number(),
6877
+ message: z19.string().nullable(),
6878
+ // Optional commit message
6879
+ created_by: z19.string(),
6880
+ created_at: timestampSchema
5944
6881
  });
5945
- var createScopeRequestSchema = z12.object({
5946
- slug: scopeSlugSchema,
5947
- displayName: z12.string().max(128).optional()
6882
+ var publicVolumeDetailSchema = publicVolumeSchema.extend({
6883
+ current_version: volumeVersionSchema.nullable()
5948
6884
  });
5949
- var updateScopeRequestSchema = z12.object({
5950
- slug: scopeSlugSchema,
5951
- force: z12.boolean().optional().default(false)
6885
+ var paginatedVolumesSchema = createPaginatedResponseSchema(publicVolumeSchema);
6886
+ var paginatedVolumeVersionsSchema = createPaginatedResponseSchema(volumeVersionSchema);
6887
+ var createVolumeRequestSchema = z19.object({
6888
+ name: z19.string().min(1).max(100).regex(
6889
+ /^[a-z0-9][a-z0-9-]*[a-z0-9]$|^[a-z0-9]$/,
6890
+ "Name must be lowercase alphanumeric with hyphens, not starting or ending with hyphen"
6891
+ )
5952
6892
  });
5953
- var scopeContract = c8.router({
5954
- /**
5955
- * GET /api/scope
5956
- * Get current user's scope
5957
- */
5958
- get: {
6893
+ var fileEntrySchema2 = z19.object({
6894
+ path: z19.string(),
6895
+ size: z19.number(),
6896
+ hash: z19.string().optional()
6897
+ // SHA-256 hash of file content
6898
+ });
6899
+ var prepareUploadRequestSchema2 = z19.object({
6900
+ files: z19.array(fileEntrySchema2),
6901
+ message: z19.string().optional()
6902
+ // Optional commit message
6903
+ });
6904
+ var presignedUploadSchema3 = z19.object({
6905
+ path: z19.string(),
6906
+ upload_url: z19.string(),
6907
+ // Presigned S3 URL
6908
+ upload_id: z19.string()
6909
+ // For multi-part uploads
6910
+ });
6911
+ var prepareUploadResponseSchema2 = z19.object({
6912
+ upload_session_id: z19.string(),
6913
+ files: z19.array(presignedUploadSchema3),
6914
+ expires_at: timestampSchema
6915
+ });
6916
+ var commitUploadRequestSchema2 = z19.object({
6917
+ upload_session_id: z19.string(),
6918
+ message: z19.string().optional()
6919
+ });
6920
+ var downloadResponseSchema2 = z19.object({
6921
+ version_id: z19.string(),
6922
+ files: z19.array(
6923
+ z19.object({
6924
+ path: z19.string(),
6925
+ size: z19.number(),
6926
+ download_url: z19.string()
6927
+ // Presigned S3 URL
6928
+ })
6929
+ ),
6930
+ expires_at: timestampSchema
6931
+ });
6932
+ var publicVolumesListContract = c14.router({
6933
+ list: {
5959
6934
  method: "GET",
5960
- path: "/api/scope",
6935
+ path: "/v1/volumes",
6936
+ query: listQuerySchema,
5961
6937
  responses: {
5962
- 200: scopeResponseSchema,
5963
- 401: apiErrorSchema,
5964
- 404: apiErrorSchema,
5965
- 500: apiErrorSchema
6938
+ 200: paginatedVolumesSchema,
6939
+ 401: publicApiErrorSchema,
6940
+ 500: publicApiErrorSchema
5966
6941
  },
5967
- summary: "Get current user's scope"
6942
+ summary: "List volumes",
6943
+ description: "List all volumes in the current scope with pagination"
5968
6944
  },
5969
- /**
5970
- * POST /api/scope
5971
- * Create user's scope
5972
- */
5973
6945
  create: {
5974
6946
  method: "POST",
5975
- path: "/api/scope",
5976
- body: createScopeRequestSchema,
6947
+ path: "/v1/volumes",
6948
+ body: createVolumeRequestSchema,
5977
6949
  responses: {
5978
- 201: scopeResponseSchema,
5979
- 400: apiErrorSchema,
5980
- 401: apiErrorSchema,
5981
- 409: apiErrorSchema,
5982
- 500: apiErrorSchema
6950
+ 201: publicVolumeDetailSchema,
6951
+ 400: publicApiErrorSchema,
6952
+ 401: publicApiErrorSchema,
6953
+ 409: publicApiErrorSchema,
6954
+ 500: publicApiErrorSchema
5983
6955
  },
5984
- summary: "Create user's scope"
6956
+ summary: "Create volume",
6957
+ description: "Create a new empty volume container"
6958
+ }
6959
+ });
6960
+ var publicVolumeByIdContract = c14.router({
6961
+ get: {
6962
+ method: "GET",
6963
+ path: "/v1/volumes/:id",
6964
+ pathParams: z19.object({
6965
+ id: z19.string().min(1, "Volume ID is required")
6966
+ }),
6967
+ responses: {
6968
+ 200: publicVolumeDetailSchema,
6969
+ 401: publicApiErrorSchema,
6970
+ 404: publicApiErrorSchema,
6971
+ 500: publicApiErrorSchema
6972
+ },
6973
+ summary: "Get volume",
6974
+ description: "Get volume details by ID"
5985
6975
  },
5986
- /**
5987
- * PUT /api/scope
5988
- * Update user's scope slug
5989
- */
5990
- update: {
5991
- method: "PUT",
5992
- path: "/api/scope",
5993
- body: updateScopeRequestSchema,
6976
+ delete: {
6977
+ method: "DELETE",
6978
+ path: "/v1/volumes/:id",
6979
+ pathParams: z19.object({
6980
+ id: z19.string().min(1, "Volume ID is required")
6981
+ }),
6982
+ body: z19.undefined(),
5994
6983
  responses: {
5995
- 200: scopeResponseSchema,
5996
- 400: apiErrorSchema,
5997
- 401: apiErrorSchema,
5998
- 403: apiErrorSchema,
5999
- 404: apiErrorSchema,
6000
- 409: apiErrorSchema,
6001
- 500: apiErrorSchema
6984
+ 204: z19.undefined(),
6985
+ 401: publicApiErrorSchema,
6986
+ 404: publicApiErrorSchema,
6987
+ 500: publicApiErrorSchema
6002
6988
  },
6003
- summary: "Update user's scope slug"
6989
+ summary: "Delete volume",
6990
+ description: "Delete a volume and all its versions"
6004
6991
  }
6005
6992
  });
6006
-
6007
- // ../../packages/core/src/contracts/sessions.ts
6008
- import { z as z13 } from "zod";
6009
- var c9 = initContract();
6010
- var sessionResponseSchema = z13.object({
6011
- id: z13.string(),
6012
- agentComposeId: z13.string(),
6013
- agentComposeVersionId: z13.string().nullable(),
6014
- conversationId: z13.string().nullable(),
6015
- artifactName: z13.string().nullable(),
6016
- vars: z13.record(z13.string(), z13.string()).nullable(),
6017
- secretNames: z13.array(z13.string()).nullable(),
6018
- volumeVersions: z13.record(z13.string(), z13.string()).nullable(),
6019
- createdAt: z13.string(),
6020
- updatedAt: z13.string()
6021
- });
6022
- var agentComposeSnapshotSchema = z13.object({
6023
- agentComposeVersionId: z13.string(),
6024
- vars: z13.record(z13.string(), z13.string()).optional(),
6025
- secretNames: z13.array(z13.string()).optional()
6026
- });
6027
- var artifactSnapshotSchema2 = z13.object({
6028
- artifactName: z13.string(),
6029
- artifactVersion: z13.string()
6030
- });
6031
- var volumeVersionsSnapshotSchema2 = z13.object({
6032
- versions: z13.record(z13.string(), z13.string())
6033
- });
6034
- var checkpointResponseSchema = z13.object({
6035
- id: z13.string(),
6036
- runId: z13.string(),
6037
- conversationId: z13.string(),
6038
- agentComposeSnapshot: agentComposeSnapshotSchema,
6039
- artifactSnapshot: artifactSnapshotSchema2.nullable(),
6040
- volumeVersionsSnapshot: volumeVersionsSnapshotSchema2.nullable(),
6041
- createdAt: z13.string()
6042
- });
6043
- var sessionsByIdContract = c9.router({
6044
- /**
6045
- * GET /api/agent/sessions/:id
6046
- * Get session by ID
6047
- */
6048
- getById: {
6993
+ var publicVolumeVersionsContract = c14.router({
6994
+ list: {
6049
6995
  method: "GET",
6050
- path: "/api/agent/sessions/:id",
6051
- pathParams: z13.object({
6052
- id: z13.string().min(1, "Session ID is required")
6996
+ path: "/v1/volumes/:id/versions",
6997
+ pathParams: z19.object({
6998
+ id: z19.string().min(1, "Volume ID is required")
6053
6999
  }),
7000
+ query: listQuerySchema,
6054
7001
  responses: {
6055
- 200: sessionResponseSchema,
6056
- 401: apiErrorSchema,
6057
- 403: apiErrorSchema,
6058
- 404: apiErrorSchema
7002
+ 200: paginatedVolumeVersionsSchema,
7003
+ 401: publicApiErrorSchema,
7004
+ 404: publicApiErrorSchema,
7005
+ 500: publicApiErrorSchema
6059
7006
  },
6060
- summary: "Get session by ID"
7007
+ summary: "List volume versions",
7008
+ description: "List all versions of a volume with pagination"
6061
7009
  }
6062
7010
  });
6063
- var checkpointsByIdContract = c9.router({
6064
- /**
6065
- * GET /api/agent/checkpoints/:id
6066
- * Get checkpoint by ID
6067
- */
6068
- getById: {
6069
- method: "GET",
6070
- path: "/api/agent/checkpoints/:id",
6071
- pathParams: z13.object({
6072
- id: z13.string().min(1, "Checkpoint ID is required")
7011
+ var publicVolumeUploadContract = c14.router({
7012
+ prepareUpload: {
7013
+ method: "POST",
7014
+ path: "/v1/volumes/:id/upload",
7015
+ pathParams: z19.object({
7016
+ id: z19.string().min(1, "Volume ID is required")
6073
7017
  }),
7018
+ body: prepareUploadRequestSchema2,
6074
7019
  responses: {
6075
- 200: checkpointResponseSchema,
6076
- 401: apiErrorSchema,
6077
- 403: apiErrorSchema,
6078
- 404: apiErrorSchema
7020
+ 200: prepareUploadResponseSchema2,
7021
+ 400: publicApiErrorSchema,
7022
+ 401: publicApiErrorSchema,
7023
+ 404: publicApiErrorSchema,
7024
+ 500: publicApiErrorSchema
6079
7025
  },
6080
- summary: "Get checkpoint by ID"
7026
+ summary: "Prepare volume upload",
7027
+ description: "Get presigned URLs for direct S3 upload. Returns upload URLs for each file."
6081
7028
  }
6082
7029
  });
6083
-
6084
- // ../../packages/core/src/contracts/runners.ts
6085
- import { z as z14 } from "zod";
6086
- var c10 = initContract();
6087
- var runnerGroupSchema = z14.string().regex(
6088
- /^[a-z0-9-]+\/[a-z0-9-]+$/,
6089
- "Runner group must be in scope/name format (e.g., acme/production)"
6090
- );
6091
- var jobSchema = z14.object({
6092
- runId: z14.string().uuid(),
6093
- prompt: z14.string(),
6094
- agentComposeVersionId: z14.string(),
6095
- vars: z14.record(z14.string(), z14.string()).nullable(),
6096
- secretNames: z14.array(z14.string()).nullable(),
6097
- checkpointId: z14.string().uuid().nullable()
6098
- });
6099
- var runnersPollContract = c10.router({
6100
- poll: {
7030
+ var publicVolumeCommitContract = c14.router({
7031
+ commitUpload: {
6101
7032
  method: "POST",
6102
- path: "/api/runners/poll",
6103
- body: z14.object({
6104
- group: runnerGroupSchema
7033
+ path: "/v1/volumes/:id/commit",
7034
+ pathParams: z19.object({
7035
+ id: z19.string().min(1, "Volume ID is required")
6105
7036
  }),
7037
+ body: commitUploadRequestSchema2,
6106
7038
  responses: {
6107
- 200: z14.object({
6108
- job: jobSchema.nullable()
6109
- }),
6110
- 400: apiErrorSchema,
6111
- 401: apiErrorSchema,
6112
- 500: apiErrorSchema
7039
+ 200: volumeVersionSchema,
7040
+ 400: publicApiErrorSchema,
7041
+ 401: publicApiErrorSchema,
7042
+ 404: publicApiErrorSchema,
7043
+ 500: publicApiErrorSchema
6113
7044
  },
6114
- summary: "Poll for pending jobs (long-polling with 30s timeout)"
7045
+ summary: "Commit volume upload",
7046
+ description: "Finalize an upload session and create a new volume version."
6115
7047
  }
6116
7048
  });
6117
- var storageEntrySchema = z14.object({
6118
- mountPath: z14.string(),
6119
- archiveUrl: z14.string().nullable()
6120
- });
6121
- var artifactEntrySchema = z14.object({
6122
- mountPath: z14.string(),
6123
- archiveUrl: z14.string().nullable(),
6124
- vasStorageName: z14.string(),
6125
- vasVersionId: z14.string()
6126
- });
6127
- var storageManifestSchema = z14.object({
6128
- storages: z14.array(storageEntrySchema),
6129
- artifact: artifactEntrySchema.nullable()
7049
+ var publicVolumeDownloadContract = c14.router({
7050
+ download: {
7051
+ method: "GET",
7052
+ path: "/v1/volumes/:id/download",
7053
+ pathParams: z19.object({
7054
+ id: z19.string().min(1, "Volume ID is required")
7055
+ }),
7056
+ query: z19.object({
7057
+ version_id: z19.string().optional()
7058
+ // Defaults to current version
7059
+ }),
7060
+ responses: {
7061
+ 200: downloadResponseSchema2,
7062
+ 401: publicApiErrorSchema,
7063
+ 404: publicApiErrorSchema,
7064
+ 500: publicApiErrorSchema
7065
+ },
7066
+ summary: "Download volume",
7067
+ description: "Get presigned URLs for downloading volume files. Defaults to current version."
7068
+ }
6130
7069
  });
6131
- var resumeSessionSchema = z14.object({
6132
- sessionId: z14.string(),
6133
- sessionHistory: z14.string()
7070
+
7071
+ // ../../packages/core/src/contracts/public/tokens.ts
7072
+ import { z as z20 } from "zod";
7073
+ var c15 = initContract();
7074
+ var publicTokenSchema = z20.object({
7075
+ id: z20.string(),
7076
+ name: z20.string(),
7077
+ token_prefix: z20.string(),
7078
+ // First 12 chars for identification (e.g., "vm0_live_abc")
7079
+ last_used_at: timestampSchema.nullable(),
7080
+ expires_at: timestampSchema,
7081
+ created_at: timestampSchema
6134
7082
  });
6135
- var storedExecutionContextSchema = z14.object({
6136
- workingDir: z14.string(),
6137
- storageManifest: storageManifestSchema.nullable(),
6138
- environment: z14.record(z14.string(), z14.string()).nullable(),
6139
- resumeSession: resumeSessionSchema.nullable(),
6140
- encryptedSecrets: z14.string().nullable(),
6141
- // AES-256-GCM encrypted secrets
6142
- cliAgentType: z14.string(),
6143
- experimentalNetworkSecurity: z14.boolean().optional()
7083
+ var publicTokenDetailSchema = publicTokenSchema.extend({
7084
+ token: z20.string().optional()
7085
+ // Full token value, only returned on creation
6144
7086
  });
6145
- var executionContextSchema = z14.object({
6146
- runId: z14.string().uuid(),
6147
- prompt: z14.string(),
6148
- agentComposeVersionId: z14.string(),
6149
- vars: z14.record(z14.string(), z14.string()).nullable(),
6150
- secretNames: z14.array(z14.string()).nullable(),
6151
- checkpointId: z14.string().uuid().nullable(),
6152
- sandboxToken: z14.string(),
6153
- // New fields for E2B parity:
6154
- workingDir: z14.string(),
6155
- storageManifest: storageManifestSchema.nullable(),
6156
- environment: z14.record(z14.string(), z14.string()).nullable(),
6157
- resumeSession: resumeSessionSchema.nullable(),
6158
- secretValues: z14.array(z14.string()).nullable(),
6159
- cliAgentType: z14.string(),
6160
- // Network security mode flag
6161
- experimentalNetworkSecurity: z14.boolean().optional()
7087
+ var paginatedTokensSchema = createPaginatedResponseSchema(publicTokenSchema);
7088
+ var createTokenRequestSchema = z20.object({
7089
+ name: z20.string().min(1, "Name is required").max(100, "Name too long"),
7090
+ expires_in_days: z20.number().min(1).max(365).optional()
7091
+ // null for no expiry (default 90 days)
6162
7092
  });
6163
- var runnersJobClaimContract = c10.router({
6164
- claim: {
7093
+ var publicTokensListContract = c15.router({
7094
+ list: {
7095
+ method: "GET",
7096
+ path: "/v1/tokens",
7097
+ query: listQuerySchema,
7098
+ responses: {
7099
+ 200: paginatedTokensSchema,
7100
+ 401: publicApiErrorSchema
7101
+ },
7102
+ summary: "List API tokens",
7103
+ description: "List all API tokens for the authenticated user"
7104
+ },
7105
+ create: {
6165
7106
  method: "POST",
6166
- path: "/api/runners/jobs/:id/claim",
6167
- pathParams: z14.object({
6168
- id: z14.string().uuid()
7107
+ path: "/v1/tokens",
7108
+ body: createTokenRequestSchema,
7109
+ responses: {
7110
+ 201: publicTokenDetailSchema,
7111
+ // Includes full token value
7112
+ 400: publicApiErrorSchema,
7113
+ 401: publicApiErrorSchema
7114
+ },
7115
+ summary: "Create API token",
7116
+ description: "Create a new API token. The token value is only returned once on creation."
7117
+ }
7118
+ });
7119
+ var publicTokenByIdContract = c15.router({
7120
+ get: {
7121
+ method: "GET",
7122
+ path: "/v1/tokens/:id",
7123
+ pathParams: z20.object({
7124
+ id: z20.string()
6169
7125
  }),
6170
- body: z14.object({}),
6171
7126
  responses: {
6172
- 200: executionContextSchema,
6173
- 400: apiErrorSchema,
6174
- 401: apiErrorSchema,
6175
- 403: apiErrorSchema,
6176
- // Job does not belong to user
6177
- 404: apiErrorSchema,
6178
- 409: apiErrorSchema,
6179
- // Already claimed
6180
- 500: apiErrorSchema
7127
+ 200: publicTokenSchema,
7128
+ // Does NOT include token value
7129
+ 401: publicApiErrorSchema,
7130
+ 404: publicApiErrorSchema
6181
7131
  },
6182
- summary: "Claim a pending job for execution"
7132
+ summary: "Get API token",
7133
+ description: "Get details of an API token (does not include the token value)"
7134
+ },
7135
+ delete: {
7136
+ method: "DELETE",
7137
+ path: "/v1/tokens/:id",
7138
+ pathParams: z20.object({
7139
+ id: z20.string()
7140
+ }),
7141
+ responses: {
7142
+ 204: z20.undefined(),
7143
+ 401: publicApiErrorSchema,
7144
+ 404: publicApiErrorSchema
7145
+ },
7146
+ summary: "Revoke API token",
7147
+ description: "Permanently revoke an API token. This action cannot be undone."
6183
7148
  }
6184
7149
  });
6185
7150
 
@@ -8611,14 +9576,21 @@ var VMRegistry = class {
8611
9576
  /**
8612
9577
  * Register a VM with its IP address
8613
9578
  */
8614
- register(vmIp, runId, sandboxToken) {
9579
+ register(vmIp, runId, sandboxToken, options) {
8615
9580
  this.data.vms[vmIp] = {
8616
9581
  runId,
8617
9582
  sandboxToken,
8618
- registeredAt: Date.now()
9583
+ registeredAt: Date.now(),
9584
+ firewallRules: options?.firewallRules,
9585
+ mitmEnabled: options?.mitmEnabled,
9586
+ sealSecretsEnabled: options?.sealSecretsEnabled
8619
9587
  };
8620
9588
  this.save();
8621
- console.log(`[VMRegistry] Registered VM ${vmIp} for run ${runId}`);
9589
+ const firewallInfo = options?.firewallRules ? ` with ${options.firewallRules.length} firewall rules` : "";
9590
+ const mitmInfo = options?.mitmEnabled ? ", MITM enabled" : "";
9591
+ console.log(
9592
+ `[VMRegistry] Registered VM ${vmIp} for run ${runId}${firewallInfo}${mitmInfo}`
9593
+ );
8622
9594
  }
8623
9595
  /**
8624
9596
  * Unregister a VM by IP address
@@ -8684,16 +9656,19 @@ mitmproxy addon for VM0 runner-level network security mode.
8684
9656
 
8685
9657
  This addon runs on the runner HOST (not inside VMs) and:
8686
9658
  1. Intercepts all HTTPS requests from VMs
8687
- 2. Looks up the source VM's runId from the VM registry
8688
- 3. Rewrites requests to go through VM0 Proxy endpoint
8689
- 4. Preserves all original headers (including encrypted tokens)
8690
- 5. Logs network activity per-run to JSONL files
9659
+ 2. Looks up the source VM's runId and firewall rules from the VM registry
9660
+ 3. Evaluates firewall rules (first-match-wins) to ALLOW or DENY
9661
+ 4. For MITM mode: Rewrites requests to go through VM0 Proxy endpoint
9662
+ 5. For SNI-only mode: Passes through or blocks without decryption
9663
+ 6. Logs network activity per-run to JSONL files
8691
9664
  """
8692
9665
  import os
8693
9666
  import json
8694
9667
  import time
8695
9668
  import urllib.parse
8696
- from mitmproxy import http, ctx
9669
+ import ipaddress
9670
+ import socket
9671
+ from mitmproxy import http, ctx, tls
8697
9672
 
8698
9673
 
8699
9674
  # VM0 Proxy configuration from environment
@@ -8776,12 +9751,189 @@ def get_original_url(flow: http.HTTPFlow) -> str:
8776
9751
  return f"{scheme}://{host_with_port}{path}"
8777
9752
 
8778
9753
 
8779
- def request(flow: http.HTTPFlow) -> None:
9754
+ # ============================================================================
9755
+ # Firewall Rule Matching
9756
+ # ============================================================================
9757
+
9758
+ def match_domain(pattern: str, hostname: str) -> bool:
9759
+ """
9760
+ Match hostname against domain pattern.
9761
+ Supports exact match and wildcard prefix (*.example.com).
9762
+ """
9763
+ if not pattern or not hostname:
9764
+ return False
9765
+
9766
+ pattern = pattern.lower()
9767
+ hostname = hostname.lower()
9768
+
9769
+ if pattern.startswith("*."):
9770
+ # Wildcard: *.example.com matches sub.example.com, www.example.com
9771
+ # Also matches example.com itself (without subdomain)
9772
+ suffix = pattern[1:] # .example.com
9773
+ base = pattern[2:] # example.com
9774
+ return hostname.endswith(suffix) or hostname == base
9775
+
9776
+ return hostname == pattern
9777
+
9778
+
9779
+ def match_ip(cidr: str, ip_str: str) -> bool:
9780
+ """
9781
+ Match IP address against CIDR range.
9782
+ Supports single IPs (1.2.3.4) and ranges (10.0.0.0/8).
9783
+ """
9784
+ if not cidr or not ip_str:
9785
+ return False
9786
+
9787
+ try:
9788
+ # Parse CIDR (automatically handles single IPs as /32)
9789
+ if "/" not in cidr:
9790
+ cidr = f"{cidr}/32"
9791
+ network = ipaddress.ip_network(cidr, strict=False)
9792
+ ip = ipaddress.ip_address(ip_str)
9793
+ return ip in network
9794
+ except ValueError:
9795
+ return False
9796
+
9797
+
9798
+ def resolve_hostname_to_ip(hostname: str) -> str | None:
9799
+ """Resolve hostname to IP address for IP-based rule matching."""
9800
+ try:
9801
+ return socket.gethostbyname(hostname)
9802
+ except socket.gaierror:
9803
+ return None
9804
+
9805
+
9806
+ def evaluate_rules(rules: list, hostname: str, ip_str: str = None) -> tuple[str, str | None]:
9807
+ """
9808
+ Evaluate firewall rules against hostname/IP.
9809
+ Returns (action, matched_rule_description).
9810
+
9811
+ Rule evaluation is first-match-wins (top to bottom).
9812
+
9813
+ Rule formats:
9814
+ - Domain/IP rule: { domain: "*.example.com", action: "ALLOW" }
9815
+ - Terminal rule: { final: "DENY" }
9816
+ """
9817
+ if not rules:
9818
+ return ("ALLOW", None) # No rules = allow all
9819
+
9820
+ for rule in rules:
9821
+ # Final/terminal rule - value is the action
9822
+ final_action = rule.get("final")
9823
+ if final_action:
9824
+ return (final_action, "final")
9825
+
9826
+ # Domain rule
9827
+ domain = rule.get("domain")
9828
+ if domain and match_domain(domain, hostname):
9829
+ return (rule.get("action", "DENY"), f"domain:{domain}")
9830
+
9831
+ # IP rule
9832
+ ip_pattern = rule.get("ip")
9833
+ if ip_pattern:
9834
+ target_ip = ip_str
9835
+ if not target_ip:
9836
+ target_ip = resolve_hostname_to_ip(hostname)
9837
+ if target_ip and match_ip(ip_pattern, target_ip):
9838
+ return (rule.get("action", "DENY"), f"ip:{ip_pattern}")
9839
+
9840
+ # No rule matched - default deny (zero-trust)
9841
+ return ("DENY", "default")
9842
+
9843
+
9844
+ # ============================================================================
9845
+ # TLS ClientHello Handler (SNI-only mode)
9846
+ # ============================================================================
9847
+
9848
+ def tls_clienthello(data: tls.ClientHelloData) -> None:
8780
9849
  """
8781
- Intercept request and rewrite to VM0 Proxy.
9850
+ Handle TLS ClientHello for SNI-based filtering.
9851
+ This is called BEFORE TLS decryption, allowing SNI-only filtering.
9852
+ """
9853
+ client_ip = data.context.client.peername[0] if data.context.client.peername else None
9854
+ if not client_ip:
9855
+ return
9856
+
9857
+ vm_info = get_vm_info(client_ip)
9858
+ if not vm_info:
9859
+ return # Not a registered VM, let it through
8782
9860
 
8783
- Identifies the source VM by client IP and looks up the associated
8784
- runId and sandboxToken from the VM registry.
9861
+ # If MITM is enabled, let the normal flow handle it
9862
+ if vm_info.get("mitmEnabled", False):
9863
+ return
9864
+
9865
+ # SNI-only mode: check rules based on SNI
9866
+ sni = data.context.client.sni
9867
+ run_id = vm_info.get("runId", "")
9868
+ rules = vm_info.get("firewallRules", [])
9869
+
9870
+ # Auto-allow VM0 API requests - the agent MUST be able to communicate with VM0
9871
+ if API_URL and sni:
9872
+ parsed_api = urllib.parse.urlparse(API_URL)
9873
+ api_hostname = parsed_api.hostname.lower() if parsed_api.hostname else ""
9874
+ sni_lower = sni.lower()
9875
+ if api_hostname and (sni_lower == api_hostname or sni_lower.endswith(f".{api_hostname}")):
9876
+ ctx.log.info(f"[{run_id}] SNI-only auto-allow VM0 API: {sni}")
9877
+ log_network_entry(run_id, {
9878
+ "timestamp": time.strftime("%Y-%m-%dT%H:%M:%S", time.gmtime()),
9879
+ "mode": "sni",
9880
+ "action": "ALLOW",
9881
+ "host": sni,
9882
+ "port": 443,
9883
+ "rule_matched": "vm0-api",
9884
+ })
9885
+ data.ignore_connection = True # Pass through without MITM
9886
+ return
9887
+
9888
+ if not sni:
9889
+ # No SNI, can't determine target - block for security
9890
+ ctx.log.warn(f"[{run_id}] SNI-only: No SNI in ClientHello, blocking")
9891
+ log_network_entry(run_id, {
9892
+ "timestamp": time.strftime("%Y-%m-%dT%H:%M:%S", time.gmtime()),
9893
+ "mode": "sni",
9894
+ "action": "DENY",
9895
+ "host": "",
9896
+ "port": 443,
9897
+ "rule_matched": "no-sni",
9898
+ })
9899
+ # Don't set ignore_connection - mitmproxy will attempt MITM handshake
9900
+ # Since VM doesn't have CA cert (SNI-only mode), TLS will fail immediately
9901
+ return
9902
+
9903
+ # Evaluate rules
9904
+ action, matched_rule = evaluate_rules(rules, sni)
9905
+
9906
+ # Log the connection
9907
+ log_network_entry(run_id, {
9908
+ "timestamp": time.strftime("%Y-%m-%dT%H:%M:%S", time.gmtime()),
9909
+ "mode": "sni",
9910
+ "action": action,
9911
+ "host": sni,
9912
+ "port": 443,
9913
+ "rule_matched": matched_rule,
9914
+ })
9915
+
9916
+ if action == "ALLOW":
9917
+ # Pass through without MITM - mitmproxy will relay without decryption
9918
+ ctx.log.info(f"[{run_id}] SNI-only ALLOW: {sni} (rule: {matched_rule})")
9919
+ data.ignore_connection = True
9920
+ else:
9921
+ # Block the connection by NOT setting ignore_connection
9922
+ # mitmproxy will attempt MITM handshake, but since VM doesn't have
9923
+ # our CA certificate installed (SNI-only mode), the TLS handshake
9924
+ # will fail immediately with a certificate error.
9925
+ ctx.log.warn(f"[{run_id}] SNI-only DENY: {sni} (rule: {matched_rule})")
9926
+ # Client will see: SSL certificate problem / certificate verify failed
9927
+
9928
+
9929
+ # ============================================================================
9930
+ # HTTP Request Handler (MITM mode)
9931
+ # ============================================================================
9932
+
9933
+ def request(flow: http.HTTPFlow) -> None:
9934
+ """
9935
+ Intercept request and apply firewall rules.
9936
+ For MITM mode, rewrites allowed requests to VM0 Proxy.
8785
9937
  """
8786
9938
  # Track request start time
8787
9939
  request_start_times[flow.id] = time.time()
@@ -8798,16 +9950,52 @@ def request(flow: http.HTTPFlow) -> None:
8798
9950
 
8799
9951
  if not vm_info:
8800
9952
  # Not a registered VM, pass through without proxying
8801
- # This allows non-VM traffic to work normally
8802
9953
  ctx.log.info(f"No VM registration for {client_ip}, passing through")
8803
9954
  return
8804
9955
 
8805
9956
  run_id = vm_info.get("runId", "")
8806
9957
  sandbox_token = vm_info.get("sandboxToken", "")
9958
+ mitm_enabled = vm_info.get("mitmEnabled", False)
9959
+ rules = vm_info.get("firewallRules", [])
8807
9960
 
8808
9961
  # Store info for response handler
8809
9962
  flow.metadata["vm_run_id"] = run_id
8810
9963
  flow.metadata["vm_client_ip"] = client_ip
9964
+ flow.metadata["vm_mitm_enabled"] = mitm_enabled
9965
+
9966
+ # Get target hostname
9967
+ hostname = flow.request.pretty_host.lower()
9968
+
9969
+ # Auto-allow VM0 API requests - the agent MUST be able to communicate with VM0
9970
+ # This is checked before user firewall rules to ensure agent functionality
9971
+ if API_URL:
9972
+ parsed_api = urllib.parse.urlparse(API_URL)
9973
+ api_hostname = parsed_api.hostname.lower() if parsed_api.hostname else ""
9974
+ if api_hostname and (hostname == api_hostname or hostname.endswith(f".{api_hostname}")):
9975
+ ctx.log.info(f"[{run_id}] Auto-allow VM0 API: {hostname}")
9976
+ flow.metadata["firewall_action"] = "ALLOW"
9977
+ flow.metadata["firewall_rule"] = "vm0-api"
9978
+ # Continue to skip rewrite check below
9979
+ flow.metadata["original_url"] = get_original_url(flow)
9980
+ flow.metadata["skip_rewrite"] = True
9981
+ return
9982
+
9983
+ # Evaluate firewall rules
9984
+ action, matched_rule = evaluate_rules(rules, hostname)
9985
+ flow.metadata["firewall_action"] = action
9986
+ flow.metadata["firewall_rule"] = matched_rule
9987
+
9988
+ if action == "DENY":
9989
+ ctx.log.warn(f"[{run_id}] Firewall DENY: {hostname} (rule: {matched_rule})")
9990
+ # Kill the flow and return error response
9991
+ flow.response = http.Response.make(
9992
+ 403,
9993
+ b"Blocked by firewall",
9994
+ {"Content-Type": "text/plain"}
9995
+ )
9996
+ return
9997
+
9998
+ # Request is ALLOWED - proceed with processing
8811
9999
 
8812
10000
  # Skip if no API URL configured
8813
10001
  if not API_URL:
@@ -8820,9 +10008,8 @@ def request(flow: http.HTTPFlow) -> None:
8820
10008
  flow.metadata["skip_rewrite"] = True
8821
10009
  return
8822
10010
 
8823
- # Skip rewriting requests to trusted domains (S3, etc.)
10011
+ # Skip rewriting requests to trusted storage domains (S3, etc.)
8824
10012
  # S3 presigned URLs have signatures that break when proxied
8825
- host = flow.request.pretty_host.lower()
8826
10013
  TRUSTED_DOMAINS = [
8827
10014
  ".s3.amazonaws.com",
8828
10015
  ".s3-", # Regional S3 endpoints like s3-us-west-2.amazonaws.com
@@ -8831,8 +10018,8 @@ def request(flow: http.HTTPFlow) -> None:
8831
10018
  ".storage.googleapis.com",
8832
10019
  ]
8833
10020
  for domain in TRUSTED_DOMAINS:
8834
- if domain in host or host.endswith(domain.lstrip(".")):
8835
- ctx.log.info(f"[{run_id}] Skipping trusted domain: {host}")
10021
+ if domain in hostname or hostname.endswith(domain.lstrip(".")):
10022
+ ctx.log.info(f"[{run_id}] Skipping trusted storage domain: {hostname}")
8836
10023
  flow.metadata["original_url"] = get_original_url(flow)
8837
10024
  flow.metadata["skip_rewrite"] = True
8838
10025
  return
@@ -8841,7 +10028,13 @@ def request(flow: http.HTTPFlow) -> None:
8841
10028
  original_url = get_original_url(flow)
8842
10029
  flow.metadata["original_url"] = original_url
8843
10030
 
8844
- ctx.log.info(f"[{run_id}] Proxying: {original_url}")
10031
+ # If MITM is not enabled, just allow the request through without rewriting
10032
+ if not mitm_enabled:
10033
+ ctx.log.info(f"[{run_id}] Firewall ALLOW (no MITM): {hostname}")
10034
+ return
10035
+
10036
+ # MITM mode: rewrite to VM0 Proxy
10037
+ ctx.log.info(f"[{run_id}] Proxying via MITM: {original_url}")
8845
10038
 
8846
10039
  # Parse proxy URL
8847
10040
  parsed = urllib.parse.urlparse(PROXY_URL)
@@ -8882,34 +10075,58 @@ def response(flow: http.HTTPFlow) -> None:
8882
10075
  # Get stored info
8883
10076
  run_id = flow.metadata.get("vm_run_id", "")
8884
10077
  original_url = flow.metadata.get("original_url", flow.request.pretty_url)
10078
+ mitm_enabled = flow.metadata.get("vm_mitm_enabled", False)
10079
+ firewall_action = flow.metadata.get("firewall_action", "ALLOW")
10080
+ firewall_rule = flow.metadata.get("firewall_rule")
8885
10081
 
8886
10082
  # Calculate sizes
8887
10083
  request_size = len(flow.request.content) if flow.request.content else 0
8888
10084
  response_size = len(flow.response.content) if flow.response and flow.response.content else 0
8889
10085
  status_code = flow.response.status_code if flow.response else 0
8890
10086
 
10087
+ # Parse URL for host
10088
+ try:
10089
+ parsed_url = urllib.parse.urlparse(original_url)
10090
+ host = parsed_url.hostname or flow.request.pretty_host
10091
+ port = parsed_url.port or (443 if parsed_url.scheme == "https" else 80)
10092
+ except:
10093
+ host = flow.request.pretty_host
10094
+ port = flow.request.port
10095
+
8891
10096
  # Log network entry for this run
8892
10097
  if run_id:
8893
10098
  log_entry = {
8894
10099
  "timestamp": time.strftime("%Y-%m-%dT%H:%M:%S", time.gmtime()),
8895
- "method": flow.request.method,
8896
- "url": original_url,
8897
- "status": status_code,
8898
- "latency_ms": latency_ms,
8899
- "request_size": request_size,
8900
- "response_size": response_size,
10100
+ "mode": "mitm" if mitm_enabled else "filter",
10101
+ "action": firewall_action,
10102
+ "host": host,
10103
+ "port": port,
10104
+ "rule_matched": firewall_rule,
8901
10105
  }
10106
+
10107
+ # Add HTTP details only in MITM mode
10108
+ if mitm_enabled:
10109
+ log_entry.update({
10110
+ "method": flow.request.method,
10111
+ "path": flow.request.path.split("?")[0], # Path without query
10112
+ "url": original_url,
10113
+ "status": status_code,
10114
+ "latency_ms": latency_ms,
10115
+ "request_size": request_size,
10116
+ "response_size": response_size,
10117
+ })
10118
+
8902
10119
  log_network_entry(run_id, log_entry)
8903
10120
 
8904
10121
  # Log errors to mitmproxy console
8905
10122
  if flow.response and flow.response.status_code >= 400:
8906
10123
  ctx.log.warn(
8907
- f"[{run_id}] Proxy response {flow.response.status_code}: {original_url}"
10124
+ f"[{run_id}] Response {flow.response.status_code}: {original_url}"
8908
10125
  )
8909
10126
 
8910
10127
 
8911
10128
  # mitmproxy addon registration
8912
- addons = [request, response]
10129
+ addons = [tls_clienthello, request, response]
8913
10130
  `;
8914
10131
 
8915
10132
  // src/lib/proxy/proxy-manager.ts
@@ -9147,7 +10364,7 @@ function buildEnvironmentVariables(context, apiUrl) {
9147
10364
  envVars[key] = value;
9148
10365
  }
9149
10366
  }
9150
- if (context.experimentalNetworkSecurity) {
10367
+ if (context.experimentalFirewall?.experimental_mitm) {
9151
10368
  envVars.NODE_EXTRA_CA_CERTS = "/usr/local/share/ca-certificates/vm0-proxy-ca.crt";
9152
10369
  }
9153
10370
  return envVars;
@@ -9321,13 +10538,22 @@ async function executeJob(context, config) {
9321
10538
  console.log(`[Executor] Waiting for SSH on ${guestIp}...`);
9322
10539
  await ssh.waitUntilReachable(12e4, 2e3);
9323
10540
  console.log(`[Executor] SSH ready on ${guestIp}`);
9324
- if (context.experimentalNetworkSecurity) {
10541
+ const firewallConfig = context.experimentalFirewall;
10542
+ if (firewallConfig?.enabled) {
10543
+ const mitmEnabled = firewallConfig.experimental_mitm ?? false;
10544
+ const sealSecretsEnabled = firewallConfig.experimental_seal_secrets ?? false;
9325
10545
  console.log(
9326
- `[Executor] Setting up network security mode for VM ${guestIp}`
10546
+ `[Executor] Setting up network security for VM ${guestIp} (mitm=${mitmEnabled}, sealSecrets=${sealSecretsEnabled})`
9327
10547
  );
9328
10548
  await setupVMProxyRules(guestIp, config.proxy.port);
9329
- getVMRegistry().register(guestIp, context.runId, context.sandboxToken);
9330
- await installProxyCA(ssh);
10549
+ getVMRegistry().register(guestIp, context.runId, context.sandboxToken, {
10550
+ firewallRules: firewallConfig?.rules,
10551
+ mitmEnabled,
10552
+ sealSecretsEnabled
10553
+ });
10554
+ if (mitmEnabled) {
10555
+ await installProxyCA(ssh);
10556
+ }
9331
10557
  }
9332
10558
  console.log(`[Executor] Configuring DNS...`);
9333
10559
  await configureDNS(ssh);
@@ -9401,7 +10627,7 @@ async function executeJob(context, config) {
9401
10627
  error: errorMsg
9402
10628
  };
9403
10629
  } finally {
9404
- if (context.experimentalNetworkSecurity && guestIp) {
10630
+ if (context.experimentalFirewall?.enabled && guestIp) {
9405
10631
  console.log(`[Executor] Cleaning up network security for VM ${guestIp}`);
9406
10632
  try {
9407
10633
  await removeVMProxyRules(guestIp, config.proxy.port);
@@ -9498,7 +10724,7 @@ var startCommand = new Command("start").description("Start the runner").option("
9498
10724
  `Network proxy not available: ${err instanceof Error ? err.message : "Unknown error"}`
9499
10725
  );
9500
10726
  console.warn(
9501
- "Jobs with experimentalNetworkSecurity enabled will run without network interception"
10727
+ "Jobs with experimentalFirewall enabled will run without network interception"
9502
10728
  );
9503
10729
  }
9504
10730
  const statusFilePath = join(dirname(options.config), "status.json");
@@ -9647,7 +10873,7 @@ var statusCommand = new Command2("status").description("Check runner connectivit
9647
10873
  });
9648
10874
 
9649
10875
  // src/index.ts
9650
- var version = true ? "2.3.1" : "0.1.0";
10876
+ var version = true ? "2.4.0" : "0.1.0";
9651
10877
  program.name("vm0-runner").version(version).description("Self-hosted runner for VM0 agents");
9652
10878
  program.addCommand(startCommand);
9653
10879
  program.addCommand(statusCommand);