@aexhq/sdk 0.13.6
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/LICENSE +201 -0
- package/README.md +160 -0
- package/dist/_contracts/connection-ticket.d.ts +21 -0
- package/dist/_contracts/connection-ticket.js +49 -0
- package/dist/_contracts/event-envelope.d.ts +276 -0
- package/dist/_contracts/event-envelope.js +324 -0
- package/dist/_contracts/event-stream-client.d.ts +47 -0
- package/dist/_contracts/event-stream-client.js +141 -0
- package/dist/_contracts/http.d.ts +35 -0
- package/dist/_contracts/http.js +114 -0
- package/dist/_contracts/index.d.ts +28 -0
- package/dist/_contracts/index.js +29 -0
- package/dist/_contracts/managed-key.d.ts +74 -0
- package/dist/_contracts/managed-key.js +110 -0
- package/dist/_contracts/operations.d.ts +237 -0
- package/dist/_contracts/operations.js +632 -0
- package/dist/_contracts/provider-support.d.ts +220 -0
- package/dist/_contracts/provider-support.js +90 -0
- package/dist/_contracts/proxy-protocol.d.ts +257 -0
- package/dist/_contracts/proxy-protocol.js +234 -0
- package/dist/_contracts/proxy-validation.d.ts +19 -0
- package/dist/_contracts/proxy-validation.js +51 -0
- package/dist/_contracts/run-artifacts.d.ts +47 -0
- package/dist/_contracts/run-artifacts.js +101 -0
- package/dist/_contracts/run-config.d.ts +304 -0
- package/dist/_contracts/run-config.js +659 -0
- package/dist/_contracts/run-cost.d.ts +125 -0
- package/dist/_contracts/run-cost.js +616 -0
- package/dist/_contracts/run-custody.d.ts +226 -0
- package/dist/_contracts/run-custody.js +465 -0
- package/dist/_contracts/run-record.d.ts +127 -0
- package/dist/_contracts/run-record.js +177 -0
- package/dist/_contracts/run-retention.d.ts +213 -0
- package/dist/_contracts/run-retention.js +484 -0
- package/dist/_contracts/run-unit.d.ts +194 -0
- package/dist/_contracts/run-unit.js +215 -0
- package/dist/_contracts/runner-event.d.ts +114 -0
- package/dist/_contracts/runner-event.js +187 -0
- package/dist/_contracts/runtime-manifest.d.ts +106 -0
- package/dist/_contracts/runtime-manifest.js +98 -0
- package/dist/_contracts/runtime-security-profile.d.ts +27 -0
- package/dist/_contracts/runtime-security-profile.js +82 -0
- package/dist/_contracts/runtime-sizes.d.ts +144 -0
- package/dist/_contracts/runtime-sizes.js +136 -0
- package/dist/_contracts/runtime-types.d.ts +212 -0
- package/dist/_contracts/runtime-types.js +2 -0
- package/dist/_contracts/sdk-errors.d.ts +34 -0
- package/dist/_contracts/sdk-errors.js +52 -0
- package/dist/_contracts/sdk-secrets.d.ts +31 -0
- package/dist/_contracts/sdk-secrets.js +220 -0
- package/dist/_contracts/side-effect-audit.d.ts +129 -0
- package/dist/_contracts/side-effect-audit.js +494 -0
- package/dist/_contracts/sse.d.ts +74 -0
- package/dist/_contracts/sse.js +0 -0
- package/dist/_contracts/stable.d.ts +26 -0
- package/dist/_contracts/stable.js +44 -0
- package/dist/_contracts/status.d.ts +19 -0
- package/dist/_contracts/status.js +61 -0
- package/dist/_contracts/submission.d.ts +383 -0
- package/dist/_contracts/submission.js +1380 -0
- package/dist/agents-md.d.ts +46 -0
- package/dist/agents-md.js +83 -0
- package/dist/agents-md.js.map +1 -0
- package/dist/asset-upload.d.ts +66 -0
- package/dist/asset-upload.js +168 -0
- package/dist/asset-upload.js.map +1 -0
- package/dist/bundle.d.ts +33 -0
- package/dist/bundle.js +89 -0
- package/dist/bundle.js.map +1 -0
- package/dist/cli.mjs +4140 -0
- package/dist/cli.mjs.sha256 +1 -0
- package/dist/client.d.ts +460 -0
- package/dist/client.js +857 -0
- package/dist/client.js.map +1 -0
- package/dist/fetch-archive.d.ts +16 -0
- package/dist/fetch-archive.js +170 -0
- package/dist/fetch-archive.js.map +1 -0
- package/dist/file.d.ts +57 -0
- package/dist/file.js +153 -0
- package/dist/file.js.map +1 -0
- package/dist/index.d.ts +30 -0
- package/dist/index.js +34 -0
- package/dist/index.js.map +1 -0
- package/dist/mcp-server.d.ts +84 -0
- package/dist/mcp-server.js +114 -0
- package/dist/mcp-server.js.map +1 -0
- package/dist/node-fs.d.ts +12 -0
- package/dist/node-fs.js +44 -0
- package/dist/node-fs.js.map +1 -0
- package/dist/proxy-endpoint.d.ts +131 -0
- package/dist/proxy-endpoint.js +147 -0
- package/dist/proxy-endpoint.js.map +1 -0
- package/dist/skill.d.ts +117 -0
- package/dist/skill.js +169 -0
- package/dist/skill.js.map +1 -0
- package/dist/version.d.ts +9 -0
- package/dist/version.js +10 -0
- package/dist/version.js.map +1 -0
- package/docs/cleanup.md +38 -0
- package/docs/credentials.md +153 -0
- package/docs/events.md +76 -0
- package/docs/mcp.md +47 -0
- package/docs/outputs.md +157 -0
- package/docs/product-boundaries.md +57 -0
- package/docs/provider-runtime-capabilities.md +103 -0
- package/docs/quickstart.md +110 -0
- package/docs/release.md +99 -0
- package/docs/run-config.md +53 -0
- package/docs/run-record.md +39 -0
- package/docs/skills.md +139 -0
- package/docs/testing.md +29 -0
- package/package.json +47 -0
package/dist/cli.mjs
ADDED
|
@@ -0,0 +1,4140 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __export = (target, all) => {
|
|
4
|
+
for (var name in all)
|
|
5
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
6
|
+
};
|
|
7
|
+
|
|
8
|
+
// dist/cli.js
|
|
9
|
+
import { readFile as readFile2, writeFile, readdir as readdir2, stat as stat2 } from "node:fs/promises";
|
|
10
|
+
import { resolve as resolvePath4 } from "node:path";
|
|
11
|
+
|
|
12
|
+
// ../contracts/dist/proxy-protocol.js
|
|
13
|
+
var PROXY_PROTOCOL_VERSION = "1";
|
|
14
|
+
var PROXY_PROTOCOL_HEADER = "x-aex-proxy-protocol";
|
|
15
|
+
var PROXY_METHOD_HEADER = "x-aex-method";
|
|
16
|
+
var PROXY_PATH_HEADER = "x-aex-path";
|
|
17
|
+
var PROXY_QUERY_HEADER = "x-aex-query";
|
|
18
|
+
var PROXY_HEADERS_HEADER = "x-aex-headers";
|
|
19
|
+
var PROXY_RESPONSE_MODE_HEADER = "x-aex-response-mode";
|
|
20
|
+
var PROXY_RESPONSE_MODES = ["status_only", "headers_only", "full"];
|
|
21
|
+
var PROXY_ENDPOINT_DEFAULTS = {
|
|
22
|
+
allowHeaders: [],
|
|
23
|
+
responseMode: "headers_only",
|
|
24
|
+
maxRequestBytes: 64 * 1024,
|
|
25
|
+
maxResponseBytes: 1024 * 1024,
|
|
26
|
+
timeoutMs: 1e4,
|
|
27
|
+
perCallBudget: 60,
|
|
28
|
+
responseByteBudget: 1024 * 1024
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
// ../contracts/dist/provider-support.js
|
|
32
|
+
var COMMON_DOCS = [
|
|
33
|
+
{ label: "Credentials", href: "credentials.md" },
|
|
34
|
+
{ label: "Events", href: "events.md" }
|
|
35
|
+
];
|
|
36
|
+
var COMMON_EVIDENCE = [
|
|
37
|
+
{ label: "Submission parser and routing parity", href: "../../contracts/test/submission.test.ts" },
|
|
38
|
+
{ label: "Runtime support validator", href: "../../contracts/test/runtime-support.test.ts" },
|
|
39
|
+
{ label: "Generated matrix freshness", href: "../../../scripts/validate/capability-matrix.test.ts" }
|
|
40
|
+
];
|
|
41
|
+
var LIVE_USER_MATRIX_EVIDENCE = [
|
|
42
|
+
{ label: "Installed-SDK live user matrix", href: "../../../apps/user-tests/test/live/live-sdk-comprehensive.test.ts" }
|
|
43
|
+
];
|
|
44
|
+
var MANAGED_PROXY_EVIDENCE = [
|
|
45
|
+
...LIVE_USER_MATRIX_EVIDENCE,
|
|
46
|
+
{ label: "Runtime support validator", href: "../../contracts/test/runtime-support.test.ts" }
|
|
47
|
+
];
|
|
48
|
+
var PROVIDER_PUBLIC_SUPPORT = {
|
|
49
|
+
anthropic: {
|
|
50
|
+
displayName: "Anthropic",
|
|
51
|
+
status: "supported",
|
|
52
|
+
docsAnchor: "anthropic",
|
|
53
|
+
docs: COMMON_DOCS,
|
|
54
|
+
evidence: [...COMMON_EVIDENCE, ...MANAGED_PROXY_EVIDENCE],
|
|
55
|
+
runtimeEvidence: {
|
|
56
|
+
managed: MANAGED_PROXY_EVIDENCE
|
|
57
|
+
}
|
|
58
|
+
},
|
|
59
|
+
deepseek: {
|
|
60
|
+
displayName: "DeepSeek",
|
|
61
|
+
status: "supported",
|
|
62
|
+
docsAnchor: "deepseek",
|
|
63
|
+
docs: COMMON_DOCS,
|
|
64
|
+
evidence: [...COMMON_EVIDENCE, ...MANAGED_PROXY_EVIDENCE],
|
|
65
|
+
runtimeEvidence: {
|
|
66
|
+
managed: MANAGED_PROXY_EVIDENCE
|
|
67
|
+
}
|
|
68
|
+
},
|
|
69
|
+
openai: {
|
|
70
|
+
displayName: "OpenAI",
|
|
71
|
+
status: "live-unverified",
|
|
72
|
+
docsAnchor: "openai",
|
|
73
|
+
docs: COMMON_DOCS,
|
|
74
|
+
evidence: COMMON_EVIDENCE,
|
|
75
|
+
runtimeEvidence: {
|
|
76
|
+
managed: COMMON_EVIDENCE
|
|
77
|
+
}
|
|
78
|
+
},
|
|
79
|
+
gemini: {
|
|
80
|
+
displayName: "Gemini",
|
|
81
|
+
status: "live-unverified",
|
|
82
|
+
docsAnchor: "gemini",
|
|
83
|
+
docs: COMMON_DOCS,
|
|
84
|
+
evidence: COMMON_EVIDENCE,
|
|
85
|
+
runtimeEvidence: {
|
|
86
|
+
managed: COMMON_EVIDENCE
|
|
87
|
+
}
|
|
88
|
+
},
|
|
89
|
+
mistral: {
|
|
90
|
+
displayName: "Mistral",
|
|
91
|
+
status: "live-unverified",
|
|
92
|
+
docsAnchor: "mistral",
|
|
93
|
+
docs: COMMON_DOCS,
|
|
94
|
+
evidence: COMMON_EVIDENCE,
|
|
95
|
+
runtimeEvidence: {
|
|
96
|
+
managed: COMMON_EVIDENCE
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
};
|
|
100
|
+
|
|
101
|
+
// ../contracts/dist/status.js
|
|
102
|
+
var TERMINAL_RUN_STATUSES = [
|
|
103
|
+
"succeeded",
|
|
104
|
+
"failed",
|
|
105
|
+
"timed_out",
|
|
106
|
+
"cancelled",
|
|
107
|
+
"cleanup_failed",
|
|
108
|
+
"pending_delete",
|
|
109
|
+
"deleted"
|
|
110
|
+
];
|
|
111
|
+
var terminalRunStatuses = new Set(TERMINAL_RUN_STATUSES);
|
|
112
|
+
|
|
113
|
+
// ../contracts/dist/run-config.js
|
|
114
|
+
var SKILL_BUNDLE_LIMITS = {
|
|
115
|
+
/** Compressed (.zip) ceiling. */
|
|
116
|
+
maxCompressedBytes: 10 * 1024 * 1024,
|
|
117
|
+
/** Sum of uncompressed file sizes. */
|
|
118
|
+
maxDecompressedBytes: 50 * 1024 * 1024,
|
|
119
|
+
/** Number of regular file entries (directories don't count). */
|
|
120
|
+
maxFiles: 1e3,
|
|
121
|
+
/** Maximum directory nesting depth — `a/b/c/d` has depth 4. */
|
|
122
|
+
maxDepth: 16,
|
|
123
|
+
/** Single-entry path length cap. */
|
|
124
|
+
maxPathLength: 512,
|
|
125
|
+
/** Stored file mode for ordinary files. */
|
|
126
|
+
defaultFileMode: 420,
|
|
127
|
+
/** Stored directory mode. */
|
|
128
|
+
defaultDirMode: 493
|
|
129
|
+
};
|
|
130
|
+
var ASSET_ID_PATTERN = /^asset_[A-Za-z0-9_-]{8,128}$/;
|
|
131
|
+
function parseSkillRef(input, path) {
|
|
132
|
+
if (input === null || typeof input !== "object" || Array.isArray(input)) {
|
|
133
|
+
throw new Error(`${path} must be a SkillRef object`);
|
|
134
|
+
}
|
|
135
|
+
const record = input;
|
|
136
|
+
const kind = record.kind;
|
|
137
|
+
if (kind === "provider") {
|
|
138
|
+
for (const key of Object.keys(record)) {
|
|
139
|
+
if (key !== "kind" && key !== "vendor" && key !== "skillId" && key !== "version") {
|
|
140
|
+
throw new Error(`${path} contains unexpected field for provider SkillRef: ${key}`);
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
const vendor = record.vendor;
|
|
144
|
+
if (vendor !== "anthropic" && vendor !== "custom") {
|
|
145
|
+
throw new Error(`${path}.vendor must be 'anthropic' or 'custom'`);
|
|
146
|
+
}
|
|
147
|
+
const skillId = record.skillId;
|
|
148
|
+
if (typeof skillId !== "string" || skillId.length === 0 || skillId.length > 256) {
|
|
149
|
+
throw new Error(`${path}.skillId must be a non-empty string (<= 256 chars)`);
|
|
150
|
+
}
|
|
151
|
+
const version = record.version;
|
|
152
|
+
if (version !== void 0 && (typeof version !== "string" || version.length === 0 || version.length > 64)) {
|
|
153
|
+
throw new Error(`${path}.version, when provided, must be a non-empty string (<= 64 chars)`);
|
|
154
|
+
}
|
|
155
|
+
return {
|
|
156
|
+
kind: "provider",
|
|
157
|
+
vendor,
|
|
158
|
+
skillId,
|
|
159
|
+
...version !== void 0 ? { version } : {}
|
|
160
|
+
};
|
|
161
|
+
}
|
|
162
|
+
if (kind === "asset") {
|
|
163
|
+
return parseAssetRefFields(record, path);
|
|
164
|
+
}
|
|
165
|
+
throw new Error(`${path}.kind must be 'provider' or 'asset'`);
|
|
166
|
+
}
|
|
167
|
+
function parseAssetRefFields(record, path) {
|
|
168
|
+
for (const key of Object.keys(record)) {
|
|
169
|
+
if (key !== "kind" && key !== "assetId" && key !== "name" && key !== "mountPath") {
|
|
170
|
+
throw new Error(`${path} contains unexpected field for asset ref: ${key}`);
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
const assetId = record.assetId;
|
|
174
|
+
if (typeof assetId !== "string" || !ASSET_ID_PATTERN.test(assetId)) {
|
|
175
|
+
throw new Error(`${path}.assetId must match ${ASSET_ID_PATTERN.source}`);
|
|
176
|
+
}
|
|
177
|
+
const name = record.name;
|
|
178
|
+
if (typeof name !== "string" || name.length === 0 || name.length > 128) {
|
|
179
|
+
throw new Error(`${path}.name must be a non-empty string (<= 128 chars)`);
|
|
180
|
+
}
|
|
181
|
+
const mountPath = record.mountPath;
|
|
182
|
+
if (mountPath !== void 0 && (typeof mountPath !== "string" || mountPath.length === 0)) {
|
|
183
|
+
throw new Error(`${path}.mountPath, when provided, must be a non-empty string`);
|
|
184
|
+
}
|
|
185
|
+
return {
|
|
186
|
+
kind: "asset",
|
|
187
|
+
assetId,
|
|
188
|
+
name,
|
|
189
|
+
...mountPath !== void 0 ? { mountPath } : {}
|
|
190
|
+
};
|
|
191
|
+
}
|
|
192
|
+
var SkillBundleValidationError = class extends Error {
|
|
193
|
+
constructor(message) {
|
|
194
|
+
super(message);
|
|
195
|
+
this.name = "SkillBundleValidationError";
|
|
196
|
+
}
|
|
197
|
+
};
|
|
198
|
+
function normaliseSkillBundlePath(input) {
|
|
199
|
+
if (typeof input !== "string") {
|
|
200
|
+
throw new SkillBundleValidationError("bundle entry path must be a string");
|
|
201
|
+
}
|
|
202
|
+
if (input.length === 0 || input.trim().length === 0) {
|
|
203
|
+
throw new SkillBundleValidationError("bundle entry path must be non-empty");
|
|
204
|
+
}
|
|
205
|
+
if (input.length > SKILL_BUNDLE_LIMITS.maxPathLength) {
|
|
206
|
+
throw new SkillBundleValidationError(`bundle entry path exceeds maxPathLength (${SKILL_BUNDLE_LIMITS.maxPathLength}): ${input}`);
|
|
207
|
+
}
|
|
208
|
+
if (input.includes("\0")) {
|
|
209
|
+
throw new SkillBundleValidationError(`bundle entry path contains NUL byte: ${JSON.stringify(input)}`);
|
|
210
|
+
}
|
|
211
|
+
if (input.includes("\\")) {
|
|
212
|
+
throw new SkillBundleValidationError(`bundle entry path uses backslash separator: ${input}`);
|
|
213
|
+
}
|
|
214
|
+
if (/^[A-Za-z]:[\\/]/.test(input)) {
|
|
215
|
+
throw new SkillBundleValidationError(`bundle entry path uses a drive letter: ${input}`);
|
|
216
|
+
}
|
|
217
|
+
if (input.startsWith("/")) {
|
|
218
|
+
throw new SkillBundleValidationError(`bundle entry path must be relative: ${input}`);
|
|
219
|
+
}
|
|
220
|
+
if (input.endsWith("/")) {
|
|
221
|
+
throw new SkillBundleValidationError(`bundle entry path must not end with '/': ${input}`);
|
|
222
|
+
}
|
|
223
|
+
const segments = input.split("/");
|
|
224
|
+
for (const segment of segments) {
|
|
225
|
+
if (segment === "..") {
|
|
226
|
+
throw new SkillBundleValidationError(`bundle entry path contains '..' segment: ${input}`);
|
|
227
|
+
}
|
|
228
|
+
if (segment === "." || segment === "") {
|
|
229
|
+
throw new SkillBundleValidationError(`bundle entry path contains empty or '.' segment: ${input}`);
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
if (segments.length > SKILL_BUNDLE_LIMITS.maxDepth) {
|
|
233
|
+
throw new SkillBundleValidationError(`bundle entry path exceeds maxDepth (${SKILL_BUNDLE_LIMITS.maxDepth}): ${input}`);
|
|
234
|
+
}
|
|
235
|
+
return input;
|
|
236
|
+
}
|
|
237
|
+
function validateSkillBundleEntry(input) {
|
|
238
|
+
const path = normaliseSkillBundlePath(input.path);
|
|
239
|
+
if (!Number.isFinite(input.size) || !Number.isInteger(input.size) || input.size < 0) {
|
|
240
|
+
throw new SkillBundleValidationError(`bundle entry size must be a non-negative integer (${path})`);
|
|
241
|
+
}
|
|
242
|
+
if (input.size > SKILL_BUNDLE_LIMITS.maxDecompressedBytes) {
|
|
243
|
+
throw new SkillBundleValidationError(`bundle entry size exceeds maxDecompressedBytes (${SKILL_BUNDLE_LIMITS.maxDecompressedBytes}): ${path}`);
|
|
244
|
+
}
|
|
245
|
+
const mode = (input.mode ?? SKILL_BUNDLE_LIMITS.defaultFileMode) & 511;
|
|
246
|
+
if (mode !== SKILL_BUNDLE_LIMITS.defaultFileMode && mode !== SKILL_BUNDLE_LIMITS.defaultDirMode) {
|
|
247
|
+
return { path, size: input.size, mode: SKILL_BUNDLE_LIMITS.defaultFileMode };
|
|
248
|
+
}
|
|
249
|
+
return { path, size: input.size, mode };
|
|
250
|
+
}
|
|
251
|
+
var REMOTE_MCP_TRANSPORTS = ["http", "sse"];
|
|
252
|
+
var REMOTE_MCP_STDIO_REJECTED_MESSAGE = "stdio MCP servers are not supported by Aex. Aex supports remote MCP servers over HTTP/SSE only.";
|
|
253
|
+
var STDIO_ONLY_FIELDS = ["command", "args", "env"];
|
|
254
|
+
var MCP_SERVER_NAME_PATTERN = /^[a-z][a-z0-9_-]{0,62}$/;
|
|
255
|
+
function parseMcpServerRef(input, path) {
|
|
256
|
+
if (input === null || typeof input !== "object" || Array.isArray(input)) {
|
|
257
|
+
throw new Error(`${path} must be an object`);
|
|
258
|
+
}
|
|
259
|
+
const record = input;
|
|
260
|
+
rejectStdioMcpShape(record);
|
|
261
|
+
for (const key of Object.keys(record)) {
|
|
262
|
+
if (key !== "name" && key !== "url" && key !== "transport") {
|
|
263
|
+
throw new Error(`${path}.${key} is not an allowed field for McpServerRef; permitted: name, url, transport`);
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
const name = record.name;
|
|
267
|
+
if (typeof name !== "string" || !MCP_SERVER_NAME_PATTERN.test(name)) {
|
|
268
|
+
throw new Error(`${path}.name must match ${MCP_SERVER_NAME_PATTERN.source}`);
|
|
269
|
+
}
|
|
270
|
+
const url = record.url;
|
|
271
|
+
if (typeof url !== "string" || url.length === 0) {
|
|
272
|
+
throw new Error(`${path}.url must be a non-empty string`);
|
|
273
|
+
}
|
|
274
|
+
try {
|
|
275
|
+
const parsed = new URL(url);
|
|
276
|
+
if (parsed.protocol !== "https:" && parsed.protocol !== "http:") {
|
|
277
|
+
throw new Error(`${path}.url must use http or https (got ${parsed.protocol})`);
|
|
278
|
+
}
|
|
279
|
+
if (parsed.username !== "" || parsed.password !== "") {
|
|
280
|
+
throw new Error(`${path}.url must not contain userinfo (username/password); use secrets.mcpServers[].headers for auth`);
|
|
281
|
+
}
|
|
282
|
+
const ssrfDenial = denyReasonForMcpHost(parsed);
|
|
283
|
+
if (ssrfDenial !== null) {
|
|
284
|
+
throw new Error(`${path}.url ${ssrfDenial}`);
|
|
285
|
+
}
|
|
286
|
+
} catch (cause) {
|
|
287
|
+
if (cause instanceof Error && cause.message.startsWith(path)) {
|
|
288
|
+
throw cause;
|
|
289
|
+
}
|
|
290
|
+
throw new Error(`${path}.url is not a valid URL: ${url}`);
|
|
291
|
+
}
|
|
292
|
+
const transport = parseRemoteMcpTransport(record.transport, `${path}.transport`);
|
|
293
|
+
return transport ? { name, url, transport } : { name, url };
|
|
294
|
+
}
|
|
295
|
+
function rejectStdioMcpShape(record) {
|
|
296
|
+
if (record.transport === "stdio") {
|
|
297
|
+
throw new Error(REMOTE_MCP_STDIO_REJECTED_MESSAGE);
|
|
298
|
+
}
|
|
299
|
+
for (const field of STDIO_ONLY_FIELDS) {
|
|
300
|
+
if (record[field] !== void 0) {
|
|
301
|
+
throw new Error(REMOTE_MCP_STDIO_REJECTED_MESSAGE);
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
function denyReasonForMcpHost(parsed) {
|
|
306
|
+
const host = parsed.hostname.toLowerCase().replace(/^\[|\]$/g, "");
|
|
307
|
+
if (host === "localhost" || host.endsWith(".localhost")) {
|
|
308
|
+
return "must not target a loopback hostname";
|
|
309
|
+
}
|
|
310
|
+
if (/^127(?:\.[0-9]+){3}$/.test(host)) {
|
|
311
|
+
return "must not target loopback IPv4 (127.0.0.0/8)";
|
|
312
|
+
}
|
|
313
|
+
if (host === "::1" || host === "0:0:0:0:0:0:0:1") {
|
|
314
|
+
return "must not target loopback IPv6 (::1)";
|
|
315
|
+
}
|
|
316
|
+
if (/^fe[89ab][0-9a-f]?:/.test(host)) {
|
|
317
|
+
return "must not target link-local IPv6 (fe80::/10)";
|
|
318
|
+
}
|
|
319
|
+
if (/^169\.254\.[0-9]+\.[0-9]+$/.test(host)) {
|
|
320
|
+
return "must not target link-local IPv4 (169.254.0.0/16) \u2014 cloud metadata range";
|
|
321
|
+
}
|
|
322
|
+
if (/^10\.[0-9]+\.[0-9]+\.[0-9]+$/.test(host)) {
|
|
323
|
+
return "must not target RFC1918 IPv4 (10.0.0.0/8)";
|
|
324
|
+
}
|
|
325
|
+
if (/^172\.(1[6-9]|2[0-9]|3[01])\.[0-9]+\.[0-9]+$/.test(host)) {
|
|
326
|
+
return "must not target RFC1918 IPv4 (172.16.0.0/12)";
|
|
327
|
+
}
|
|
328
|
+
if (/^192\.168\.[0-9]+\.[0-9]+$/.test(host)) {
|
|
329
|
+
return "must not target RFC1918 IPv4 (192.168.0.0/16)";
|
|
330
|
+
}
|
|
331
|
+
if (parsed.protocol === "https:" && parsed.port !== "" && parsed.port !== "443") {
|
|
332
|
+
return `must use port 443 for https (got ${parsed.port})`;
|
|
333
|
+
}
|
|
334
|
+
return null;
|
|
335
|
+
}
|
|
336
|
+
function parseRemoteMcpTransport(input, field) {
|
|
337
|
+
if (input === void 0) {
|
|
338
|
+
return void 0;
|
|
339
|
+
}
|
|
340
|
+
if (typeof input !== "string" || !REMOTE_MCP_TRANSPORTS.includes(input)) {
|
|
341
|
+
throw new Error(`${field} must be one of: ${REMOTE_MCP_TRANSPORTS.join(", ")} (got ${JSON.stringify(input)})`);
|
|
342
|
+
}
|
|
343
|
+
return input;
|
|
344
|
+
}
|
|
345
|
+
function parseRunConfigMcpServerRef(input, path) {
|
|
346
|
+
if (input === null || typeof input !== "object" || Array.isArray(input)) {
|
|
347
|
+
throw new Error(`${path} must be an object`);
|
|
348
|
+
}
|
|
349
|
+
const record = input;
|
|
350
|
+
rejectStdioMcpShape(record);
|
|
351
|
+
for (const key of Object.keys(record)) {
|
|
352
|
+
if (key !== "name" && key !== "url" && key !== "headers" && key !== "transport") {
|
|
353
|
+
throw new Error(`${path}.${key} is not an allowed field for RunConfigMcpServer; permitted: name, url, transport, headers`);
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
const stripped = { name: record.name, url: record.url };
|
|
357
|
+
if (record.transport !== void 0)
|
|
358
|
+
stripped.transport = record.transport;
|
|
359
|
+
const ref = parseMcpServerRef(stripped, path);
|
|
360
|
+
const rawHeaders = record.headers;
|
|
361
|
+
if (rawHeaders === void 0) {
|
|
362
|
+
return ref;
|
|
363
|
+
}
|
|
364
|
+
if (rawHeaders === null || typeof rawHeaders !== "object" || Array.isArray(rawHeaders)) {
|
|
365
|
+
throw new Error(`${path}.headers, when provided, must be a string-keyed object`);
|
|
366
|
+
}
|
|
367
|
+
const headers = {};
|
|
368
|
+
for (const [hk, hv] of Object.entries(rawHeaders)) {
|
|
369
|
+
if (typeof hv !== "string") {
|
|
370
|
+
throw new Error(`${path}.headers.${hk} must be a string`);
|
|
371
|
+
}
|
|
372
|
+
headers[hk] = hv;
|
|
373
|
+
}
|
|
374
|
+
return { ...ref, headers };
|
|
375
|
+
}
|
|
376
|
+
function parseRunRequestConfig(input) {
|
|
377
|
+
if (input === null || typeof input !== "object" || Array.isArray(input)) {
|
|
378
|
+
throw new Error("run request config must be an object");
|
|
379
|
+
}
|
|
380
|
+
const record = input;
|
|
381
|
+
const allowed = /* @__PURE__ */ new Set([
|
|
382
|
+
"model",
|
|
383
|
+
"system",
|
|
384
|
+
"prompt",
|
|
385
|
+
"skills",
|
|
386
|
+
"mcpServers",
|
|
387
|
+
"environment",
|
|
388
|
+
"runtimeSize",
|
|
389
|
+
"timeout",
|
|
390
|
+
"proxyEndpoints",
|
|
391
|
+
"metadata"
|
|
392
|
+
]);
|
|
393
|
+
for (const key of Object.keys(record)) {
|
|
394
|
+
if (!allowed.has(key)) {
|
|
395
|
+
throw new Error(`run request config contains unexpected field: ${key}`);
|
|
396
|
+
}
|
|
397
|
+
}
|
|
398
|
+
const model = record.model;
|
|
399
|
+
if (typeof model !== "string" || model.length === 0) {
|
|
400
|
+
throw new Error("run request config model must be a non-empty string");
|
|
401
|
+
}
|
|
402
|
+
const system = record.system;
|
|
403
|
+
if (system !== void 0 && typeof system !== "string") {
|
|
404
|
+
throw new Error("run request config system, when provided, must be a string");
|
|
405
|
+
}
|
|
406
|
+
const prompt = parseRunRequestConfigPrompt(record.prompt);
|
|
407
|
+
const skills = parseRunRequestConfigSkills(record.skills);
|
|
408
|
+
const mcpServers = parseRunRequestConfigMcpServers(record.mcpServers);
|
|
409
|
+
return {
|
|
410
|
+
model,
|
|
411
|
+
...system !== void 0 ? { system } : {},
|
|
412
|
+
prompt,
|
|
413
|
+
...skills !== void 0 ? { skills } : {},
|
|
414
|
+
...mcpServers !== void 0 ? { mcpServers } : {},
|
|
415
|
+
// environment / proxyEndpoints / metadata: passed through
|
|
416
|
+
// as-is — the BFF revalidates them via `parseRunSubmissionRequest`,
|
|
417
|
+
// so duplicating the heavyweight parsers here would mean two sources
|
|
418
|
+
// of truth. The CLI surfaces structural errors at submission time.
|
|
419
|
+
...record.environment !== void 0 ? { environment: record.environment } : {},
|
|
420
|
+
...record.runtimeSize !== void 0 ? { runtimeSize: record.runtimeSize } : {},
|
|
421
|
+
...record.timeout !== void 0 ? { timeout: record.timeout } : {},
|
|
422
|
+
...record.proxyEndpoints !== void 0 ? { proxyEndpoints: record.proxyEndpoints } : {},
|
|
423
|
+
...record.metadata !== void 0 ? { metadata: record.metadata } : {}
|
|
424
|
+
};
|
|
425
|
+
}
|
|
426
|
+
function parseRunRequestConfigPrompt(value) {
|
|
427
|
+
if (typeof value === "string") {
|
|
428
|
+
if (value.length === 0) {
|
|
429
|
+
throw new Error("run request config prompt must be a non-empty string");
|
|
430
|
+
}
|
|
431
|
+
return value;
|
|
432
|
+
}
|
|
433
|
+
if (Array.isArray(value)) {
|
|
434
|
+
const arr = [];
|
|
435
|
+
for (let i = 0; i < value.length; i++) {
|
|
436
|
+
const item = value[i];
|
|
437
|
+
if (typeof item !== "string" || item.length === 0) {
|
|
438
|
+
throw new Error(`run request config prompt[${i}] must be a non-empty string`);
|
|
439
|
+
}
|
|
440
|
+
arr.push(item);
|
|
441
|
+
}
|
|
442
|
+
if (arr.length === 0) {
|
|
443
|
+
throw new Error("run request config prompt must be a non-empty string or array of strings");
|
|
444
|
+
}
|
|
445
|
+
return arr;
|
|
446
|
+
}
|
|
447
|
+
throw new Error("run request config prompt must be a string or array of strings");
|
|
448
|
+
}
|
|
449
|
+
function parseRunRequestConfigSkills(value) {
|
|
450
|
+
if (value === void 0) {
|
|
451
|
+
return void 0;
|
|
452
|
+
}
|
|
453
|
+
if (!Array.isArray(value)) {
|
|
454
|
+
throw new Error("run request config skills must be an array");
|
|
455
|
+
}
|
|
456
|
+
return value.map((item, index) => parseSkillRef(item, `run request config skills[${index}]`));
|
|
457
|
+
}
|
|
458
|
+
function parseRunRequestConfigMcpServers(value) {
|
|
459
|
+
if (value === void 0) {
|
|
460
|
+
return void 0;
|
|
461
|
+
}
|
|
462
|
+
if (!Array.isArray(value)) {
|
|
463
|
+
throw new Error("run request config mcpServers must be an array");
|
|
464
|
+
}
|
|
465
|
+
const seen = /* @__PURE__ */ new Set();
|
|
466
|
+
return value.map((item, index) => {
|
|
467
|
+
const entry = parseRunConfigMcpServerRef(item, `run request config mcpServers[${index}]`);
|
|
468
|
+
if (seen.has(entry.name)) {
|
|
469
|
+
throw new Error(`run request config mcpServers duplicate name: ${entry.name}`);
|
|
470
|
+
}
|
|
471
|
+
seen.add(entry.name);
|
|
472
|
+
return entry;
|
|
473
|
+
});
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
// ../contracts/dist/runtime-sizes.js
|
|
477
|
+
var RUNTIME_SIZE_PRESETS = {
|
|
478
|
+
"shared-1x-256mb": { cpus: 1, memoryMb: 256 },
|
|
479
|
+
"shared-1x-512mb": { cpus: 1, memoryMb: 512 },
|
|
480
|
+
"shared-1x-1gb": { cpus: 1, memoryMb: 1024 },
|
|
481
|
+
"shared-1x-2gb": { cpus: 1, memoryMb: 2048 },
|
|
482
|
+
"shared-2x-512mb": { cpus: 2, memoryMb: 512 },
|
|
483
|
+
"shared-2x-1gb": { cpus: 2, memoryMb: 1024 },
|
|
484
|
+
"shared-2x-2gb": { cpus: 2, memoryMb: 2048 },
|
|
485
|
+
"shared-2x-4gb": { cpus: 2, memoryMb: 4096 },
|
|
486
|
+
"shared-4x-1gb": { cpus: 4, memoryMb: 1024 },
|
|
487
|
+
"shared-4x-2gb": { cpus: 4, memoryMb: 2048 },
|
|
488
|
+
"shared-4x-4gb": { cpus: 4, memoryMb: 4096 },
|
|
489
|
+
"shared-4x-8gb": { cpus: 4, memoryMb: 8192 },
|
|
490
|
+
"shared-8x-2gb": { cpus: 8, memoryMb: 2048 },
|
|
491
|
+
"shared-8x-4gb": { cpus: 8, memoryMb: 4096 },
|
|
492
|
+
"shared-8x-8gb": { cpus: 8, memoryMb: 8192 },
|
|
493
|
+
"shared-8x-16gb": { cpus: 8, memoryMb: 16384 }
|
|
494
|
+
};
|
|
495
|
+
var RUNTIME_SIZES = Object.keys(RUNTIME_SIZE_PRESETS);
|
|
496
|
+
var DEFAULT_RUN_TIMEOUT_MS = 60 * 60 * 1e3;
|
|
497
|
+
var MAX_RUN_TIMEOUT_MS = 6 * 60 * 60 * 1e3;
|
|
498
|
+
var MIN_RUN_TIMEOUT_MS = 60 * 1e3;
|
|
499
|
+
var RUN_PROCESS_KILL_GRACE_MS = 60 * 1e3;
|
|
500
|
+
var RUN_TERMINAL_GRACE_MS = 90 * 1e3;
|
|
501
|
+
|
|
502
|
+
// ../contracts/dist/runtime-security-profile.js
|
|
503
|
+
var RUNTIME_SECURITY_PROFILE_CONFIG = Object.freeze({
|
|
504
|
+
strict: Object.freeze({
|
|
505
|
+
name: "strict",
|
|
506
|
+
defaultNetworkingMode: "limited",
|
|
507
|
+
allowOpenNetworking: false,
|
|
508
|
+
allowRuntimePackages: false,
|
|
509
|
+
allowCustomerEnvVars: true,
|
|
510
|
+
allowProxyEndpoints: true,
|
|
511
|
+
allowMcpServers: true
|
|
512
|
+
}),
|
|
513
|
+
standard: Object.freeze({
|
|
514
|
+
name: "standard",
|
|
515
|
+
defaultNetworkingMode: "limited",
|
|
516
|
+
allowOpenNetworking: true,
|
|
517
|
+
allowRuntimePackages: true,
|
|
518
|
+
allowCustomerEnvVars: true,
|
|
519
|
+
allowProxyEndpoints: true,
|
|
520
|
+
allowMcpServers: true
|
|
521
|
+
}),
|
|
522
|
+
developer: Object.freeze({
|
|
523
|
+
name: "developer",
|
|
524
|
+
defaultNetworkingMode: "open",
|
|
525
|
+
allowOpenNetworking: true,
|
|
526
|
+
allowRuntimePackages: true,
|
|
527
|
+
allowCustomerEnvVars: true,
|
|
528
|
+
allowProxyEndpoints: true,
|
|
529
|
+
allowMcpServers: true
|
|
530
|
+
})
|
|
531
|
+
});
|
|
532
|
+
|
|
533
|
+
// ../contracts/dist/managed-key.js
|
|
534
|
+
var MANAGED_KEY_POLICY_SCHEMA_VERSION = 1;
|
|
535
|
+
var BLOCKED_MANAGED_KEY_FEATURE_POLICY_V1 = Object.freeze({
|
|
536
|
+
files: "disabled",
|
|
537
|
+
packages: "disabled",
|
|
538
|
+
builtins: "disabled",
|
|
539
|
+
mcpServers: "disabled",
|
|
540
|
+
proxyEndpoints: "disabled",
|
|
541
|
+
openNetworking: "disabled"
|
|
542
|
+
});
|
|
543
|
+
var BLOCKED_MANAGED_KEY_POLICY_V1 = Object.freeze({
|
|
544
|
+
schemaVersion: MANAGED_KEY_POLICY_SCHEMA_VERSION,
|
|
545
|
+
credentialMode: "managed",
|
|
546
|
+
launchStage: "blocked",
|
|
547
|
+
serviceAvailable: false,
|
|
548
|
+
billingRequired: true,
|
|
549
|
+
providers: Object.freeze([]),
|
|
550
|
+
runtimes: Object.freeze([]),
|
|
551
|
+
features: BLOCKED_MANAGED_KEY_FEATURE_POLICY_V1
|
|
552
|
+
});
|
|
553
|
+
|
|
554
|
+
// ../contracts/dist/submission.js
|
|
555
|
+
var RUN_PROVIDERS = [
|
|
556
|
+
"anthropic",
|
|
557
|
+
"deepseek",
|
|
558
|
+
"openai",
|
|
559
|
+
"gemini",
|
|
560
|
+
"mistral"
|
|
561
|
+
];
|
|
562
|
+
var DEFAULT_RUN_PROVIDER = "anthropic";
|
|
563
|
+
var RUNTIME_KINDS = ["managed"];
|
|
564
|
+
var MIN_REDACTION_TARGET_BYTES = 4;
|
|
565
|
+
var MIN_PROXY_SECRET_BYTES = 8;
|
|
566
|
+
var _MIN_PROXY_SECRET_BYTES_OK = MIN_PROXY_SECRET_BYTES >= MIN_REDACTION_TARGET_BYTES;
|
|
567
|
+
|
|
568
|
+
// ../contracts/dist/connection-ticket.js
|
|
569
|
+
var encoder = new TextEncoder();
|
|
570
|
+
|
|
571
|
+
// ../contracts/dist/runtime-manifest.js
|
|
572
|
+
var ANTHROPIC_PATHS = Object.freeze({
|
|
573
|
+
skillsRoot: "/workspace/skills",
|
|
574
|
+
filesRoot: "/mnt/session/uploads/aex/files",
|
|
575
|
+
assetsRoot: "/mnt/session/uploads/aex/assets",
|
|
576
|
+
aexCli: "/mnt/session/uploads/aex/aex",
|
|
577
|
+
indexJson: "/mnt/session/uploads/aex/index.json",
|
|
578
|
+
readme: "/mnt/session/uploads/aex/SKILLS.md",
|
|
579
|
+
runtimeJson: "/mnt/session/uploads/aex/RUNTIME.json",
|
|
580
|
+
runtimeEnv: "/mnt/session/uploads/aex/RUNTIME.env"
|
|
581
|
+
});
|
|
582
|
+
|
|
583
|
+
// ../contracts/dist/run-custody.js
|
|
584
|
+
function scanCustodyPayloadForSensitiveValues(input) {
|
|
585
|
+
const findings = [];
|
|
586
|
+
visitCustodyValue(input, "$", findings);
|
|
587
|
+
return Object.freeze(findings);
|
|
588
|
+
}
|
|
589
|
+
function visitCustodyValue(input, path, findings) {
|
|
590
|
+
if (typeof input === "string") {
|
|
591
|
+
scanStringValue(input, path, findings);
|
|
592
|
+
return;
|
|
593
|
+
}
|
|
594
|
+
if (Array.isArray(input)) {
|
|
595
|
+
input.forEach((value, index) => visitCustodyValue(value, `${path}[${index}]`, findings));
|
|
596
|
+
return;
|
|
597
|
+
}
|
|
598
|
+
if (!input || typeof input !== "object") {
|
|
599
|
+
return;
|
|
600
|
+
}
|
|
601
|
+
for (const [key, value] of Object.entries(input)) {
|
|
602
|
+
const childPath = `${path}.${key}`;
|
|
603
|
+
if (isForbiddenCustodyFieldName(key)) {
|
|
604
|
+
findings.push(Object.freeze({ path: childPath, reason: "forbidden_field_name" }));
|
|
605
|
+
}
|
|
606
|
+
visitCustodyValue(value, childPath, findings);
|
|
607
|
+
}
|
|
608
|
+
}
|
|
609
|
+
function scanStringValue(value, path, findings) {
|
|
610
|
+
for (const pattern of forbiddenStringPatterns) {
|
|
611
|
+
if (pattern.regex.test(value)) {
|
|
612
|
+
findings.push(Object.freeze({
|
|
613
|
+
path,
|
|
614
|
+
reason: pattern.reason,
|
|
615
|
+
valueLength: value.length
|
|
616
|
+
}));
|
|
617
|
+
}
|
|
618
|
+
}
|
|
619
|
+
}
|
|
620
|
+
var forbiddenStringPatterns = Object.freeze([
|
|
621
|
+
{ reason: "bearer_token", regex: /\bBearer\s+[A-Za-z0-9._~+/=-]{8,}/i },
|
|
622
|
+
{
|
|
623
|
+
reason: "provider_key",
|
|
624
|
+
regex: /\b(?:sk-(?:ant|proj|live|test|deepseek|openai)|xox[baprs]-|AIza)[A-Za-z0-9_-]{8,}/i
|
|
625
|
+
},
|
|
626
|
+
{ reason: "signed_url", regex: /[?&](?:X-Amz-Signature|X-Amz-Credential|X-Amz-Algorithm|AWSAccessKeyId)=/i },
|
|
627
|
+
{ reason: "r2_object_key", regex: /(^|[\s"'`])(?:runs|assets)\/[^?<#\s"'`]+/i },
|
|
628
|
+
{ reason: "vault_id", regex: /\b(?:vault|vlt|secret)[_:-][A-Za-z0-9][A-Za-z0-9_-]{7,}\b/i },
|
|
629
|
+
{
|
|
630
|
+
reason: "private_resource_handle",
|
|
631
|
+
regex: /\b(?:machine|session|agent|file|skill|env|resource|handle|token_hash|bearer_hash)[_:-][A-Za-z0-9][A-Za-z0-9_-]{7,}\b/i
|
|
632
|
+
},
|
|
633
|
+
{ reason: "high_entropy_token", regex: /\b(?=[A-Za-z0-9_-]{40,}\b)(?=.*[A-Za-z])(?=.*\d)[A-Za-z0-9_-]{40,}\b/ }
|
|
634
|
+
]);
|
|
635
|
+
function isForbiddenCustodyFieldName(key) {
|
|
636
|
+
return /^(apiKey|secretValue|bearerHash|signedUrl|r2Key|objectKey|vaultId|providerResponseBody|responseBody|privateResourceHandle|resourceHandle|rawBody)$/i.test(key);
|
|
637
|
+
}
|
|
638
|
+
|
|
639
|
+
// ../contracts/dist/run-record.js
|
|
640
|
+
var RUN_RECORD_SCHEMA_VERSION = "aex.run-record.v1";
|
|
641
|
+
var RUN_RECORD_MANIFEST_SCHEMA_VERSION = "aex.run-record.manifest.v1";
|
|
642
|
+
var RunRecordArchiveRedactionError = class extends Error {
|
|
643
|
+
code = "run_record_archive_not_public_safe";
|
|
644
|
+
findings;
|
|
645
|
+
constructor(findings) {
|
|
646
|
+
super(`run record archive contains non-public data at ${formatArchiveFindingPaths(findings)}`);
|
|
647
|
+
this.name = "RunRecordArchiveRedactionError";
|
|
648
|
+
this.findings = Object.freeze([...findings]);
|
|
649
|
+
}
|
|
650
|
+
};
|
|
651
|
+
function buildRunRecordDownloadManifestV1(input) {
|
|
652
|
+
const outputs = input.outputs.map((file2) => normalizeArtifactSummary(file2));
|
|
653
|
+
const logs = input.logs.map((file2) => normalizeArtifactSummary(file2));
|
|
654
|
+
const errors = (input.errors ?? []).map((error) => Object.freeze({ ...error }));
|
|
655
|
+
return Object.freeze({
|
|
656
|
+
schemaVersion: RUN_RECORD_MANIFEST_SCHEMA_VERSION,
|
|
657
|
+
runRecordSchemaVersion: RUN_RECORD_SCHEMA_VERSION,
|
|
658
|
+
runId: input.runId,
|
|
659
|
+
namespaces: Object.freeze([
|
|
660
|
+
namespace("metadata", "Run metadata, submission snapshot, custody, and cost files."),
|
|
661
|
+
namespace("events", "Typed event-channel exports and optional full-stream/log-channel exports."),
|
|
662
|
+
namespace("outputs", "Captured deliverables produced by the run."),
|
|
663
|
+
namespace("logs", "Platform diagnostics and runtime log artifacts.")
|
|
664
|
+
]),
|
|
665
|
+
files: Object.freeze([
|
|
666
|
+
file("metadata", "metadata/run.json", "run_metadata", "present"),
|
|
667
|
+
file("metadata", "metadata/submission.json", "submission_snapshot", input.submission?.status ?? "unavailable"),
|
|
668
|
+
file("metadata", "metadata/cost.json", "cost", input.cost?.status ?? "pending"),
|
|
669
|
+
file("metadata", "metadata/custody.json", "custody", input.custody?.status ?? "pending"),
|
|
670
|
+
file("events", "events/events.jsonl", "typed_events", "present", {
|
|
671
|
+
recordCount: input.typedEventCount ?? 0
|
|
672
|
+
}),
|
|
673
|
+
file("events", "events/logs.jsonl", "log_events", input.logEvents?.status ?? "unavailable", recordCountExtra(input.logEvents)),
|
|
674
|
+
file("events", "events/all.jsonl", "all_events", input.allEvents?.status ?? "unavailable", recordCountExtra(input.allEvents)),
|
|
675
|
+
file("events", "events/manifest.json", "coordinator_events_manifest", input.coordinatorEventsManifest?.status ?? "unavailable"),
|
|
676
|
+
...outputs.map((output) => artifactFile("outputs", "output", "outputs/", output)),
|
|
677
|
+
...logs.map((log) => artifactFile("logs", "log", "logs/", log))
|
|
678
|
+
]),
|
|
679
|
+
outputs: Object.freeze(outputs),
|
|
680
|
+
logs: Object.freeze(logs),
|
|
681
|
+
errors: Object.freeze(errors)
|
|
682
|
+
});
|
|
683
|
+
}
|
|
684
|
+
function namespace(name, description) {
|
|
685
|
+
return Object.freeze({
|
|
686
|
+
name,
|
|
687
|
+
prefix: `${name}/`,
|
|
688
|
+
status: "present",
|
|
689
|
+
description
|
|
690
|
+
});
|
|
691
|
+
}
|
|
692
|
+
function file(namespaceName, path, role, status, extra) {
|
|
693
|
+
return Object.freeze({
|
|
694
|
+
namespace: namespaceName,
|
|
695
|
+
path,
|
|
696
|
+
role,
|
|
697
|
+
status,
|
|
698
|
+
...extra?.recordCount !== void 0 ? { recordCount: extra.recordCount } : {}
|
|
699
|
+
});
|
|
700
|
+
}
|
|
701
|
+
function recordCountExtra(input) {
|
|
702
|
+
return input?.status === "present" && input.recordCount !== void 0 ? { recordCount: input.recordCount } : void 0;
|
|
703
|
+
}
|
|
704
|
+
function artifactFile(namespaceName, role, prefix, artifact) {
|
|
705
|
+
return Object.freeze({
|
|
706
|
+
namespace: namespaceName,
|
|
707
|
+
path: `${prefix}${artifact.filename ?? artifact.id}`,
|
|
708
|
+
role,
|
|
709
|
+
status: "present",
|
|
710
|
+
id: artifact.id,
|
|
711
|
+
filename: artifact.filename,
|
|
712
|
+
...artifact.sizeBytes !== void 0 ? { sizeBytes: artifact.sizeBytes } : {},
|
|
713
|
+
...artifact.contentType !== void 0 ? { contentType: artifact.contentType } : {}
|
|
714
|
+
});
|
|
715
|
+
}
|
|
716
|
+
function normalizeArtifactSummary(input) {
|
|
717
|
+
return Object.freeze({
|
|
718
|
+
id: input.id,
|
|
719
|
+
filename: input.filename,
|
|
720
|
+
...input.sizeBytes !== void 0 ? { sizeBytes: input.sizeBytes } : {},
|
|
721
|
+
...input.contentType !== void 0 ? { contentType: input.contentType } : {}
|
|
722
|
+
});
|
|
723
|
+
}
|
|
724
|
+
function scanRunRecordArchiveEntriesV1(entries) {
|
|
725
|
+
const findings = [];
|
|
726
|
+
for (const entry of entries) {
|
|
727
|
+
if (entry.customerContent || !shouldScanArchiveEntry(entry)) {
|
|
728
|
+
continue;
|
|
729
|
+
}
|
|
730
|
+
for (const finding of scanArchiveEntry(entry)) {
|
|
731
|
+
findings.push(finding);
|
|
732
|
+
}
|
|
733
|
+
}
|
|
734
|
+
return Object.freeze(findings);
|
|
735
|
+
}
|
|
736
|
+
function assertRunRecordArchivePublicSafeV1(entries) {
|
|
737
|
+
const findings = scanRunRecordArchiveEntriesV1(entries);
|
|
738
|
+
if (findings.length > 0) {
|
|
739
|
+
throw new RunRecordArchiveRedactionError(findings);
|
|
740
|
+
}
|
|
741
|
+
}
|
|
742
|
+
function shouldScanArchiveEntry(entry) {
|
|
743
|
+
if (entry.path.startsWith("outputs/")) {
|
|
744
|
+
return false;
|
|
745
|
+
}
|
|
746
|
+
const contentType = entry.contentType?.toLowerCase() ?? "";
|
|
747
|
+
if (contentType.startsWith("text/") || contentType.includes("json") || contentType.includes("xml") || contentType.includes("yaml")) {
|
|
748
|
+
return true;
|
|
749
|
+
}
|
|
750
|
+
return /\.(?:json|jsonl|ndjson|txt|log|md|csv|tsv|ya?ml)$/i.test(entry.path);
|
|
751
|
+
}
|
|
752
|
+
function scanArchiveEntry(entry) {
|
|
753
|
+
const text = new TextDecoder().decode(entry.bytes);
|
|
754
|
+
const parsedValues = parseArchiveTextValues(entry.path, text);
|
|
755
|
+
const rawFindings = parsedValues.length > 0 ? parsedValues.flatMap((value) => [...scanCustodyPayloadForSensitiveValues(value.value)].map((finding) => ({
|
|
756
|
+
...finding,
|
|
757
|
+
path: `${value.path}${finding.path === "$" ? "" : finding.path.slice(1)}`
|
|
758
|
+
}))) : scanCustodyPayloadForSensitiveValues(text);
|
|
759
|
+
return Object.freeze(rawFindings.filter((finding) => !isAllowedArchiveHighEntropyField(entry.path, finding)).map((finding) => Object.freeze({
|
|
760
|
+
entryPath: entry.path,
|
|
761
|
+
path: finding.path,
|
|
762
|
+
reason: finding.reason,
|
|
763
|
+
...finding.valueLength !== void 0 ? { valueLength: finding.valueLength } : {}
|
|
764
|
+
})));
|
|
765
|
+
}
|
|
766
|
+
function isAllowedArchiveHighEntropyField(entryPath, finding) {
|
|
767
|
+
if (finding.reason !== "high_entropy_token" || !entryPath.endsWith("manifest.json")) {
|
|
768
|
+
return false;
|
|
769
|
+
}
|
|
770
|
+
return /^\$(?:\.files\[\d+\]|\.outputs\[\d+\]|\.logs\[\d+\])\.id$/.test(finding.path);
|
|
771
|
+
}
|
|
772
|
+
function parseArchiveTextValues(path, text) {
|
|
773
|
+
if (/\.json$/i.test(path)) {
|
|
774
|
+
const parsed = tryParseJson(text);
|
|
775
|
+
return parsed.ok ? Object.freeze([{ path: "$", value: parsed.value }]) : Object.freeze([]);
|
|
776
|
+
}
|
|
777
|
+
if (/\.(?:jsonl|ndjson)$/i.test(path)) {
|
|
778
|
+
const values = [];
|
|
779
|
+
const lines = text.split(/\r?\n/);
|
|
780
|
+
for (let i = 0; i < lines.length; i++) {
|
|
781
|
+
const line = lines[i];
|
|
782
|
+
if (!line?.trim()) {
|
|
783
|
+
continue;
|
|
784
|
+
}
|
|
785
|
+
const parsed = tryParseJson(line);
|
|
786
|
+
if (!parsed.ok) {
|
|
787
|
+
return Object.freeze([]);
|
|
788
|
+
}
|
|
789
|
+
values.push({ path: `$[${i}]`, value: parsed.value });
|
|
790
|
+
}
|
|
791
|
+
return Object.freeze(values);
|
|
792
|
+
}
|
|
793
|
+
return Object.freeze([]);
|
|
794
|
+
}
|
|
795
|
+
function tryParseJson(text) {
|
|
796
|
+
try {
|
|
797
|
+
return { ok: true, value: JSON.parse(text) };
|
|
798
|
+
} catch {
|
|
799
|
+
return { ok: false };
|
|
800
|
+
}
|
|
801
|
+
}
|
|
802
|
+
function formatArchiveFindingPaths(findings) {
|
|
803
|
+
return findings.map((finding) => `${finding.entryPath}${finding.path} (${finding.reason})`).join(", ");
|
|
804
|
+
}
|
|
805
|
+
|
|
806
|
+
// ../contracts/dist/run-retention.js
|
|
807
|
+
var forbiddenStringPatterns2 = Object.freeze([
|
|
808
|
+
{ reason: "signed_url", regex: /[?&](?:X-Amz-Signature|X-Amz-Credential|X-Amz-Algorithm|AWSAccessKeyId)=/i },
|
|
809
|
+
{ reason: "r2_object_key", regex: /(^|[\s"'`])(?:runs|assets)\/[^?<#\s"'`]+/i },
|
|
810
|
+
{ reason: "vault_id", regex: /\b(?:vault|vlt|secret)[_:-][A-Za-z0-9][A-Za-z0-9_-]{7,}\b/i },
|
|
811
|
+
{
|
|
812
|
+
reason: "private_resource_handle",
|
|
813
|
+
regex: /\b(?:machine|session|resource|handle|provider|asset)[_:-][A-Za-z0-9][A-Za-z0-9_-]{7,}\b/i
|
|
814
|
+
},
|
|
815
|
+
{ reason: "hash_like_value", regex: /\b(?:sha256|hash)[:_-][A-Fa-f0-9]{16,}\b/ }
|
|
816
|
+
]);
|
|
817
|
+
|
|
818
|
+
// ../contracts/dist/side-effect-audit.js
|
|
819
|
+
var forbiddenStringPatterns3 = Object.freeze([
|
|
820
|
+
{ reason: "bearer_token", regex: /\bBearer\s+[A-Za-z0-9._~+/=-]{8,}/i },
|
|
821
|
+
{
|
|
822
|
+
reason: "provider_key",
|
|
823
|
+
regex: /\b(?:sk-(?:ant|proj|live|test|deepseek|openai)|xox[baprs]-|AIza)[A-Za-z0-9_-]{8,}/i
|
|
824
|
+
},
|
|
825
|
+
{ reason: "signed_url", regex: /[?&](?:X-Amz-Signature|X-Amz-Credential|X-Amz-Algorithm|AWSAccessKeyId)=/i },
|
|
826
|
+
{ reason: "r2_object_key", regex: /(^|[\s"'`])(?:runs|assets)\/[^?<#\s"'`]+/i },
|
|
827
|
+
{ reason: "vault_id", regex: /\b(?:vault|vlt|secret)[_:-][A-Za-z0-9][A-Za-z0-9_-]{7,}\b/i },
|
|
828
|
+
{
|
|
829
|
+
reason: "private_resource_handle",
|
|
830
|
+
regex: /\b(?:machine|session|agent|file|skill|env|resource|handle|token_hash|bearer_hash)[_:-][A-Za-z0-9][A-Za-z0-9_-]{7,}\b/i
|
|
831
|
+
},
|
|
832
|
+
{ reason: "raw_url", regex: /\bhttps?:\/\/\S+/i },
|
|
833
|
+
{ reason: "raw_path", regex: /(^|[\s"'`])\/[A-Za-z0-9._~!$&'()*+,;=:@%-]+(?:[/?#][^\s"'`]*)?/ },
|
|
834
|
+
{ reason: "high_entropy_token", regex: /\b(?=[A-Za-z0-9_-]{40,}\b)(?=.*[A-Za-z])(?=.*\d)[A-Za-z0-9_-]{40,}\b/ }
|
|
835
|
+
]);
|
|
836
|
+
|
|
837
|
+
// ../contracts/dist/stable.js
|
|
838
|
+
import { createHash } from "node:crypto";
|
|
839
|
+
var AEX_DEFAULT_BASE_URL = "https://api.aex.dev";
|
|
840
|
+
|
|
841
|
+
// ../contracts/dist/sdk-secrets.js
|
|
842
|
+
import { Transform } from "node:stream";
|
|
843
|
+
var SECRET_PATTERNS = [
|
|
844
|
+
// postgres / postgresql connection strings — redact the whole URI so the
|
|
845
|
+
// embedded password can never survive as a substring (the `sed`-mask leak).
|
|
846
|
+
/\bpostgres(?:ql)?:\/\/[^\s"']+/gi,
|
|
847
|
+
// Authorization: Bearer <token> — redact the credential, keep the header name
|
|
848
|
+
// so logs stay legible.
|
|
849
|
+
/\b(Authorization\s*:\s*Bearer)\s+[A-Za-z0-9._~+/=-]{8,}/gi,
|
|
850
|
+
// Anthropic + OpenAI-style prefixed keys.
|
|
851
|
+
/sk-ant-[A-Za-z0-9_-]{16,}/g,
|
|
852
|
+
/sk-[A-Za-z0-9_-]{20,}/g,
|
|
853
|
+
// aex workspace / proxy tokens: apt_… / ant_….
|
|
854
|
+
/\b(?:apt|ant)_[A-Za-z0-9_-]{16,}/g,
|
|
855
|
+
// Slack tokens.
|
|
856
|
+
/xox[pbar]-[A-Za-z0-9-]{10,}/g,
|
|
857
|
+
// AWS access key id + secret access key shapes.
|
|
858
|
+
/\b(?:AKIA|ASIA)[A-Z0-9]{16}\b/g,
|
|
859
|
+
/\baws_secret_access_key["'\s:=]+[A-Za-z0-9/+=]{40}/gi,
|
|
860
|
+
// JWT-shaped: header.payload.signature, each base64url, header starts `eyJ`.
|
|
861
|
+
/\beyJ[A-Za-z0-9_-]{8,}\.[A-Za-z0-9_-]{8,}\.[A-Za-z0-9_-]{8,}/g,
|
|
862
|
+
// Keyword-introduced secret assignments (bearer/token/api_key/…).
|
|
863
|
+
/(?:bearer|token|api[_-]?key|access[_-]?token|refresh[_-]?token|client[_-]?secret)["'\s:=]+[A-Za-z0-9_\-./+=]{12,}/gi
|
|
864
|
+
];
|
|
865
|
+
var REDACTED = "[REDACTED]";
|
|
866
|
+
var HIGH_ENTROPY_CANDIDATE = /[A-Za-z0-9+/=-]{24,}/g;
|
|
867
|
+
var ENTROPY_BITS_PER_CHAR = 3;
|
|
868
|
+
var MIN_CHAR_CLASSES = 2;
|
|
869
|
+
var HIGH_ENTROPY_NO_DIGIT_MIN_LEN = 40;
|
|
870
|
+
function redactSecrets(value) {
|
|
871
|
+
if (typeof value === "string") {
|
|
872
|
+
return redactString(value);
|
|
873
|
+
}
|
|
874
|
+
if (Array.isArray(value)) {
|
|
875
|
+
return value.map((item) => redactSecrets(item));
|
|
876
|
+
}
|
|
877
|
+
if (value && typeof value === "object") {
|
|
878
|
+
const out = {};
|
|
879
|
+
for (const [key, item] of Object.entries(value)) {
|
|
880
|
+
if (isSecretKey(key)) {
|
|
881
|
+
out[key] = REDACTED;
|
|
882
|
+
} else {
|
|
883
|
+
out[key] = redactSecrets(item);
|
|
884
|
+
}
|
|
885
|
+
}
|
|
886
|
+
return out;
|
|
887
|
+
}
|
|
888
|
+
return value;
|
|
889
|
+
}
|
|
890
|
+
function redactString(input, known = []) {
|
|
891
|
+
let out = input;
|
|
892
|
+
for (const value of known) {
|
|
893
|
+
if (value && value.length >= 4) {
|
|
894
|
+
out = out.split(value).join(REDACTED);
|
|
895
|
+
}
|
|
896
|
+
}
|
|
897
|
+
out = SECRET_PATTERNS.reduce((current, pattern) => current.replace(pattern, (match, captured) => (
|
|
898
|
+
// Patterns with a captured prefix (Authorization header) keep the
|
|
899
|
+
// prefix; the rest replace the whole match.
|
|
900
|
+
typeof captured === "string" ? `${captured} ${REDACTED}` : REDACTED
|
|
901
|
+
)), out);
|
|
902
|
+
return out.replace(HIGH_ENTROPY_CANDIDATE, (match) => looksHighEntropySecret(match) ? REDACTED : match);
|
|
903
|
+
}
|
|
904
|
+
function isSecretKey(key) {
|
|
905
|
+
return /(?:api[_-]?key|authorization|token|secret|password|credential)/i.test(key);
|
|
906
|
+
}
|
|
907
|
+
function looksHighEntropySecret(value) {
|
|
908
|
+
if (charClassCount(value) < MIN_CHAR_CLASSES)
|
|
909
|
+
return false;
|
|
910
|
+
if (shannonEntropyBits(value) < ENTROPY_BITS_PER_CHAR)
|
|
911
|
+
return false;
|
|
912
|
+
return /[0-9]/.test(value) || value.length >= HIGH_ENTROPY_NO_DIGIT_MIN_LEN;
|
|
913
|
+
}
|
|
914
|
+
function charClassCount(value) {
|
|
915
|
+
let count = 0;
|
|
916
|
+
if (/[a-z]/.test(value))
|
|
917
|
+
count++;
|
|
918
|
+
if (/[A-Z]/.test(value))
|
|
919
|
+
count++;
|
|
920
|
+
if (/[0-9]/.test(value))
|
|
921
|
+
count++;
|
|
922
|
+
return count;
|
|
923
|
+
}
|
|
924
|
+
function shannonEntropyBits(value) {
|
|
925
|
+
if (value.length === 0) {
|
|
926
|
+
return 0;
|
|
927
|
+
}
|
|
928
|
+
const counts = /* @__PURE__ */ new Map();
|
|
929
|
+
for (const char of value) {
|
|
930
|
+
counts.set(char, (counts.get(char) ?? 0) + 1);
|
|
931
|
+
}
|
|
932
|
+
let bits = 0;
|
|
933
|
+
for (const count of counts.values()) {
|
|
934
|
+
const p = count / value.length;
|
|
935
|
+
bits -= p * Math.log2(p);
|
|
936
|
+
}
|
|
937
|
+
return bits;
|
|
938
|
+
}
|
|
939
|
+
|
|
940
|
+
// ../contracts/dist/sdk-errors.js
|
|
941
|
+
var AexError = class extends Error {
|
|
942
|
+
code;
|
|
943
|
+
details;
|
|
944
|
+
constructor(code, message, details) {
|
|
945
|
+
super(redactSecrets(message));
|
|
946
|
+
this.name = this.constructor.name;
|
|
947
|
+
this.code = code;
|
|
948
|
+
this.details = details === void 0 ? void 0 : redactSecrets(details);
|
|
949
|
+
}
|
|
950
|
+
};
|
|
951
|
+
var RunStateError = class extends AexError {
|
|
952
|
+
constructor(message, details) {
|
|
953
|
+
super("RUN_STATE_ERROR", message, details);
|
|
954
|
+
}
|
|
955
|
+
};
|
|
956
|
+
var AexApiError = class extends AexError {
|
|
957
|
+
status;
|
|
958
|
+
body;
|
|
959
|
+
constructor(status, message, body) {
|
|
960
|
+
super("API_ERROR", message, body);
|
|
961
|
+
this.status = status;
|
|
962
|
+
this.body = redactSecrets(body);
|
|
963
|
+
}
|
|
964
|
+
};
|
|
965
|
+
|
|
966
|
+
// ../contracts/dist/http.js
|
|
967
|
+
var HttpClient = class {
|
|
968
|
+
#baseUrl;
|
|
969
|
+
#apiToken;
|
|
970
|
+
#fetch;
|
|
971
|
+
#debug;
|
|
972
|
+
constructor(options) {
|
|
973
|
+
if (!options.apiToken) {
|
|
974
|
+
throw new Error("HttpClient: apiToken is required");
|
|
975
|
+
}
|
|
976
|
+
const raw = options.baseUrl ?? AEX_DEFAULT_BASE_URL;
|
|
977
|
+
const normalized = raw.endsWith("/") ? raw : `${raw}/`;
|
|
978
|
+
this.#baseUrl = new URL(normalized);
|
|
979
|
+
this.#apiToken = options.apiToken;
|
|
980
|
+
this.#fetch = options.fetch ?? fetch;
|
|
981
|
+
this.#debug = options.debug;
|
|
982
|
+
}
|
|
983
|
+
/** Emit a redacted round-trip trace (no auth header, body, or query). */
|
|
984
|
+
#trace(method, url, status, startedMs) {
|
|
985
|
+
this.#debug?.(`[aex] ${(method ?? "GET").toUpperCase()} ${url.pathname} -> ${status} ${Date.now() - startedMs}ms`);
|
|
986
|
+
}
|
|
987
|
+
async request(path, init = {}, query = {}) {
|
|
988
|
+
const url = new URL(path.replace(/^\//, ""), this.#baseUrl);
|
|
989
|
+
for (const [key, value] of Object.entries(query)) {
|
|
990
|
+
url.searchParams.set(key, value);
|
|
991
|
+
}
|
|
992
|
+
const headers = {
|
|
993
|
+
accept: "application/json",
|
|
994
|
+
authorization: `Bearer ${this.#apiToken}`,
|
|
995
|
+
...normalizeHeaders(init.headers)
|
|
996
|
+
};
|
|
997
|
+
if (init.body !== void 0 && init.body !== null && !headers["content-type"]) {
|
|
998
|
+
if (typeof init.body === "string") {
|
|
999
|
+
headers["content-type"] = "application/json";
|
|
1000
|
+
}
|
|
1001
|
+
}
|
|
1002
|
+
const startedMs = Date.now();
|
|
1003
|
+
const response = await this.#fetch(url, { ...init, headers });
|
|
1004
|
+
this.#trace(init.method, url, response.status, startedMs);
|
|
1005
|
+
const body = await readJson(response);
|
|
1006
|
+
if (!response.ok) {
|
|
1007
|
+
throw new AexApiError(response.status, extractErrorMessage(body), body);
|
|
1008
|
+
}
|
|
1009
|
+
return body;
|
|
1010
|
+
}
|
|
1011
|
+
async download(path, init = {}, query = {}) {
|
|
1012
|
+
const url = new URL(path.replace(/^\//, ""), this.#baseUrl);
|
|
1013
|
+
for (const [key, value] of Object.entries(query)) {
|
|
1014
|
+
url.searchParams.set(key, value);
|
|
1015
|
+
}
|
|
1016
|
+
const headers = {
|
|
1017
|
+
authorization: `Bearer ${this.#apiToken}`,
|
|
1018
|
+
...normalizeHeaders(init.headers)
|
|
1019
|
+
};
|
|
1020
|
+
const startedMs = Date.now();
|
|
1021
|
+
const response = await this.#fetch(url, { ...init, headers });
|
|
1022
|
+
this.#trace(init.method, url, response.status, startedMs);
|
|
1023
|
+
if (!response.ok) {
|
|
1024
|
+
const body = await readJson(response);
|
|
1025
|
+
throw new AexApiError(response.status, extractErrorMessage(body), body);
|
|
1026
|
+
}
|
|
1027
|
+
return { response };
|
|
1028
|
+
}
|
|
1029
|
+
};
|
|
1030
|
+
function normalizeHeaders(headers) {
|
|
1031
|
+
if (!headers)
|
|
1032
|
+
return {};
|
|
1033
|
+
if (headers instanceof Headers)
|
|
1034
|
+
return Object.fromEntries(headers.entries());
|
|
1035
|
+
if (Array.isArray(headers))
|
|
1036
|
+
return Object.fromEntries(headers);
|
|
1037
|
+
return headers;
|
|
1038
|
+
}
|
|
1039
|
+
async function readJson(response) {
|
|
1040
|
+
const text = await response.text();
|
|
1041
|
+
if (text.length === 0)
|
|
1042
|
+
return {};
|
|
1043
|
+
try {
|
|
1044
|
+
return JSON.parse(text);
|
|
1045
|
+
} catch {
|
|
1046
|
+
return { raw: text };
|
|
1047
|
+
}
|
|
1048
|
+
}
|
|
1049
|
+
function extractErrorMessage(body) {
|
|
1050
|
+
if (body && typeof body === "object") {
|
|
1051
|
+
const obj = body;
|
|
1052
|
+
if (typeof obj.error === "string")
|
|
1053
|
+
return obj.error;
|
|
1054
|
+
if (obj.error && typeof obj.error === "object" && "message" in obj.error) {
|
|
1055
|
+
const message = obj.error.message;
|
|
1056
|
+
if (typeof message === "string")
|
|
1057
|
+
return message;
|
|
1058
|
+
}
|
|
1059
|
+
if (typeof obj.message === "string")
|
|
1060
|
+
return obj.message;
|
|
1061
|
+
}
|
|
1062
|
+
return "aex API request failed";
|
|
1063
|
+
}
|
|
1064
|
+
|
|
1065
|
+
// ../contracts/dist/run-artifacts.js
|
|
1066
|
+
function runArtifactRel(rel) {
|
|
1067
|
+
if (rel.startsWith(".runtime-logs/"))
|
|
1068
|
+
return `runtime/${rel.slice(".runtime-logs/".length)}`;
|
|
1069
|
+
if (rel.startsWith("runtime/"))
|
|
1070
|
+
return rel;
|
|
1071
|
+
if (rel.startsWith(".host-logs/"))
|
|
1072
|
+
return `host/${rel.slice(".host-logs/".length)}`;
|
|
1073
|
+
if (rel.startsWith("host/"))
|
|
1074
|
+
return rel;
|
|
1075
|
+
if (rel.startsWith(".provider-proxy/"))
|
|
1076
|
+
return `provider-proxy/${rel.slice(".provider-proxy/".length)}`;
|
|
1077
|
+
if (rel.startsWith("provider-proxy/"))
|
|
1078
|
+
return rel;
|
|
1079
|
+
if (rel.startsWith(".control-plane/"))
|
|
1080
|
+
return `control-plane/${rel.slice(".control-plane/".length)}`;
|
|
1081
|
+
if (rel.startsWith("control-plane/"))
|
|
1082
|
+
return rel;
|
|
1083
|
+
if (rel.startsWith(".goose-logs/"))
|
|
1084
|
+
return `runtime/${rel.slice(".goose-logs/".length)}`;
|
|
1085
|
+
if (rel.startsWith("goose-logs/"))
|
|
1086
|
+
return `runtime/${rel.slice("goose-logs/".length)}`;
|
|
1087
|
+
if (rel.startsWith(".fly-logs/"))
|
|
1088
|
+
return `host/${rel.slice(".fly-logs/".length)}`;
|
|
1089
|
+
if (rel.startsWith("fly-logs/"))
|
|
1090
|
+
return `host/${rel.slice("fly-logs/".length)}`;
|
|
1091
|
+
if (rel.startsWith(".anthropic-debug/"))
|
|
1092
|
+
return `provider-proxy/${rel.slice(".anthropic-debug/".length)}`;
|
|
1093
|
+
if (rel.startsWith("anthropic-debug/"))
|
|
1094
|
+
return `provider-proxy/${rel.slice("anthropic-debug/".length)}`;
|
|
1095
|
+
return rel;
|
|
1096
|
+
}
|
|
1097
|
+
|
|
1098
|
+
// ../contracts/dist/operations.js
|
|
1099
|
+
var operations_exports = {};
|
|
1100
|
+
__export(operations_exports, {
|
|
1101
|
+
cancelRun: () => cancelRun,
|
|
1102
|
+
createAgentsMd: () => createAgentsMd,
|
|
1103
|
+
createFile: () => createFile,
|
|
1104
|
+
createOutputLink: () => createOutputLink,
|
|
1105
|
+
createSkillBundle: () => createSkillBundle,
|
|
1106
|
+
createSkillBundleDirect: () => createSkillBundleDirect,
|
|
1107
|
+
deleteAgentsMd: () => deleteAgentsMd,
|
|
1108
|
+
deleteFile: () => deleteFile,
|
|
1109
|
+
deleteRun: () => deleteRun,
|
|
1110
|
+
deleteSkill: () => deleteSkill,
|
|
1111
|
+
deleteWorkspaceAsset: () => deleteWorkspaceAsset,
|
|
1112
|
+
download: () => download,
|
|
1113
|
+
downloadEvents: () => downloadEvents,
|
|
1114
|
+
downloadLogs: () => downloadLogs,
|
|
1115
|
+
downloadMetadata: () => downloadMetadata,
|
|
1116
|
+
downloadOutput: () => downloadOutput,
|
|
1117
|
+
downloadOutputs: () => downloadOutputs,
|
|
1118
|
+
findSkillByHash: () => findSkillByHash,
|
|
1119
|
+
findSkillByName: () => findSkillByName,
|
|
1120
|
+
getAgentsMd: () => getAgentsMd,
|
|
1121
|
+
getCoordinatorTicket: () => getCoordinatorTicket,
|
|
1122
|
+
getFile: () => getFile,
|
|
1123
|
+
getRun: () => getRun,
|
|
1124
|
+
getRunUnit: () => getRunUnit,
|
|
1125
|
+
getSkill: () => getSkill,
|
|
1126
|
+
listAgentsMd: () => listAgentsMd,
|
|
1127
|
+
listFiles: () => listFiles,
|
|
1128
|
+
listLogs: () => listLogs,
|
|
1129
|
+
listOutputs: () => listOutputs,
|
|
1130
|
+
listRunEvents: () => listRunEvents,
|
|
1131
|
+
listSkills: () => listSkills,
|
|
1132
|
+
resolveOutputFileSelector: () => resolveOutputFileSelector,
|
|
1133
|
+
submitRun: () => submitRun,
|
|
1134
|
+
submitRunMultipart: () => submitRunMultipart,
|
|
1135
|
+
uploadWorkspaceAsset: () => uploadWorkspaceAsset,
|
|
1136
|
+
whoami: () => whoami
|
|
1137
|
+
});
|
|
1138
|
+
|
|
1139
|
+
// ../../node_modules/.pnpm/fflate@0.8.3/node_modules/fflate/esm/index.mjs
|
|
1140
|
+
import { createRequire } from "module";
|
|
1141
|
+
var require2 = createRequire("/");
|
|
1142
|
+
var _a;
|
|
1143
|
+
var Worker;
|
|
1144
|
+
var isMarkedAsUntransferable;
|
|
1145
|
+
try {
|
|
1146
|
+
_a = require2("worker_threads"), Worker = _a.Worker, isMarkedAsUntransferable = _a.isMarkedAsUntransferable;
|
|
1147
|
+
} catch (e) {
|
|
1148
|
+
}
|
|
1149
|
+
var u8 = Uint8Array;
|
|
1150
|
+
var u16 = Uint16Array;
|
|
1151
|
+
var i32 = Int32Array;
|
|
1152
|
+
var fleb = new u8([
|
|
1153
|
+
0,
|
|
1154
|
+
0,
|
|
1155
|
+
0,
|
|
1156
|
+
0,
|
|
1157
|
+
0,
|
|
1158
|
+
0,
|
|
1159
|
+
0,
|
|
1160
|
+
0,
|
|
1161
|
+
1,
|
|
1162
|
+
1,
|
|
1163
|
+
1,
|
|
1164
|
+
1,
|
|
1165
|
+
2,
|
|
1166
|
+
2,
|
|
1167
|
+
2,
|
|
1168
|
+
2,
|
|
1169
|
+
3,
|
|
1170
|
+
3,
|
|
1171
|
+
3,
|
|
1172
|
+
3,
|
|
1173
|
+
4,
|
|
1174
|
+
4,
|
|
1175
|
+
4,
|
|
1176
|
+
4,
|
|
1177
|
+
5,
|
|
1178
|
+
5,
|
|
1179
|
+
5,
|
|
1180
|
+
5,
|
|
1181
|
+
0,
|
|
1182
|
+
/* unused */
|
|
1183
|
+
0,
|
|
1184
|
+
0,
|
|
1185
|
+
/* impossible */
|
|
1186
|
+
0
|
|
1187
|
+
]);
|
|
1188
|
+
var fdeb = new u8([
|
|
1189
|
+
0,
|
|
1190
|
+
0,
|
|
1191
|
+
0,
|
|
1192
|
+
0,
|
|
1193
|
+
1,
|
|
1194
|
+
1,
|
|
1195
|
+
2,
|
|
1196
|
+
2,
|
|
1197
|
+
3,
|
|
1198
|
+
3,
|
|
1199
|
+
4,
|
|
1200
|
+
4,
|
|
1201
|
+
5,
|
|
1202
|
+
5,
|
|
1203
|
+
6,
|
|
1204
|
+
6,
|
|
1205
|
+
7,
|
|
1206
|
+
7,
|
|
1207
|
+
8,
|
|
1208
|
+
8,
|
|
1209
|
+
9,
|
|
1210
|
+
9,
|
|
1211
|
+
10,
|
|
1212
|
+
10,
|
|
1213
|
+
11,
|
|
1214
|
+
11,
|
|
1215
|
+
12,
|
|
1216
|
+
12,
|
|
1217
|
+
13,
|
|
1218
|
+
13,
|
|
1219
|
+
/* unused */
|
|
1220
|
+
0,
|
|
1221
|
+
0
|
|
1222
|
+
]);
|
|
1223
|
+
var clim = new u8([16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15]);
|
|
1224
|
+
var freb = function(eb, start) {
|
|
1225
|
+
var b = new u16(31);
|
|
1226
|
+
for (var i = 0; i < 31; ++i) {
|
|
1227
|
+
b[i] = start += 1 << eb[i - 1];
|
|
1228
|
+
}
|
|
1229
|
+
var r = new i32(b[30]);
|
|
1230
|
+
for (var i = 1; i < 30; ++i) {
|
|
1231
|
+
for (var j = b[i]; j < b[i + 1]; ++j) {
|
|
1232
|
+
r[j] = j - b[i] << 5 | i;
|
|
1233
|
+
}
|
|
1234
|
+
}
|
|
1235
|
+
return { b, r };
|
|
1236
|
+
};
|
|
1237
|
+
var _a = freb(fleb, 2);
|
|
1238
|
+
var fl = _a.b;
|
|
1239
|
+
var revfl = _a.r;
|
|
1240
|
+
fl[28] = 258, revfl[258] = 28;
|
|
1241
|
+
var _b = freb(fdeb, 0);
|
|
1242
|
+
var fd = _b.b;
|
|
1243
|
+
var revfd = _b.r;
|
|
1244
|
+
var rev = new u16(32768);
|
|
1245
|
+
for (i = 0; i < 32768; ++i) {
|
|
1246
|
+
x = (i & 43690) >> 1 | (i & 21845) << 1;
|
|
1247
|
+
x = (x & 52428) >> 2 | (x & 13107) << 2;
|
|
1248
|
+
x = (x & 61680) >> 4 | (x & 3855) << 4;
|
|
1249
|
+
rev[i] = ((x & 65280) >> 8 | (x & 255) << 8) >> 1;
|
|
1250
|
+
}
|
|
1251
|
+
var x;
|
|
1252
|
+
var i;
|
|
1253
|
+
var hMap = (function(cd, mb, r) {
|
|
1254
|
+
var s = cd.length;
|
|
1255
|
+
var i = 0;
|
|
1256
|
+
var l = new u16(mb);
|
|
1257
|
+
for (; i < s; ++i) {
|
|
1258
|
+
if (cd[i])
|
|
1259
|
+
++l[cd[i] - 1];
|
|
1260
|
+
}
|
|
1261
|
+
var le = new u16(mb);
|
|
1262
|
+
for (i = 1; i < mb; ++i) {
|
|
1263
|
+
le[i] = le[i - 1] + l[i - 1] << 1;
|
|
1264
|
+
}
|
|
1265
|
+
var co;
|
|
1266
|
+
if (r) {
|
|
1267
|
+
co = new u16(1 << mb);
|
|
1268
|
+
var rvb = 15 - mb;
|
|
1269
|
+
for (i = 0; i < s; ++i) {
|
|
1270
|
+
if (cd[i]) {
|
|
1271
|
+
var sv = i << 4 | cd[i];
|
|
1272
|
+
var r_1 = mb - cd[i];
|
|
1273
|
+
var v = le[cd[i] - 1]++ << r_1;
|
|
1274
|
+
for (var m = v | (1 << r_1) - 1; v <= m; ++v) {
|
|
1275
|
+
co[rev[v] >> rvb] = sv;
|
|
1276
|
+
}
|
|
1277
|
+
}
|
|
1278
|
+
}
|
|
1279
|
+
} else {
|
|
1280
|
+
co = new u16(s);
|
|
1281
|
+
for (i = 0; i < s; ++i) {
|
|
1282
|
+
if (cd[i]) {
|
|
1283
|
+
co[i] = rev[le[cd[i] - 1]++] >> 15 - cd[i];
|
|
1284
|
+
}
|
|
1285
|
+
}
|
|
1286
|
+
}
|
|
1287
|
+
return co;
|
|
1288
|
+
});
|
|
1289
|
+
var flt = new u8(288);
|
|
1290
|
+
for (i = 0; i < 144; ++i)
|
|
1291
|
+
flt[i] = 8;
|
|
1292
|
+
var i;
|
|
1293
|
+
for (i = 144; i < 256; ++i)
|
|
1294
|
+
flt[i] = 9;
|
|
1295
|
+
var i;
|
|
1296
|
+
for (i = 256; i < 280; ++i)
|
|
1297
|
+
flt[i] = 7;
|
|
1298
|
+
var i;
|
|
1299
|
+
for (i = 280; i < 288; ++i)
|
|
1300
|
+
flt[i] = 8;
|
|
1301
|
+
var i;
|
|
1302
|
+
var fdt = new u8(32);
|
|
1303
|
+
for (i = 0; i < 32; ++i)
|
|
1304
|
+
fdt[i] = 5;
|
|
1305
|
+
var i;
|
|
1306
|
+
var flm = /* @__PURE__ */ hMap(flt, 9, 0);
|
|
1307
|
+
var fdm = /* @__PURE__ */ hMap(fdt, 5, 0);
|
|
1308
|
+
var shft = function(p) {
|
|
1309
|
+
return (p + 7) / 8 | 0;
|
|
1310
|
+
};
|
|
1311
|
+
var slc = function(v, s, e) {
|
|
1312
|
+
if (s == null || s < 0)
|
|
1313
|
+
s = 0;
|
|
1314
|
+
if (e == null || e > v.length)
|
|
1315
|
+
e = v.length;
|
|
1316
|
+
return new u8(v.subarray(s, e));
|
|
1317
|
+
};
|
|
1318
|
+
var ec = [
|
|
1319
|
+
"unexpected EOF",
|
|
1320
|
+
"invalid block type",
|
|
1321
|
+
"invalid length/literal",
|
|
1322
|
+
"invalid distance",
|
|
1323
|
+
"stream finished",
|
|
1324
|
+
"no stream handler",
|
|
1325
|
+
,
|
|
1326
|
+
// determined by compression function
|
|
1327
|
+
"no callback",
|
|
1328
|
+
"invalid UTF-8 data",
|
|
1329
|
+
"extra field too long",
|
|
1330
|
+
"date not in range 1980-2099",
|
|
1331
|
+
"filename too long",
|
|
1332
|
+
"stream finishing",
|
|
1333
|
+
"invalid zip data"
|
|
1334
|
+
// determined by unknown compression method
|
|
1335
|
+
];
|
|
1336
|
+
var err = function(ind, msg, nt) {
|
|
1337
|
+
var e = new Error(msg || ec[ind]);
|
|
1338
|
+
e.code = ind;
|
|
1339
|
+
if (Error.captureStackTrace)
|
|
1340
|
+
Error.captureStackTrace(e, err);
|
|
1341
|
+
if (!nt)
|
|
1342
|
+
throw e;
|
|
1343
|
+
return e;
|
|
1344
|
+
};
|
|
1345
|
+
var wbits = function(d, p, v) {
|
|
1346
|
+
v <<= p & 7;
|
|
1347
|
+
var o = p / 8 | 0;
|
|
1348
|
+
d[o] |= v;
|
|
1349
|
+
d[o + 1] |= v >> 8;
|
|
1350
|
+
};
|
|
1351
|
+
var wbits16 = function(d, p, v) {
|
|
1352
|
+
v <<= p & 7;
|
|
1353
|
+
var o = p / 8 | 0;
|
|
1354
|
+
d[o] |= v;
|
|
1355
|
+
d[o + 1] |= v >> 8;
|
|
1356
|
+
d[o + 2] |= v >> 16;
|
|
1357
|
+
};
|
|
1358
|
+
var hTree = function(d, mb) {
|
|
1359
|
+
var t = [];
|
|
1360
|
+
for (var i = 0; i < d.length; ++i) {
|
|
1361
|
+
if (d[i])
|
|
1362
|
+
t.push({ s: i, f: d[i] });
|
|
1363
|
+
}
|
|
1364
|
+
var s = t.length;
|
|
1365
|
+
var t2 = t.slice();
|
|
1366
|
+
if (!s)
|
|
1367
|
+
return { t: et, l: 0 };
|
|
1368
|
+
if (s == 1) {
|
|
1369
|
+
var v = new u8(t[0].s + 1);
|
|
1370
|
+
v[t[0].s] = 1;
|
|
1371
|
+
return { t: v, l: 1 };
|
|
1372
|
+
}
|
|
1373
|
+
t.sort(function(a, b) {
|
|
1374
|
+
return a.f - b.f;
|
|
1375
|
+
});
|
|
1376
|
+
t.push({ s: -1, f: 25001 });
|
|
1377
|
+
var l = t[0], r = t[1], i0 = 0, i1 = 1, i2 = 2;
|
|
1378
|
+
t[0] = { s: -1, f: l.f + r.f, l, r };
|
|
1379
|
+
while (i1 != s - 1) {
|
|
1380
|
+
l = t[t[i0].f < t[i2].f ? i0++ : i2++];
|
|
1381
|
+
r = t[i0 != i1 && t[i0].f < t[i2].f ? i0++ : i2++];
|
|
1382
|
+
t[i1++] = { s: -1, f: l.f + r.f, l, r };
|
|
1383
|
+
}
|
|
1384
|
+
var maxSym = t2[0].s;
|
|
1385
|
+
for (var i = 1; i < s; ++i) {
|
|
1386
|
+
if (t2[i].s > maxSym)
|
|
1387
|
+
maxSym = t2[i].s;
|
|
1388
|
+
}
|
|
1389
|
+
var tr = new u16(maxSym + 1);
|
|
1390
|
+
var mbt = ln(t[i1 - 1], tr, 0);
|
|
1391
|
+
if (mbt > mb) {
|
|
1392
|
+
var i = 0, dt = 0;
|
|
1393
|
+
var lft = mbt - mb, cst = 1 << lft;
|
|
1394
|
+
t2.sort(function(a, b) {
|
|
1395
|
+
return tr[b.s] - tr[a.s] || a.f - b.f;
|
|
1396
|
+
});
|
|
1397
|
+
for (; i < s; ++i) {
|
|
1398
|
+
var i2_1 = t2[i].s;
|
|
1399
|
+
if (tr[i2_1] > mb) {
|
|
1400
|
+
dt += cst - (1 << mbt - tr[i2_1]);
|
|
1401
|
+
tr[i2_1] = mb;
|
|
1402
|
+
} else
|
|
1403
|
+
break;
|
|
1404
|
+
}
|
|
1405
|
+
dt >>= lft;
|
|
1406
|
+
while (dt > 0) {
|
|
1407
|
+
var i2_2 = t2[i].s;
|
|
1408
|
+
if (tr[i2_2] < mb)
|
|
1409
|
+
dt -= 1 << mb - tr[i2_2]++ - 1;
|
|
1410
|
+
else
|
|
1411
|
+
++i;
|
|
1412
|
+
}
|
|
1413
|
+
for (; i >= 0 && dt; --i) {
|
|
1414
|
+
var i2_3 = t2[i].s;
|
|
1415
|
+
if (tr[i2_3] == mb) {
|
|
1416
|
+
--tr[i2_3];
|
|
1417
|
+
++dt;
|
|
1418
|
+
}
|
|
1419
|
+
}
|
|
1420
|
+
mbt = mb;
|
|
1421
|
+
}
|
|
1422
|
+
return { t: new u8(tr), l: mbt };
|
|
1423
|
+
};
|
|
1424
|
+
var ln = function(n, l, d) {
|
|
1425
|
+
return n.s == -1 ? Math.max(ln(n.l, l, d + 1), ln(n.r, l, d + 1)) : l[n.s] = d;
|
|
1426
|
+
};
|
|
1427
|
+
var lc = function(c) {
|
|
1428
|
+
var s = c.length;
|
|
1429
|
+
while (s && !c[--s])
|
|
1430
|
+
;
|
|
1431
|
+
var cl = new u16(++s);
|
|
1432
|
+
var cli = 0, cln = c[0], cls = 1;
|
|
1433
|
+
var w = function(v) {
|
|
1434
|
+
cl[cli++] = v;
|
|
1435
|
+
};
|
|
1436
|
+
for (var i = 1; i <= s; ++i) {
|
|
1437
|
+
if (c[i] == cln && i != s)
|
|
1438
|
+
++cls;
|
|
1439
|
+
else {
|
|
1440
|
+
if (!cln && cls > 2) {
|
|
1441
|
+
for (; cls > 138; cls -= 138)
|
|
1442
|
+
w(32754);
|
|
1443
|
+
if (cls > 2) {
|
|
1444
|
+
w(cls > 10 ? cls - 11 << 5 | 28690 : cls - 3 << 5 | 12305);
|
|
1445
|
+
cls = 0;
|
|
1446
|
+
}
|
|
1447
|
+
} else if (cls > 3) {
|
|
1448
|
+
w(cln), --cls;
|
|
1449
|
+
for (; cls > 6; cls -= 6)
|
|
1450
|
+
w(8304);
|
|
1451
|
+
if (cls > 2)
|
|
1452
|
+
w(cls - 3 << 5 | 8208), cls = 0;
|
|
1453
|
+
}
|
|
1454
|
+
while (cls--)
|
|
1455
|
+
w(cln);
|
|
1456
|
+
cls = 1;
|
|
1457
|
+
cln = c[i];
|
|
1458
|
+
}
|
|
1459
|
+
}
|
|
1460
|
+
return { c: cl.subarray(0, cli), n: s };
|
|
1461
|
+
};
|
|
1462
|
+
var clen = function(cf, cl) {
|
|
1463
|
+
var l = 0;
|
|
1464
|
+
for (var i = 0; i < cl.length; ++i)
|
|
1465
|
+
l += cf[i] * cl[i];
|
|
1466
|
+
return l;
|
|
1467
|
+
};
|
|
1468
|
+
var wfblk = function(out, pos, dat) {
|
|
1469
|
+
var s = dat.length;
|
|
1470
|
+
var o = shft(pos + 2);
|
|
1471
|
+
out[o] = s & 255;
|
|
1472
|
+
out[o + 1] = s >> 8;
|
|
1473
|
+
out[o + 2] = out[o] ^ 255;
|
|
1474
|
+
out[o + 3] = out[o + 1] ^ 255;
|
|
1475
|
+
for (var i = 0; i < s; ++i)
|
|
1476
|
+
out[o + i + 4] = dat[i];
|
|
1477
|
+
return (o + 4 + s) * 8;
|
|
1478
|
+
};
|
|
1479
|
+
var wblk = function(dat, out, final, syms, lf, df, eb, li, bs, bl, p) {
|
|
1480
|
+
wbits(out, p++, final);
|
|
1481
|
+
++lf[256];
|
|
1482
|
+
var _a2 = hTree(lf, 15), dlt = _a2.t, mlb = _a2.l;
|
|
1483
|
+
var _b2 = hTree(df, 15), ddt = _b2.t, mdb = _b2.l;
|
|
1484
|
+
var _c = lc(dlt), lclt = _c.c, nlc = _c.n;
|
|
1485
|
+
var _d = lc(ddt), lcdt = _d.c, ndc = _d.n;
|
|
1486
|
+
var lcfreq = new u16(19);
|
|
1487
|
+
for (var i = 0; i < lclt.length; ++i)
|
|
1488
|
+
++lcfreq[lclt[i] & 31];
|
|
1489
|
+
for (var i = 0; i < lcdt.length; ++i)
|
|
1490
|
+
++lcfreq[lcdt[i] & 31];
|
|
1491
|
+
var _e = hTree(lcfreq, 7), lct = _e.t, mlcb = _e.l;
|
|
1492
|
+
var nlcc = 19;
|
|
1493
|
+
for (; nlcc > 4 && !lct[clim[nlcc - 1]]; --nlcc)
|
|
1494
|
+
;
|
|
1495
|
+
var flen = bl + 5 << 3;
|
|
1496
|
+
var ftlen = clen(lf, flt) + clen(df, fdt) + eb;
|
|
1497
|
+
var dtlen = clen(lf, dlt) + clen(df, ddt) + eb + 14 + 3 * nlcc + clen(lcfreq, lct) + 2 * lcfreq[16] + 3 * lcfreq[17] + 7 * lcfreq[18];
|
|
1498
|
+
if (bs >= 0 && flen <= ftlen && flen <= dtlen)
|
|
1499
|
+
return wfblk(out, p, dat.subarray(bs, bs + bl));
|
|
1500
|
+
var lm, ll, dm, dl;
|
|
1501
|
+
wbits(out, p, 1 + (dtlen < ftlen)), p += 2;
|
|
1502
|
+
if (dtlen < ftlen) {
|
|
1503
|
+
lm = hMap(dlt, mlb, 0), ll = dlt, dm = hMap(ddt, mdb, 0), dl = ddt;
|
|
1504
|
+
var llm = hMap(lct, mlcb, 0);
|
|
1505
|
+
wbits(out, p, nlc - 257);
|
|
1506
|
+
wbits(out, p + 5, ndc - 1);
|
|
1507
|
+
wbits(out, p + 10, nlcc - 4);
|
|
1508
|
+
p += 14;
|
|
1509
|
+
for (var i = 0; i < nlcc; ++i)
|
|
1510
|
+
wbits(out, p + 3 * i, lct[clim[i]]);
|
|
1511
|
+
p += 3 * nlcc;
|
|
1512
|
+
var lcts = [lclt, lcdt];
|
|
1513
|
+
for (var it = 0; it < 2; ++it) {
|
|
1514
|
+
var clct = lcts[it];
|
|
1515
|
+
for (var i = 0; i < clct.length; ++i) {
|
|
1516
|
+
var len = clct[i] & 31;
|
|
1517
|
+
wbits(out, p, llm[len]), p += lct[len];
|
|
1518
|
+
if (len > 15)
|
|
1519
|
+
wbits(out, p, clct[i] >> 5 & 127), p += clct[i] >> 12;
|
|
1520
|
+
}
|
|
1521
|
+
}
|
|
1522
|
+
} else {
|
|
1523
|
+
lm = flm, ll = flt, dm = fdm, dl = fdt;
|
|
1524
|
+
}
|
|
1525
|
+
for (var i = 0; i < li; ++i) {
|
|
1526
|
+
var sym = syms[i];
|
|
1527
|
+
if (sym > 255) {
|
|
1528
|
+
var len = sym >> 18 & 31;
|
|
1529
|
+
wbits16(out, p, lm[len + 257]), p += ll[len + 257];
|
|
1530
|
+
if (len > 7)
|
|
1531
|
+
wbits(out, p, sym >> 23 & 31), p += fleb[len];
|
|
1532
|
+
var dst = sym & 31;
|
|
1533
|
+
wbits16(out, p, dm[dst]), p += dl[dst];
|
|
1534
|
+
if (dst > 3)
|
|
1535
|
+
wbits16(out, p, sym >> 5 & 8191), p += fdeb[dst];
|
|
1536
|
+
} else {
|
|
1537
|
+
wbits16(out, p, lm[sym]), p += ll[sym];
|
|
1538
|
+
}
|
|
1539
|
+
}
|
|
1540
|
+
wbits16(out, p, lm[256]);
|
|
1541
|
+
return p + ll[256];
|
|
1542
|
+
};
|
|
1543
|
+
var deo = /* @__PURE__ */ new i32([65540, 131080, 131088, 131104, 262176, 1048704, 1048832, 2114560, 2117632]);
|
|
1544
|
+
var et = /* @__PURE__ */ new u8(0);
|
|
1545
|
+
var dflt = function(dat, lvl, plvl, pre, post, st) {
|
|
1546
|
+
var s = st.z || dat.length;
|
|
1547
|
+
var o = new u8(pre + s + 5 * (1 + Math.ceil(s / 7e3)) + post);
|
|
1548
|
+
var w = o.subarray(pre, o.length - post);
|
|
1549
|
+
var lst = st.l;
|
|
1550
|
+
var pos = (st.r || 0) & 7;
|
|
1551
|
+
if (lvl) {
|
|
1552
|
+
if (pos)
|
|
1553
|
+
w[0] = st.r >> 3;
|
|
1554
|
+
var opt = deo[lvl - 1];
|
|
1555
|
+
var n = opt >> 13, c = opt & 8191;
|
|
1556
|
+
var msk_1 = (1 << plvl) - 1;
|
|
1557
|
+
var prev = st.p || new u16(32768), head = st.h || new u16(msk_1 + 1);
|
|
1558
|
+
var bs1_1 = Math.ceil(plvl / 3), bs2_1 = 2 * bs1_1;
|
|
1559
|
+
var hsh = function(i2) {
|
|
1560
|
+
return (dat[i2] ^ dat[i2 + 1] << bs1_1 ^ dat[i2 + 2] << bs2_1) & msk_1;
|
|
1561
|
+
};
|
|
1562
|
+
var syms = new i32(25e3);
|
|
1563
|
+
var lf = new u16(288), df = new u16(32);
|
|
1564
|
+
var lc_1 = 0, eb = 0, i = st.i || 0, li = 0, wi = st.w || 0, bs = 0;
|
|
1565
|
+
for (; i + 2 < s; ++i) {
|
|
1566
|
+
var hv = hsh(i);
|
|
1567
|
+
var imod = i & 32767, pimod = head[hv];
|
|
1568
|
+
prev[imod] = pimod;
|
|
1569
|
+
head[hv] = imod;
|
|
1570
|
+
if (wi <= i) {
|
|
1571
|
+
var rem = s - i;
|
|
1572
|
+
if ((lc_1 > 7e3 || li > 24576) && (rem > 423 || !lst)) {
|
|
1573
|
+
pos = wblk(dat, w, 0, syms, lf, df, eb, li, bs, i - bs, pos);
|
|
1574
|
+
li = lc_1 = eb = 0, bs = i;
|
|
1575
|
+
for (var j = 0; j < 286; ++j)
|
|
1576
|
+
lf[j] = 0;
|
|
1577
|
+
for (var j = 0; j < 30; ++j)
|
|
1578
|
+
df[j] = 0;
|
|
1579
|
+
}
|
|
1580
|
+
var l = 2, d = 0, ch_1 = c, dif = imod - pimod & 32767;
|
|
1581
|
+
if (rem > 2 && hv == hsh(i - dif)) {
|
|
1582
|
+
var maxn = Math.min(n, rem) - 1;
|
|
1583
|
+
var maxd = Math.min(32767, i);
|
|
1584
|
+
var ml = Math.min(258, rem);
|
|
1585
|
+
while (dif <= maxd && --ch_1 && imod != pimod) {
|
|
1586
|
+
if (dat[i + l] == dat[i + l - dif]) {
|
|
1587
|
+
var nl = 0;
|
|
1588
|
+
for (; nl < ml && dat[i + nl] == dat[i + nl - dif]; ++nl)
|
|
1589
|
+
;
|
|
1590
|
+
if (nl > l) {
|
|
1591
|
+
l = nl, d = dif;
|
|
1592
|
+
if (nl > maxn)
|
|
1593
|
+
break;
|
|
1594
|
+
var mmd = Math.min(dif, nl - 2);
|
|
1595
|
+
var md = 0;
|
|
1596
|
+
for (var j = 0; j < mmd; ++j) {
|
|
1597
|
+
var ti = i - dif + j & 32767;
|
|
1598
|
+
var pti = prev[ti];
|
|
1599
|
+
var cd = ti - pti & 32767;
|
|
1600
|
+
if (cd > md)
|
|
1601
|
+
md = cd, pimod = ti;
|
|
1602
|
+
}
|
|
1603
|
+
}
|
|
1604
|
+
}
|
|
1605
|
+
imod = pimod, pimod = prev[imod];
|
|
1606
|
+
dif += imod - pimod & 32767;
|
|
1607
|
+
}
|
|
1608
|
+
}
|
|
1609
|
+
if (d) {
|
|
1610
|
+
syms[li++] = 268435456 | revfl[l] << 18 | revfd[d];
|
|
1611
|
+
var lin = revfl[l] & 31, din = revfd[d] & 31;
|
|
1612
|
+
eb += fleb[lin] + fdeb[din];
|
|
1613
|
+
++lf[257 + lin];
|
|
1614
|
+
++df[din];
|
|
1615
|
+
wi = i + l;
|
|
1616
|
+
++lc_1;
|
|
1617
|
+
} else {
|
|
1618
|
+
syms[li++] = dat[i];
|
|
1619
|
+
++lf[dat[i]];
|
|
1620
|
+
}
|
|
1621
|
+
}
|
|
1622
|
+
}
|
|
1623
|
+
for (i = Math.max(i, wi); i < s; ++i) {
|
|
1624
|
+
syms[li++] = dat[i];
|
|
1625
|
+
++lf[dat[i]];
|
|
1626
|
+
}
|
|
1627
|
+
pos = wblk(dat, w, lst, syms, lf, df, eb, li, bs, i - bs, pos);
|
|
1628
|
+
if (!lst) {
|
|
1629
|
+
st.r = pos & 7 | w[pos / 8 | 0] << 3;
|
|
1630
|
+
pos -= 7;
|
|
1631
|
+
st.h = head, st.p = prev, st.i = i, st.w = wi;
|
|
1632
|
+
}
|
|
1633
|
+
} else {
|
|
1634
|
+
for (var i = st.w || 0; i < s + lst; i += 65535) {
|
|
1635
|
+
var e = i + 65535;
|
|
1636
|
+
if (e >= s) {
|
|
1637
|
+
w[pos / 8 | 0] = lst;
|
|
1638
|
+
e = s;
|
|
1639
|
+
}
|
|
1640
|
+
pos = wfblk(w, pos + 1, dat.subarray(i, e));
|
|
1641
|
+
}
|
|
1642
|
+
st.i = s;
|
|
1643
|
+
}
|
|
1644
|
+
return slc(o, 0, pre + shft(pos) + post);
|
|
1645
|
+
};
|
|
1646
|
+
var crct = /* @__PURE__ */ (function() {
|
|
1647
|
+
var t = new Int32Array(256);
|
|
1648
|
+
for (var i = 0; i < 256; ++i) {
|
|
1649
|
+
var c = i, k = 9;
|
|
1650
|
+
while (--k)
|
|
1651
|
+
c = (c & 1 && -306674912) ^ c >>> 1;
|
|
1652
|
+
t[i] = c;
|
|
1653
|
+
}
|
|
1654
|
+
return t;
|
|
1655
|
+
})();
|
|
1656
|
+
var crc = function() {
|
|
1657
|
+
var c = -1;
|
|
1658
|
+
return {
|
|
1659
|
+
p: function(d) {
|
|
1660
|
+
var cr = c;
|
|
1661
|
+
for (var i = 0; i < d.length; ++i)
|
|
1662
|
+
cr = crct[cr & 255 ^ d[i]] ^ cr >>> 8;
|
|
1663
|
+
c = cr;
|
|
1664
|
+
},
|
|
1665
|
+
d: function() {
|
|
1666
|
+
return ~c;
|
|
1667
|
+
}
|
|
1668
|
+
};
|
|
1669
|
+
};
|
|
1670
|
+
var dopt = function(dat, opt, pre, post, st) {
|
|
1671
|
+
if (!st) {
|
|
1672
|
+
st = { l: 1 };
|
|
1673
|
+
if (opt.dictionary) {
|
|
1674
|
+
var dict = opt.dictionary.subarray(-32768);
|
|
1675
|
+
var newDat = new u8(dict.length + dat.length);
|
|
1676
|
+
newDat.set(dict);
|
|
1677
|
+
newDat.set(dat, dict.length);
|
|
1678
|
+
dat = newDat;
|
|
1679
|
+
st.w = dict.length;
|
|
1680
|
+
}
|
|
1681
|
+
}
|
|
1682
|
+
return dflt(dat, opt.level == null ? 6 : opt.level, opt.mem == null ? st.l ? Math.ceil(Math.max(8, Math.min(13, Math.log(dat.length))) * 1.5) : 20 : 12 + opt.mem, pre, post, st);
|
|
1683
|
+
};
|
|
1684
|
+
var mrg = function(a, b) {
|
|
1685
|
+
var o = {};
|
|
1686
|
+
for (var k in a)
|
|
1687
|
+
o[k] = a[k];
|
|
1688
|
+
for (var k in b)
|
|
1689
|
+
o[k] = b[k];
|
|
1690
|
+
return o;
|
|
1691
|
+
};
|
|
1692
|
+
var wbytes = function(d, b, v) {
|
|
1693
|
+
for (; v; ++b)
|
|
1694
|
+
d[b] = v, v >>>= 8;
|
|
1695
|
+
};
|
|
1696
|
+
function deflateSync(data, opts) {
|
|
1697
|
+
return dopt(data, opts || {}, 0, 0);
|
|
1698
|
+
}
|
|
1699
|
+
var fltn = function(d, p, t, o) {
|
|
1700
|
+
for (var k in d) {
|
|
1701
|
+
var val = d[k], n = p + k, op = o;
|
|
1702
|
+
if (Array.isArray(val))
|
|
1703
|
+
op = mrg(o, val[1]), val = val[0];
|
|
1704
|
+
if (ArrayBuffer.isView(val))
|
|
1705
|
+
t[n] = [val, op];
|
|
1706
|
+
else {
|
|
1707
|
+
t[n += "/"] = [new u8(0), op];
|
|
1708
|
+
fltn(val, n, t, o);
|
|
1709
|
+
}
|
|
1710
|
+
}
|
|
1711
|
+
};
|
|
1712
|
+
var te = typeof TextEncoder != "undefined" && /* @__PURE__ */ new TextEncoder();
|
|
1713
|
+
var td = typeof TextDecoder != "undefined" && /* @__PURE__ */ new TextDecoder();
|
|
1714
|
+
var tds = 0;
|
|
1715
|
+
try {
|
|
1716
|
+
td.decode(et, { stream: true });
|
|
1717
|
+
tds = 1;
|
|
1718
|
+
} catch (e) {
|
|
1719
|
+
}
|
|
1720
|
+
function strToU8(str, latin1) {
|
|
1721
|
+
if (latin1) {
|
|
1722
|
+
var ar_1 = new u8(str.length);
|
|
1723
|
+
for (var i = 0; i < str.length; ++i)
|
|
1724
|
+
ar_1[i] = str.charCodeAt(i);
|
|
1725
|
+
return ar_1;
|
|
1726
|
+
}
|
|
1727
|
+
if (te)
|
|
1728
|
+
return te.encode(str);
|
|
1729
|
+
var l = str.length;
|
|
1730
|
+
var ar = new u8(str.length + (str.length >> 1));
|
|
1731
|
+
var ai = 0;
|
|
1732
|
+
var w = function(v) {
|
|
1733
|
+
ar[ai++] = v;
|
|
1734
|
+
};
|
|
1735
|
+
for (var i = 0; i < l; ++i) {
|
|
1736
|
+
if (ai + 5 > ar.length) {
|
|
1737
|
+
var n = new u8(ai + 8 + (l - i << 1));
|
|
1738
|
+
n.set(ar);
|
|
1739
|
+
ar = n;
|
|
1740
|
+
}
|
|
1741
|
+
var c = str.charCodeAt(i);
|
|
1742
|
+
if (c < 128 || latin1)
|
|
1743
|
+
w(c);
|
|
1744
|
+
else if (c < 2048)
|
|
1745
|
+
w(192 | c >> 6), w(128 | c & 63);
|
|
1746
|
+
else if (c > 55295 && c < 57344)
|
|
1747
|
+
c = 65536 + (c & 1023 << 10) | str.charCodeAt(++i) & 1023, w(240 | c >> 18), w(128 | c >> 12 & 63), w(128 | c >> 6 & 63), w(128 | c & 63);
|
|
1748
|
+
else
|
|
1749
|
+
w(224 | c >> 12), w(128 | c >> 6 & 63), w(128 | c & 63);
|
|
1750
|
+
}
|
|
1751
|
+
return slc(ar, 0, ai);
|
|
1752
|
+
}
|
|
1753
|
+
var exfl = function(ex) {
|
|
1754
|
+
var le = 0;
|
|
1755
|
+
if (ex) {
|
|
1756
|
+
for (var k in ex) {
|
|
1757
|
+
var l = ex[k].length;
|
|
1758
|
+
if (l > 65535)
|
|
1759
|
+
err(9);
|
|
1760
|
+
le += l + 4;
|
|
1761
|
+
}
|
|
1762
|
+
}
|
|
1763
|
+
return le;
|
|
1764
|
+
};
|
|
1765
|
+
var wzh = function(d, b, f, fn, u, c, ce, co) {
|
|
1766
|
+
var fl2 = fn.length, ex = f.extra, col = co && co.length;
|
|
1767
|
+
var exl = exfl(ex);
|
|
1768
|
+
wbytes(d, b, ce != null ? 33639248 : 67324752), b += 4;
|
|
1769
|
+
if (ce != null)
|
|
1770
|
+
d[b++] = 20, d[b++] = f.os;
|
|
1771
|
+
d[b] = 20, b += 2;
|
|
1772
|
+
d[b++] = f.flag << 1 | (c < 0 && 8), d[b++] = u && 8;
|
|
1773
|
+
d[b++] = f.compression & 255, d[b++] = f.compression >> 8;
|
|
1774
|
+
var dt = new Date(f.mtime == null ? Date.now() : f.mtime), y = dt.getFullYear() - 1980;
|
|
1775
|
+
if (y < 0 || y > 119)
|
|
1776
|
+
err(10);
|
|
1777
|
+
wbytes(d, b, y << 25 | dt.getMonth() + 1 << 21 | dt.getDate() << 16 | dt.getHours() << 11 | dt.getMinutes() << 5 | dt.getSeconds() >> 1), b += 4;
|
|
1778
|
+
if (c != -1) {
|
|
1779
|
+
wbytes(d, b, f.crc);
|
|
1780
|
+
wbytes(d, b + 4, c < 0 ? -c - 2 : c);
|
|
1781
|
+
wbytes(d, b + 8, f.size);
|
|
1782
|
+
}
|
|
1783
|
+
wbytes(d, b + 12, fl2);
|
|
1784
|
+
wbytes(d, b + 14, exl), b += 16;
|
|
1785
|
+
if (ce != null) {
|
|
1786
|
+
wbytes(d, b, col);
|
|
1787
|
+
wbytes(d, b + 6, f.attrs);
|
|
1788
|
+
wbytes(d, b + 10, ce), b += 14;
|
|
1789
|
+
}
|
|
1790
|
+
d.set(fn, b);
|
|
1791
|
+
b += fl2;
|
|
1792
|
+
if (exl) {
|
|
1793
|
+
for (var k in ex) {
|
|
1794
|
+
var exf = ex[k], l = exf.length;
|
|
1795
|
+
wbytes(d, b, +k);
|
|
1796
|
+
wbytes(d, b + 2, l);
|
|
1797
|
+
d.set(exf, b + 4), b += 4 + l;
|
|
1798
|
+
}
|
|
1799
|
+
}
|
|
1800
|
+
if (col)
|
|
1801
|
+
d.set(co, b), b += col;
|
|
1802
|
+
return b;
|
|
1803
|
+
};
|
|
1804
|
+
var wzf = function(o, b, c, d, e) {
|
|
1805
|
+
wbytes(o, b, 101010256);
|
|
1806
|
+
wbytes(o, b + 8, c);
|
|
1807
|
+
wbytes(o, b + 10, c);
|
|
1808
|
+
wbytes(o, b + 12, d);
|
|
1809
|
+
wbytes(o, b + 16, e);
|
|
1810
|
+
};
|
|
1811
|
+
function zipSync(data, opts) {
|
|
1812
|
+
if (!opts)
|
|
1813
|
+
opts = {};
|
|
1814
|
+
var r = {};
|
|
1815
|
+
var files = [];
|
|
1816
|
+
fltn(data, "", r, opts);
|
|
1817
|
+
var o = 0;
|
|
1818
|
+
var tot = 0;
|
|
1819
|
+
for (var fn in r) {
|
|
1820
|
+
var _a2 = r[fn], file2 = _a2[0], p = _a2[1];
|
|
1821
|
+
var compression = p.level == 0 ? 0 : 8;
|
|
1822
|
+
var f = strToU8(fn), s = f.length;
|
|
1823
|
+
var com = p.comment, m = com && strToU8(com), ms = m && m.length;
|
|
1824
|
+
var exl = exfl(p.extra);
|
|
1825
|
+
if (s > 65535)
|
|
1826
|
+
err(11);
|
|
1827
|
+
var d = compression ? deflateSync(file2, p) : file2, l = d.length;
|
|
1828
|
+
var c = crc();
|
|
1829
|
+
c.p(file2);
|
|
1830
|
+
files.push(mrg(p, {
|
|
1831
|
+
size: file2.length,
|
|
1832
|
+
crc: c.d(),
|
|
1833
|
+
c: d,
|
|
1834
|
+
f,
|
|
1835
|
+
m,
|
|
1836
|
+
u: s != fn.length || m && com.length != ms,
|
|
1837
|
+
o,
|
|
1838
|
+
compression
|
|
1839
|
+
}));
|
|
1840
|
+
o += 30 + s + exl + l;
|
|
1841
|
+
tot += 76 + 2 * (s + exl) + (ms || 0) + l;
|
|
1842
|
+
}
|
|
1843
|
+
var out = new u8(tot + 22), oe = o, cdl = tot - o;
|
|
1844
|
+
for (var i = 0; i < files.length; ++i) {
|
|
1845
|
+
var f = files[i];
|
|
1846
|
+
wzh(out, f.o, f, f.f, f.u, f.c.length);
|
|
1847
|
+
var badd = 30 + f.f.length + exfl(f.extra);
|
|
1848
|
+
out.set(f.c, f.o + badd);
|
|
1849
|
+
wzh(out, o, f, f.f, f.u, f.c.length, f.o, f.m), o += 16 + badd + (f.m ? f.m.length : 0);
|
|
1850
|
+
}
|
|
1851
|
+
wzf(out, o, files.length, cdl, oe);
|
|
1852
|
+
return out;
|
|
1853
|
+
}
|
|
1854
|
+
|
|
1855
|
+
// ../contracts/dist/operations.js
|
|
1856
|
+
async function getRun(http, runId) {
|
|
1857
|
+
const result = await http.request(`/api/runs/${encodeURIComponent(runId)}`);
|
|
1858
|
+
return hasRun(result) ? result.run : result;
|
|
1859
|
+
}
|
|
1860
|
+
async function getRunUnit(http, runId) {
|
|
1861
|
+
return http.request(`/api/runs/${encodeURIComponent(runId)}`);
|
|
1862
|
+
}
|
|
1863
|
+
async function listRunEvents(http, runId, options = {}) {
|
|
1864
|
+
const query = options.channel && options.channel !== "event" ? { channel: options.channel } : {};
|
|
1865
|
+
const result = await http.request(`/api/runs/${encodeURIComponent(runId)}/events`, {}, query);
|
|
1866
|
+
return result.events;
|
|
1867
|
+
}
|
|
1868
|
+
async function getCoordinatorTicket(http, runId) {
|
|
1869
|
+
return http.request(`/api/runs/${encodeURIComponent(runId)}/events/ticket`, { method: "POST" });
|
|
1870
|
+
}
|
|
1871
|
+
async function listOutputs(http, runId) {
|
|
1872
|
+
const result = await http.request(`/api/runs/${encodeURIComponent(runId)}/outputs`);
|
|
1873
|
+
return result.outputs;
|
|
1874
|
+
}
|
|
1875
|
+
async function listLogs(http, runId) {
|
|
1876
|
+
const result = await http.request(`/api/runs/${encodeURIComponent(runId)}/logs`);
|
|
1877
|
+
return result.logs.map((log) => typeof log.filename === "string" ? { ...log, filename: runArtifactRel(log.filename) } : log);
|
|
1878
|
+
}
|
|
1879
|
+
async function createOutputLink(http, runId, outputId) {
|
|
1880
|
+
return http.request(`/api/runs/${encodeURIComponent(runId)}/outputs/${encodeURIComponent(outputId)}/link`, { method: "POST" });
|
|
1881
|
+
}
|
|
1882
|
+
function resolveOutputFileSelector(outputs, selector, runId) {
|
|
1883
|
+
if (isPathSelector(selector)) {
|
|
1884
|
+
const target = normalizeOutputLookupPath(selector.path);
|
|
1885
|
+
if (!target) {
|
|
1886
|
+
throw new RunStateError("downloadOutput: output path must be non-empty", { runId, path: selector.path });
|
|
1887
|
+
}
|
|
1888
|
+
const matches = outputs.filter((output) => {
|
|
1889
|
+
if (typeof output.filename !== "string")
|
|
1890
|
+
return false;
|
|
1891
|
+
const filename = normalizeOutputLookupPath(output.filename);
|
|
1892
|
+
if (selector.match === "suffix") {
|
|
1893
|
+
return filename === target || filename.endsWith(`/${target}`);
|
|
1894
|
+
}
|
|
1895
|
+
return filename === target;
|
|
1896
|
+
});
|
|
1897
|
+
if (matches.length === 1)
|
|
1898
|
+
return matches[0];
|
|
1899
|
+
if (matches.length > 1) {
|
|
1900
|
+
throw new RunStateError(`downloadOutput: output path "${selector.path}" matched multiple files`, { runId, path: selector.path, matches: matches.map((output) => output.filename ?? output.id) });
|
|
1901
|
+
}
|
|
1902
|
+
throw new RunStateError(`downloadOutput: output path "${selector.path}" was not found`, {
|
|
1903
|
+
runId,
|
|
1904
|
+
path: selector.path
|
|
1905
|
+
});
|
|
1906
|
+
}
|
|
1907
|
+
if (typeof selector?.id !== "string" || selector.id.length === 0) {
|
|
1908
|
+
throw new RunStateError("downloadOutput: selector must include an output id or path", { runId });
|
|
1909
|
+
}
|
|
1910
|
+
return { ...selector, id: selector.id };
|
|
1911
|
+
}
|
|
1912
|
+
async function downloadOutput(http, runId, selector) {
|
|
1913
|
+
const output = isPathSelector(selector) ? resolveOutputFileSelector(await listOutputs(http, runId), selector, runId) : resolveOutputFileSelector([], selector, runId);
|
|
1914
|
+
const { response } = await http.download(`/api/runs/${encodeURIComponent(runId)}/outputs/${encodeURIComponent(output.id)}/download`);
|
|
1915
|
+
return { output, bytes: new Uint8Array(await response.arrayBuffer()) };
|
|
1916
|
+
}
|
|
1917
|
+
async function cancelRun(http, runId) {
|
|
1918
|
+
await http.request(`/api/runs/${encodeURIComponent(runId)}/cancel`, { method: "POST" });
|
|
1919
|
+
}
|
|
1920
|
+
async function deleteRun(http, runId) {
|
|
1921
|
+
await http.request(`/api/runs/${encodeURIComponent(runId)}`, { method: "DELETE" });
|
|
1922
|
+
}
|
|
1923
|
+
async function deleteWorkspaceAsset(http, hash) {
|
|
1924
|
+
const assetId = hash.startsWith("asset_") ? hash : `asset_${hash.startsWith("sha256:") ? hash.slice("sha256:".length) : hash}`;
|
|
1925
|
+
await http.request(`/assets/${encodeURIComponent(assetId)}`, { method: "DELETE" });
|
|
1926
|
+
}
|
|
1927
|
+
async function whoami(http) {
|
|
1928
|
+
return http.request("/api/whoami");
|
|
1929
|
+
}
|
|
1930
|
+
async function collectArtifactBytes(http, runId, items, zipPrefix, namespace2) {
|
|
1931
|
+
const entries = [];
|
|
1932
|
+
const captured = [];
|
|
1933
|
+
const errors = [];
|
|
1934
|
+
for (const item of items) {
|
|
1935
|
+
const rel = item.filename ?? item.id;
|
|
1936
|
+
try {
|
|
1937
|
+
const { response } = await http.download(`/api/runs/${encodeURIComponent(runId)}/${namespace2}/${encodeURIComponent(item.id)}/download`);
|
|
1938
|
+
entries.push({
|
|
1939
|
+
path: `${zipPrefix}${rel}`,
|
|
1940
|
+
bytes: new Uint8Array(await response.arrayBuffer()),
|
|
1941
|
+
...item.contentType !== void 0 ? { contentType: item.contentType } : {},
|
|
1942
|
+
...namespace2 === "outputs" ? { customerContent: true } : {}
|
|
1943
|
+
});
|
|
1944
|
+
captured.push({
|
|
1945
|
+
id: item.id,
|
|
1946
|
+
filename: item.filename ?? null,
|
|
1947
|
+
...item.sizeBytes !== void 0 ? { sizeBytes: item.sizeBytes } : {},
|
|
1948
|
+
...item.contentType !== void 0 ? { contentType: item.contentType } : {}
|
|
1949
|
+
});
|
|
1950
|
+
} catch (err2) {
|
|
1951
|
+
errors.push({ namespace: namespace2, id: item.id, filename: item.filename ?? null, message: err2.message });
|
|
1952
|
+
}
|
|
1953
|
+
}
|
|
1954
|
+
return { entries: Object.freeze(entries), captured, errors };
|
|
1955
|
+
}
|
|
1956
|
+
function eventsJsonl(events) {
|
|
1957
|
+
return strToU8(events.map((event) => JSON.stringify(event)).join("\n"));
|
|
1958
|
+
}
|
|
1959
|
+
async function tryListOptionalRunEvents(http, runId, channel) {
|
|
1960
|
+
try {
|
|
1961
|
+
const events = await listRunEvents(http, runId, { channel });
|
|
1962
|
+
if (channel === "log") {
|
|
1963
|
+
return events.length > 0 && events.every(isLogChannelEvent) ? { status: "present", events } : { status: "unavailable", events: [] };
|
|
1964
|
+
}
|
|
1965
|
+
return hasUnifiedStreamEvidence(events) ? { status: "present", events } : { status: "unavailable", events: [] };
|
|
1966
|
+
} catch {
|
|
1967
|
+
return { status: "unavailable", events: [] };
|
|
1968
|
+
}
|
|
1969
|
+
}
|
|
1970
|
+
function isLogChannelEvent(event) {
|
|
1971
|
+
return event.channel === "log";
|
|
1972
|
+
}
|
|
1973
|
+
function hasUnifiedStreamEvidence(events) {
|
|
1974
|
+
return events.some((event) => event.channel === "log" || event.channel === "event");
|
|
1975
|
+
}
|
|
1976
|
+
function isPathSelector(selector) {
|
|
1977
|
+
return Boolean(selector && typeof selector === "object" && "path" in selector);
|
|
1978
|
+
}
|
|
1979
|
+
function normalizeOutputLookupPath(path) {
|
|
1980
|
+
return path.replace(/\\/g, "/").replace(/^\/+/, "");
|
|
1981
|
+
}
|
|
1982
|
+
async function download(http, runId) {
|
|
1983
|
+
const [run, events, logEvents, allEvents, outputs, logItems] = await Promise.all([
|
|
1984
|
+
getRun(http, runId),
|
|
1985
|
+
listRunEvents(http, runId),
|
|
1986
|
+
tryListOptionalRunEvents(http, runId, "log"),
|
|
1987
|
+
tryListOptionalRunEvents(http, runId, "all"),
|
|
1988
|
+
listOutputs(http, runId),
|
|
1989
|
+
listLogs(http, runId)
|
|
1990
|
+
]);
|
|
1991
|
+
const out = await collectArtifactBytes(http, runId, outputs, "outputs/", "outputs");
|
|
1992
|
+
const logs = await collectArtifactBytes(http, runId, logItems, "logs/", "logs");
|
|
1993
|
+
const submissionSnapshot = extractSubmissionSnapshot(run);
|
|
1994
|
+
const costTelemetry = extractCostTelemetry(run);
|
|
1995
|
+
const manifest = buildRunRecordDownloadManifestV1({
|
|
1996
|
+
runId,
|
|
1997
|
+
outputs: out.captured,
|
|
1998
|
+
logs: logs.captured,
|
|
1999
|
+
errors: [...out.errors, ...logs.errors],
|
|
2000
|
+
typedEventCount: events.length,
|
|
2001
|
+
...submissionSnapshot ? { submission: { status: "present" } } : {},
|
|
2002
|
+
...costTelemetry ? { cost: { status: "present" } } : {},
|
|
2003
|
+
logEvents: { status: logEvents.status, recordCount: logEvents.events.length },
|
|
2004
|
+
allEvents: { status: allEvents.status, recordCount: allEvents.events.length }
|
|
2005
|
+
});
|
|
2006
|
+
return zipEntries([
|
|
2007
|
+
jsonEntry("metadata/run.json", run),
|
|
2008
|
+
...submissionSnapshot ? [jsonEntry("metadata/submission.json", submissionSnapshot)] : [],
|
|
2009
|
+
...costTelemetry ? [jsonEntry("metadata/cost.json", costTelemetry)] : [],
|
|
2010
|
+
jsonlEntry("events/events.jsonl", events),
|
|
2011
|
+
...logEvents.status === "present" ? [jsonlEntry("events/logs.jsonl", logEvents.events)] : [],
|
|
2012
|
+
...allEvents.status === "present" ? [jsonlEntry("events/all.jsonl", allEvents.events)] : [],
|
|
2013
|
+
...out.entries,
|
|
2014
|
+
...logs.entries,
|
|
2015
|
+
jsonEntry("manifest.json", manifest)
|
|
2016
|
+
]);
|
|
2017
|
+
}
|
|
2018
|
+
async function downloadOutputs(http, runId) {
|
|
2019
|
+
const outputs = await listOutputs(http, runId);
|
|
2020
|
+
const { entries, captured, errors } = await collectArtifactBytes(http, runId, outputs, "", "outputs");
|
|
2021
|
+
return zipEntries([
|
|
2022
|
+
...entries,
|
|
2023
|
+
jsonEntry("manifest.json", { runId, namespace: "outputs", outputs: captured, errors })
|
|
2024
|
+
]);
|
|
2025
|
+
}
|
|
2026
|
+
async function downloadLogs(http, runId) {
|
|
2027
|
+
const logItems = await listLogs(http, runId);
|
|
2028
|
+
const { entries, captured, errors } = await collectArtifactBytes(http, runId, logItems, "", "logs");
|
|
2029
|
+
return zipEntries([
|
|
2030
|
+
...entries,
|
|
2031
|
+
jsonEntry("manifest.json", { runId, namespace: "logs", logs: captured, errors })
|
|
2032
|
+
]);
|
|
2033
|
+
}
|
|
2034
|
+
async function downloadEvents(http, runId) {
|
|
2035
|
+
const [events, logEvents, allEvents] = await Promise.all([
|
|
2036
|
+
listRunEvents(http, runId),
|
|
2037
|
+
tryListOptionalRunEvents(http, runId, "log"),
|
|
2038
|
+
tryListOptionalRunEvents(http, runId, "all")
|
|
2039
|
+
]);
|
|
2040
|
+
return zipEntries([
|
|
2041
|
+
jsonlEntry("events.jsonl", events),
|
|
2042
|
+
...logEvents.status === "present" ? [jsonlEntry("logs.jsonl", logEvents.events)] : [],
|
|
2043
|
+
...allEvents.status === "present" ? [jsonlEntry("all.jsonl", allEvents.events)] : []
|
|
2044
|
+
]);
|
|
2045
|
+
}
|
|
2046
|
+
async function downloadMetadata(http, runId) {
|
|
2047
|
+
const run = await getRun(http, runId);
|
|
2048
|
+
return zipEntries([jsonEntry("run.json", run)]);
|
|
2049
|
+
}
|
|
2050
|
+
function zipEntries(entries) {
|
|
2051
|
+
assertRunRecordArchivePublicSafeV1(entries);
|
|
2052
|
+
const files = {};
|
|
2053
|
+
for (const entry of entries) {
|
|
2054
|
+
files[entry.path] = entry.bytes;
|
|
2055
|
+
}
|
|
2056
|
+
return zipSync(files);
|
|
2057
|
+
}
|
|
2058
|
+
function jsonEntry(path, value) {
|
|
2059
|
+
return {
|
|
2060
|
+
path,
|
|
2061
|
+
bytes: strToU8(JSON.stringify(value, null, 2)),
|
|
2062
|
+
contentType: "application/json; charset=utf-8"
|
|
2063
|
+
};
|
|
2064
|
+
}
|
|
2065
|
+
function jsonlEntry(path, events) {
|
|
2066
|
+
return {
|
|
2067
|
+
path,
|
|
2068
|
+
bytes: eventsJsonl(events),
|
|
2069
|
+
contentType: "application/jsonl; charset=utf-8"
|
|
2070
|
+
};
|
|
2071
|
+
}
|
|
2072
|
+
function extractSubmissionSnapshot(run) {
|
|
2073
|
+
const raw = run.submission;
|
|
2074
|
+
if (!isRecord(raw) || raw.kind !== "submission" || !isRecord(raw.submission)) {
|
|
2075
|
+
return void 0;
|
|
2076
|
+
}
|
|
2077
|
+
return {
|
|
2078
|
+
submission: raw.submission
|
|
2079
|
+
};
|
|
2080
|
+
}
|
|
2081
|
+
function extractCostTelemetry(run) {
|
|
2082
|
+
const raw = run.costTelemetry;
|
|
2083
|
+
return isRecord(raw) ? raw : void 0;
|
|
2084
|
+
}
|
|
2085
|
+
function isRecord(value) {
|
|
2086
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
2087
|
+
}
|
|
2088
|
+
async function submitRun(http, request) {
|
|
2089
|
+
return http.request("/api/runs", {
|
|
2090
|
+
method: "POST",
|
|
2091
|
+
body: JSON.stringify(request)
|
|
2092
|
+
});
|
|
2093
|
+
}
|
|
2094
|
+
async function submitRunMultipart(http, request, bundles, agentsMdParts, fileParts) {
|
|
2095
|
+
const hasBundles = Array.isArray(bundles) && bundles.length > 0;
|
|
2096
|
+
const hasAgentsMd = Array.isArray(agentsMdParts) && agentsMdParts.length > 0;
|
|
2097
|
+
const hasFiles = Array.isArray(fileParts) && fileParts.length > 0;
|
|
2098
|
+
if (!hasBundles && !hasAgentsMd && !hasFiles) {
|
|
2099
|
+
throw new Error("submitRunMultipart: bundles, agentsMdParts, or fileParts must be non-empty");
|
|
2100
|
+
}
|
|
2101
|
+
const form = new FormData();
|
|
2102
|
+
form.append("submission", new Blob([JSON.stringify(request)], { type: "application/json" }), "submission.json");
|
|
2103
|
+
const seen = /* @__PURE__ */ new Set();
|
|
2104
|
+
for (const bundle of bundles) {
|
|
2105
|
+
if (typeof bundle.slot !== "string" || !bundle.slot) {
|
|
2106
|
+
throw new Error("submitRunMultipart: each bundle must have a non-empty slot id");
|
|
2107
|
+
}
|
|
2108
|
+
if (seen.has(bundle.slot)) {
|
|
2109
|
+
throw new Error(`submitRunMultipart: duplicate inline skill slot "${bundle.slot}"`);
|
|
2110
|
+
}
|
|
2111
|
+
seen.add(bundle.slot);
|
|
2112
|
+
const blob = toBlob(bundle.bytes, "application/zip");
|
|
2113
|
+
form.append(`skill:${bundle.slot}`, blob, bundle.filename);
|
|
2114
|
+
}
|
|
2115
|
+
for (const part of agentsMdParts ?? []) {
|
|
2116
|
+
if (typeof part.slot !== "string" || !part.slot) {
|
|
2117
|
+
throw new Error("submitRunMultipart: each agentsMd part must have a non-empty slot id");
|
|
2118
|
+
}
|
|
2119
|
+
const partKey = `agentsmd:${part.slot}`;
|
|
2120
|
+
if (seen.has(partKey)) {
|
|
2121
|
+
throw new Error(`submitRunMultipart: duplicate agentsMd slot "${part.slot}"`);
|
|
2122
|
+
}
|
|
2123
|
+
seen.add(partKey);
|
|
2124
|
+
const blob = new Blob([part.content], { type: "text/plain" });
|
|
2125
|
+
form.append(partKey, blob, part.filename);
|
|
2126
|
+
}
|
|
2127
|
+
for (const part of fileParts ?? []) {
|
|
2128
|
+
if (typeof part.slot !== "string" || !part.slot) {
|
|
2129
|
+
throw new Error("submitRunMultipart: each file part must have a non-empty slot id");
|
|
2130
|
+
}
|
|
2131
|
+
const partKey = `file:${part.slot}`;
|
|
2132
|
+
if (seen.has(partKey)) {
|
|
2133
|
+
throw new Error(`submitRunMultipart: duplicate file slot "${part.slot}"`);
|
|
2134
|
+
}
|
|
2135
|
+
seen.add(partKey);
|
|
2136
|
+
const blob = toBlob(part.bytes, "application/zip");
|
|
2137
|
+
form.append(partKey, blob, part.filename);
|
|
2138
|
+
}
|
|
2139
|
+
return http.request("/api/runs", {
|
|
2140
|
+
method: "POST",
|
|
2141
|
+
body: form
|
|
2142
|
+
});
|
|
2143
|
+
}
|
|
2144
|
+
async function createSkillBundle(http, args) {
|
|
2145
|
+
const form = new FormData();
|
|
2146
|
+
form.append("name", args.name);
|
|
2147
|
+
const blobBody = toBlob(args.body, args.contentType ?? "application/zip");
|
|
2148
|
+
form.append("bundle", blobBody, args.filename ?? `${args.name}.zip`);
|
|
2149
|
+
const result = await http.request("/api/skills", {
|
|
2150
|
+
method: "POST",
|
|
2151
|
+
body: form
|
|
2152
|
+
});
|
|
2153
|
+
return unwrapSkill(result);
|
|
2154
|
+
}
|
|
2155
|
+
async function createSkillBundleDirect(http, fetchImpl, args) {
|
|
2156
|
+
let presign;
|
|
2157
|
+
try {
|
|
2158
|
+
presign = await http.request("/api/skills/presign", {
|
|
2159
|
+
method: "POST",
|
|
2160
|
+
headers: { "content-type": "application/json" },
|
|
2161
|
+
body: JSON.stringify({ name: args.name, hash: args.contentHash, sizeBytes: args.body.byteLength })
|
|
2162
|
+
});
|
|
2163
|
+
} catch (err2) {
|
|
2164
|
+
const status = err2.status;
|
|
2165
|
+
const code = (err2.details ?? {}).code;
|
|
2166
|
+
if (status === 503 && code === "presign_unconfigured") {
|
|
2167
|
+
return createSkillBundle(http, {
|
|
2168
|
+
name: args.name,
|
|
2169
|
+
body: args.body,
|
|
2170
|
+
...args.contentType ? { contentType: args.contentType } : {}
|
|
2171
|
+
});
|
|
2172
|
+
}
|
|
2173
|
+
throw err2;
|
|
2174
|
+
}
|
|
2175
|
+
const putRes = await fetchImpl(presign.uploadUrl, {
|
|
2176
|
+
method: "PUT",
|
|
2177
|
+
headers: { "content-type": args.contentType ?? "application/zip", ...presign.requiredHeaders ?? {} },
|
|
2178
|
+
body: args.body
|
|
2179
|
+
});
|
|
2180
|
+
if (!putRes.ok) {
|
|
2181
|
+
const detail = await putRes.text().catch(() => "");
|
|
2182
|
+
throw new Error(`createSkillBundleDirect: direct upload PUT failed (status ${putRes.status})${detail ? `: ${detail.slice(0, 500)}` : ""}`);
|
|
2183
|
+
}
|
|
2184
|
+
const result = await http.request(`/api/skills/${encodeURIComponent(presign.skillId)}/finalize`, {
|
|
2185
|
+
method: "POST",
|
|
2186
|
+
headers: { "content-type": "application/json" },
|
|
2187
|
+
body: JSON.stringify({ manifest: args.manifest })
|
|
2188
|
+
});
|
|
2189
|
+
return unwrapSkill(result);
|
|
2190
|
+
}
|
|
2191
|
+
async function listSkills(http) {
|
|
2192
|
+
const result = await http.request("/api/skills");
|
|
2193
|
+
if (Array.isArray(result)) {
|
|
2194
|
+
return result;
|
|
2195
|
+
}
|
|
2196
|
+
return result.skills;
|
|
2197
|
+
}
|
|
2198
|
+
async function getSkill(http, skillId) {
|
|
2199
|
+
const result = await http.request(`/api/skills/${encodeURIComponent(skillId)}`);
|
|
2200
|
+
return unwrapSkill(result);
|
|
2201
|
+
}
|
|
2202
|
+
async function deleteSkill(http, skillId) {
|
|
2203
|
+
await http.request(`/api/skills/${encodeURIComponent(skillId)}`, {
|
|
2204
|
+
method: "DELETE"
|
|
2205
|
+
});
|
|
2206
|
+
}
|
|
2207
|
+
async function findSkillByHash(http, args) {
|
|
2208
|
+
const params = new URLSearchParams({
|
|
2209
|
+
name: args.name,
|
|
2210
|
+
content_hash: args.contentHash
|
|
2211
|
+
});
|
|
2212
|
+
const result = await http.request(`/api/skills/by-hash?${params.toString()}`);
|
|
2213
|
+
return result.skill ?? null;
|
|
2214
|
+
}
|
|
2215
|
+
async function findSkillByName(http, name) {
|
|
2216
|
+
const skills = await listSkills(http);
|
|
2217
|
+
return skills.find((skill) => skill.name === name) ?? null;
|
|
2218
|
+
}
|
|
2219
|
+
async function createAgentsMd(http, args) {
|
|
2220
|
+
const form = new FormData();
|
|
2221
|
+
form.append("name", args.name);
|
|
2222
|
+
form.append("content", new Blob([args.content], { type: "text/plain" }), "AGENTS.md");
|
|
2223
|
+
const result = await http.request("/api/agentsmd", { method: "POST", body: form });
|
|
2224
|
+
return unwrapAgentsMd(result);
|
|
2225
|
+
}
|
|
2226
|
+
async function listAgentsMd(http) {
|
|
2227
|
+
const result = await http.request("/api/agentsmd");
|
|
2228
|
+
if (Array.isArray(result)) {
|
|
2229
|
+
return result;
|
|
2230
|
+
}
|
|
2231
|
+
return result.agentsMd;
|
|
2232
|
+
}
|
|
2233
|
+
async function getAgentsMd(http, agentsMdId) {
|
|
2234
|
+
const result = await http.request(`/api/agentsmd/${encodeURIComponent(agentsMdId)}`);
|
|
2235
|
+
return unwrapAgentsMd(result);
|
|
2236
|
+
}
|
|
2237
|
+
async function deleteAgentsMd(http, agentsMdId) {
|
|
2238
|
+
await http.request(`/api/agentsmd/${encodeURIComponent(agentsMdId)}`, {
|
|
2239
|
+
method: "DELETE"
|
|
2240
|
+
});
|
|
2241
|
+
}
|
|
2242
|
+
function unwrapAgentsMd(result) {
|
|
2243
|
+
if (result && typeof result === "object" && "agentsMd" in result) {
|
|
2244
|
+
return result.agentsMd;
|
|
2245
|
+
}
|
|
2246
|
+
return result;
|
|
2247
|
+
}
|
|
2248
|
+
async function createFile(http, args) {
|
|
2249
|
+
const form = new FormData();
|
|
2250
|
+
form.append("name", args.name);
|
|
2251
|
+
const blob = toBlob(args.bytes, "application/zip");
|
|
2252
|
+
form.append("bundle", blob, `${args.name}.zip`);
|
|
2253
|
+
const result = await http.request("/api/files", { method: "POST", body: form });
|
|
2254
|
+
return unwrapFile(result);
|
|
2255
|
+
}
|
|
2256
|
+
async function listFiles(http) {
|
|
2257
|
+
const result = await http.request("/api/files");
|
|
2258
|
+
if (Array.isArray(result)) {
|
|
2259
|
+
return result;
|
|
2260
|
+
}
|
|
2261
|
+
return result.files;
|
|
2262
|
+
}
|
|
2263
|
+
async function getFile(http, fileId) {
|
|
2264
|
+
const result = await http.request(`/api/files/${encodeURIComponent(fileId)}`);
|
|
2265
|
+
return unwrapFile(result);
|
|
2266
|
+
}
|
|
2267
|
+
async function deleteFile(http, fileId) {
|
|
2268
|
+
await http.request(`/api/files/${encodeURIComponent(fileId)}`, {
|
|
2269
|
+
method: "DELETE"
|
|
2270
|
+
});
|
|
2271
|
+
}
|
|
2272
|
+
function unwrapFile(result) {
|
|
2273
|
+
if (result && typeof result === "object" && "file" in result) {
|
|
2274
|
+
return result.file;
|
|
2275
|
+
}
|
|
2276
|
+
return result;
|
|
2277
|
+
}
|
|
2278
|
+
function unwrapSkill(result) {
|
|
2279
|
+
if (result && typeof result === "object" && "skill" in result) {
|
|
2280
|
+
return result.skill;
|
|
2281
|
+
}
|
|
2282
|
+
return result;
|
|
2283
|
+
}
|
|
2284
|
+
function toBlob(input, contentType) {
|
|
2285
|
+
if (input instanceof Blob) {
|
|
2286
|
+
return input;
|
|
2287
|
+
}
|
|
2288
|
+
if (input instanceof Uint8Array) {
|
|
2289
|
+
const copy = new Uint8Array(input.byteLength);
|
|
2290
|
+
copy.set(input);
|
|
2291
|
+
return new Blob([copy.buffer], { type: contentType });
|
|
2292
|
+
}
|
|
2293
|
+
return new Blob([input], { type: contentType });
|
|
2294
|
+
}
|
|
2295
|
+
function hasRun(value) {
|
|
2296
|
+
return Boolean(value && typeof value === "object" && "run" in value);
|
|
2297
|
+
}
|
|
2298
|
+
async function uploadWorkspaceAsset(http, input) {
|
|
2299
|
+
return http.request("/assets", {
|
|
2300
|
+
method: "POST",
|
|
2301
|
+
headers: {
|
|
2302
|
+
"content-type": input.contentType ?? "application/octet-stream",
|
|
2303
|
+
"content-length": String(input.bytes.byteLength),
|
|
2304
|
+
...input.contentHash ? { "x-asset-hash": input.contentHash } : {}
|
|
2305
|
+
},
|
|
2306
|
+
body: input.bytes
|
|
2307
|
+
});
|
|
2308
|
+
}
|
|
2309
|
+
|
|
2310
|
+
// ../contracts/dist/proxy-validation.js
|
|
2311
|
+
function validateProxyAuth(endpoints, auth) {
|
|
2312
|
+
const authList = auth ?? [];
|
|
2313
|
+
const endpointNames = new Set(endpoints.map((e) => e.name));
|
|
2314
|
+
const authNames = /* @__PURE__ */ new Set();
|
|
2315
|
+
for (const entry of authList) {
|
|
2316
|
+
if (authNames.has(entry.name)) {
|
|
2317
|
+
throw new Error(`secrets.proxyEndpointAuth contains duplicate name '${entry.name}'`);
|
|
2318
|
+
}
|
|
2319
|
+
authNames.add(entry.name);
|
|
2320
|
+
if (!endpointNames.has(entry.name)) {
|
|
2321
|
+
throw new Error(`secrets.proxyEndpointAuth[].name='${entry.name}' has no matching proxyEndpoints[].name`);
|
|
2322
|
+
}
|
|
2323
|
+
}
|
|
2324
|
+
for (const endpoint of endpoints) {
|
|
2325
|
+
const match = authList.find((a) => a.name === endpoint.name);
|
|
2326
|
+
if (!match) {
|
|
2327
|
+
throw new Error(`proxyEndpoints[].name='${endpoint.name}' is missing a matching secrets.proxyEndpointAuth entry`);
|
|
2328
|
+
}
|
|
2329
|
+
if (match.value.type !== endpoint.authShape.type) {
|
|
2330
|
+
throw new Error(`secrets.proxyEndpointAuth[name='${endpoint.name}'].value.type='${match.value.type}' does not match proxyEndpoints[name='${endpoint.name}'].authShape.type='${endpoint.authShape.type}'`);
|
|
2331
|
+
}
|
|
2332
|
+
}
|
|
2333
|
+
}
|
|
2334
|
+
|
|
2335
|
+
// dist/internal.js
|
|
2336
|
+
var AEX_INDEX_PATH = "/mnt/session/uploads/aex/index.json";
|
|
2337
|
+
var AEX_RUN_TOKEN_PATH = "/mnt/session/uploads/aex/run-token";
|
|
2338
|
+
|
|
2339
|
+
// dist/host/common.js
|
|
2340
|
+
var SUCCESS = { code: 0 };
|
|
2341
|
+
var USAGE_ERR = { code: 2 };
|
|
2342
|
+
var RUNTIME_ERR = { code: 1 };
|
|
2343
|
+
var TIMEOUT_ERR = { code: 3 };
|
|
2344
|
+
function parseCommonHostFlags(argv) {
|
|
2345
|
+
let apiToken = null;
|
|
2346
|
+
let aexUrl = null;
|
|
2347
|
+
let debug = false;
|
|
2348
|
+
const rest = [];
|
|
2349
|
+
for (let i = 0; i < argv.length; i++) {
|
|
2350
|
+
const arg = argv[i];
|
|
2351
|
+
if (arg === "--debug") {
|
|
2352
|
+
debug = true;
|
|
2353
|
+
continue;
|
|
2354
|
+
}
|
|
2355
|
+
if (arg === "--api-token") {
|
|
2356
|
+
const v = argv[++i];
|
|
2357
|
+
if (v === void 0)
|
|
2358
|
+
return { ok: false, reason: "--api-token requires a value" };
|
|
2359
|
+
apiToken = v;
|
|
2360
|
+
continue;
|
|
2361
|
+
}
|
|
2362
|
+
if (arg === "--aex-url") {
|
|
2363
|
+
const v = argv[++i];
|
|
2364
|
+
if (v === void 0)
|
|
2365
|
+
return { ok: false, reason: "--aex-url requires a value" };
|
|
2366
|
+
aexUrl = v;
|
|
2367
|
+
continue;
|
|
2368
|
+
}
|
|
2369
|
+
if (arg === "--workspace" || arg === "--workspace-id") {
|
|
2370
|
+
return {
|
|
2371
|
+
ok: false,
|
|
2372
|
+
reason: `unknown flag ${arg}: workspace is derived from --api-token on the server; drop this flag`
|
|
2373
|
+
};
|
|
2374
|
+
}
|
|
2375
|
+
rest.push(arg);
|
|
2376
|
+
}
|
|
2377
|
+
if (!apiToken)
|
|
2378
|
+
return { ok: false, reason: "--api-token is required" };
|
|
2379
|
+
return {
|
|
2380
|
+
ok: true,
|
|
2381
|
+
flags: { apiToken, aexUrl: aexUrl ?? AEX_DEFAULT_BASE_URL, debug },
|
|
2382
|
+
rest
|
|
2383
|
+
};
|
|
2384
|
+
}
|
|
2385
|
+
function makeHttpClient(io2, flags) {
|
|
2386
|
+
return new HttpClient({
|
|
2387
|
+
baseUrl: flags.aexUrl,
|
|
2388
|
+
apiToken: flags.apiToken,
|
|
2389
|
+
fetch: io2.fetchImpl,
|
|
2390
|
+
// `--debug`: route the transport's redacted per-request traces to stderr.
|
|
2391
|
+
...flags.debug ? { debug: (line) => io2.stderr(`${line}
|
|
2392
|
+
`) } : {}
|
|
2393
|
+
});
|
|
2394
|
+
}
|
|
2395
|
+
async function refuseInsideManagedRun(io2, verb) {
|
|
2396
|
+
try {
|
|
2397
|
+
await io2.readFile(AEX_INDEX_PATH);
|
|
2398
|
+
io2.stderr(`\`aex ${verb}\` is a host command and cannot run inside a managed run container.
|
|
2399
|
+
Use \`aex proxy ...\` to call your declared upstream endpoints from inside the run.
|
|
2400
|
+
`);
|
|
2401
|
+
return true;
|
|
2402
|
+
} catch (err2) {
|
|
2403
|
+
const code = err2?.code;
|
|
2404
|
+
if (code === "ENOENT" || code === "ENOTDIR") {
|
|
2405
|
+
return false;
|
|
2406
|
+
}
|
|
2407
|
+
io2.stderr(`\`aex ${verb}\` could not determine whether it is running inside a managed run container (error reading ${AEX_INDEX_PATH}: ${err2.message ?? "unknown"}). Refusing to proceed.
|
|
2408
|
+
`);
|
|
2409
|
+
return true;
|
|
2410
|
+
}
|
|
2411
|
+
}
|
|
2412
|
+
function emitJsonError(io2, code, message, extra = {}) {
|
|
2413
|
+
io2.stderr(JSON.stringify({ error: code, message, ...extra }) + "\n");
|
|
2414
|
+
return RUNTIME_ERR;
|
|
2415
|
+
}
|
|
2416
|
+
function collectRepeatedKv(rest, flag) {
|
|
2417
|
+
const entries = {};
|
|
2418
|
+
const remaining = [];
|
|
2419
|
+
for (let i = 0; i < rest.length; i++) {
|
|
2420
|
+
const arg = rest[i];
|
|
2421
|
+
if (arg === flag) {
|
|
2422
|
+
const kv = rest[++i];
|
|
2423
|
+
if (kv === void 0) {
|
|
2424
|
+
return { entries, remaining, error: `${flag} requires a KEY=VALUE argument` };
|
|
2425
|
+
}
|
|
2426
|
+
const eq = kv.indexOf("=");
|
|
2427
|
+
if (eq <= 0) {
|
|
2428
|
+
return { entries, remaining, error: `${flag} must be in the form KEY=VALUE (got: ${kv})` };
|
|
2429
|
+
}
|
|
2430
|
+
entries[kv.slice(0, eq)] = kv.slice(eq + 1);
|
|
2431
|
+
continue;
|
|
2432
|
+
}
|
|
2433
|
+
remaining.push(arg);
|
|
2434
|
+
}
|
|
2435
|
+
return { entries, remaining, error: null };
|
|
2436
|
+
}
|
|
2437
|
+
function collectRepeated(rest, flag) {
|
|
2438
|
+
const values = [];
|
|
2439
|
+
const remaining = [];
|
|
2440
|
+
for (let i = 0; i < rest.length; i++) {
|
|
2441
|
+
const arg = rest[i];
|
|
2442
|
+
if (arg === flag) {
|
|
2443
|
+
const v = rest[++i];
|
|
2444
|
+
if (v === void 0) {
|
|
2445
|
+
return { values, remaining, error: `${flag} requires a value` };
|
|
2446
|
+
}
|
|
2447
|
+
values.push(v);
|
|
2448
|
+
continue;
|
|
2449
|
+
}
|
|
2450
|
+
remaining.push(arg);
|
|
2451
|
+
}
|
|
2452
|
+
return { values, remaining, error: null };
|
|
2453
|
+
}
|
|
2454
|
+
function collectRepeatedKvList(rest, flag) {
|
|
2455
|
+
const entries = [];
|
|
2456
|
+
const remaining = [];
|
|
2457
|
+
for (let i = 0; i < rest.length; i++) {
|
|
2458
|
+
const arg = rest[i];
|
|
2459
|
+
if (arg === flag) {
|
|
2460
|
+
const kv = rest[++i];
|
|
2461
|
+
if (kv === void 0) {
|
|
2462
|
+
return { entries, remaining, error: `${flag} requires a KEY=VALUE argument` };
|
|
2463
|
+
}
|
|
2464
|
+
const eq = kv.indexOf("=");
|
|
2465
|
+
if (eq <= 0) {
|
|
2466
|
+
return { entries, remaining, error: `${flag} must be in the form KEY=VALUE (got: ${kv})` };
|
|
2467
|
+
}
|
|
2468
|
+
entries.push([kv.slice(0, eq), kv.slice(eq + 1)]);
|
|
2469
|
+
continue;
|
|
2470
|
+
}
|
|
2471
|
+
remaining.push(arg);
|
|
2472
|
+
}
|
|
2473
|
+
return { entries, remaining, error: null };
|
|
2474
|
+
}
|
|
2475
|
+
function takeFlagValue(rest, flag) {
|
|
2476
|
+
let value = null;
|
|
2477
|
+
const remaining = [];
|
|
2478
|
+
for (let i = 0; i < rest.length; i++) {
|
|
2479
|
+
const arg = rest[i];
|
|
2480
|
+
if (arg === flag) {
|
|
2481
|
+
const v = rest[++i];
|
|
2482
|
+
if (v === void 0) {
|
|
2483
|
+
return { value, remaining, error: `${flag} requires a value` };
|
|
2484
|
+
}
|
|
2485
|
+
value = v;
|
|
2486
|
+
continue;
|
|
2487
|
+
}
|
|
2488
|
+
remaining.push(arg);
|
|
2489
|
+
}
|
|
2490
|
+
return { value, remaining, error: null };
|
|
2491
|
+
}
|
|
2492
|
+
function parseDuration(input) {
|
|
2493
|
+
const match = /^(\d+(?:\.\d+)?)(ms|s|m|h)?$/.exec(input.trim());
|
|
2494
|
+
if (!match) {
|
|
2495
|
+
return { ms: null, error: `invalid duration "${input}" (expected e.g. 500ms, 30s, 8m, 1h, or a bare ms integer)` };
|
|
2496
|
+
}
|
|
2497
|
+
const value = Number(match[1]);
|
|
2498
|
+
if (!Number.isFinite(value) || value < 0) {
|
|
2499
|
+
return { ms: null, error: `invalid duration "${input}" (must be a non-negative number)` };
|
|
2500
|
+
}
|
|
2501
|
+
const unit = match[2] ?? "ms";
|
|
2502
|
+
const factor = unit === "h" ? 36e5 : unit === "m" ? 6e4 : unit === "s" ? 1e3 : 1;
|
|
2503
|
+
return { ms: Math.round(value * factor), error: null };
|
|
2504
|
+
}
|
|
2505
|
+
function takeBooleanFlag(rest, flag) {
|
|
2506
|
+
const remaining = [];
|
|
2507
|
+
let present = false;
|
|
2508
|
+
for (const arg of rest) {
|
|
2509
|
+
if (arg === flag) {
|
|
2510
|
+
present = true;
|
|
2511
|
+
continue;
|
|
2512
|
+
}
|
|
2513
|
+
remaining.push(arg);
|
|
2514
|
+
}
|
|
2515
|
+
return { present, remaining };
|
|
2516
|
+
}
|
|
2517
|
+
function takeOptionFlag(rest, flag) {
|
|
2518
|
+
const remaining = [];
|
|
2519
|
+
let value;
|
|
2520
|
+
const prefix = `${flag}=`;
|
|
2521
|
+
for (let i = 0; i < rest.length; i++) {
|
|
2522
|
+
const arg = rest[i];
|
|
2523
|
+
if (arg === flag) {
|
|
2524
|
+
const next = rest[++i];
|
|
2525
|
+
if (next !== void 0)
|
|
2526
|
+
value = next;
|
|
2527
|
+
continue;
|
|
2528
|
+
}
|
|
2529
|
+
if (arg.startsWith(prefix)) {
|
|
2530
|
+
value = arg.slice(prefix.length);
|
|
2531
|
+
continue;
|
|
2532
|
+
}
|
|
2533
|
+
remaining.push(arg);
|
|
2534
|
+
}
|
|
2535
|
+
return { value, remaining };
|
|
2536
|
+
}
|
|
2537
|
+
|
|
2538
|
+
// dist/outputs-sync.js
|
|
2539
|
+
async function runOutputsSyncCmd(io2, dirs) {
|
|
2540
|
+
if (dirs.length === 0) {
|
|
2541
|
+
io2.stderr("usage: aex outputs sync <dir> [<dir> ...]\n");
|
|
2542
|
+
return USAGE_ERR;
|
|
2543
|
+
}
|
|
2544
|
+
try {
|
|
2545
|
+
await io2.readFile(AEX_INDEX_PATH);
|
|
2546
|
+
} catch {
|
|
2547
|
+
io2.stderr("`aex outputs sync` is an in-container internal command and cannot run on the host.\n");
|
|
2548
|
+
return USAGE_ERR;
|
|
2549
|
+
}
|
|
2550
|
+
if (!io2.walkDirectory) {
|
|
2551
|
+
io2.stderr("aex outputs sync: walkDirectory IO is not available\n");
|
|
2552
|
+
return RUNTIME_ERR;
|
|
2553
|
+
}
|
|
2554
|
+
let scanned = 0;
|
|
2555
|
+
let missing = 0;
|
|
2556
|
+
for (const dir of dirs) {
|
|
2557
|
+
if (!dir.startsWith("/")) {
|
|
2558
|
+
io2.stderr(JSON.stringify({ dir, error: "non_absolute_path", message: "skipping non-absolute output dir" }) + "\n");
|
|
2559
|
+
missing++;
|
|
2560
|
+
continue;
|
|
2561
|
+
}
|
|
2562
|
+
let entries;
|
|
2563
|
+
try {
|
|
2564
|
+
entries = await io2.walkDirectory(dir);
|
|
2565
|
+
} catch (err2) {
|
|
2566
|
+
io2.stderr(JSON.stringify({ dir, error: "walk_failed", message: err2.message ?? "walk failed" }) + "\n");
|
|
2567
|
+
missing++;
|
|
2568
|
+
continue;
|
|
2569
|
+
}
|
|
2570
|
+
if (entries === null) {
|
|
2571
|
+
io2.stderr(JSON.stringify({ dir, error: "missing_or_unreadable" }) + "\n");
|
|
2572
|
+
missing++;
|
|
2573
|
+
continue;
|
|
2574
|
+
}
|
|
2575
|
+
for (const entry of entries) {
|
|
2576
|
+
io2.stdout(JSON.stringify({ dir, path: entry.path, sizeBytes: entry.sizeBytes }) + "\n");
|
|
2577
|
+
scanned++;
|
|
2578
|
+
}
|
|
2579
|
+
}
|
|
2580
|
+
io2.stdout(JSON.stringify({ summary: { dirs: dirs.length, files: scanned, missing } }) + "\n");
|
|
2581
|
+
return SUCCESS;
|
|
2582
|
+
}
|
|
2583
|
+
|
|
2584
|
+
// dist/proxy.js
|
|
2585
|
+
function parseProxyFlags(rest) {
|
|
2586
|
+
let endpointName = null;
|
|
2587
|
+
let method = "GET";
|
|
2588
|
+
let path = "/";
|
|
2589
|
+
let query = null;
|
|
2590
|
+
const headers = /* @__PURE__ */ new Map();
|
|
2591
|
+
let dataSpec = null;
|
|
2592
|
+
let responseMode = null;
|
|
2593
|
+
let showHelp = false;
|
|
2594
|
+
for (let i = 0; i < rest.length; i++) {
|
|
2595
|
+
const arg = rest[i];
|
|
2596
|
+
if (arg === "--help" || arg === "-h") {
|
|
2597
|
+
showHelp = true;
|
|
2598
|
+
continue;
|
|
2599
|
+
}
|
|
2600
|
+
if (arg === "--method") {
|
|
2601
|
+
method = expect(rest, ++i, "--method");
|
|
2602
|
+
continue;
|
|
2603
|
+
}
|
|
2604
|
+
if (arg === "--path") {
|
|
2605
|
+
path = expect(rest, ++i, "--path");
|
|
2606
|
+
continue;
|
|
2607
|
+
}
|
|
2608
|
+
if (arg === "--query") {
|
|
2609
|
+
query = expect(rest, ++i, "--query");
|
|
2610
|
+
continue;
|
|
2611
|
+
}
|
|
2612
|
+
if (arg === "--header") {
|
|
2613
|
+
const kv = expect(rest, ++i, "--header");
|
|
2614
|
+
const eq = kv.indexOf("=");
|
|
2615
|
+
if (eq <= 0)
|
|
2616
|
+
return { ok: false, reason: "--header must be in the form KEY=VALUE" };
|
|
2617
|
+
headers.set(kv.slice(0, eq).toLowerCase(), kv.slice(eq + 1));
|
|
2618
|
+
continue;
|
|
2619
|
+
}
|
|
2620
|
+
if (arg === "--data") {
|
|
2621
|
+
dataSpec = expect(rest, ++i, "--data");
|
|
2622
|
+
continue;
|
|
2623
|
+
}
|
|
2624
|
+
if (arg === "--response-mode") {
|
|
2625
|
+
responseMode = expect(rest, ++i, "--response-mode");
|
|
2626
|
+
continue;
|
|
2627
|
+
}
|
|
2628
|
+
if (arg.startsWith("--")) {
|
|
2629
|
+
return { ok: false, reason: `unknown flag: ${arg}` };
|
|
2630
|
+
}
|
|
2631
|
+
if (endpointName === null) {
|
|
2632
|
+
endpointName = arg;
|
|
2633
|
+
continue;
|
|
2634
|
+
}
|
|
2635
|
+
return { ok: false, reason: `unexpected positional argument: ${arg}` };
|
|
2636
|
+
}
|
|
2637
|
+
return { ok: true, flags: { endpointName, method, path, query, headers, dataSpec, responseMode, showHelp } };
|
|
2638
|
+
}
|
|
2639
|
+
function expect(arr, idx, flag) {
|
|
2640
|
+
const v = arr[idx];
|
|
2641
|
+
if (v === void 0) {
|
|
2642
|
+
throw new CliUsageError(`${flag} requires a value`);
|
|
2643
|
+
}
|
|
2644
|
+
return v;
|
|
2645
|
+
}
|
|
2646
|
+
var CliUsageError = class extends Error {
|
|
2647
|
+
};
|
|
2648
|
+
async function printProxyHelp(io2) {
|
|
2649
|
+
io2.stdout("aex proxy \u2014 call an upstream HTTP endpoint via the managed proxy.\n\n");
|
|
2650
|
+
io2.stdout("Usage:\n");
|
|
2651
|
+
io2.stdout(" aex proxy <endpoint-name> [flags]\n\n");
|
|
2652
|
+
io2.stdout("Flags:\n");
|
|
2653
|
+
io2.stdout(" --method <verb> HTTP method (default: GET)\n");
|
|
2654
|
+
io2.stdout(" --path <path> Caller-supplied path; must match policy prefixes\n");
|
|
2655
|
+
io2.stdout(` --query <json> JSON object of query parameters (e.g. '{"q":"x"}')
|
|
2656
|
+
`);
|
|
2657
|
+
io2.stdout(" --header K=V Add a caller header (repeatable)\n");
|
|
2658
|
+
io2.stdout(" --data <value> Request body. Use '-' for stdin, '@<file>' for file content\n");
|
|
2659
|
+
io2.stdout(" --response-mode <mode> status_only | headers_only | full (may only narrow policy)\n");
|
|
2660
|
+
io2.stdout(" --help Show this message\n\n");
|
|
2661
|
+
const manifest = await tryReadManifest(io2);
|
|
2662
|
+
if (manifest && manifest.endpoints.length > 0) {
|
|
2663
|
+
io2.stdout("Declared endpoints:\n");
|
|
2664
|
+
for (const ep of manifest.endpoints) {
|
|
2665
|
+
io2.stdout(` \u2022 ${ep.name}: ${ep.allowMethods.join(",")} ${ep.allowPathPrefixes.join(",")} (mode=${ep.responseMode}, budget=${ep.perCallBudget}/run)
|
|
2666
|
+
`);
|
|
2667
|
+
}
|
|
2668
|
+
}
|
|
2669
|
+
return SUCCESS;
|
|
2670
|
+
}
|
|
2671
|
+
async function runProxy(io2, rest) {
|
|
2672
|
+
let parsed;
|
|
2673
|
+
try {
|
|
2674
|
+
parsed = parseProxyFlags(rest);
|
|
2675
|
+
} catch (err2) {
|
|
2676
|
+
if (err2 instanceof CliUsageError) {
|
|
2677
|
+
io2.stderr(`${err2.message}
|
|
2678
|
+
`);
|
|
2679
|
+
return USAGE_ERR;
|
|
2680
|
+
}
|
|
2681
|
+
throw err2;
|
|
2682
|
+
}
|
|
2683
|
+
if (!parsed.ok) {
|
|
2684
|
+
io2.stderr(`${parsed.reason}
|
|
2685
|
+
`);
|
|
2686
|
+
return USAGE_ERR;
|
|
2687
|
+
}
|
|
2688
|
+
const f = parsed.flags;
|
|
2689
|
+
if (f.showHelp) {
|
|
2690
|
+
return await printProxyHelp(io2);
|
|
2691
|
+
}
|
|
2692
|
+
if (!f.endpointName) {
|
|
2693
|
+
io2.stderr("missing endpoint-name\n");
|
|
2694
|
+
io2.stderr("usage: aex proxy <endpoint-name> [flags]\n");
|
|
2695
|
+
return USAGE_ERR;
|
|
2696
|
+
}
|
|
2697
|
+
if (f.responseMode && !PROXY_RESPONSE_MODES.includes(f.responseMode)) {
|
|
2698
|
+
io2.stderr(`--response-mode must be one of: ${PROXY_RESPONSE_MODES.join(", ")}
|
|
2699
|
+
`);
|
|
2700
|
+
return USAGE_ERR;
|
|
2701
|
+
}
|
|
2702
|
+
const manifest = await tryReadManifest(io2);
|
|
2703
|
+
if (!manifest) {
|
|
2704
|
+
emitError(io2, {
|
|
2705
|
+
error: "internal_error",
|
|
2706
|
+
message: "manifest not mounted; this CLI must run inside an aex-managed run"
|
|
2707
|
+
});
|
|
2708
|
+
return RUNTIME_ERR;
|
|
2709
|
+
}
|
|
2710
|
+
if (!manifest.proxyBaseUrl) {
|
|
2711
|
+
emitError(io2, {
|
|
2712
|
+
error: "endpoint_not_found",
|
|
2713
|
+
message: "this run has no proxy endpoints declared",
|
|
2714
|
+
endpointName: f.endpointName
|
|
2715
|
+
});
|
|
2716
|
+
return RUNTIME_ERR;
|
|
2717
|
+
}
|
|
2718
|
+
let token;
|
|
2719
|
+
try {
|
|
2720
|
+
token = (await io2.readFile(AEX_RUN_TOKEN_PATH)).trim();
|
|
2721
|
+
} catch {
|
|
2722
|
+
emitError(io2, {
|
|
2723
|
+
error: "unauthorized",
|
|
2724
|
+
message: "run token file missing; this run has no proxy bearer"
|
|
2725
|
+
});
|
|
2726
|
+
return RUNTIME_ERR;
|
|
2727
|
+
}
|
|
2728
|
+
if (!token) {
|
|
2729
|
+
emitError(io2, { error: "unauthorized", message: "run token is empty" });
|
|
2730
|
+
return RUNTIME_ERR;
|
|
2731
|
+
}
|
|
2732
|
+
let body;
|
|
2733
|
+
if (f.dataSpec !== null) {
|
|
2734
|
+
try {
|
|
2735
|
+
body = await resolveBody(io2, f.dataSpec);
|
|
2736
|
+
} catch (err2) {
|
|
2737
|
+
io2.stderr(`failed to read request body: ${err2.message}
|
|
2738
|
+
`);
|
|
2739
|
+
return RUNTIME_ERR;
|
|
2740
|
+
}
|
|
2741
|
+
}
|
|
2742
|
+
const url = `${manifest.proxyBaseUrl.replace(/\/+$/, "")}/${encodeURIComponent(f.endpointName)}`;
|
|
2743
|
+
const requestHeaders = new Headers();
|
|
2744
|
+
requestHeaders.set("authorization", `Bearer ${token}`);
|
|
2745
|
+
requestHeaders.set(PROXY_PROTOCOL_HEADER, PROXY_PROTOCOL_VERSION);
|
|
2746
|
+
requestHeaders.set(PROXY_METHOD_HEADER, f.method.toUpperCase());
|
|
2747
|
+
requestHeaders.set(PROXY_PATH_HEADER, f.path);
|
|
2748
|
+
if (f.query) {
|
|
2749
|
+
requestHeaders.set(PROXY_QUERY_HEADER, f.query);
|
|
2750
|
+
}
|
|
2751
|
+
if (f.headers.size > 0) {
|
|
2752
|
+
requestHeaders.set(PROXY_HEADERS_HEADER, JSON.stringify(Object.fromEntries(f.headers)));
|
|
2753
|
+
}
|
|
2754
|
+
if (f.responseMode) {
|
|
2755
|
+
requestHeaders.set(PROXY_RESPONSE_MODE_HEADER, f.responseMode);
|
|
2756
|
+
}
|
|
2757
|
+
if (body !== void 0) {
|
|
2758
|
+
requestHeaders.set("content-length", String(body.byteLength));
|
|
2759
|
+
}
|
|
2760
|
+
const init = {
|
|
2761
|
+
method: "POST",
|
|
2762
|
+
headers: requestHeaders,
|
|
2763
|
+
redirect: "manual"
|
|
2764
|
+
};
|
|
2765
|
+
if (body !== void 0) {
|
|
2766
|
+
init.body = body;
|
|
2767
|
+
}
|
|
2768
|
+
let response;
|
|
2769
|
+
try {
|
|
2770
|
+
response = await io2.fetchImpl(url, init);
|
|
2771
|
+
} catch (err2) {
|
|
2772
|
+
emitError(io2, {
|
|
2773
|
+
error: "upstream_error",
|
|
2774
|
+
message: `proxy request failed: ${err2.message}`,
|
|
2775
|
+
endpointName: f.endpointName
|
|
2776
|
+
});
|
|
2777
|
+
return RUNTIME_ERR;
|
|
2778
|
+
}
|
|
2779
|
+
const text = await response.text();
|
|
2780
|
+
let parsedBody;
|
|
2781
|
+
try {
|
|
2782
|
+
parsedBody = text ? JSON.parse(text) : {};
|
|
2783
|
+
} catch {
|
|
2784
|
+
const snippet = text.slice(0, 200).replace(/\s+/g, " ").trim();
|
|
2785
|
+
emitError(io2, {
|
|
2786
|
+
error: "internal_error",
|
|
2787
|
+
message: `proxy returned non-JSON response (HTTP ${response.status}, body=${JSON.stringify(snippet)})`,
|
|
2788
|
+
endpointName: f.endpointName
|
|
2789
|
+
});
|
|
2790
|
+
return RUNTIME_ERR;
|
|
2791
|
+
}
|
|
2792
|
+
if (!response.ok) {
|
|
2793
|
+
io2.stderr(JSON.stringify(parsedBody) + "\n");
|
|
2794
|
+
return RUNTIME_ERR;
|
|
2795
|
+
}
|
|
2796
|
+
io2.stdout(JSON.stringify(parsedBody) + "\n");
|
|
2797
|
+
return SUCCESS;
|
|
2798
|
+
}
|
|
2799
|
+
async function resolveBody(io2, spec) {
|
|
2800
|
+
if (spec === "-") {
|
|
2801
|
+
const data = await io2.readFile("/dev/stdin");
|
|
2802
|
+
return new Uint8Array(Buffer.from(data, "utf8"));
|
|
2803
|
+
}
|
|
2804
|
+
if (spec.startsWith("@")) {
|
|
2805
|
+
const path = spec.slice(1);
|
|
2806
|
+
if (!path)
|
|
2807
|
+
throw new Error("--data @<file> requires a path");
|
|
2808
|
+
const data = await io2.readFile(path);
|
|
2809
|
+
return new Uint8Array(Buffer.from(data, "utf8"));
|
|
2810
|
+
}
|
|
2811
|
+
return new Uint8Array(Buffer.from(spec, "utf8"));
|
|
2812
|
+
}
|
|
2813
|
+
function emitError(io2, body) {
|
|
2814
|
+
io2.stderr(JSON.stringify(body) + "\n");
|
|
2815
|
+
}
|
|
2816
|
+
async function tryReadManifest(io2) {
|
|
2817
|
+
try {
|
|
2818
|
+
const raw = await io2.readFile(AEX_INDEX_PATH);
|
|
2819
|
+
return JSON.parse(raw);
|
|
2820
|
+
} catch {
|
|
2821
|
+
return null;
|
|
2822
|
+
}
|
|
2823
|
+
}
|
|
2824
|
+
|
|
2825
|
+
// dist/host/run-cmd.js
|
|
2826
|
+
import { resolve as resolvePath } from "node:path";
|
|
2827
|
+
var TERMINAL_STATUSES = new Set(TERMINAL_RUN_STATUSES);
|
|
2828
|
+
async function runRunCmd(io2, argv) {
|
|
2829
|
+
if (await refuseInsideManagedRun(io2, "run"))
|
|
2830
|
+
return USAGE_ERR;
|
|
2831
|
+
const common = parseCommonHostFlags(argv);
|
|
2832
|
+
if (!common.ok) {
|
|
2833
|
+
io2.stderr(`${common.reason}
|
|
2834
|
+
`);
|
|
2835
|
+
return USAGE_ERR;
|
|
2836
|
+
}
|
|
2837
|
+
let rest = common.rest;
|
|
2838
|
+
const providerFlag = takeFlagValue(rest, "--provider");
|
|
2839
|
+
if (providerFlag.error) {
|
|
2840
|
+
io2.stderr(`${providerFlag.error}
|
|
2841
|
+
`);
|
|
2842
|
+
return USAGE_ERR;
|
|
2843
|
+
}
|
|
2844
|
+
rest = providerFlag.remaining;
|
|
2845
|
+
let provider = DEFAULT_RUN_PROVIDER;
|
|
2846
|
+
if (providerFlag.value !== null) {
|
|
2847
|
+
if (!RUN_PROVIDERS.includes(providerFlag.value)) {
|
|
2848
|
+
io2.stderr(`--provider must be one of: ${RUN_PROVIDERS.join(", ")} (got: ${providerFlag.value})
|
|
2849
|
+
`);
|
|
2850
|
+
return USAGE_ERR;
|
|
2851
|
+
}
|
|
2852
|
+
provider = providerFlag.value;
|
|
2853
|
+
}
|
|
2854
|
+
const providerKeyValues = {};
|
|
2855
|
+
for (const p of RUN_PROVIDERS) {
|
|
2856
|
+
const flag = takeFlagValue(rest, `--${p}-api-key`);
|
|
2857
|
+
if (flag.error) {
|
|
2858
|
+
io2.stderr(`${flag.error}
|
|
2859
|
+
`);
|
|
2860
|
+
return USAGE_ERR;
|
|
2861
|
+
}
|
|
2862
|
+
rest = flag.remaining;
|
|
2863
|
+
if (flag.value !== null)
|
|
2864
|
+
providerKeyValues[p] = flag.value;
|
|
2865
|
+
}
|
|
2866
|
+
if (!providerKeyValues[provider]) {
|
|
2867
|
+
io2.stderr(`--${provider}-api-key is required when --provider is ${provider} (the platform does not store provider keys on your behalf)
|
|
2868
|
+
`);
|
|
2869
|
+
return USAGE_ERR;
|
|
2870
|
+
}
|
|
2871
|
+
for (const p of RUN_PROVIDERS) {
|
|
2872
|
+
if (p === provider)
|
|
2873
|
+
continue;
|
|
2874
|
+
if (providerKeyValues[p] !== void 0) {
|
|
2875
|
+
io2.stderr(`--${p}-api-key is not allowed when --provider is ${provider}
|
|
2876
|
+
`);
|
|
2877
|
+
return USAGE_ERR;
|
|
2878
|
+
}
|
|
2879
|
+
}
|
|
2880
|
+
const runtimeFlag = takeFlagValue(rest, "--runtime");
|
|
2881
|
+
if (runtimeFlag.error) {
|
|
2882
|
+
io2.stderr(`${runtimeFlag.error}
|
|
2883
|
+
`);
|
|
2884
|
+
return USAGE_ERR;
|
|
2885
|
+
}
|
|
2886
|
+
rest = runtimeFlag.remaining;
|
|
2887
|
+
let runtime;
|
|
2888
|
+
if (runtimeFlag.value !== null) {
|
|
2889
|
+
if (!RUNTIME_KINDS.includes(runtimeFlag.value)) {
|
|
2890
|
+
io2.stderr(`--runtime must be one of: ${RUNTIME_KINDS.join(", ")} (got: ${runtimeFlag.value})
|
|
2891
|
+
`);
|
|
2892
|
+
return USAGE_ERR;
|
|
2893
|
+
}
|
|
2894
|
+
runtime = runtimeFlag.value;
|
|
2895
|
+
}
|
|
2896
|
+
const idempotency = takeFlagValue(rest, "--idempotency-key");
|
|
2897
|
+
if (idempotency.error) {
|
|
2898
|
+
io2.stderr(`${idempotency.error}
|
|
2899
|
+
`);
|
|
2900
|
+
return USAGE_ERR;
|
|
2901
|
+
}
|
|
2902
|
+
rest = idempotency.remaining;
|
|
2903
|
+
const runtimeSizeFlag = takeFlagValue(rest, "--runtime-size");
|
|
2904
|
+
if (runtimeSizeFlag.error) {
|
|
2905
|
+
io2.stderr(`${runtimeSizeFlag.error}
|
|
2906
|
+
`);
|
|
2907
|
+
return USAGE_ERR;
|
|
2908
|
+
}
|
|
2909
|
+
rest = runtimeSizeFlag.remaining;
|
|
2910
|
+
if (runtimeSizeFlag.value && !RUNTIME_SIZES.includes(runtimeSizeFlag.value)) {
|
|
2911
|
+
io2.stderr(`--runtime-size must be one of: ${RUNTIME_SIZES.join(", ")}
|
|
2912
|
+
`);
|
|
2913
|
+
return USAGE_ERR;
|
|
2914
|
+
}
|
|
2915
|
+
const runTimeoutFlag = takeFlagValue(rest, "--run-timeout");
|
|
2916
|
+
if (runTimeoutFlag.error) {
|
|
2917
|
+
io2.stderr(`${runTimeoutFlag.error}
|
|
2918
|
+
`);
|
|
2919
|
+
return USAGE_ERR;
|
|
2920
|
+
}
|
|
2921
|
+
rest = runTimeoutFlag.remaining;
|
|
2922
|
+
if (runTimeoutFlag.value) {
|
|
2923
|
+
const parsed = parseDuration(runTimeoutFlag.value);
|
|
2924
|
+
if (parsed.error) {
|
|
2925
|
+
io2.stderr(`--run-timeout: ${parsed.error}
|
|
2926
|
+
`);
|
|
2927
|
+
return USAGE_ERR;
|
|
2928
|
+
}
|
|
2929
|
+
}
|
|
2930
|
+
const follow = takeBooleanFlag(rest, "--follow");
|
|
2931
|
+
rest = follow.remaining;
|
|
2932
|
+
const timeoutFlag = takeOptionFlag(rest, "--timeout");
|
|
2933
|
+
rest = timeoutFlag.remaining;
|
|
2934
|
+
let followTimeoutMs = null;
|
|
2935
|
+
if (timeoutFlag.value !== void 0) {
|
|
2936
|
+
const parsed = parseDuration(timeoutFlag.value);
|
|
2937
|
+
if (parsed.error) {
|
|
2938
|
+
io2.stderr(`--timeout: ${parsed.error}
|
|
2939
|
+
`);
|
|
2940
|
+
return USAGE_ERR;
|
|
2941
|
+
}
|
|
2942
|
+
followTimeoutMs = parsed.ms;
|
|
2943
|
+
}
|
|
2944
|
+
const config = takeFlagValue(rest, "--config");
|
|
2945
|
+
if (config.error) {
|
|
2946
|
+
io2.stderr(`${config.error}
|
|
2947
|
+
`);
|
|
2948
|
+
return USAGE_ERR;
|
|
2949
|
+
}
|
|
2950
|
+
rest = config.remaining;
|
|
2951
|
+
const modelFlag = takeFlagValue(rest, "--model");
|
|
2952
|
+
if (modelFlag.error) {
|
|
2953
|
+
io2.stderr(`${modelFlag.error}
|
|
2954
|
+
`);
|
|
2955
|
+
return USAGE_ERR;
|
|
2956
|
+
}
|
|
2957
|
+
rest = modelFlag.remaining;
|
|
2958
|
+
const systemFlag = takeFlagValue(rest, "--system");
|
|
2959
|
+
if (systemFlag.error) {
|
|
2960
|
+
io2.stderr(`${systemFlag.error}
|
|
2961
|
+
`);
|
|
2962
|
+
return USAGE_ERR;
|
|
2963
|
+
}
|
|
2964
|
+
rest = systemFlag.remaining;
|
|
2965
|
+
const promptFlags = collectRepeated(rest, "--prompt");
|
|
2966
|
+
if (promptFlags.error) {
|
|
2967
|
+
io2.stderr(`${promptFlags.error}
|
|
2968
|
+
`);
|
|
2969
|
+
return USAGE_ERR;
|
|
2970
|
+
}
|
|
2971
|
+
rest = promptFlags.remaining;
|
|
2972
|
+
const mcpFlags = collectRepeatedKv(rest, "--mcp");
|
|
2973
|
+
if (mcpFlags.error) {
|
|
2974
|
+
io2.stderr(`${mcpFlags.error}
|
|
2975
|
+
`);
|
|
2976
|
+
return USAGE_ERR;
|
|
2977
|
+
}
|
|
2978
|
+
rest = mcpFlags.remaining;
|
|
2979
|
+
const mcpAuthFlags = collectRepeatedKvList(rest, "--mcp-auth");
|
|
2980
|
+
if (mcpAuthFlags.error) {
|
|
2981
|
+
io2.stderr(`${mcpAuthFlags.error}
|
|
2982
|
+
`);
|
|
2983
|
+
return USAGE_ERR;
|
|
2984
|
+
}
|
|
2985
|
+
rest = mcpAuthFlags.remaining;
|
|
2986
|
+
const metadataFlags = collectRepeatedKv(rest, "--metadata");
|
|
2987
|
+
if (metadataFlags.error) {
|
|
2988
|
+
io2.stderr(`${metadataFlags.error}
|
|
2989
|
+
`);
|
|
2990
|
+
return USAGE_ERR;
|
|
2991
|
+
}
|
|
2992
|
+
rest = metadataFlags.remaining;
|
|
2993
|
+
const proxyEndpointFlags = collectRepeated(rest, "--proxy-endpoint");
|
|
2994
|
+
if (proxyEndpointFlags.error) {
|
|
2995
|
+
io2.stderr(`${proxyEndpointFlags.error}
|
|
2996
|
+
`);
|
|
2997
|
+
return USAGE_ERR;
|
|
2998
|
+
}
|
|
2999
|
+
rest = proxyEndpointFlags.remaining;
|
|
3000
|
+
const proxyAuthFlags = collectRepeatedKv(rest, "--proxy-auth");
|
|
3001
|
+
if (proxyAuthFlags.error) {
|
|
3002
|
+
io2.stderr(`${proxyAuthFlags.error}
|
|
3003
|
+
`);
|
|
3004
|
+
return USAGE_ERR;
|
|
3005
|
+
}
|
|
3006
|
+
rest = proxyAuthFlags.remaining;
|
|
3007
|
+
const positional = rest.filter((a) => !a.startsWith("--"));
|
|
3008
|
+
const unknownFlags = rest.filter((a) => a.startsWith("--"));
|
|
3009
|
+
if (unknownFlags.length > 0) {
|
|
3010
|
+
io2.stderr(`unknown flag: ${unknownFlags[0]}
|
|
3011
|
+
`);
|
|
3012
|
+
return USAGE_ERR;
|
|
3013
|
+
}
|
|
3014
|
+
if (positional.length > 0) {
|
|
3015
|
+
io2.stderr(`aex run takes no positional arguments (got: ${positional.join(" ")})
|
|
3016
|
+
`);
|
|
3017
|
+
return USAGE_ERR;
|
|
3018
|
+
}
|
|
3019
|
+
let runConfig;
|
|
3020
|
+
let mcpHeadersFromConfig = /* @__PURE__ */ new Map();
|
|
3021
|
+
if (config.value) {
|
|
3022
|
+
if (modelFlag.value || systemFlag.value || promptFlags.values.length || Object.keys(mcpFlags.entries).length || Object.keys(metadataFlags.entries).length) {
|
|
3023
|
+
io2.stderr("--config cannot be combined with --model/--system/--prompt/--mcp/--metadata\n");
|
|
3024
|
+
return USAGE_ERR;
|
|
3025
|
+
}
|
|
3026
|
+
try {
|
|
3027
|
+
const absPath = resolvePath(io2.cwd(), config.value);
|
|
3028
|
+
const text = await io2.readFile(absPath);
|
|
3029
|
+
const raw = JSON.parse(text);
|
|
3030
|
+
const { mcpHeaders, normalised } = stripMcpHeadersForParsing(raw);
|
|
3031
|
+
mcpHeadersFromConfig = mcpHeaders;
|
|
3032
|
+
runConfig = parseRunRequestConfig(normalised);
|
|
3033
|
+
} catch (err2) {
|
|
3034
|
+
io2.stderr(`failed to load --config: ${err2.message}
|
|
3035
|
+
`);
|
|
3036
|
+
return USAGE_ERR;
|
|
3037
|
+
}
|
|
3038
|
+
} else {
|
|
3039
|
+
if (!modelFlag.value) {
|
|
3040
|
+
io2.stderr("--model is required when --config is not provided\n");
|
|
3041
|
+
return USAGE_ERR;
|
|
3042
|
+
}
|
|
3043
|
+
if (promptFlags.values.length === 0) {
|
|
3044
|
+
io2.stderr("--prompt is required (repeatable)\n");
|
|
3045
|
+
return USAGE_ERR;
|
|
3046
|
+
}
|
|
3047
|
+
let resolvedPrompt;
|
|
3048
|
+
try {
|
|
3049
|
+
resolvedPrompt = await Promise.all(promptFlags.values.map((v) => readMaybeFile(io2, v)));
|
|
3050
|
+
} catch (err2) {
|
|
3051
|
+
io2.stderr(`failed to read --prompt file: ${err2.message}
|
|
3052
|
+
`);
|
|
3053
|
+
return USAGE_ERR;
|
|
3054
|
+
}
|
|
3055
|
+
let resolvedSystem;
|
|
3056
|
+
if (systemFlag.value !== null) {
|
|
3057
|
+
try {
|
|
3058
|
+
resolvedSystem = await readMaybeFile(io2, systemFlag.value);
|
|
3059
|
+
} catch (err2) {
|
|
3060
|
+
io2.stderr(`failed to read --system file: ${err2.message}
|
|
3061
|
+
`);
|
|
3062
|
+
return USAGE_ERR;
|
|
3063
|
+
}
|
|
3064
|
+
}
|
|
3065
|
+
const mcpRefs = [];
|
|
3066
|
+
for (const [name, url] of Object.entries(mcpFlags.entries)) {
|
|
3067
|
+
mcpRefs.push({ name, url });
|
|
3068
|
+
}
|
|
3069
|
+
runConfig = {
|
|
3070
|
+
model: modelFlag.value,
|
|
3071
|
+
...resolvedSystem ? { system: resolvedSystem } : {},
|
|
3072
|
+
prompt: resolvedPrompt,
|
|
3073
|
+
...mcpRefs.length > 0 ? { mcpServers: mcpRefs } : {},
|
|
3074
|
+
...Object.keys(metadataFlags.entries).length > 0 ? { metadata: { ...metadataFlags.entries } } : {}
|
|
3075
|
+
};
|
|
3076
|
+
}
|
|
3077
|
+
const mcpServersForSubmission = [...runConfig.mcpServers ?? []];
|
|
3078
|
+
const mcpServerSecrets = [];
|
|
3079
|
+
const mcpHeaderBag = new Map(mcpHeadersFromConfig);
|
|
3080
|
+
for (const [name, headerSpec] of mcpAuthFlags.entries) {
|
|
3081
|
+
const colon = headerSpec.indexOf(":");
|
|
3082
|
+
if (colon <= 0 || colon >= headerSpec.length - 1) {
|
|
3083
|
+
io2.stderr(`--mcp-auth ${name}: expected 'HeaderName:Value' (got: ${headerSpec})
|
|
3084
|
+
`);
|
|
3085
|
+
return USAGE_ERR;
|
|
3086
|
+
}
|
|
3087
|
+
const headerName = headerSpec.slice(0, colon).trim();
|
|
3088
|
+
const headerValue = headerSpec.slice(colon + 1).trim();
|
|
3089
|
+
if (!headerName || !headerValue) {
|
|
3090
|
+
io2.stderr(`--mcp-auth ${name}: header name and value must be non-empty
|
|
3091
|
+
`);
|
|
3092
|
+
return USAGE_ERR;
|
|
3093
|
+
}
|
|
3094
|
+
const existing = mcpHeaderBag.get(name) ?? {};
|
|
3095
|
+
if (Object.prototype.hasOwnProperty.call(existing, headerName)) {
|
|
3096
|
+
io2.stderr(`--mcp-auth ${name}: duplicate header "${headerName}" \u2014 each header may be set only once per server
|
|
3097
|
+
`);
|
|
3098
|
+
return USAGE_ERR;
|
|
3099
|
+
}
|
|
3100
|
+
existing[headerName] = headerValue;
|
|
3101
|
+
mcpHeaderBag.set(name, existing);
|
|
3102
|
+
}
|
|
3103
|
+
for (const ref of mcpServersForSubmission) {
|
|
3104
|
+
const headers = mcpHeaderBag.get(ref.name);
|
|
3105
|
+
if (headers && Object.keys(headers).length > 0) {
|
|
3106
|
+
mcpServerSecrets.push({ name: ref.name, url: ref.url, headers });
|
|
3107
|
+
}
|
|
3108
|
+
}
|
|
3109
|
+
for (const name of mcpHeaderBag.keys()) {
|
|
3110
|
+
if (!mcpServersForSubmission.some((m) => m.name === name)) {
|
|
3111
|
+
io2.stderr(`--mcp-auth ${name}: no matching --mcp / mcpServers entry declared
|
|
3112
|
+
`);
|
|
3113
|
+
return USAGE_ERR;
|
|
3114
|
+
}
|
|
3115
|
+
}
|
|
3116
|
+
let proxyEndpoints = runConfig.proxyEndpoints ?? [];
|
|
3117
|
+
if (proxyEndpointFlags.values.length > 0) {
|
|
3118
|
+
try {
|
|
3119
|
+
proxyEndpoints = proxyEndpointFlags.values.map((raw, i) => parseJsonOrThrow(raw, `--proxy-endpoint[${i}]`));
|
|
3120
|
+
} catch (err2) {
|
|
3121
|
+
io2.stderr(`${err2.message}
|
|
3122
|
+
`);
|
|
3123
|
+
return USAGE_ERR;
|
|
3124
|
+
}
|
|
3125
|
+
}
|
|
3126
|
+
const proxyAuth = [];
|
|
3127
|
+
for (const [name, spec] of Object.entries(proxyAuthFlags.entries)) {
|
|
3128
|
+
const parsed = parseProxyAuth(spec);
|
|
3129
|
+
if (!parsed.ok) {
|
|
3130
|
+
io2.stderr(`--proxy-auth ${name}: ${parsed.reason}
|
|
3131
|
+
`);
|
|
3132
|
+
return USAGE_ERR;
|
|
3133
|
+
}
|
|
3134
|
+
proxyAuth.push({ name, value: parsed.value });
|
|
3135
|
+
}
|
|
3136
|
+
if (proxyEndpoints.length > 0) {
|
|
3137
|
+
try {
|
|
3138
|
+
validateProxyAuth(proxyEndpoints, proxyAuth);
|
|
3139
|
+
} catch (err2) {
|
|
3140
|
+
io2.stderr(`proxy auth validation failed: ${err2.message}
|
|
3141
|
+
`);
|
|
3142
|
+
return USAGE_ERR;
|
|
3143
|
+
}
|
|
3144
|
+
}
|
|
3145
|
+
const promptArray = Array.isArray(runConfig.prompt) ? [...runConfig.prompt] : [runConfig.prompt];
|
|
3146
|
+
const skills = runConfig.skills ? [...runConfig.skills] : [];
|
|
3147
|
+
const submission = {
|
|
3148
|
+
model: runConfig.model,
|
|
3149
|
+
...runConfig.system ? { system: runConfig.system } : {},
|
|
3150
|
+
prompt: promptArray,
|
|
3151
|
+
skills,
|
|
3152
|
+
agentsMd: [],
|
|
3153
|
+
files: [],
|
|
3154
|
+
mcpServers: mcpServersForSubmission,
|
|
3155
|
+
...runConfig.environment ? { environment: runConfig.environment } : {},
|
|
3156
|
+
...runConfig.metadata ? { metadata: runConfig.metadata } : {}
|
|
3157
|
+
};
|
|
3158
|
+
const providerSecrets = {
|
|
3159
|
+
[provider]: { apiKey: providerKeyValues[provider] }
|
|
3160
|
+
};
|
|
3161
|
+
const secrets = {
|
|
3162
|
+
...providerSecrets,
|
|
3163
|
+
...mcpServerSecrets.length > 0 ? { mcpServers: mcpServerSecrets } : {},
|
|
3164
|
+
...proxyAuth.length > 0 ? { proxyEndpointAuth: proxyAuth } : {}
|
|
3165
|
+
};
|
|
3166
|
+
const request = {
|
|
3167
|
+
idempotencyKey: idempotency.value ?? generateIdempotencyKey(),
|
|
3168
|
+
provider,
|
|
3169
|
+
...runtime ? { runtime } : {},
|
|
3170
|
+
submission,
|
|
3171
|
+
secrets,
|
|
3172
|
+
...runtimeSizeFlag.value ? { runtimeSize: runtimeSizeFlag.value } : runConfig.runtimeSize ? { runtimeSize: runConfig.runtimeSize } : {},
|
|
3173
|
+
...runTimeoutFlag.value ? { timeout: runTimeoutFlag.value } : runConfig.timeout ? { timeout: runConfig.timeout } : {},
|
|
3174
|
+
...proxyEndpoints.length > 0 ? { proxyEndpoints } : {}
|
|
3175
|
+
};
|
|
3176
|
+
const http = makeHttpClient(io2, common.flags);
|
|
3177
|
+
let run;
|
|
3178
|
+
try {
|
|
3179
|
+
run = await operations_exports.submitRun(http, request);
|
|
3180
|
+
} catch (err2) {
|
|
3181
|
+
return emitJsonError(io2, "submit_failed", err2.message ?? "submission failed");
|
|
3182
|
+
}
|
|
3183
|
+
io2.stdout(JSON.stringify(run) + "\n");
|
|
3184
|
+
if (!follow.present)
|
|
3185
|
+
return SUCCESS;
|
|
3186
|
+
let emittedEventCount = 0;
|
|
3187
|
+
let currentStatus = run.status;
|
|
3188
|
+
const deadline = followTimeoutMs === null ? Number.POSITIVE_INFINITY : Date.now() + followTimeoutMs;
|
|
3189
|
+
while (!TERMINAL_STATUSES.has(currentStatus)) {
|
|
3190
|
+
await sleep(2e3);
|
|
3191
|
+
try {
|
|
3192
|
+
const events = await operations_exports.listRunEvents(http, run.id);
|
|
3193
|
+
for (let i = emittedEventCount; i < events.length; i++) {
|
|
3194
|
+
io2.stdout(JSON.stringify(events[i]) + "\n");
|
|
3195
|
+
}
|
|
3196
|
+
emittedEventCount = events.length;
|
|
3197
|
+
} catch (err2) {
|
|
3198
|
+
io2.stderr(`(transient) event poll failed: ${err2.message}
|
|
3199
|
+
`);
|
|
3200
|
+
}
|
|
3201
|
+
try {
|
|
3202
|
+
const updated = await operations_exports.getRun(http, run.id);
|
|
3203
|
+
currentStatus = updated.status;
|
|
3204
|
+
} catch (err2) {
|
|
3205
|
+
io2.stderr(`(transient) status poll failed: ${err2.message}
|
|
3206
|
+
`);
|
|
3207
|
+
}
|
|
3208
|
+
if (!TERMINAL_STATUSES.has(currentStatus) && Date.now() >= deadline) {
|
|
3209
|
+
emitJsonError(io2, "run_follow_timeout", `timed out after ${followTimeoutMs}ms following run`, { runId: run.id });
|
|
3210
|
+
return TIMEOUT_ERR;
|
|
3211
|
+
}
|
|
3212
|
+
}
|
|
3213
|
+
try {
|
|
3214
|
+
const final = await operations_exports.getRun(http, run.id);
|
|
3215
|
+
io2.stdout(JSON.stringify(final) + "\n");
|
|
3216
|
+
return final.status === "succeeded" ? SUCCESS : RUNTIME_ERR;
|
|
3217
|
+
} catch (err2) {
|
|
3218
|
+
io2.stderr(`final status fetch failed: ${err2.message}
|
|
3219
|
+
`);
|
|
3220
|
+
return RUNTIME_ERR;
|
|
3221
|
+
}
|
|
3222
|
+
}
|
|
3223
|
+
function parseProxyAuth(spec) {
|
|
3224
|
+
const idx = spec.indexOf(":");
|
|
3225
|
+
if (idx <= 0) {
|
|
3226
|
+
return { ok: false, reason: `expected '<type>:<value>' (got: ${spec})` };
|
|
3227
|
+
}
|
|
3228
|
+
const type = spec.slice(0, idx);
|
|
3229
|
+
const restValue = spec.slice(idx + 1);
|
|
3230
|
+
switch (type) {
|
|
3231
|
+
case "bearer":
|
|
3232
|
+
if (!restValue)
|
|
3233
|
+
return { ok: false, reason: "bearer requires a token value" };
|
|
3234
|
+
return { ok: true, value: { type: "bearer", token: restValue } };
|
|
3235
|
+
case "header":
|
|
3236
|
+
if (!restValue)
|
|
3237
|
+
return { ok: false, reason: "header requires a value" };
|
|
3238
|
+
return { ok: true, value: { type: "header", value: restValue } };
|
|
3239
|
+
case "query":
|
|
3240
|
+
if (!restValue)
|
|
3241
|
+
return { ok: false, reason: "query requires a value" };
|
|
3242
|
+
return { ok: true, value: { type: "query", value: restValue } };
|
|
3243
|
+
case "basic": {
|
|
3244
|
+
const sep2 = restValue.indexOf(":");
|
|
3245
|
+
if (sep2 <= 0 || sep2 >= restValue.length - 1) {
|
|
3246
|
+
return { ok: false, reason: "basic requires <username>:<password>" };
|
|
3247
|
+
}
|
|
3248
|
+
return {
|
|
3249
|
+
ok: true,
|
|
3250
|
+
value: { type: "basic", username: restValue.slice(0, sep2), password: restValue.slice(sep2 + 1) }
|
|
3251
|
+
};
|
|
3252
|
+
}
|
|
3253
|
+
default:
|
|
3254
|
+
return { ok: false, reason: `unknown auth type '${type}' (expected bearer|basic|header|query)` };
|
|
3255
|
+
}
|
|
3256
|
+
}
|
|
3257
|
+
function parseJsonOrThrow(raw, label) {
|
|
3258
|
+
try {
|
|
3259
|
+
return JSON.parse(raw);
|
|
3260
|
+
} catch (err2) {
|
|
3261
|
+
throw new Error(`${label} is not valid JSON: ${err2.message}`);
|
|
3262
|
+
}
|
|
3263
|
+
}
|
|
3264
|
+
function stripMcpHeadersForParsing(input) {
|
|
3265
|
+
const mcpHeaders = /* @__PURE__ */ new Map();
|
|
3266
|
+
if (input === null || typeof input !== "object" || Array.isArray(input)) {
|
|
3267
|
+
return { normalised: input, mcpHeaders };
|
|
3268
|
+
}
|
|
3269
|
+
const record = input;
|
|
3270
|
+
if (!Array.isArray(record.mcpServers)) {
|
|
3271
|
+
return { normalised: input, mcpHeaders };
|
|
3272
|
+
}
|
|
3273
|
+
const stripped = record.mcpServers.map((entry, i) => {
|
|
3274
|
+
if (!entry || typeof entry !== "object")
|
|
3275
|
+
return entry;
|
|
3276
|
+
const r = entry;
|
|
3277
|
+
if (r.headers && typeof r.headers === "object" && !Array.isArray(r.headers)) {
|
|
3278
|
+
const name = typeof r.name === "string" ? r.name : `__index_${i}__`;
|
|
3279
|
+
const headerObj = {};
|
|
3280
|
+
for (const [k, v] of Object.entries(r.headers)) {
|
|
3281
|
+
if (typeof v !== "string") {
|
|
3282
|
+
throw new Error(`mcpServers[${i}].headers["${k}"] must be a string`);
|
|
3283
|
+
}
|
|
3284
|
+
headerObj[k] = v;
|
|
3285
|
+
}
|
|
3286
|
+
mcpHeaders.set(name, headerObj);
|
|
3287
|
+
const { headers: _omit, ...rest } = r;
|
|
3288
|
+
void _omit;
|
|
3289
|
+
return rest;
|
|
3290
|
+
}
|
|
3291
|
+
return r;
|
|
3292
|
+
});
|
|
3293
|
+
return { normalised: { ...record, mcpServers: stripped }, mcpHeaders };
|
|
3294
|
+
}
|
|
3295
|
+
async function readMaybeFile(io2, value) {
|
|
3296
|
+
if (value.startsWith("@@")) {
|
|
3297
|
+
return value.slice(1);
|
|
3298
|
+
}
|
|
3299
|
+
if (value.startsWith("@")) {
|
|
3300
|
+
const path = resolvePath(io2.cwd(), value.slice(1));
|
|
3301
|
+
return io2.readFile(path);
|
|
3302
|
+
}
|
|
3303
|
+
return value;
|
|
3304
|
+
}
|
|
3305
|
+
function generateIdempotencyKey() {
|
|
3306
|
+
const c = globalThis.crypto;
|
|
3307
|
+
if (c?.randomUUID)
|
|
3308
|
+
return c.randomUUID();
|
|
3309
|
+
return `idem-${Date.now().toString(36)}-${Math.random().toString(36).slice(2)}`;
|
|
3310
|
+
}
|
|
3311
|
+
function sleep(ms) {
|
|
3312
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
3313
|
+
}
|
|
3314
|
+
|
|
3315
|
+
// dist/host/skills-cmd.js
|
|
3316
|
+
import { readFile, readdir, stat } from "node:fs/promises";
|
|
3317
|
+
import { basename, join, posix, relative, resolve as resolvePath2, sep } from "node:path";
|
|
3318
|
+
async function runSkillsCmd(io2, argv) {
|
|
3319
|
+
if (await refuseInsideManagedRun(io2, "skills"))
|
|
3320
|
+
return USAGE_ERR;
|
|
3321
|
+
const [verb, ...rest] = argv;
|
|
3322
|
+
if (!verb) {
|
|
3323
|
+
io2.stderr("usage: aex skills <upload|list|get|delete> [flags]\n");
|
|
3324
|
+
return USAGE_ERR;
|
|
3325
|
+
}
|
|
3326
|
+
switch (verb) {
|
|
3327
|
+
case "upload":
|
|
3328
|
+
return runSkillsUpload(io2, rest);
|
|
3329
|
+
case "list":
|
|
3330
|
+
return runSkillsList(io2, rest);
|
|
3331
|
+
case "get":
|
|
3332
|
+
return runSkillsGet(io2, rest);
|
|
3333
|
+
case "delete":
|
|
3334
|
+
return runSkillsDelete(io2, rest);
|
|
3335
|
+
default:
|
|
3336
|
+
io2.stderr(`unknown skills verb: ${verb}
|
|
3337
|
+
`);
|
|
3338
|
+
return USAGE_ERR;
|
|
3339
|
+
}
|
|
3340
|
+
}
|
|
3341
|
+
async function runSkillsUpload(io2, argv) {
|
|
3342
|
+
const common = parseCommonHostFlags(argv);
|
|
3343
|
+
if (!common.ok) {
|
|
3344
|
+
io2.stderr(`${common.reason}
|
|
3345
|
+
`);
|
|
3346
|
+
return USAGE_ERR;
|
|
3347
|
+
}
|
|
3348
|
+
let rest = common.rest;
|
|
3349
|
+
const nameFlag = takeFlagValue(rest, "--name");
|
|
3350
|
+
if (nameFlag.error) {
|
|
3351
|
+
io2.stderr(`${nameFlag.error}
|
|
3352
|
+
`);
|
|
3353
|
+
return USAGE_ERR;
|
|
3354
|
+
}
|
|
3355
|
+
rest = nameFlag.remaining;
|
|
3356
|
+
if (!nameFlag.value) {
|
|
3357
|
+
io2.stderr("--name is required\n");
|
|
3358
|
+
return USAGE_ERR;
|
|
3359
|
+
}
|
|
3360
|
+
const fromPath = takeFlagValue(rest, "--from-path");
|
|
3361
|
+
if (fromPath.error) {
|
|
3362
|
+
io2.stderr(`${fromPath.error}
|
|
3363
|
+
`);
|
|
3364
|
+
return USAGE_ERR;
|
|
3365
|
+
}
|
|
3366
|
+
rest = fromPath.remaining;
|
|
3367
|
+
const fileFlags = collectRepeated(rest, "--file");
|
|
3368
|
+
if (fileFlags.error) {
|
|
3369
|
+
io2.stderr(`${fileFlags.error}
|
|
3370
|
+
`);
|
|
3371
|
+
return USAGE_ERR;
|
|
3372
|
+
}
|
|
3373
|
+
rest = fileFlags.remaining;
|
|
3374
|
+
const unknown = rest.filter((a) => a.startsWith("--"));
|
|
3375
|
+
if (unknown.length > 0) {
|
|
3376
|
+
io2.stderr(`unknown flag: ${unknown[0]}
|
|
3377
|
+
`);
|
|
3378
|
+
return USAGE_ERR;
|
|
3379
|
+
}
|
|
3380
|
+
if (fromPath.value && fileFlags.values.length > 0 || !fromPath.value && fileFlags.values.length === 0) {
|
|
3381
|
+
io2.stderr("aex skills upload requires exactly one of: --from-path <dir> | --file <path> [--file ...]\n");
|
|
3382
|
+
return USAGE_ERR;
|
|
3383
|
+
}
|
|
3384
|
+
let built;
|
|
3385
|
+
try {
|
|
3386
|
+
if (fromPath.value) {
|
|
3387
|
+
built = await zipDirectory(resolvePath2(io2.cwd(), fromPath.value));
|
|
3388
|
+
} else {
|
|
3389
|
+
built = await zipFiles(io2.cwd(), fileFlags.values);
|
|
3390
|
+
}
|
|
3391
|
+
} catch (err2) {
|
|
3392
|
+
io2.stderr(`failed to build skill bundle: ${err2.message}
|
|
3393
|
+
`);
|
|
3394
|
+
return USAGE_ERR;
|
|
3395
|
+
}
|
|
3396
|
+
const contentHash = `sha256:${await sha256Hex(built.zip)}`;
|
|
3397
|
+
const http = makeHttpClient(io2, common.flags);
|
|
3398
|
+
try {
|
|
3399
|
+
const skill = await operations_exports.createSkillBundleDirect(http, io2.fetchImpl, {
|
|
3400
|
+
name: nameFlag.value,
|
|
3401
|
+
body: built.zip,
|
|
3402
|
+
contentHash,
|
|
3403
|
+
manifest: built.manifest,
|
|
3404
|
+
contentType: "application/zip"
|
|
3405
|
+
});
|
|
3406
|
+
io2.stdout(JSON.stringify(skill) + "\n");
|
|
3407
|
+
return SUCCESS;
|
|
3408
|
+
} catch (err2) {
|
|
3409
|
+
return emitJsonError(io2, "skill_upload_failed", err2.message ?? "upload failed");
|
|
3410
|
+
}
|
|
3411
|
+
}
|
|
3412
|
+
async function sha256Hex(bytes) {
|
|
3413
|
+
const subtle = globalThis.crypto?.subtle;
|
|
3414
|
+
if (!subtle)
|
|
3415
|
+
throw new Error("aex skills upload: globalThis.crypto.subtle is required (Node 18+)");
|
|
3416
|
+
const copy = new Uint8Array(bytes.byteLength);
|
|
3417
|
+
copy.set(bytes);
|
|
3418
|
+
const digest = await subtle.digest("SHA-256", copy.buffer);
|
|
3419
|
+
return Array.from(new Uint8Array(digest), (b) => b.toString(16).padStart(2, "0")).join("");
|
|
3420
|
+
}
|
|
3421
|
+
async function runSkillsList(io2, argv) {
|
|
3422
|
+
const common = parseCommonHostFlags(argv);
|
|
3423
|
+
if (!common.ok) {
|
|
3424
|
+
io2.stderr(`${common.reason}
|
|
3425
|
+
`);
|
|
3426
|
+
return USAGE_ERR;
|
|
3427
|
+
}
|
|
3428
|
+
const positional = common.rest.filter((a) => !a.startsWith("--"));
|
|
3429
|
+
const unknown = common.rest.filter((a) => a.startsWith("--"));
|
|
3430
|
+
if (unknown.length > 0) {
|
|
3431
|
+
io2.stderr(`unknown flag: ${unknown[0]}
|
|
3432
|
+
`);
|
|
3433
|
+
return USAGE_ERR;
|
|
3434
|
+
}
|
|
3435
|
+
if (positional.length > 0) {
|
|
3436
|
+
io2.stderr(`aex skills list takes no positional arguments
|
|
3437
|
+
`);
|
|
3438
|
+
return USAGE_ERR;
|
|
3439
|
+
}
|
|
3440
|
+
const http = makeHttpClient(io2, common.flags);
|
|
3441
|
+
try {
|
|
3442
|
+
const skills = await operations_exports.listSkills(http);
|
|
3443
|
+
for (const s of skills)
|
|
3444
|
+
io2.stdout(JSON.stringify(s) + "\n");
|
|
3445
|
+
return SUCCESS;
|
|
3446
|
+
} catch (err2) {
|
|
3447
|
+
return emitJsonError(io2, "skills_list_failed", err2.message ?? "list failed");
|
|
3448
|
+
}
|
|
3449
|
+
}
|
|
3450
|
+
async function runSkillsGet(io2, argv) {
|
|
3451
|
+
const common = parseCommonHostFlags(argv);
|
|
3452
|
+
if (!common.ok) {
|
|
3453
|
+
io2.stderr(`${common.reason}
|
|
3454
|
+
`);
|
|
3455
|
+
return USAGE_ERR;
|
|
3456
|
+
}
|
|
3457
|
+
const positional = common.rest.filter((a) => !a.startsWith("--"));
|
|
3458
|
+
const unknown = common.rest.filter((a) => a.startsWith("--"));
|
|
3459
|
+
if (unknown.length > 0) {
|
|
3460
|
+
io2.stderr(`unknown flag: ${unknown[0]}
|
|
3461
|
+
`);
|
|
3462
|
+
return USAGE_ERR;
|
|
3463
|
+
}
|
|
3464
|
+
if (positional.length !== 1) {
|
|
3465
|
+
io2.stderr("usage: aex skills get <skill-id>\n");
|
|
3466
|
+
return USAGE_ERR;
|
|
3467
|
+
}
|
|
3468
|
+
const skillId = positional[0];
|
|
3469
|
+
const http = makeHttpClient(io2, common.flags);
|
|
3470
|
+
try {
|
|
3471
|
+
const skill = await operations_exports.getSkill(http, skillId);
|
|
3472
|
+
io2.stdout(JSON.stringify(skill) + "\n");
|
|
3473
|
+
return SUCCESS;
|
|
3474
|
+
} catch (err2) {
|
|
3475
|
+
return emitJsonError(io2, "skill_get_failed", err2.message ?? "get failed");
|
|
3476
|
+
}
|
|
3477
|
+
}
|
|
3478
|
+
async function runSkillsDelete(io2, argv) {
|
|
3479
|
+
const common = parseCommonHostFlags(argv);
|
|
3480
|
+
if (!common.ok) {
|
|
3481
|
+
io2.stderr(`${common.reason}
|
|
3482
|
+
`);
|
|
3483
|
+
return USAGE_ERR;
|
|
3484
|
+
}
|
|
3485
|
+
const positional = common.rest.filter((a) => !a.startsWith("--"));
|
|
3486
|
+
const unknown = common.rest.filter((a) => a.startsWith("--"));
|
|
3487
|
+
if (unknown.length > 0) {
|
|
3488
|
+
io2.stderr(`unknown flag: ${unknown[0]}
|
|
3489
|
+
`);
|
|
3490
|
+
return USAGE_ERR;
|
|
3491
|
+
}
|
|
3492
|
+
if (positional.length !== 1) {
|
|
3493
|
+
io2.stderr("usage: aex skills delete <skill-id>\n");
|
|
3494
|
+
return USAGE_ERR;
|
|
3495
|
+
}
|
|
3496
|
+
const skillId = positional[0];
|
|
3497
|
+
const http = makeHttpClient(io2, common.flags);
|
|
3498
|
+
try {
|
|
3499
|
+
await operations_exports.deleteSkill(http, skillId);
|
|
3500
|
+
io2.stdout(JSON.stringify({ skillId, deleted: true }) + "\n");
|
|
3501
|
+
return SUCCESS;
|
|
3502
|
+
} catch (err2) {
|
|
3503
|
+
return emitJsonError(io2, "skill_delete_failed", err2.message ?? "delete failed");
|
|
3504
|
+
}
|
|
3505
|
+
}
|
|
3506
|
+
var ZIP_EPOCH = new Date(Date.UTC(1980, 0, 1));
|
|
3507
|
+
function zipEntryFor(bytes) {
|
|
3508
|
+
return [bytes, { mtime: ZIP_EPOCH }];
|
|
3509
|
+
}
|
|
3510
|
+
async function zipDirectory(rootDir) {
|
|
3511
|
+
const rootStat = await stat(rootDir);
|
|
3512
|
+
if (!rootStat.isDirectory()) {
|
|
3513
|
+
throw new Error(`${rootDir} is not a directory`);
|
|
3514
|
+
}
|
|
3515
|
+
const collected = /* @__PURE__ */ new Map();
|
|
3516
|
+
let totalDecompressed = 0;
|
|
3517
|
+
let hasSkillMd = false;
|
|
3518
|
+
await walk(rootDir, rootDir, async (relPathPosix, bytes) => {
|
|
3519
|
+
const entry = validateSkillBundleEntry({ path: relPathPosix, size: bytes.byteLength });
|
|
3520
|
+
if (entry.path === "SKILL.md")
|
|
3521
|
+
hasSkillMd = true;
|
|
3522
|
+
totalDecompressed += bytes.byteLength;
|
|
3523
|
+
if (totalDecompressed > SKILL_BUNDLE_LIMITS.maxDecompressedBytes) {
|
|
3524
|
+
throw new Error(`skill bundle exceeds decompressed cap of ${SKILL_BUNDLE_LIMITS.maxDecompressedBytes} bytes`);
|
|
3525
|
+
}
|
|
3526
|
+
if (collected.has(entry.path)) {
|
|
3527
|
+
throw new Error(`skill bundle contains duplicate path: ${entry.path}`);
|
|
3528
|
+
}
|
|
3529
|
+
if (collected.size >= SKILL_BUNDLE_LIMITS.maxFiles) {
|
|
3530
|
+
throw new Error(`skill bundle exceeds ${SKILL_BUNDLE_LIMITS.maxFiles} file limit`);
|
|
3531
|
+
}
|
|
3532
|
+
collected.set(entry.path, bytes);
|
|
3533
|
+
});
|
|
3534
|
+
if (collected.size === 0) {
|
|
3535
|
+
throw new Error(`${rootDir} contains no regular files`);
|
|
3536
|
+
}
|
|
3537
|
+
if (!hasSkillMd) {
|
|
3538
|
+
throw new Error('skill bundle must contain a "SKILL.md" file at the root. For AGENTS.md / generic files use the corresponding `aex agentsmd` / `aex files` commands instead.');
|
|
3539
|
+
}
|
|
3540
|
+
const sorted = [...collected.entries()].sort((a, b) => a[0] < b[0] ? -1 : a[0] > b[0] ? 1 : 0);
|
|
3541
|
+
const zippable = {};
|
|
3542
|
+
for (const [path, bytes] of sorted)
|
|
3543
|
+
zippable[path] = zipEntryFor(bytes);
|
|
3544
|
+
const out = zipSync(zippable, { level: 6 });
|
|
3545
|
+
if (out.byteLength > SKILL_BUNDLE_LIMITS.maxCompressedBytes) {
|
|
3546
|
+
throw new Error(`skill bundle exceeds compressed cap of ${SKILL_BUNDLE_LIMITS.maxCompressedBytes} bytes (got ${out.byteLength})`);
|
|
3547
|
+
}
|
|
3548
|
+
return { zip: out, manifest: sorted.map(([path, bytes]) => ({ path, size: bytes.byteLength })) };
|
|
3549
|
+
}
|
|
3550
|
+
async function zipFiles(cwd, paths) {
|
|
3551
|
+
if (paths.length > SKILL_BUNDLE_LIMITS.maxFiles) {
|
|
3552
|
+
throw new Error(`skill bundle exceeds ${SKILL_BUNDLE_LIMITS.maxFiles} file limit`);
|
|
3553
|
+
}
|
|
3554
|
+
const collected = /* @__PURE__ */ new Map();
|
|
3555
|
+
let totalDecompressed = 0;
|
|
3556
|
+
let hasSkillMd = false;
|
|
3557
|
+
for (const p of paths) {
|
|
3558
|
+
const abs = resolvePath2(cwd, p);
|
|
3559
|
+
const bytes = await readFile(abs);
|
|
3560
|
+
const name = basename(p);
|
|
3561
|
+
const entry = validateSkillBundleEntry({ path: name, size: bytes.byteLength });
|
|
3562
|
+
if (entry.path === "SKILL.md")
|
|
3563
|
+
hasSkillMd = true;
|
|
3564
|
+
totalDecompressed += bytes.byteLength;
|
|
3565
|
+
if (totalDecompressed > SKILL_BUNDLE_LIMITS.maxDecompressedBytes) {
|
|
3566
|
+
throw new Error(`skill bundle exceeds decompressed cap of ${SKILL_BUNDLE_LIMITS.maxDecompressedBytes} bytes`);
|
|
3567
|
+
}
|
|
3568
|
+
if (collected.has(entry.path)) {
|
|
3569
|
+
throw new Error(`skill bundle contains duplicate path (basenames must be unique): ${entry.path}`);
|
|
3570
|
+
}
|
|
3571
|
+
collected.set(entry.path, bytes);
|
|
3572
|
+
}
|
|
3573
|
+
if (!hasSkillMd) {
|
|
3574
|
+
throw new Error('skill bundle must contain a "SKILL.md" file at the root');
|
|
3575
|
+
}
|
|
3576
|
+
const sorted = [...collected.entries()].sort((a, b) => a[0] < b[0] ? -1 : a[0] > b[0] ? 1 : 0);
|
|
3577
|
+
const zippable = {};
|
|
3578
|
+
for (const [path, bytes] of sorted)
|
|
3579
|
+
zippable[path] = zipEntryFor(bytes);
|
|
3580
|
+
const out = zipSync(zippable, { level: 6 });
|
|
3581
|
+
if (out.byteLength > SKILL_BUNDLE_LIMITS.maxCompressedBytes) {
|
|
3582
|
+
throw new Error(`skill bundle exceeds compressed cap of ${SKILL_BUNDLE_LIMITS.maxCompressedBytes} bytes`);
|
|
3583
|
+
}
|
|
3584
|
+
return { zip: out, manifest: sorted.map(([path, bytes]) => ({ path, size: bytes.byteLength })) };
|
|
3585
|
+
}
|
|
3586
|
+
async function walk(rootDir, currentDir, visit) {
|
|
3587
|
+
const entries = await readdir(currentDir, { withFileTypes: true });
|
|
3588
|
+
for (const dirent of entries) {
|
|
3589
|
+
const full = join(currentDir, dirent.name);
|
|
3590
|
+
if (dirent.isSymbolicLink())
|
|
3591
|
+
continue;
|
|
3592
|
+
if (dirent.isDirectory()) {
|
|
3593
|
+
await walk(rootDir, full, visit);
|
|
3594
|
+
continue;
|
|
3595
|
+
}
|
|
3596
|
+
if (!dirent.isFile())
|
|
3597
|
+
continue;
|
|
3598
|
+
const rel = relative(rootDir, full);
|
|
3599
|
+
const posixPath = sep === "/" ? rel : rel.split(sep).join(posix.sep);
|
|
3600
|
+
const bytes = await readFile(full);
|
|
3601
|
+
await visit(posixPath, bytes);
|
|
3602
|
+
}
|
|
3603
|
+
}
|
|
3604
|
+
|
|
3605
|
+
// dist/host/status.js
|
|
3606
|
+
async function runStatusCmd(io2, argv) {
|
|
3607
|
+
if (await refuseInsideManagedRun(io2, "status"))
|
|
3608
|
+
return USAGE_ERR;
|
|
3609
|
+
const common = parseCommonHostFlags(argv);
|
|
3610
|
+
if (!common.ok) {
|
|
3611
|
+
io2.stderr(`${common.reason}
|
|
3612
|
+
`);
|
|
3613
|
+
return USAGE_ERR;
|
|
3614
|
+
}
|
|
3615
|
+
const positional = common.rest.filter((arg) => !arg.startsWith("--"));
|
|
3616
|
+
if (positional.length !== 1) {
|
|
3617
|
+
io2.stderr("usage: aex status <run-id> [common flags]\n");
|
|
3618
|
+
return USAGE_ERR;
|
|
3619
|
+
}
|
|
3620
|
+
const runId = positional[0];
|
|
3621
|
+
const http = makeHttpClient(io2, common.flags);
|
|
3622
|
+
try {
|
|
3623
|
+
const run = await operations_exports.getRun(http, runId);
|
|
3624
|
+
io2.stdout(JSON.stringify(run) + "\n");
|
|
3625
|
+
return SUCCESS;
|
|
3626
|
+
} catch (err2) {
|
|
3627
|
+
return emitJsonError(io2, "status_failed", err2.message ?? "status fetch failed", { runId });
|
|
3628
|
+
}
|
|
3629
|
+
}
|
|
3630
|
+
|
|
3631
|
+
// dist/host/wait.js
|
|
3632
|
+
var TERMINAL_STATUSES2 = new Set(TERMINAL_RUN_STATUSES);
|
|
3633
|
+
var DEFAULT_INTERVAL_MS = 2e3;
|
|
3634
|
+
async function runWaitCmd(io2, argv) {
|
|
3635
|
+
if (await refuseInsideManagedRun(io2, "wait"))
|
|
3636
|
+
return USAGE_ERR;
|
|
3637
|
+
const common = parseCommonHostFlags(argv);
|
|
3638
|
+
if (!common.ok) {
|
|
3639
|
+
io2.stderr(`${common.reason}
|
|
3640
|
+
`);
|
|
3641
|
+
return USAGE_ERR;
|
|
3642
|
+
}
|
|
3643
|
+
const timeoutFlag = takeOptionFlag(common.rest, "--timeout");
|
|
3644
|
+
const intervalFlag = takeOptionFlag(timeoutFlag.remaining, "--interval");
|
|
3645
|
+
let timeoutMs = null;
|
|
3646
|
+
if (timeoutFlag.value !== void 0) {
|
|
3647
|
+
const parsed = parseDuration(timeoutFlag.value);
|
|
3648
|
+
if (parsed.error) {
|
|
3649
|
+
io2.stderr(`--timeout: ${parsed.error}
|
|
3650
|
+
`);
|
|
3651
|
+
return USAGE_ERR;
|
|
3652
|
+
}
|
|
3653
|
+
timeoutMs = parsed.ms;
|
|
3654
|
+
}
|
|
3655
|
+
let intervalMs = DEFAULT_INTERVAL_MS;
|
|
3656
|
+
if (intervalFlag.value !== void 0) {
|
|
3657
|
+
const parsed = parseDuration(intervalFlag.value);
|
|
3658
|
+
if (parsed.error) {
|
|
3659
|
+
io2.stderr(`--interval: ${parsed.error}
|
|
3660
|
+
`);
|
|
3661
|
+
return USAGE_ERR;
|
|
3662
|
+
}
|
|
3663
|
+
intervalMs = parsed.ms;
|
|
3664
|
+
}
|
|
3665
|
+
const positional = intervalFlag.remaining.filter((arg) => !arg.startsWith("--"));
|
|
3666
|
+
if (positional.length !== 1) {
|
|
3667
|
+
io2.stderr("usage: aex wait <run-id> [--timeout <dur>] [--interval <dur>] [common flags]\n");
|
|
3668
|
+
return USAGE_ERR;
|
|
3669
|
+
}
|
|
3670
|
+
const runId = positional[0];
|
|
3671
|
+
const http = makeHttpClient(io2, common.flags);
|
|
3672
|
+
const deadline = timeoutMs === null ? Number.POSITIVE_INFINITY : Date.now() + timeoutMs;
|
|
3673
|
+
const timeout = (extra) => {
|
|
3674
|
+
emitJsonError(io2, "wait_timeout", `timed out after ${timeoutMs}ms waiting for run to finish`, { runId, ...extra });
|
|
3675
|
+
return TIMEOUT_ERR;
|
|
3676
|
+
};
|
|
3677
|
+
while (true) {
|
|
3678
|
+
let run;
|
|
3679
|
+
try {
|
|
3680
|
+
run = await operations_exports.getRun(http, runId);
|
|
3681
|
+
} catch (err2) {
|
|
3682
|
+
io2.stderr(`(transient) status poll failed: ${err2.message}
|
|
3683
|
+
`);
|
|
3684
|
+
if (Date.now() >= deadline)
|
|
3685
|
+
return timeout({});
|
|
3686
|
+
await sleep2(intervalMs);
|
|
3687
|
+
continue;
|
|
3688
|
+
}
|
|
3689
|
+
if (TERMINAL_STATUSES2.has(run.status)) {
|
|
3690
|
+
io2.stdout(JSON.stringify(run) + "\n");
|
|
3691
|
+
return run.status === "succeeded" ? SUCCESS : RUNTIME_ERR;
|
|
3692
|
+
}
|
|
3693
|
+
if (Date.now() >= deadline)
|
|
3694
|
+
return timeout({ lastStatus: run.status });
|
|
3695
|
+
await sleep2(intervalMs);
|
|
3696
|
+
}
|
|
3697
|
+
}
|
|
3698
|
+
function sleep2(ms) {
|
|
3699
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
3700
|
+
}
|
|
3701
|
+
|
|
3702
|
+
// dist/host/events.js
|
|
3703
|
+
var TERMINAL_STATUSES3 = new Set(TERMINAL_RUN_STATUSES);
|
|
3704
|
+
async function runEventsCmd(io2, argv) {
|
|
3705
|
+
if (await refuseInsideManagedRun(io2, "events"))
|
|
3706
|
+
return USAGE_ERR;
|
|
3707
|
+
const common = parseCommonHostFlags(argv);
|
|
3708
|
+
if (!common.ok) {
|
|
3709
|
+
io2.stderr(`${common.reason}
|
|
3710
|
+
`);
|
|
3711
|
+
return USAGE_ERR;
|
|
3712
|
+
}
|
|
3713
|
+
const followResult = takeBooleanFlag(common.rest, "--follow");
|
|
3714
|
+
const timeoutFlag = takeOptionFlag(followResult.remaining, "--timeout");
|
|
3715
|
+
let timeoutMs = null;
|
|
3716
|
+
if (timeoutFlag.value !== void 0) {
|
|
3717
|
+
const parsed = parseDuration(timeoutFlag.value);
|
|
3718
|
+
if (parsed.error) {
|
|
3719
|
+
io2.stderr(`--timeout: ${parsed.error}
|
|
3720
|
+
`);
|
|
3721
|
+
return USAGE_ERR;
|
|
3722
|
+
}
|
|
3723
|
+
timeoutMs = parsed.ms;
|
|
3724
|
+
}
|
|
3725
|
+
const positional = timeoutFlag.remaining.filter((arg) => !arg.startsWith("--"));
|
|
3726
|
+
if (positional.length !== 1) {
|
|
3727
|
+
io2.stderr("usage: aex events <run-id> [--follow] [--timeout <dur>] [common flags]\n");
|
|
3728
|
+
return USAGE_ERR;
|
|
3729
|
+
}
|
|
3730
|
+
const runId = positional[0];
|
|
3731
|
+
const http = makeHttpClient(io2, common.flags);
|
|
3732
|
+
if (!followResult.present) {
|
|
3733
|
+
try {
|
|
3734
|
+
const events = await operations_exports.listRunEvents(http, runId);
|
|
3735
|
+
for (const event of events) {
|
|
3736
|
+
io2.stdout(JSON.stringify(event) + "\n");
|
|
3737
|
+
}
|
|
3738
|
+
return SUCCESS;
|
|
3739
|
+
} catch (err2) {
|
|
3740
|
+
return emitJsonError(io2, "events_failed", err2.message ?? "event fetch failed", { runId });
|
|
3741
|
+
}
|
|
3742
|
+
}
|
|
3743
|
+
const seen = /* @__PURE__ */ new Set();
|
|
3744
|
+
const deadline = timeoutMs === null ? Number.POSITIVE_INFINITY : Date.now() + timeoutMs;
|
|
3745
|
+
while (true) {
|
|
3746
|
+
let events;
|
|
3747
|
+
try {
|
|
3748
|
+
events = await operations_exports.listRunEvents(http, runId);
|
|
3749
|
+
} catch (err2) {
|
|
3750
|
+
io2.stderr(`(transient) event poll failed: ${err2.message}
|
|
3751
|
+
`);
|
|
3752
|
+
if (Date.now() >= deadline)
|
|
3753
|
+
return emitTimeout(io2, runId, timeoutMs);
|
|
3754
|
+
await sleep3(2e3);
|
|
3755
|
+
continue;
|
|
3756
|
+
}
|
|
3757
|
+
for (const event of events) {
|
|
3758
|
+
if (!seen.has(event.id)) {
|
|
3759
|
+
seen.add(event.id);
|
|
3760
|
+
io2.stdout(JSON.stringify(event) + "\n");
|
|
3761
|
+
}
|
|
3762
|
+
}
|
|
3763
|
+
try {
|
|
3764
|
+
const run = await operations_exports.getRun(http, runId);
|
|
3765
|
+
if (TERMINAL_STATUSES3.has(run.status)) {
|
|
3766
|
+
return SUCCESS;
|
|
3767
|
+
}
|
|
3768
|
+
} catch (err2) {
|
|
3769
|
+
io2.stderr(`(transient) status poll failed: ${err2.message}
|
|
3770
|
+
`);
|
|
3771
|
+
}
|
|
3772
|
+
if (Date.now() >= deadline)
|
|
3773
|
+
return emitTimeout(io2, runId, timeoutMs);
|
|
3774
|
+
await sleep3(2e3);
|
|
3775
|
+
}
|
|
3776
|
+
}
|
|
3777
|
+
function emitTimeout(io2, runId, timeoutMs) {
|
|
3778
|
+
emitJsonError(io2, "events_follow_timeout", `timed out after ${timeoutMs}ms following run events`, { runId });
|
|
3779
|
+
return TIMEOUT_ERR;
|
|
3780
|
+
}
|
|
3781
|
+
function sleep3(ms) {
|
|
3782
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
3783
|
+
}
|
|
3784
|
+
|
|
3785
|
+
// dist/host/outputs.js
|
|
3786
|
+
async function runOutputsCmd(io2, argv) {
|
|
3787
|
+
if (await refuseInsideManagedRun(io2, "outputs"))
|
|
3788
|
+
return USAGE_ERR;
|
|
3789
|
+
const common = parseCommonHostFlags(argv);
|
|
3790
|
+
if (!common.ok) {
|
|
3791
|
+
io2.stderr(`${common.reason}
|
|
3792
|
+
`);
|
|
3793
|
+
return USAGE_ERR;
|
|
3794
|
+
}
|
|
3795
|
+
const positional = common.rest.filter((arg) => !arg.startsWith("--"));
|
|
3796
|
+
if (positional.length !== 1) {
|
|
3797
|
+
io2.stderr("usage: aex outputs <run-id> [common flags]\n");
|
|
3798
|
+
return USAGE_ERR;
|
|
3799
|
+
}
|
|
3800
|
+
const runId = positional[0];
|
|
3801
|
+
const http = makeHttpClient(io2, common.flags);
|
|
3802
|
+
try {
|
|
3803
|
+
const outputs = await operations_exports.listOutputs(http, runId);
|
|
3804
|
+
for (const out of outputs) {
|
|
3805
|
+
io2.stdout(JSON.stringify(out) + "\n");
|
|
3806
|
+
}
|
|
3807
|
+
return SUCCESS;
|
|
3808
|
+
} catch (err2) {
|
|
3809
|
+
return emitJsonError(io2, "outputs_failed", err2.message ?? "outputs fetch failed", { runId });
|
|
3810
|
+
}
|
|
3811
|
+
}
|
|
3812
|
+
|
|
3813
|
+
// dist/host/download.js
|
|
3814
|
+
import { resolve as resolvePath3 } from "node:path";
|
|
3815
|
+
var NAMESPACE_DOWNLOADERS = {
|
|
3816
|
+
outputs: operations_exports.downloadOutputs,
|
|
3817
|
+
logs: operations_exports.downloadLogs,
|
|
3818
|
+
events: operations_exports.downloadEvents,
|
|
3819
|
+
metadata: operations_exports.downloadMetadata
|
|
3820
|
+
};
|
|
3821
|
+
async function runDownloadCmd(io2, argv) {
|
|
3822
|
+
if (await refuseInsideManagedRun(io2, "download"))
|
|
3823
|
+
return USAGE_ERR;
|
|
3824
|
+
const common = parseCommonHostFlags(argv);
|
|
3825
|
+
if (!common.ok) {
|
|
3826
|
+
io2.stderr(`${common.reason}
|
|
3827
|
+
`);
|
|
3828
|
+
return USAGE_ERR;
|
|
3829
|
+
}
|
|
3830
|
+
const outFlag = takeFlagValue(common.rest, "--out");
|
|
3831
|
+
if (outFlag.error) {
|
|
3832
|
+
io2.stderr(`${outFlag.error}
|
|
3833
|
+
`);
|
|
3834
|
+
return USAGE_ERR;
|
|
3835
|
+
}
|
|
3836
|
+
const onlyFlag = takeFlagValue(outFlag.remaining, "--only");
|
|
3837
|
+
if (onlyFlag.error) {
|
|
3838
|
+
io2.stderr(`${onlyFlag.error}
|
|
3839
|
+
`);
|
|
3840
|
+
return USAGE_ERR;
|
|
3841
|
+
}
|
|
3842
|
+
if (onlyFlag.value !== null && !(onlyFlag.value in NAMESPACE_DOWNLOADERS)) {
|
|
3843
|
+
io2.stderr(`--only must be one of: ${Object.keys(NAMESPACE_DOWNLOADERS).join(", ")}
|
|
3844
|
+
`);
|
|
3845
|
+
return USAGE_ERR;
|
|
3846
|
+
}
|
|
3847
|
+
const namespace2 = onlyFlag.value;
|
|
3848
|
+
const positional = onlyFlag.remaining.filter((arg) => !arg.startsWith("--"));
|
|
3849
|
+
if (positional.length !== 1) {
|
|
3850
|
+
io2.stderr("usage: aex download <run-id> [--only outputs|logs|events|metadata] [--out path] [common flags]\n");
|
|
3851
|
+
return USAGE_ERR;
|
|
3852
|
+
}
|
|
3853
|
+
const runId = positional[0];
|
|
3854
|
+
const http = makeHttpClient(io2, common.flags);
|
|
3855
|
+
const downloader = namespace2 ? NAMESPACE_DOWNLOADERS[namespace2] : operations_exports.download;
|
|
3856
|
+
let bytes;
|
|
3857
|
+
try {
|
|
3858
|
+
bytes = await downloader(http, runId);
|
|
3859
|
+
} catch (err2) {
|
|
3860
|
+
return emitJsonError(io2, "download_failed", err2.message ?? "download failed", { runId });
|
|
3861
|
+
}
|
|
3862
|
+
const destination = resolveDestination(io2, outFlag.value, runId, namespace2);
|
|
3863
|
+
try {
|
|
3864
|
+
await io2.writeFile(destination, bytes);
|
|
3865
|
+
} catch (err2) {
|
|
3866
|
+
return emitJsonError(io2, "write_failed", `failed to write archive: ${err2.message}`, { destination });
|
|
3867
|
+
}
|
|
3868
|
+
io2.stdout(JSON.stringify({ runId, namespace: namespace2 ?? "all", path: destination, bytes: bytes.byteLength }) + "\n");
|
|
3869
|
+
return SUCCESS;
|
|
3870
|
+
}
|
|
3871
|
+
function resolveDestination(io2, out, runId, namespace2) {
|
|
3872
|
+
if (out) {
|
|
3873
|
+
return resolvePath3(io2.cwd(), out);
|
|
3874
|
+
}
|
|
3875
|
+
const suffix = namespace2 ? `-${namespace2}` : "";
|
|
3876
|
+
return resolvePath3(io2.cwd(), `aex-run-${runId}${suffix}.zip`);
|
|
3877
|
+
}
|
|
3878
|
+
|
|
3879
|
+
// dist/host/cancel.js
|
|
3880
|
+
async function runCancelCmd(io2, argv) {
|
|
3881
|
+
if (await refuseInsideManagedRun(io2, "cancel"))
|
|
3882
|
+
return USAGE_ERR;
|
|
3883
|
+
const common = parseCommonHostFlags(argv);
|
|
3884
|
+
if (!common.ok) {
|
|
3885
|
+
io2.stderr(`${common.reason}
|
|
3886
|
+
`);
|
|
3887
|
+
return USAGE_ERR;
|
|
3888
|
+
}
|
|
3889
|
+
const positional = common.rest.filter((arg) => !arg.startsWith("--"));
|
|
3890
|
+
if (positional.length !== 1) {
|
|
3891
|
+
io2.stderr("usage: aex cancel <run-id> [common flags]\n");
|
|
3892
|
+
return USAGE_ERR;
|
|
3893
|
+
}
|
|
3894
|
+
const runId = positional[0];
|
|
3895
|
+
const http = makeHttpClient(io2, common.flags);
|
|
3896
|
+
try {
|
|
3897
|
+
await operations_exports.cancelRun(http, runId);
|
|
3898
|
+
io2.stdout(JSON.stringify({ runId, status: "cancel_requested" }) + "\n");
|
|
3899
|
+
return SUCCESS;
|
|
3900
|
+
} catch (err2) {
|
|
3901
|
+
return emitJsonError(io2, "cancel_failed", err2.message ?? "cancel failed", { runId });
|
|
3902
|
+
}
|
|
3903
|
+
}
|
|
3904
|
+
|
|
3905
|
+
// dist/host/delete.js
|
|
3906
|
+
async function runDeleteCmd(io2, argv) {
|
|
3907
|
+
if (await refuseInsideManagedRun(io2, "delete"))
|
|
3908
|
+
return USAGE_ERR;
|
|
3909
|
+
const common = parseCommonHostFlags(argv);
|
|
3910
|
+
if (!common.ok) {
|
|
3911
|
+
io2.stderr(`${common.reason}
|
|
3912
|
+
`);
|
|
3913
|
+
return USAGE_ERR;
|
|
3914
|
+
}
|
|
3915
|
+
const positional = common.rest.filter((arg) => !arg.startsWith("--"));
|
|
3916
|
+
if (positional.length !== 1) {
|
|
3917
|
+
io2.stderr("usage: aex delete <run-id> [common flags]\n");
|
|
3918
|
+
return USAGE_ERR;
|
|
3919
|
+
}
|
|
3920
|
+
const runId = positional[0];
|
|
3921
|
+
const http = makeHttpClient(io2, common.flags);
|
|
3922
|
+
try {
|
|
3923
|
+
await operations_exports.deleteRun(http, runId);
|
|
3924
|
+
io2.stdout(JSON.stringify({ runId, deleted: true }) + "\n");
|
|
3925
|
+
return SUCCESS;
|
|
3926
|
+
} catch (err2) {
|
|
3927
|
+
return emitJsonError(io2, "delete_failed", err2.message ?? "delete failed", { runId });
|
|
3928
|
+
}
|
|
3929
|
+
}
|
|
3930
|
+
|
|
3931
|
+
// dist/host/delete-asset.js
|
|
3932
|
+
async function runDeleteAssetCmd(io2, argv) {
|
|
3933
|
+
if (await refuseInsideManagedRun(io2, "delete-asset"))
|
|
3934
|
+
return USAGE_ERR;
|
|
3935
|
+
const common = parseCommonHostFlags(argv);
|
|
3936
|
+
if (!common.ok) {
|
|
3937
|
+
io2.stderr(`${common.reason}
|
|
3938
|
+
`);
|
|
3939
|
+
return USAGE_ERR;
|
|
3940
|
+
}
|
|
3941
|
+
const positional = common.rest.filter((arg) => !arg.startsWith("--"));
|
|
3942
|
+
if (positional.length !== 1) {
|
|
3943
|
+
io2.stderr("usage: aex delete-asset <hash> [common flags]\n");
|
|
3944
|
+
return USAGE_ERR;
|
|
3945
|
+
}
|
|
3946
|
+
const hash = positional[0];
|
|
3947
|
+
const http = makeHttpClient(io2, common.flags);
|
|
3948
|
+
try {
|
|
3949
|
+
await operations_exports.deleteWorkspaceAsset(http, hash);
|
|
3950
|
+
io2.stdout(JSON.stringify({ hash, deleted: true }) + "\n");
|
|
3951
|
+
return SUCCESS;
|
|
3952
|
+
} catch (err2) {
|
|
3953
|
+
return emitJsonError(io2, "delete_asset_failed", err2.message ?? "delete-asset failed", { hash });
|
|
3954
|
+
}
|
|
3955
|
+
}
|
|
3956
|
+
|
|
3957
|
+
// dist/host/whoami.js
|
|
3958
|
+
async function runWhoamiCmd(io2, argv) {
|
|
3959
|
+
if (await refuseInsideManagedRun(io2, "whoami"))
|
|
3960
|
+
return USAGE_ERR;
|
|
3961
|
+
const common = parseCommonHostFlags(argv);
|
|
3962
|
+
if (!common.ok) {
|
|
3963
|
+
io2.stderr(`${common.reason}
|
|
3964
|
+
`);
|
|
3965
|
+
return USAGE_ERR;
|
|
3966
|
+
}
|
|
3967
|
+
if (common.rest.length > 0) {
|
|
3968
|
+
io2.stderr(`unexpected arguments: ${common.rest.join(" ")}
|
|
3969
|
+
`);
|
|
3970
|
+
return USAGE_ERR;
|
|
3971
|
+
}
|
|
3972
|
+
const http = makeHttpClient(io2, common.flags);
|
|
3973
|
+
try {
|
|
3974
|
+
const me = await operations_exports.whoami(http);
|
|
3975
|
+
io2.stdout(JSON.stringify(me) + "\n");
|
|
3976
|
+
return SUCCESS;
|
|
3977
|
+
} catch (err2) {
|
|
3978
|
+
return emitJsonError(io2, "whoami_failed", err2.message ?? "whoami failed");
|
|
3979
|
+
}
|
|
3980
|
+
}
|
|
3981
|
+
|
|
3982
|
+
// dist/run.js
|
|
3983
|
+
async function runCli(io2) {
|
|
3984
|
+
const args = io2.argv.slice(2);
|
|
3985
|
+
try {
|
|
3986
|
+
const exit = await dispatch(io2, args);
|
|
3987
|
+
io2.exit(exit.code);
|
|
3988
|
+
} catch (err2) {
|
|
3989
|
+
const body = { error: "internal_error", message: err2.message ?? "unknown error" };
|
|
3990
|
+
io2.stderr(JSON.stringify(body) + "\n");
|
|
3991
|
+
io2.exit(RUNTIME_ERR.code);
|
|
3992
|
+
}
|
|
3993
|
+
}
|
|
3994
|
+
async function dispatch(io2, args) {
|
|
3995
|
+
if (args.length === 0 || args[0] === "--help" || args[0] === "-h") {
|
|
3996
|
+
return printGlobalHelp(io2);
|
|
3997
|
+
}
|
|
3998
|
+
const sub = args[0];
|
|
3999
|
+
const rest = args.slice(1);
|
|
4000
|
+
switch (sub) {
|
|
4001
|
+
case "proxy":
|
|
4002
|
+
return runProxy(io2, rest);
|
|
4003
|
+
case "run":
|
|
4004
|
+
return runRunCmd(io2, rest);
|
|
4005
|
+
case "skills":
|
|
4006
|
+
return runSkillsCmd(io2, rest);
|
|
4007
|
+
case "status":
|
|
4008
|
+
return runStatusCmd(io2, rest);
|
|
4009
|
+
case "wait":
|
|
4010
|
+
return runWaitCmd(io2, rest);
|
|
4011
|
+
case "events":
|
|
4012
|
+
return runEventsCmd(io2, rest);
|
|
4013
|
+
case "outputs":
|
|
4014
|
+
if (rest[0] === "sync") {
|
|
4015
|
+
return runOutputsSyncCmd(io2, rest.slice(1));
|
|
4016
|
+
}
|
|
4017
|
+
return runOutputsCmd(io2, rest);
|
|
4018
|
+
case "download":
|
|
4019
|
+
return runDownloadCmd(io2, rest);
|
|
4020
|
+
case "cancel":
|
|
4021
|
+
return runCancelCmd(io2, rest);
|
|
4022
|
+
case "delete":
|
|
4023
|
+
return runDeleteCmd(io2, rest);
|
|
4024
|
+
case "delete-asset":
|
|
4025
|
+
return runDeleteAssetCmd(io2, rest);
|
|
4026
|
+
case "whoami":
|
|
4027
|
+
return runWhoamiCmd(io2, rest);
|
|
4028
|
+
default:
|
|
4029
|
+
io2.stderr(`unknown subcommand: ${sub}
|
|
4030
|
+
`);
|
|
4031
|
+
io2.stderr("run `aex --help` for usage\n");
|
|
4032
|
+
return USAGE_ERR;
|
|
4033
|
+
}
|
|
4034
|
+
}
|
|
4035
|
+
async function printGlobalHelp(io2) {
|
|
4036
|
+
const manifest = await tryReadManifest(io2);
|
|
4037
|
+
if (manifest) {
|
|
4038
|
+
io2.stdout("aex \u2014 in-container CLI for managed run sessions\n\n");
|
|
4039
|
+
io2.stdout("Usage:\n");
|
|
4040
|
+
io2.stdout(" aex proxy <endpoint-name> [flags]\n");
|
|
4041
|
+
io2.stdout(" aex proxy --help\n\n");
|
|
4042
|
+
if (manifest.endpoints.length === 0) {
|
|
4043
|
+
io2.stdout("This run declared no proxy endpoints.\n");
|
|
4044
|
+
} else {
|
|
4045
|
+
io2.stdout("Declared proxy endpoints for this run:\n");
|
|
4046
|
+
for (const ep of manifest.endpoints) {
|
|
4047
|
+
io2.stdout(` \u2022 ${ep.name} (${ep.allowMethods.join("/")} ${ep.allowPathPrefixes.join(",")}, mode=${ep.responseMode})
|
|
4048
|
+
`);
|
|
4049
|
+
}
|
|
4050
|
+
}
|
|
4051
|
+
io2.stdout(`
|
|
4052
|
+
Protocol version: ${manifest.protocolVersion}
|
|
4053
|
+
`);
|
|
4054
|
+
return SUCCESS;
|
|
4055
|
+
}
|
|
4056
|
+
io2.stdout("aex \u2014 unified CLI for the aex platform (mirrors the SDK 1:1)\n\n");
|
|
4057
|
+
io2.stdout("Usage:\n");
|
|
4058
|
+
io2.stdout(" aex run --config <run.json> --<provider>-api-key K --api-token T [flags]\n");
|
|
4059
|
+
io2.stdout(" aex run --model M --prompt P [--system S] [--mcp name=url ...] --<provider>-api-key K --api-token T [flags]\n");
|
|
4060
|
+
io2.stdout(" aex skills upload --name N --from-path <dir> --api-token T\n");
|
|
4061
|
+
io2.stdout(" aex skills upload --name N --file <path> [--file <path> ...] --api-token T\n");
|
|
4062
|
+
io2.stdout(" aex skills list --api-token T\n");
|
|
4063
|
+
io2.stdout(" aex skills get <skill-id> --api-token T\n");
|
|
4064
|
+
io2.stdout(" aex skills delete <skill-id> --api-token T\n");
|
|
4065
|
+
io2.stdout(" aex status <run-id> --api-token T\n");
|
|
4066
|
+
io2.stdout(" aex wait <run-id> [--timeout 8m] [--interval 2s] --api-token T\n");
|
|
4067
|
+
io2.stdout(" aex events <run-id> [--follow] [--timeout 8m] --api-token T\n");
|
|
4068
|
+
io2.stdout(" aex outputs <run-id> --api-token T\n");
|
|
4069
|
+
io2.stdout(" aex download <run-id> [--out path] --api-token T\n");
|
|
4070
|
+
io2.stdout(" aex cancel <run-id> --api-token T\n");
|
|
4071
|
+
io2.stdout(" aex delete <run-id> --api-token T\n");
|
|
4072
|
+
io2.stdout(" aex delete-asset <assetId|hash> --api-token T\n");
|
|
4073
|
+
io2.stdout(" aex whoami --api-token T\n");
|
|
4074
|
+
io2.stdout(" aex --help\n\n");
|
|
4075
|
+
io2.stdout("Common flags on every host subcommand:\n");
|
|
4076
|
+
io2.stdout(" --api-token <token> REQUIRED \u2014 aex SDK API token (workspace is derived from it)\n");
|
|
4077
|
+
io2.stdout(" --aex-url <url> Optional; defaults to https://api.aex.dev (local/staging/hosted plane)\n");
|
|
4078
|
+
io2.stdout(" --debug Optional; print a redacted per-request trace to stderr (uploads nothing)\n\n");
|
|
4079
|
+
io2.stdout("aex run flags:\n");
|
|
4080
|
+
io2.stdout(` --provider <name> Optional; one of: ${RUN_PROVIDERS.join(", ")} (default anthropic)
|
|
4081
|
+
`);
|
|
4082
|
+
io2.stdout(" --runtime managed Optional runtime selector; omitted also uses managed\n");
|
|
4083
|
+
for (const provider of RUN_PROVIDERS) {
|
|
4084
|
+
io2.stdout(` --${provider}-api-key <key>${" ".repeat(Math.max(1, 13 - provider.length))}REQUIRED when --provider ${provider}; never stored
|
|
4085
|
+
`);
|
|
4086
|
+
}
|
|
4087
|
+
io2.stdout(" --config <path> Run-request JSON (mutually exclusive with the flat --model/--prompt flags)\n");
|
|
4088
|
+
io2.stdout(" --model <model-id> Provider model id (required in flat mode)\n");
|
|
4089
|
+
io2.stdout(" --system @file | <text> System message; @-prefix reads from file\n");
|
|
4090
|
+
io2.stdout(" --prompt @file | <text> User message; @-prefix reads from file (repeatable)\n");
|
|
4091
|
+
io2.stdout(" --mcp name=url MCP server entry (repeatable)\n");
|
|
4092
|
+
io2.stdout(" --mcp-auth name=Hdr:Val Auth header on the matching --mcp; routed into vaulted secrets (repeatable)\n");
|
|
4093
|
+
io2.stdout(" --metadata key=value Submission metadata entry (repeatable)\n");
|
|
4094
|
+
io2.stdout(" --proxy-endpoint '<json>' PlatformProxyEndpoint JSON (repeatable)\n");
|
|
4095
|
+
io2.stdout(" --proxy-auth name=<spec> bearer:tok | basic:u:p | header:v | query:v (repeatable)\n");
|
|
4096
|
+
io2.stdout(" --runtime-size <size> managed runtime preset\n");
|
|
4097
|
+
io2.stdout(" --run-timeout <dur> Server-side run deadline (e.g. 1h); distinct from --timeout\n");
|
|
4098
|
+
io2.stdout(" --idempotency-key <key> Optional; defaults to a fresh UUID\n");
|
|
4099
|
+
io2.stdout(" --follow Poll events to stdout until the run terminates\n");
|
|
4100
|
+
io2.stdout(" --timeout <dur> With --follow: give up after this long (e.g. 8m, 30s, 500ms); exit code 3\n");
|
|
4101
|
+
return SUCCESS;
|
|
4102
|
+
}
|
|
4103
|
+
|
|
4104
|
+
// dist/cli.js
|
|
4105
|
+
async function walkDirectory(root) {
|
|
4106
|
+
try {
|
|
4107
|
+
const rootStat = await stat2(root);
|
|
4108
|
+
if (!rootStat.isDirectory())
|
|
4109
|
+
return null;
|
|
4110
|
+
} catch {
|
|
4111
|
+
return null;
|
|
4112
|
+
}
|
|
4113
|
+
const out = [];
|
|
4114
|
+
async function visit(dir) {
|
|
4115
|
+
const entries = await readdir2(dir, { withFileTypes: true });
|
|
4116
|
+
for (const entry of entries) {
|
|
4117
|
+
const full = resolvePath4(dir, entry.name);
|
|
4118
|
+
if (entry.isDirectory()) {
|
|
4119
|
+
await visit(full);
|
|
4120
|
+
} else if (entry.isFile()) {
|
|
4121
|
+
const s = await stat2(full);
|
|
4122
|
+
out.push({ path: full, sizeBytes: s.size });
|
|
4123
|
+
}
|
|
4124
|
+
}
|
|
4125
|
+
}
|
|
4126
|
+
await visit(root);
|
|
4127
|
+
return out;
|
|
4128
|
+
}
|
|
4129
|
+
var io = {
|
|
4130
|
+
readFile: (path) => readFile2(path, "utf8"),
|
|
4131
|
+
writeFile: (path, data) => writeFile(path, data),
|
|
4132
|
+
fetchImpl: fetch,
|
|
4133
|
+
stdout: (chunk) => process.stdout.write(chunk),
|
|
4134
|
+
stderr: (chunk) => process.stderr.write(chunk),
|
|
4135
|
+
exit: (code) => process.exit(code),
|
|
4136
|
+
argv: process.argv,
|
|
4137
|
+
cwd: () => process.cwd(),
|
|
4138
|
+
walkDirectory
|
|
4139
|
+
};
|
|
4140
|
+
await runCli(io);
|