@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.
- package/index.js +1909 -683
- 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
|
|
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
|
-
|
|
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 =
|
|
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 =
|
|
4833
|
-
name:
|
|
4834
|
-
version:
|
|
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 =
|
|
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 =
|
|
4848
|
-
description:
|
|
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:
|
|
4854
|
-
provider:
|
|
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:
|
|
4862
|
-
volumes:
|
|
4863
|
-
working_dir:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
4888
|
-
group:
|
|
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 =
|
|
4895
|
-
version:
|
|
4896
|
-
agents:
|
|
4897
|
-
volumes:
|
|
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 =
|
|
4900
|
-
id:
|
|
4901
|
-
name:
|
|
4902
|
-
headVersionId:
|
|
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:
|
|
4905
|
-
updatedAt:
|
|
5028
|
+
createdAt: z5.string(),
|
|
5029
|
+
updatedAt: z5.string()
|
|
4906
5030
|
});
|
|
4907
|
-
var createComposeResponseSchema =
|
|
4908
|
-
composeId:
|
|
4909
|
-
name:
|
|
4910
|
-
versionId:
|
|
4911
|
-
action:
|
|
4912
|
-
updatedAt:
|
|
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 =
|
|
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:
|
|
4924
|
-
name:
|
|
4925
|
-
scope:
|
|
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:
|
|
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 =
|
|
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:
|
|
4965
|
-
id:
|
|
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 =
|
|
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:
|
|
4984
|
-
composeId:
|
|
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:
|
|
4989
|
-
versionId:
|
|
4990
|
-
tag:
|
|
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
|
|
5002
|
-
var
|
|
5003
|
-
var runStatusSchema =
|
|
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 =
|
|
5161
|
+
var unifiedRunRequestSchema = z6.object({
|
|
5011
5162
|
// High-level shortcuts (mutually exclusive with each other)
|
|
5012
|
-
checkpointId:
|
|
5013
|
-
sessionId:
|
|
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:
|
|
5016
|
-
agentComposeVersionId:
|
|
5017
|
-
conversationId:
|
|
5018
|
-
artifactName:
|
|
5019
|
-
artifactVersion:
|
|
5020
|
-
vars:
|
|
5021
|
-
secrets:
|
|
5022
|
-
volumeVersions:
|
|
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:
|
|
5175
|
+
prompt: z6.string().min(1, "Missing prompt")
|
|
5025
5176
|
});
|
|
5026
|
-
var createRunResponseSchema =
|
|
5027
|
-
runId:
|
|
5177
|
+
var createRunResponseSchema = z6.object({
|
|
5178
|
+
runId: z6.string(),
|
|
5028
5179
|
status: runStatusSchema,
|
|
5029
|
-
sandboxId:
|
|
5030
|
-
output:
|
|
5031
|
-
error:
|
|
5032
|
-
executionTimeMs:
|
|
5033
|
-
createdAt:
|
|
5034
|
-
});
|
|
5035
|
-
var getRunResponseSchema =
|
|
5036
|
-
runId:
|
|
5037
|
-
agentComposeVersionId:
|
|
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:
|
|
5040
|
-
vars:
|
|
5041
|
-
sandboxId:
|
|
5042
|
-
result:
|
|
5043
|
-
output:
|
|
5044
|
-
executionTimeMs:
|
|
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:
|
|
5047
|
-
createdAt:
|
|
5048
|
-
startedAt:
|
|
5049
|
-
completedAt:
|
|
5050
|
-
});
|
|
5051
|
-
var runEventSchema =
|
|
5052
|
-
sequenceNumber:
|
|
5053
|
-
eventType:
|
|
5054
|
-
eventData:
|
|
5055
|
-
createdAt:
|
|
5056
|
-
});
|
|
5057
|
-
var runResultSchema =
|
|
5058
|
-
checkpointId:
|
|
5059
|
-
agentSessionId:
|
|
5060
|
-
conversationId:
|
|
5061
|
-
artifact:
|
|
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:
|
|
5214
|
+
volumes: z6.record(z6.string(), z6.string()).optional()
|
|
5064
5215
|
});
|
|
5065
|
-
var runStateSchema =
|
|
5216
|
+
var runStateSchema = z6.object({
|
|
5066
5217
|
status: runStatusSchema,
|
|
5067
5218
|
result: runResultSchema.optional(),
|
|
5068
|
-
error:
|
|
5219
|
+
error: z6.string().optional()
|
|
5069
5220
|
});
|
|
5070
|
-
var eventsResponseSchema =
|
|
5071
|
-
events:
|
|
5072
|
-
hasMore:
|
|
5073
|
-
nextSequence:
|
|
5221
|
+
var eventsResponseSchema = z6.object({
|
|
5222
|
+
events: z6.array(runEventSchema),
|
|
5223
|
+
hasMore: z6.boolean(),
|
|
5224
|
+
nextSequence: z6.number(),
|
|
5074
5225
|
run: runStateSchema,
|
|
5075
|
-
provider:
|
|
5226
|
+
provider: z6.string()
|
|
5076
5227
|
});
|
|
5077
|
-
var runsMainContract =
|
|
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 =
|
|
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:
|
|
5104
|
-
id:
|
|
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 =
|
|
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:
|
|
5124
|
-
id:
|
|
5274
|
+
pathParams: z6.object({
|
|
5275
|
+
id: z6.string().min(1, "Run ID is required")
|
|
5125
5276
|
}),
|
|
5126
|
-
query:
|
|
5127
|
-
since:
|
|
5128
|
-
limit:
|
|
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 =
|
|
5139
|
-
ts:
|
|
5140
|
-
cpu:
|
|
5141
|
-
mem_used:
|
|
5142
|
-
mem_total:
|
|
5143
|
-
disk_used:
|
|
5144
|
-
disk_total:
|
|
5145
|
-
});
|
|
5146
|
-
var systemLogResponseSchema =
|
|
5147
|
-
systemLog:
|
|
5148
|
-
hasMore:
|
|
5149
|
-
});
|
|
5150
|
-
var metricsResponseSchema =
|
|
5151
|
-
metrics:
|
|
5152
|
-
hasMore:
|
|
5153
|
-
});
|
|
5154
|
-
var agentEventsResponseSchema =
|
|
5155
|
-
events:
|
|
5156
|
-
hasMore:
|
|
5157
|
-
provider:
|
|
5158
|
-
});
|
|
5159
|
-
var networkLogEntrySchema =
|
|
5160
|
-
timestamp:
|
|
5161
|
-
method:
|
|
5162
|
-
url:
|
|
5163
|
-
status:
|
|
5164
|
-
latency_ms:
|
|
5165
|
-
request_size:
|
|
5166
|
-
response_size:
|
|
5167
|
-
});
|
|
5168
|
-
var networkLogsResponseSchema =
|
|
5169
|
-
networkLogs:
|
|
5170
|
-
hasMore:
|
|
5171
|
-
});
|
|
5172
|
-
var telemetryResponseSchema =
|
|
5173
|
-
systemLog:
|
|
5174
|
-
metrics:
|
|
5175
|
-
});
|
|
5176
|
-
var runTelemetryContract =
|
|
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:
|
|
5185
|
-
id:
|
|
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 =
|
|
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:
|
|
5204
|
-
id:
|
|
5354
|
+
pathParams: z6.object({
|
|
5355
|
+
id: z6.string().min(1, "Run ID is required")
|
|
5205
5356
|
}),
|
|
5206
|
-
query:
|
|
5207
|
-
since:
|
|
5208
|
-
limit:
|
|
5209
|
-
order:
|
|
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 =
|
|
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:
|
|
5228
|
-
id:
|
|
5378
|
+
pathParams: z6.object({
|
|
5379
|
+
id: z6.string().min(1, "Run ID is required")
|
|
5229
5380
|
}),
|
|
5230
|
-
query:
|
|
5231
|
-
since:
|
|
5232
|
-
limit:
|
|
5233
|
-
order:
|
|
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 =
|
|
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:
|
|
5252
|
-
id:
|
|
5402
|
+
pathParams: z6.object({
|
|
5403
|
+
id: z6.string().min(1, "Run ID is required")
|
|
5253
5404
|
}),
|
|
5254
|
-
query:
|
|
5255
|
-
since:
|
|
5256
|
-
limit:
|
|
5257
|
-
order:
|
|
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 =
|
|
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:
|
|
5276
|
-
id:
|
|
5426
|
+
pathParams: z6.object({
|
|
5427
|
+
id: z6.string().min(1, "Run ID is required")
|
|
5277
5428
|
}),
|
|
5278
|
-
query:
|
|
5279
|
-
since:
|
|
5280
|
-
limit:
|
|
5281
|
-
order:
|
|
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
|
|
5294
|
-
var
|
|
5295
|
-
var storageTypeSchema =
|
|
5296
|
-
var versionQuerySchema =
|
|
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
|
-
|
|
5449
|
+
z7.string().regex(/^[a-f0-9]{8,64}$/i, "Version must be 8-64 hex characters").optional()
|
|
5299
5450
|
);
|
|
5300
|
-
var uploadStorageResponseSchema =
|
|
5301
|
-
name:
|
|
5302
|
-
versionId:
|
|
5303
|
-
size:
|
|
5304
|
-
fileCount:
|
|
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:
|
|
5457
|
+
deduplicated: z7.boolean()
|
|
5307
5458
|
});
|
|
5308
|
-
var storagesContract =
|
|
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:
|
|
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:
|
|
5347
|
-
name:
|
|
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:
|
|
5503
|
+
200: c4.otherResponse({
|
|
5353
5504
|
contentType: "application/gzip",
|
|
5354
|
-
body:
|
|
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 =
|
|
5365
|
-
path:
|
|
5366
|
-
hash:
|
|
5367
|
-
size:
|
|
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 =
|
|
5370
|
-
added:
|
|
5371
|
-
modified:
|
|
5372
|
-
deleted:
|
|
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 =
|
|
5375
|
-
key:
|
|
5376
|
-
presignedUrl:
|
|
5525
|
+
var presignedUploadSchema = z7.object({
|
|
5526
|
+
key: z7.string(),
|
|
5527
|
+
presignedUrl: z7.string().url()
|
|
5377
5528
|
});
|
|
5378
|
-
var storagesPrepareContract =
|
|
5529
|
+
var storagesPrepareContract = c4.router({
|
|
5379
5530
|
prepare: {
|
|
5380
5531
|
method: "POST",
|
|
5381
5532
|
path: "/api/storages/prepare",
|
|
5382
|
-
body:
|
|
5383
|
-
storageName:
|
|
5533
|
+
body: z7.object({
|
|
5534
|
+
storageName: z7.string().min(1, "Storage name is required"),
|
|
5384
5535
|
storageType: storageTypeSchema,
|
|
5385
|
-
files:
|
|
5386
|
-
force:
|
|
5387
|
-
runId:
|
|
5536
|
+
files: z7.array(fileEntryWithHashSchema),
|
|
5537
|
+
force: z7.boolean().optional(),
|
|
5538
|
+
runId: z7.string().optional(),
|
|
5388
5539
|
// For sandbox auth
|
|
5389
|
-
baseVersion:
|
|
5540
|
+
baseVersion: z7.string().optional(),
|
|
5390
5541
|
// For incremental uploads
|
|
5391
5542
|
changes: storageChangesSchema.optional()
|
|
5392
5543
|
}),
|
|
5393
5544
|
responses: {
|
|
5394
|
-
200:
|
|
5395
|
-
versionId:
|
|
5396
|
-
existing:
|
|
5397
|
-
uploads:
|
|
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 =
|
|
5561
|
+
var storagesCommitContract = c4.router({
|
|
5411
5562
|
commit: {
|
|
5412
5563
|
method: "POST",
|
|
5413
5564
|
path: "/api/storages/commit",
|
|
5414
|
-
body:
|
|
5415
|
-
storageName:
|
|
5565
|
+
body: z7.object({
|
|
5566
|
+
storageName: z7.string().min(1, "Storage name is required"),
|
|
5416
5567
|
storageType: storageTypeSchema,
|
|
5417
|
-
versionId:
|
|
5418
|
-
files:
|
|
5419
|
-
runId:
|
|
5420
|
-
message:
|
|
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:
|
|
5424
|
-
success:
|
|
5425
|
-
versionId:
|
|
5426
|
-
storageName:
|
|
5427
|
-
size:
|
|
5428
|
-
fileCount:
|
|
5429
|
-
deduplicated:
|
|
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 =
|
|
5592
|
+
var storagesDownloadContract = c4.router({
|
|
5442
5593
|
download: {
|
|
5443
5594
|
method: "GET",
|
|
5444
5595
|
path: "/api/storages/download",
|
|
5445
|
-
query:
|
|
5446
|
-
name:
|
|
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:
|
|
5453
|
-
|
|
5454
|
-
url:
|
|
5455
|
-
versionId:
|
|
5456
|
-
fileCount:
|
|
5457
|
-
size:
|
|
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
|
-
|
|
5461
|
-
empty:
|
|
5462
|
-
versionId:
|
|
5463
|
-
fileCount:
|
|
5464
|
-
size:
|
|
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 =
|
|
5626
|
+
var storagesListContract = c4.router({
|
|
5476
5627
|
list: {
|
|
5477
5628
|
method: "GET",
|
|
5478
5629
|
path: "/api/storages/list",
|
|
5479
|
-
query:
|
|
5630
|
+
query: z7.object({
|
|
5480
5631
|
type: storageTypeSchema
|
|
5481
5632
|
}),
|
|
5482
5633
|
responses: {
|
|
5483
|
-
200:
|
|
5484
|
-
|
|
5485
|
-
name:
|
|
5486
|
-
size:
|
|
5487
|
-
fileCount:
|
|
5488
|
-
updatedAt:
|
|
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
|
|
5500
|
-
var
|
|
5501
|
-
var agentEventSchema =
|
|
5502
|
-
type:
|
|
5503
|
-
sequenceNumber:
|
|
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 =
|
|
5506
|
-
artifactName:
|
|
5507
|
-
artifactVersion:
|
|
5656
|
+
var artifactSnapshotSchema = z8.object({
|
|
5657
|
+
artifactName: z8.string(),
|
|
5658
|
+
artifactVersion: z8.string()
|
|
5508
5659
|
});
|
|
5509
|
-
var volumeVersionsSnapshotSchema =
|
|
5510
|
-
versions:
|
|
5660
|
+
var volumeVersionsSnapshotSchema = z8.object({
|
|
5661
|
+
versions: z8.record(z8.string(), z8.string())
|
|
5511
5662
|
});
|
|
5512
|
-
var webhookEventsContract =
|
|
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:
|
|
5521
|
-
runId:
|
|
5522
|
-
events:
|
|
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:
|
|
5526
|
-
received:
|
|
5527
|
-
firstSequence:
|
|
5528
|
-
lastSequence:
|
|
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 =
|
|
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:
|
|
5547
|
-
runId:
|
|
5548
|
-
exitCode:
|
|
5549
|
-
error:
|
|
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:
|
|
5553
|
-
success:
|
|
5554
|
-
status:
|
|
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 =
|
|
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:
|
|
5573
|
-
runId:
|
|
5574
|
-
cliAgentType:
|
|
5575
|
-
cliAgentSessionId:
|
|
5576
|
-
cliAgentSessionHistory:
|
|
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:
|
|
5582
|
-
checkpointId:
|
|
5583
|
-
agentSessionId:
|
|
5584
|
-
conversationId:
|
|
5732
|
+
200: z8.object({
|
|
5733
|
+
checkpointId: z8.string(),
|
|
5734
|
+
agentSessionId: z8.string(),
|
|
5735
|
+
conversationId: z8.string(),
|
|
5585
5736
|
artifact: artifactSnapshotSchema.optional(),
|
|
5586
|
-
volumes:
|
|
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 =
|
|
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:
|
|
5605
|
-
runId:
|
|
5755
|
+
body: z8.object({
|
|
5756
|
+
runId: z8.string().min(1, "runId is required")
|
|
5606
5757
|
}),
|
|
5607
5758
|
responses: {
|
|
5608
|
-
200:
|
|
5609
|
-
ok:
|
|
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 =
|
|
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:
|
|
5785
|
+
body: c5.type(),
|
|
5635
5786
|
responses: {
|
|
5636
|
-
200:
|
|
5637
|
-
versionId:
|
|
5638
|
-
storageName:
|
|
5639
|
-
size:
|
|
5640
|
-
fileCount:
|
|
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 =
|
|
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:
|
|
5818
|
+
body: c5.type(),
|
|
5668
5819
|
responses: {
|
|
5669
|
-
200:
|
|
5670
|
-
versionId:
|
|
5671
|
-
storageName:
|
|
5672
|
-
size:
|
|
5673
|
-
fileCount:
|
|
5674
|
-
incrementalStats:
|
|
5675
|
-
addedFiles:
|
|
5676
|
-
modifiedFiles:
|
|
5677
|
-
deletedFiles:
|
|
5678
|
-
unchangedFiles:
|
|
5679
|
-
bytesUploaded:
|
|
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 =
|
|
5691
|
-
ts:
|
|
5692
|
-
cpu:
|
|
5693
|
-
mem_used:
|
|
5694
|
-
mem_total:
|
|
5695
|
-
disk_used:
|
|
5696
|
-
disk_total:
|
|
5697
|
-
});
|
|
5698
|
-
var networkLogSchema =
|
|
5699
|
-
timestamp:
|
|
5700
|
-
method:
|
|
5701
|
-
url:
|
|
5702
|
-
status:
|
|
5703
|
-
latency_ms:
|
|
5704
|
-
request_size:
|
|
5705
|
-
response_size:
|
|
5706
|
-
});
|
|
5707
|
-
var webhookTelemetryContract =
|
|
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:
|
|
5716
|
-
runId:
|
|
5717
|
-
systemLog:
|
|
5718
|
-
metrics:
|
|
5719
|
-
networkLogs:
|
|
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:
|
|
5723
|
-
success:
|
|
5724
|
-
id:
|
|
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 =
|
|
5885
|
+
var webhookStoragesPrepareContract = c5.router({
|
|
5735
5886
|
prepare: {
|
|
5736
5887
|
method: "POST",
|
|
5737
5888
|
path: "/api/webhooks/agent/storages/prepare",
|
|
5738
|
-
body:
|
|
5739
|
-
runId:
|
|
5889
|
+
body: z8.object({
|
|
5890
|
+
runId: z8.string().min(1, "runId is required"),
|
|
5740
5891
|
// Required for webhook auth
|
|
5741
|
-
storageName:
|
|
5892
|
+
storageName: z8.string().min(1, "Storage name is required"),
|
|
5742
5893
|
storageType: storageTypeSchema,
|
|
5743
|
-
files:
|
|
5744
|
-
force:
|
|
5745
|
-
baseVersion:
|
|
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:
|
|
5750
|
-
versionId:
|
|
5751
|
-
existing:
|
|
5752
|
-
uploads:
|
|
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 =
|
|
5916
|
+
var webhookStoragesCommitContract = c5.router({
|
|
5766
5917
|
commit: {
|
|
5767
5918
|
method: "POST",
|
|
5768
5919
|
path: "/api/webhooks/agent/storages/commit",
|
|
5769
|
-
body:
|
|
5770
|
-
runId:
|
|
5920
|
+
body: z8.object({
|
|
5921
|
+
runId: z8.string().min(1, "runId is required"),
|
|
5771
5922
|
// Required for webhook auth
|
|
5772
|
-
storageName:
|
|
5923
|
+
storageName: z8.string().min(1, "Storage name is required"),
|
|
5773
5924
|
storageType: storageTypeSchema,
|
|
5774
|
-
versionId:
|
|
5775
|
-
files:
|
|
5776
|
-
message:
|
|
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:
|
|
5780
|
-
success:
|
|
5781
|
-
versionId:
|
|
5782
|
-
storageName:
|
|
5783
|
-
size:
|
|
5784
|
-
fileCount:
|
|
5785
|
-
deduplicated:
|
|
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
|
|
5800
|
-
var
|
|
5801
|
-
var oauthErrorSchema =
|
|
5802
|
-
error:
|
|
5803
|
-
error_description:
|
|
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 =
|
|
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:
|
|
5964
|
+
body: z9.object({}).optional(),
|
|
5814
5965
|
responses: {
|
|
5815
|
-
200:
|
|
5816
|
-
device_code:
|
|
5817
|
-
user_code:
|
|
5818
|
-
verification_url:
|
|
5819
|
-
expires_in:
|
|
5820
|
-
interval:
|
|
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 =
|
|
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:
|
|
5836
|
-
device_code:
|
|
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:
|
|
5841
|
-
access_token:
|
|
5842
|
-
refresh_token:
|
|
5843
|
-
token_type:
|
|
5844
|
-
expires_in:
|
|
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
|
|
5858
|
-
var
|
|
5859
|
-
var authContract =
|
|
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:
|
|
5869
|
-
userId:
|
|
5870
|
-
email:
|
|
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
|
|
5882
|
-
var
|
|
5883
|
-
var cleanupResultSchema =
|
|
5884
|
-
runId:
|
|
5885
|
-
sandboxId:
|
|
5886
|
-
status:
|
|
5887
|
-
error:
|
|
5888
|
-
});
|
|
5889
|
-
var cleanupResponseSchema =
|
|
5890
|
-
cleaned:
|
|
5891
|
-
errors:
|
|
5892
|
-
results:
|
|
5893
|
-
});
|
|
5894
|
-
var cronCleanupSandboxesContract =
|
|
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: "
|
|
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/
|
|
5912
|
-
import { z as
|
|
5913
|
-
var
|
|
5914
|
-
|
|
5915
|
-
|
|
5916
|
-
|
|
5917
|
-
|
|
5918
|
-
|
|
5919
|
-
|
|
5920
|
-
|
|
5921
|
-
|
|
5922
|
-
|
|
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
|
-
|
|
5927
|
-
|
|
5928
|
-
|
|
5929
|
-
|
|
5930
|
-
|
|
5931
|
-
|
|
5932
|
-
|
|
5933
|
-
|
|
5934
|
-
|
|
5935
|
-
|
|
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
|
|
5946
|
-
|
|
5947
|
-
displayName: z12.string().max(128).optional()
|
|
6882
|
+
var publicVolumeDetailSchema = publicVolumeSchema.extend({
|
|
6883
|
+
current_version: volumeVersionSchema.nullable()
|
|
5948
6884
|
});
|
|
5949
|
-
var
|
|
5950
|
-
|
|
5951
|
-
|
|
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
|
|
5954
|
-
|
|
5955
|
-
|
|
5956
|
-
|
|
5957
|
-
|
|
5958
|
-
|
|
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: "/
|
|
6935
|
+
path: "/v1/volumes",
|
|
6936
|
+
query: listQuerySchema,
|
|
5961
6937
|
responses: {
|
|
5962
|
-
200:
|
|
5963
|
-
401:
|
|
5964
|
-
|
|
5965
|
-
500: apiErrorSchema
|
|
6938
|
+
200: paginatedVolumesSchema,
|
|
6939
|
+
401: publicApiErrorSchema,
|
|
6940
|
+
500: publicApiErrorSchema
|
|
5966
6941
|
},
|
|
5967
|
-
summary: "
|
|
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: "/
|
|
5976
|
-
body:
|
|
6947
|
+
path: "/v1/volumes",
|
|
6948
|
+
body: createVolumeRequestSchema,
|
|
5977
6949
|
responses: {
|
|
5978
|
-
201:
|
|
5979
|
-
400:
|
|
5980
|
-
401:
|
|
5981
|
-
409:
|
|
5982
|
-
500:
|
|
6950
|
+
201: publicVolumeDetailSchema,
|
|
6951
|
+
400: publicApiErrorSchema,
|
|
6952
|
+
401: publicApiErrorSchema,
|
|
6953
|
+
409: publicApiErrorSchema,
|
|
6954
|
+
500: publicApiErrorSchema
|
|
5983
6955
|
},
|
|
5984
|
-
summary: "Create
|
|
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
|
-
|
|
5988
|
-
|
|
5989
|
-
|
|
5990
|
-
|
|
5991
|
-
|
|
5992
|
-
|
|
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
|
-
|
|
5996
|
-
|
|
5997
|
-
|
|
5998
|
-
|
|
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: "
|
|
6989
|
+
summary: "Delete volume",
|
|
6990
|
+
description: "Delete a volume and all its versions"
|
|
6004
6991
|
}
|
|
6005
6992
|
});
|
|
6006
|
-
|
|
6007
|
-
|
|
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: "/
|
|
6051
|
-
pathParams:
|
|
6052
|
-
id:
|
|
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:
|
|
6056
|
-
401:
|
|
6057
|
-
|
|
6058
|
-
|
|
7002
|
+
200: paginatedVolumeVersionsSchema,
|
|
7003
|
+
401: publicApiErrorSchema,
|
|
7004
|
+
404: publicApiErrorSchema,
|
|
7005
|
+
500: publicApiErrorSchema
|
|
6059
7006
|
},
|
|
6060
|
-
summary: "
|
|
7007
|
+
summary: "List volume versions",
|
|
7008
|
+
description: "List all versions of a volume with pagination"
|
|
6061
7009
|
}
|
|
6062
7010
|
});
|
|
6063
|
-
var
|
|
6064
|
-
|
|
6065
|
-
|
|
6066
|
-
|
|
6067
|
-
|
|
6068
|
-
|
|
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:
|
|
6076
|
-
|
|
6077
|
-
|
|
6078
|
-
404:
|
|
7020
|
+
200: prepareUploadResponseSchema2,
|
|
7021
|
+
400: publicApiErrorSchema,
|
|
7022
|
+
401: publicApiErrorSchema,
|
|
7023
|
+
404: publicApiErrorSchema,
|
|
7024
|
+
500: publicApiErrorSchema
|
|
6079
7025
|
},
|
|
6080
|
-
summary: "
|
|
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
|
-
|
|
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: "/
|
|
6103
|
-
|
|
6104
|
-
|
|
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:
|
|
6108
|
-
|
|
6109
|
-
|
|
6110
|
-
|
|
6111
|
-
|
|
6112
|
-
500: apiErrorSchema
|
|
7039
|
+
200: volumeVersionSchema,
|
|
7040
|
+
400: publicApiErrorSchema,
|
|
7041
|
+
401: publicApiErrorSchema,
|
|
7042
|
+
404: publicApiErrorSchema,
|
|
7043
|
+
500: publicApiErrorSchema
|
|
6113
7044
|
},
|
|
6114
|
-
summary: "
|
|
7045
|
+
summary: "Commit volume upload",
|
|
7046
|
+
description: "Finalize an upload session and create a new volume version."
|
|
6115
7047
|
}
|
|
6116
7048
|
});
|
|
6117
|
-
var
|
|
6118
|
-
|
|
6119
|
-
|
|
6120
|
-
|
|
6121
|
-
|
|
6122
|
-
|
|
6123
|
-
|
|
6124
|
-
|
|
6125
|
-
|
|
6126
|
-
|
|
6127
|
-
|
|
6128
|
-
|
|
6129
|
-
|
|
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
|
-
|
|
6132
|
-
|
|
6133
|
-
|
|
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
|
|
6136
|
-
|
|
6137
|
-
|
|
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
|
|
6146
|
-
|
|
6147
|
-
|
|
6148
|
-
|
|
6149
|
-
|
|
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
|
|
6164
|
-
|
|
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: "/
|
|
6167
|
-
|
|
6168
|
-
|
|
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:
|
|
6173
|
-
|
|
6174
|
-
401:
|
|
6175
|
-
|
|
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: "
|
|
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
|
-
|
|
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.
|
|
8689
|
-
4.
|
|
8690
|
-
5.
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
8784
|
-
|
|
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
|
|
8835
|
-
ctx.log.info(f"[{run_id}] Skipping trusted domain: {
|
|
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
|
-
|
|
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
|
-
"
|
|
8896
|
-
"
|
|
8897
|
-
"
|
|
8898
|
-
"
|
|
8899
|
-
"
|
|
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}]
|
|
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.
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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.
|
|
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
|
|
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.
|
|
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);
|