@aexhq/sdk 0.34.0 → 0.36.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +16 -15
- package/dist/_contracts/index.d.ts +3 -4
- package/dist/_contracts/index.js +1 -4
- package/dist/_contracts/operations.d.ts +2 -1
- package/dist/_contracts/operations.js +10 -0
- package/dist/_contracts/run-config.d.ts +1 -3
- package/dist/_contracts/run-config.js +2 -7
- package/dist/_contracts/run-trace.d.ts +0 -86
- package/dist/_contracts/run-trace.js +1 -184
- package/dist/_contracts/run-unit.d.ts +2 -25
- package/dist/_contracts/run-unit.js +1 -2
- package/dist/_contracts/runtime-manifest.d.ts +1 -1
- package/dist/_contracts/runtime-security-profile.d.ts +0 -2
- package/dist/_contracts/runtime-security-profile.js +0 -9
- package/dist/_contracts/runtime-types.d.ts +25 -4
- package/dist/_contracts/stable.d.ts +1 -1
- package/dist/_contracts/stable.js +1 -1
- package/dist/_contracts/submission.d.ts +62 -95
- package/dist/_contracts/submission.js +59 -482
- package/dist/cli.mjs +99 -442
- package/dist/cli.mjs.sha256 +1 -1
- package/dist/client.d.ts +49 -25
- package/dist/client.js +341 -70
- package/dist/client.js.map +1 -1
- package/dist/index.d.ts +9 -15
- package/dist/index.js +11 -17
- package/dist/index.js.map +1 -1
- package/dist/retry.d.ts +162 -0
- package/dist/retry.js +320 -0
- package/dist/retry.js.map +1 -0
- package/dist/secret.d.ts +2 -2
- package/dist/secret.js +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/docs/concepts/composition.md +8 -14
- package/docs/credentials.md +59 -101
- package/docs/defaults.md +0 -8
- package/docs/events.md +8 -9
- package/docs/limits-and-quotas.md +1 -4
- package/docs/limits.md +2 -6
- package/docs/mcp.md +4 -5
- package/docs/networking.md +6 -16
- package/docs/outputs.md +0 -4
- package/docs/public-surface.json +3 -3
- package/docs/quickstart.md +3 -7
- package/docs/retries.md +129 -0
- package/docs/run-config.md +6 -3
- package/docs/secrets.md +1 -1
- package/docs/skills.md +3 -3
- package/docs/vision-skills.md +52 -101
- package/examples/feature-tour.ts +284 -0
- package/package.json +1 -1
- package/dist/_contracts/proxy-protocol.d.ts +0 -305
- package/dist/_contracts/proxy-protocol.js +0 -297
- package/dist/_contracts/proxy-validation.d.ts +0 -19
- package/dist/_contracts/proxy-validation.js +0 -51
- package/dist/data-tools.d.ts +0 -82
- package/dist/data-tools.js +0 -251
- package/dist/data-tools.js.map +0 -1
- package/dist/proxy-endpoint.d.ts +0 -131
- package/dist/proxy-endpoint.js +0 -144
- package/dist/proxy-endpoint.js.map +0 -1
- package/examples/chat-corpus.ts +0 -84
package/dist/cli.mjs
CHANGED
|
@@ -10,34 +10,6 @@ import { readFile, writeFile, readdir, stat, mkdir, chmod, rm } from "node:fs/pr
|
|
|
10
10
|
import { resolve as resolvePath4, join, dirname as dirname2 } from "node:path";
|
|
11
11
|
import { homedir } from "node:os";
|
|
12
12
|
|
|
13
|
-
// ../contracts/dist/proxy-protocol.js
|
|
14
|
-
var PROXY_PROTOCOL_VERSION_V2 = "2";
|
|
15
|
-
var PROXY_PROTOCOL_HEADER = "x-aex-proxy-protocol";
|
|
16
|
-
var PROXY_RESP_STATUS_HEADER = "x-aex-proxy-status";
|
|
17
|
-
var PROXY_RESP_MODE_HEADER = "x-aex-proxy-effective-mode";
|
|
18
|
-
var PROXY_RESP_TRUNCATED_HEADER = "x-aex-proxy-truncated";
|
|
19
|
-
var PROXY_RESP_UPSTREAM_HEADERS_HEADER = "x-aex-proxy-upstream-headers";
|
|
20
|
-
var PROXY_METHOD_HEADER = "x-aex-method";
|
|
21
|
-
var PROXY_PATH_HEADER = "x-aex-path";
|
|
22
|
-
var PROXY_QUERY_HEADER = "x-aex-query";
|
|
23
|
-
var PROXY_HEADERS_HEADER = "x-aex-headers";
|
|
24
|
-
var PROXY_RESPONSE_MODE_HEADER = "x-aex-response-mode";
|
|
25
|
-
var PROXY_RESPONSE_MODES = ["status_only", "headers_only", "full"];
|
|
26
|
-
var PROXY_ENDPOINT_DEFAULTS = {
|
|
27
|
-
allowHeaders: [],
|
|
28
|
-
responseMode: "headers_only",
|
|
29
|
-
// 10 MiB. The body is buffered in the hosted API to enforce this cap, while the
|
|
30
|
-
// launch default fits practical multimodal/tool POSTs without every endpoint
|
|
31
|
-
// needing an override.
|
|
32
|
-
maxRequestBytes: 10 * 1024 * 1024,
|
|
33
|
-
// Unlimited (0). The request body is buffered to enforce its cap, so that
|
|
34
|
-
// stays finite; the response is streamed, so it does not need one.
|
|
35
|
-
maxResponseBytes: 0,
|
|
36
|
-
// 5 minutes. Long-running upstream tool/model calls should not fail under a
|
|
37
|
-
// development-oriented 10s ceiling; endpoints can still set a smaller value.
|
|
38
|
-
timeoutMs: 5 * 60 * 1e3
|
|
39
|
-
};
|
|
40
|
-
|
|
41
13
|
// ../contracts/dist/provider-support.js
|
|
42
14
|
var COMMON_DOCS = [
|
|
43
15
|
{ label: "Secrets", href: "secrets.md" },
|
|
@@ -392,7 +364,6 @@ function parseRunRequestConfig(input) {
|
|
|
392
364
|
"environment",
|
|
393
365
|
"runtimeSize",
|
|
394
366
|
"timeout",
|
|
395
|
-
"proxyEndpoints",
|
|
396
367
|
"metadata"
|
|
397
368
|
]);
|
|
398
369
|
for (const key of Object.keys(record)) {
|
|
@@ -412,14 +383,13 @@ function parseRunRequestConfig(input) {
|
|
|
412
383
|
...system !== void 0 ? { system } : {},
|
|
413
384
|
prompt,
|
|
414
385
|
...mcpServers !== void 0 ? { mcpServers } : {},
|
|
415
|
-
// environment /
|
|
416
|
-
//
|
|
386
|
+
// environment / metadata: passed through as-is — the BFF revalidates
|
|
387
|
+
// them via `parseRunSubmissionRequest`,
|
|
417
388
|
// so duplicating the heavyweight parsers here would mean two sources
|
|
418
389
|
// of truth. The CLI surfaces structural errors at submission time.
|
|
419
390
|
...record.environment !== void 0 ? { environment: record.environment } : {},
|
|
420
391
|
...record.runtimeSize !== void 0 ? { runtimeSize: record.runtimeSize } : {},
|
|
421
392
|
...record.timeout !== void 0 ? { timeout: record.timeout } : {},
|
|
422
|
-
...record.proxyEndpoints !== void 0 ? { proxyEndpoints: record.proxyEndpoints } : {},
|
|
423
393
|
...record.metadata !== void 0 ? { metadata: record.metadata } : {}
|
|
424
394
|
};
|
|
425
395
|
}
|
|
@@ -489,7 +459,6 @@ var RUNTIME_SECURITY_PROFILE_CONFIG = Object.freeze({
|
|
|
489
459
|
allowOpenNetworking: false,
|
|
490
460
|
allowRuntimePackages: false,
|
|
491
461
|
allowCustomerEnvVars: true,
|
|
492
|
-
allowProxyEndpoints: true,
|
|
493
462
|
allowMcpServers: true
|
|
494
463
|
}),
|
|
495
464
|
standard: Object.freeze({
|
|
@@ -498,7 +467,6 @@ var RUNTIME_SECURITY_PROFILE_CONFIG = Object.freeze({
|
|
|
498
467
|
allowOpenNetworking: true,
|
|
499
468
|
allowRuntimePackages: true,
|
|
500
469
|
allowCustomerEnvVars: true,
|
|
501
|
-
allowProxyEndpoints: true,
|
|
502
470
|
allowMcpServers: true
|
|
503
471
|
}),
|
|
504
472
|
developer: Object.freeze({
|
|
@@ -507,7 +475,6 @@ var RUNTIME_SECURITY_PROFILE_CONFIG = Object.freeze({
|
|
|
507
475
|
allowOpenNetworking: true,
|
|
508
476
|
allowRuntimePackages: true,
|
|
509
477
|
allowCustomerEnvVars: true,
|
|
510
|
-
allowProxyEndpoints: true,
|
|
511
478
|
allowMcpServers: true
|
|
512
479
|
})
|
|
513
480
|
});
|
|
@@ -524,9 +491,6 @@ var RUN_PROVIDERS = [
|
|
|
524
491
|
"doubao-cn"
|
|
525
492
|
];
|
|
526
493
|
var DEFAULT_RUN_PROVIDER = "anthropic";
|
|
527
|
-
var MIN_REDACTION_TARGET_BYTES = 4;
|
|
528
|
-
var MIN_PROXY_SECRET_BYTES = 8;
|
|
529
|
-
var _MIN_PROXY_SECRET_BYTES_OK = MIN_PROXY_SECRET_BYTES >= MIN_REDACTION_TARGET_BYTES;
|
|
530
494
|
var BUILTIN_TOOL_NAMES = [
|
|
531
495
|
"bash",
|
|
532
496
|
"read_file",
|
|
@@ -1400,6 +1364,7 @@ __export(operations_exports, {
|
|
|
1400
1364
|
listRuns: () => listRuns,
|
|
1401
1365
|
listSecrets: () => listSecrets,
|
|
1402
1366
|
listSessionEvents: () => listSessionEvents,
|
|
1367
|
+
listSessionMessages: () => listSessionMessages,
|
|
1403
1368
|
listSessionOutputs: () => listSessionOutputs,
|
|
1404
1369
|
listSessions: () => listSessions,
|
|
1405
1370
|
normalizeOutputLinkExpiresIn: () => normalizeOutputLinkExpiresIn,
|
|
@@ -2188,6 +2153,16 @@ async function sendSessionMessage(http, sessionId, request, options) {
|
|
|
2188
2153
|
body: JSON.stringify(request)
|
|
2189
2154
|
});
|
|
2190
2155
|
}
|
|
2156
|
+
async function listSessionMessages(http, sessionId, query) {
|
|
2157
|
+
const params = {};
|
|
2158
|
+
if (query?.limit !== void 0)
|
|
2159
|
+
params.limit = String(query.limit);
|
|
2160
|
+
if (query?.cursor !== void 0)
|
|
2161
|
+
params.cursor = query.cursor;
|
|
2162
|
+
if (query?.since !== void 0)
|
|
2163
|
+
params.since = query.since;
|
|
2164
|
+
return http.request(`/api/sessions/${encodeURIComponent(sessionId)}/messages`, {}, params);
|
|
2165
|
+
}
|
|
2191
2166
|
async function suspendSession(http, sessionId, options) {
|
|
2192
2167
|
const headers = idempotencyHeaders(options);
|
|
2193
2168
|
return http.request(`/api/sessions/${encodeURIComponent(sessionId)}/suspend`, { method: "POST", ...headers ? { headers } : {} });
|
|
@@ -2800,34 +2775,8 @@ async function uploadWorkspaceAsset(http, input) {
|
|
|
2800
2775
|
});
|
|
2801
2776
|
}
|
|
2802
2777
|
|
|
2803
|
-
// ../contracts/dist/proxy-validation.js
|
|
2804
|
-
function validateProxyAuth(endpoints, auth) {
|
|
2805
|
-
const authList = auth ?? [];
|
|
2806
|
-
const endpointNames = new Set(endpoints.map((e) => e.name));
|
|
2807
|
-
const authNames = /* @__PURE__ */ new Set();
|
|
2808
|
-
for (const entry of authList) {
|
|
2809
|
-
if (authNames.has(entry.name)) {
|
|
2810
|
-
throw new Error(`secrets.proxyEndpointAuth contains duplicate name '${entry.name}'`);
|
|
2811
|
-
}
|
|
2812
|
-
authNames.add(entry.name);
|
|
2813
|
-
if (!endpointNames.has(entry.name)) {
|
|
2814
|
-
throw new Error(`secrets.proxyEndpointAuth[].name='${entry.name}' has no matching proxyEndpoints[].name`);
|
|
2815
|
-
}
|
|
2816
|
-
}
|
|
2817
|
-
for (const endpoint of endpoints) {
|
|
2818
|
-
const match = authList.find((a) => a.name === endpoint.name);
|
|
2819
|
-
if (!match) {
|
|
2820
|
-
throw new Error(`proxyEndpoints[].name='${endpoint.name}' is missing a matching secrets.proxyEndpointAuth entry`);
|
|
2821
|
-
}
|
|
2822
|
-
if (match.value.type !== endpoint.authShape.type) {
|
|
2823
|
-
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}'`);
|
|
2824
|
-
}
|
|
2825
|
-
}
|
|
2826
|
-
}
|
|
2827
|
-
|
|
2828
2778
|
// dist/internal.js
|
|
2829
2779
|
var AEX_INDEX_PATH = "/mnt/session/uploads/aex/index.json";
|
|
2830
|
-
var AEX_RUN_TOKEN_PATH = "/mnt/session/uploads/aex/run-token";
|
|
2831
2780
|
|
|
2832
2781
|
// dist/host/common.js
|
|
2833
2782
|
var SUCCESS = { code: 0 };
|
|
@@ -2986,7 +2935,7 @@ async function refuseInsideManagedRun(io2, verb) {
|
|
|
2986
2935
|
try {
|
|
2987
2936
|
await io2.readFile(AEX_INDEX_PATH);
|
|
2988
2937
|
io2.stderr(`\`aex ${verb}\` is a host command and cannot run inside a managed run container.
|
|
2989
|
-
|
|
2938
|
+
Make HTTP calls from your code and pass credentials through secrets.
|
|
2990
2939
|
`);
|
|
2991
2940
|
return true;
|
|
2992
2941
|
} catch (err2) {
|
|
@@ -3171,285 +3120,6 @@ async function runOutputsSyncCmd(io2, dirs) {
|
|
|
3171
3120
|
return SUCCESS;
|
|
3172
3121
|
}
|
|
3173
3122
|
|
|
3174
|
-
// dist/proxy.js
|
|
3175
|
-
function parseProxyFlags(rest) {
|
|
3176
|
-
let endpointName = null;
|
|
3177
|
-
let method = "GET";
|
|
3178
|
-
let path = "/";
|
|
3179
|
-
let query = null;
|
|
3180
|
-
const headers = /* @__PURE__ */ new Map();
|
|
3181
|
-
let dataSpec = null;
|
|
3182
|
-
let responseMode = null;
|
|
3183
|
-
let showHelp = false;
|
|
3184
|
-
for (let i2 = 0; i2 < rest.length; i2++) {
|
|
3185
|
-
const arg = rest[i2];
|
|
3186
|
-
if (arg === "--help" || arg === "-h") {
|
|
3187
|
-
showHelp = true;
|
|
3188
|
-
continue;
|
|
3189
|
-
}
|
|
3190
|
-
if (arg === "--method") {
|
|
3191
|
-
method = expect(rest, ++i2, "--method");
|
|
3192
|
-
continue;
|
|
3193
|
-
}
|
|
3194
|
-
if (arg === "--path") {
|
|
3195
|
-
path = expect(rest, ++i2, "--path");
|
|
3196
|
-
continue;
|
|
3197
|
-
}
|
|
3198
|
-
if (arg === "--query") {
|
|
3199
|
-
query = expect(rest, ++i2, "--query");
|
|
3200
|
-
continue;
|
|
3201
|
-
}
|
|
3202
|
-
if (arg === "--header") {
|
|
3203
|
-
const kv = expect(rest, ++i2, "--header");
|
|
3204
|
-
const eq = kv.indexOf("=");
|
|
3205
|
-
if (eq <= 0)
|
|
3206
|
-
return { ok: false, reason: "--header must be in the form KEY=VALUE" };
|
|
3207
|
-
headers.set(kv.slice(0, eq).toLowerCase(), kv.slice(eq + 1));
|
|
3208
|
-
continue;
|
|
3209
|
-
}
|
|
3210
|
-
if (arg === "--data") {
|
|
3211
|
-
dataSpec = expect(rest, ++i2, "--data");
|
|
3212
|
-
continue;
|
|
3213
|
-
}
|
|
3214
|
-
if (arg === "--response-mode") {
|
|
3215
|
-
responseMode = expect(rest, ++i2, "--response-mode");
|
|
3216
|
-
continue;
|
|
3217
|
-
}
|
|
3218
|
-
if (arg.startsWith("--")) {
|
|
3219
|
-
return { ok: false, reason: `unknown flag: ${arg}` };
|
|
3220
|
-
}
|
|
3221
|
-
if (endpointName === null) {
|
|
3222
|
-
endpointName = arg;
|
|
3223
|
-
continue;
|
|
3224
|
-
}
|
|
3225
|
-
return { ok: false, reason: `unexpected positional argument: ${arg}` };
|
|
3226
|
-
}
|
|
3227
|
-
return { ok: true, flags: { endpointName, method, path, query, headers, dataSpec, responseMode, showHelp } };
|
|
3228
|
-
}
|
|
3229
|
-
function expect(arr, idx, flag) {
|
|
3230
|
-
const v = arr[idx];
|
|
3231
|
-
if (v === void 0) {
|
|
3232
|
-
throw new CliUsageError(`${flag} requires a value`);
|
|
3233
|
-
}
|
|
3234
|
-
return v;
|
|
3235
|
-
}
|
|
3236
|
-
var CliUsageError = class extends Error {
|
|
3237
|
-
};
|
|
3238
|
-
async function printProxyHelp(io2) {
|
|
3239
|
-
io2.stdout("aex proxy \u2014 call an upstream HTTP endpoint via the managed proxy.\n\n");
|
|
3240
|
-
io2.stdout("Usage:\n");
|
|
3241
|
-
io2.stdout(" aex proxy <endpoint-name> [flags]\n\n");
|
|
3242
|
-
io2.stdout("Flags:\n");
|
|
3243
|
-
io2.stdout(" --method <verb> HTTP method (default: GET)\n");
|
|
3244
|
-
io2.stdout(" --path <path> Caller-supplied path; must match policy prefixes\n");
|
|
3245
|
-
io2.stdout(` --query <json> JSON object of query parameters (e.g. '{"q":"x"}')
|
|
3246
|
-
`);
|
|
3247
|
-
io2.stdout(" --header K=V Add a caller header (repeatable)\n");
|
|
3248
|
-
io2.stdout(" --data <value> Request body. Use '-' for stdin, '@<file>' for file content\n");
|
|
3249
|
-
io2.stdout(" --response-mode <mode> status_only | headers_only | full (may only narrow policy)\n");
|
|
3250
|
-
io2.stdout(" --help Show this message\n\n");
|
|
3251
|
-
const manifest = await tryReadManifest(io2);
|
|
3252
|
-
if (manifest && manifest.endpoints.length > 0) {
|
|
3253
|
-
io2.stdout("Declared endpoints:\n");
|
|
3254
|
-
for (const ep of manifest.endpoints) {
|
|
3255
|
-
io2.stdout(` \u2022 ${formatProxyEndpointSummary(ep)}
|
|
3256
|
-
`);
|
|
3257
|
-
}
|
|
3258
|
-
}
|
|
3259
|
-
return SUCCESS;
|
|
3260
|
-
}
|
|
3261
|
-
function formatProxyEndpointSummary(ep) {
|
|
3262
|
-
const retry = ep.retry ? `, retry=${ep.retry.maxAttempts}x ${ep.retry.retryOnMethods.join("/")} ${ep.retry.retryOnStatuses.join("/")} delay=${ep.retry.initialDelayMs}-${ep.retry.maxDelayMs}ms jitter=${ep.retry.jitter}${ep.retry.respectRetryAfter ? " retry-after" : ""}` : "";
|
|
3263
|
-
return `${ep.name}: ${ep.allowMethods.join(",")} ${ep.allowPathPrefixes.join(",")} (mode=${ep.responseMode}${retry})`;
|
|
3264
|
-
}
|
|
3265
|
-
async function runProxy(io2, rest) {
|
|
3266
|
-
let parsed;
|
|
3267
|
-
try {
|
|
3268
|
-
parsed = parseProxyFlags(rest);
|
|
3269
|
-
} catch (err2) {
|
|
3270
|
-
if (err2 instanceof CliUsageError) {
|
|
3271
|
-
io2.stderr(`${err2.message}
|
|
3272
|
-
`);
|
|
3273
|
-
return USAGE_ERR;
|
|
3274
|
-
}
|
|
3275
|
-
throw err2;
|
|
3276
|
-
}
|
|
3277
|
-
if (!parsed.ok) {
|
|
3278
|
-
io2.stderr(`${parsed.reason}
|
|
3279
|
-
`);
|
|
3280
|
-
return USAGE_ERR;
|
|
3281
|
-
}
|
|
3282
|
-
const f = parsed.flags;
|
|
3283
|
-
if (f.showHelp) {
|
|
3284
|
-
return await printProxyHelp(io2);
|
|
3285
|
-
}
|
|
3286
|
-
if (!f.endpointName) {
|
|
3287
|
-
io2.stderr("missing endpoint-name\n");
|
|
3288
|
-
io2.stderr("usage: aex proxy <endpoint-name> [flags]\n");
|
|
3289
|
-
return USAGE_ERR;
|
|
3290
|
-
}
|
|
3291
|
-
if (f.responseMode && !PROXY_RESPONSE_MODES.includes(f.responseMode)) {
|
|
3292
|
-
io2.stderr(`--response-mode must be one of: ${PROXY_RESPONSE_MODES.join(", ")}
|
|
3293
|
-
`);
|
|
3294
|
-
return USAGE_ERR;
|
|
3295
|
-
}
|
|
3296
|
-
const manifest = await tryReadManifest(io2);
|
|
3297
|
-
if (!manifest) {
|
|
3298
|
-
emitError(io2, {
|
|
3299
|
-
error: "internal_error",
|
|
3300
|
-
message: "manifest not mounted; this CLI must run inside an aex-managed run"
|
|
3301
|
-
});
|
|
3302
|
-
return RUNTIME_ERR;
|
|
3303
|
-
}
|
|
3304
|
-
if (!manifest.proxyBaseUrl) {
|
|
3305
|
-
emitError(io2, {
|
|
3306
|
-
error: "endpoint_not_found",
|
|
3307
|
-
message: "this run has no proxy endpoints declared",
|
|
3308
|
-
endpointName: f.endpointName
|
|
3309
|
-
});
|
|
3310
|
-
return RUNTIME_ERR;
|
|
3311
|
-
}
|
|
3312
|
-
let token;
|
|
3313
|
-
try {
|
|
3314
|
-
token = (await io2.readFile(AEX_RUN_TOKEN_PATH)).trim();
|
|
3315
|
-
} catch {
|
|
3316
|
-
emitError(io2, {
|
|
3317
|
-
error: "unauthorized",
|
|
3318
|
-
message: "run token file missing; this run has no proxy bearer"
|
|
3319
|
-
});
|
|
3320
|
-
return RUNTIME_ERR;
|
|
3321
|
-
}
|
|
3322
|
-
if (!token) {
|
|
3323
|
-
emitError(io2, { error: "unauthorized", message: "run token is empty" });
|
|
3324
|
-
return RUNTIME_ERR;
|
|
3325
|
-
}
|
|
3326
|
-
let body;
|
|
3327
|
-
if (f.dataSpec !== null) {
|
|
3328
|
-
try {
|
|
3329
|
-
body = await resolveBody(io2, f.dataSpec);
|
|
3330
|
-
} catch (err2) {
|
|
3331
|
-
io2.stderr(`failed to read request body: ${err2.message}
|
|
3332
|
-
`);
|
|
3333
|
-
return RUNTIME_ERR;
|
|
3334
|
-
}
|
|
3335
|
-
}
|
|
3336
|
-
const url = `${manifest.proxyBaseUrl.replace(/\/+$/, "")}/${encodeURIComponent(f.endpointName)}`;
|
|
3337
|
-
const requestHeaders = new Headers();
|
|
3338
|
-
requestHeaders.set("authorization", `Bearer ${token}`);
|
|
3339
|
-
requestHeaders.set(PROXY_PROTOCOL_HEADER, PROXY_PROTOCOL_VERSION_V2);
|
|
3340
|
-
requestHeaders.set(PROXY_METHOD_HEADER, f.method.toUpperCase());
|
|
3341
|
-
requestHeaders.set(PROXY_PATH_HEADER, f.path);
|
|
3342
|
-
if (f.query) {
|
|
3343
|
-
requestHeaders.set(PROXY_QUERY_HEADER, f.query);
|
|
3344
|
-
}
|
|
3345
|
-
if (f.headers.size > 0) {
|
|
3346
|
-
requestHeaders.set(PROXY_HEADERS_HEADER, JSON.stringify(Object.fromEntries(f.headers)));
|
|
3347
|
-
}
|
|
3348
|
-
if (f.responseMode) {
|
|
3349
|
-
requestHeaders.set(PROXY_RESPONSE_MODE_HEADER, f.responseMode);
|
|
3350
|
-
}
|
|
3351
|
-
if (body !== void 0) {
|
|
3352
|
-
requestHeaders.set("content-length", String(body.byteLength));
|
|
3353
|
-
}
|
|
3354
|
-
const init = {
|
|
3355
|
-
method: "POST",
|
|
3356
|
-
headers: requestHeaders,
|
|
3357
|
-
redirect: "manual"
|
|
3358
|
-
};
|
|
3359
|
-
if (body !== void 0) {
|
|
3360
|
-
init.body = body;
|
|
3361
|
-
}
|
|
3362
|
-
let response;
|
|
3363
|
-
try {
|
|
3364
|
-
response = await io2.fetchImpl(url, init);
|
|
3365
|
-
} catch (err2) {
|
|
3366
|
-
emitError(io2, {
|
|
3367
|
-
error: "upstream_error",
|
|
3368
|
-
message: `proxy request failed: ${err2.message}`,
|
|
3369
|
-
endpointName: f.endpointName
|
|
3370
|
-
});
|
|
3371
|
-
return RUNTIME_ERR;
|
|
3372
|
-
}
|
|
3373
|
-
if (response.headers.get(PROXY_RESP_STATUS_HEADER) !== null) {
|
|
3374
|
-
const envelope = await readStreamedEnvelope(response, f.endpointName);
|
|
3375
|
-
io2.stdout(JSON.stringify(envelope) + "\n");
|
|
3376
|
-
return SUCCESS;
|
|
3377
|
-
}
|
|
3378
|
-
const text = await response.text();
|
|
3379
|
-
let parsedBody;
|
|
3380
|
-
try {
|
|
3381
|
-
parsedBody = text ? JSON.parse(text) : {};
|
|
3382
|
-
} catch {
|
|
3383
|
-
const snippet = text.slice(0, 200).replace(/\s+/g, " ").trim();
|
|
3384
|
-
emitError(io2, {
|
|
3385
|
-
error: "internal_error",
|
|
3386
|
-
message: `proxy returned non-JSON response (HTTP ${response.status}, body=${JSON.stringify(snippet)})`,
|
|
3387
|
-
endpointName: f.endpointName
|
|
3388
|
-
});
|
|
3389
|
-
return RUNTIME_ERR;
|
|
3390
|
-
}
|
|
3391
|
-
if (!response.ok) {
|
|
3392
|
-
io2.stderr(JSON.stringify(parsedBody) + "\n");
|
|
3393
|
-
return RUNTIME_ERR;
|
|
3394
|
-
}
|
|
3395
|
-
io2.stdout(JSON.stringify(parsedBody) + "\n");
|
|
3396
|
-
return SUCCESS;
|
|
3397
|
-
}
|
|
3398
|
-
async function resolveBody(io2, spec) {
|
|
3399
|
-
if (spec === "-") {
|
|
3400
|
-
const data = await io2.readFile("/dev/stdin");
|
|
3401
|
-
return new Uint8Array(Buffer.from(data, "utf8"));
|
|
3402
|
-
}
|
|
3403
|
-
if (spec.startsWith("@")) {
|
|
3404
|
-
const path = spec.slice(1);
|
|
3405
|
-
if (!path)
|
|
3406
|
-
throw new Error("--data @<file> requires a path");
|
|
3407
|
-
const data = await io2.readFile(path);
|
|
3408
|
-
return new Uint8Array(Buffer.from(data, "utf8"));
|
|
3409
|
-
}
|
|
3410
|
-
return new Uint8Array(Buffer.from(spec, "utf8"));
|
|
3411
|
-
}
|
|
3412
|
-
function emitError(io2, body) {
|
|
3413
|
-
io2.stderr(JSON.stringify(body) + "\n");
|
|
3414
|
-
}
|
|
3415
|
-
async function readStreamedEnvelope(response, endpointName) {
|
|
3416
|
-
const effectiveResponseMode = response.headers.get(PROXY_RESP_MODE_HEADER) ?? "headers_only";
|
|
3417
|
-
const upstreamStatus = Number.parseInt(response.headers.get(PROXY_RESP_STATUS_HEADER) ?? "0", 10);
|
|
3418
|
-
let upstreamHeaders = {};
|
|
3419
|
-
const rawHeaders = response.headers.get(PROXY_RESP_UPSTREAM_HEADERS_HEADER);
|
|
3420
|
-
if (rawHeaders) {
|
|
3421
|
-
try {
|
|
3422
|
-
const parsed = JSON.parse(rawHeaders);
|
|
3423
|
-
if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
|
|
3424
|
-
upstreamHeaders = parsed;
|
|
3425
|
-
}
|
|
3426
|
-
} catch {
|
|
3427
|
-
}
|
|
3428
|
-
}
|
|
3429
|
-
const truncatedRaw = response.headers.get(PROXY_RESP_TRUNCATED_HEADER);
|
|
3430
|
-
const bytes = new Uint8Array(await response.arrayBuffer());
|
|
3431
|
-
return {
|
|
3432
|
-
endpointName,
|
|
3433
|
-
upstreamStatus,
|
|
3434
|
-
upstreamHeaders,
|
|
3435
|
-
effectiveResponseMode,
|
|
3436
|
-
// The streamed path can't echo the request-side clamp decision (it
|
|
3437
|
-
// isn't carried back); the effective mode is authoritative for the
|
|
3438
|
-
// agent and matches what v1 surfaced for an un-clamped call.
|
|
3439
|
-
modeClamped: false,
|
|
3440
|
-
...effectiveResponseMode === "full" && bytes.byteLength > 0 ? { upstreamBodyBase64: Buffer.from(bytes).toString("base64") } : {},
|
|
3441
|
-
...truncatedRaw === "true" ? { truncated: true } : {}
|
|
3442
|
-
};
|
|
3443
|
-
}
|
|
3444
|
-
async function tryReadManifest(io2) {
|
|
3445
|
-
try {
|
|
3446
|
-
const raw = await io2.readFile(AEX_INDEX_PATH);
|
|
3447
|
-
return JSON.parse(raw);
|
|
3448
|
-
} catch {
|
|
3449
|
-
return null;
|
|
3450
|
-
}
|
|
3451
|
-
}
|
|
3452
|
-
|
|
3453
3123
|
// dist/host/run-cmd.js
|
|
3454
3124
|
import { resolve as resolvePath } from "node:path";
|
|
3455
3125
|
var DEFAULT_SESSION_IDLE_TTL = "3m";
|
|
@@ -3616,6 +3286,10 @@ async function runRunCmd(io2, argv) {
|
|
|
3616
3286
|
return USAGE_ERR;
|
|
3617
3287
|
}
|
|
3618
3288
|
rest = proxyAuthFlags.remaining;
|
|
3289
|
+
if (proxyEndpointFlags.values.length > 0 || Object.keys(proxyAuthFlags.entries).length > 0) {
|
|
3290
|
+
io2.stderr("--proxy-endpoint and --proxy-auth are no longer supported; make HTTP calls from your code and pass credentials via secrets.\n");
|
|
3291
|
+
return USAGE_ERR;
|
|
3292
|
+
}
|
|
3619
3293
|
const positional = rest.filter((a) => !a.startsWith("--"));
|
|
3620
3294
|
const unknownFlags = rest.filter((a) => a.startsWith("--"));
|
|
3621
3295
|
if (unknownFlags.length > 0) {
|
|
@@ -3727,35 +3401,6 @@ async function runRunCmd(io2, argv) {
|
|
|
3727
3401
|
for (const name of mcpHeaderBag.keys()) {
|
|
3728
3402
|
if (!mcpServersForSubmission.some((m) => m.name === name)) {
|
|
3729
3403
|
io2.stderr(`--mcp-auth ${name}: no matching --mcp / mcpServers entry declared
|
|
3730
|
-
`);
|
|
3731
|
-
return USAGE_ERR;
|
|
3732
|
-
}
|
|
3733
|
-
}
|
|
3734
|
-
let proxyEndpoints = runConfig.proxyEndpoints ?? [];
|
|
3735
|
-
if (proxyEndpointFlags.values.length > 0) {
|
|
3736
|
-
try {
|
|
3737
|
-
proxyEndpoints = proxyEndpointFlags.values.map((raw, i2) => parseJsonOrThrow(raw, `--proxy-endpoint[${i2}]`));
|
|
3738
|
-
} catch (err2) {
|
|
3739
|
-
io2.stderr(`${err2.message}
|
|
3740
|
-
`);
|
|
3741
|
-
return USAGE_ERR;
|
|
3742
|
-
}
|
|
3743
|
-
}
|
|
3744
|
-
const proxyAuth = [];
|
|
3745
|
-
for (const [name, spec] of Object.entries(proxyAuthFlags.entries)) {
|
|
3746
|
-
const parsed = parseProxyAuth(spec);
|
|
3747
|
-
if (!parsed.ok) {
|
|
3748
|
-
io2.stderr(`--proxy-auth ${name}: ${parsed.reason}
|
|
3749
|
-
`);
|
|
3750
|
-
return USAGE_ERR;
|
|
3751
|
-
}
|
|
3752
|
-
proxyAuth.push({ name, value: parsed.value });
|
|
3753
|
-
}
|
|
3754
|
-
if (proxyEndpoints.length > 0) {
|
|
3755
|
-
try {
|
|
3756
|
-
validateProxyAuth(proxyEndpoints, proxyAuth);
|
|
3757
|
-
} catch (err2) {
|
|
3758
|
-
io2.stderr(`proxy auth validation failed: ${err2.message}
|
|
3759
3404
|
`);
|
|
3760
3405
|
return USAGE_ERR;
|
|
3761
3406
|
}
|
|
@@ -3774,8 +3419,7 @@ async function runRunCmd(io2, argv) {
|
|
|
3774
3419
|
const hasAdditionalProviderKeys = Object.keys(providerKeyValues).some((p) => p !== provider);
|
|
3775
3420
|
const secrets = {
|
|
3776
3421
|
apiKeys: hasAdditionalProviderKeys ? providerKeyValues : { [provider]: providerKeyValues[provider] },
|
|
3777
|
-
...mcpServerSecrets.length > 0 ? { mcpServers: mcpServerSecrets } : {}
|
|
3778
|
-
...proxyAuth.length > 0 ? { proxyEndpointAuth: proxyAuth } : {}
|
|
3422
|
+
...mcpServerSecrets.length > 0 ? { mcpServers: mcpServerSecrets } : {}
|
|
3779
3423
|
};
|
|
3780
3424
|
const request = {
|
|
3781
3425
|
provider,
|
|
@@ -3784,8 +3428,7 @@ async function runRunCmd(io2, argv) {
|
|
|
3784
3428
|
retention: { idleTtl: DEFAULT_SESSION_IDLE_TTL },
|
|
3785
3429
|
...runtimeSizeFlag.value ? { runtimeSize: runtimeSizeFlag.value } : runConfig.runtimeSize ? { runtimeSize: runConfig.runtimeSize } : {},
|
|
3786
3430
|
...runTimeoutFlag.value ? { timeout: runTimeoutFlag.value } : runConfig.timeout ? { timeout: runConfig.timeout } : {},
|
|
3787
|
-
...webhookFlag.value ? { webhook: { url: webhookFlag.value } } : {}
|
|
3788
|
-
...proxyEndpoints.length > 0 ? { proxyEndpoints } : {}
|
|
3431
|
+
...webhookFlag.value ? { webhook: { url: webhookFlag.value } } : {}
|
|
3789
3432
|
};
|
|
3790
3433
|
const createKey = idempotency.value ?? generateIdempotencyKey();
|
|
3791
3434
|
const messageKey = `${createKey}:message`;
|
|
@@ -3864,47 +3507,6 @@ async function runRunCmd(io2, argv) {
|
|
|
3864
3507
|
return RUNTIME_ERR;
|
|
3865
3508
|
}
|
|
3866
3509
|
}
|
|
3867
|
-
function parseProxyAuth(spec) {
|
|
3868
|
-
const idx = spec.indexOf(":");
|
|
3869
|
-
if (idx <= 0) {
|
|
3870
|
-
return { ok: false, reason: `expected '<type>:<value>' (got: ${spec})` };
|
|
3871
|
-
}
|
|
3872
|
-
const type = spec.slice(0, idx);
|
|
3873
|
-
const restValue = spec.slice(idx + 1);
|
|
3874
|
-
switch (type) {
|
|
3875
|
-
case "bearer":
|
|
3876
|
-
if (!restValue)
|
|
3877
|
-
return { ok: false, reason: "bearer requires a token value" };
|
|
3878
|
-
return { ok: true, value: { type: "bearer", token: restValue } };
|
|
3879
|
-
case "header":
|
|
3880
|
-
if (!restValue)
|
|
3881
|
-
return { ok: false, reason: "header requires a value" };
|
|
3882
|
-
return { ok: true, value: { type: "header", value: restValue } };
|
|
3883
|
-
case "query":
|
|
3884
|
-
if (!restValue)
|
|
3885
|
-
return { ok: false, reason: "query requires a value" };
|
|
3886
|
-
return { ok: true, value: { type: "query", value: restValue } };
|
|
3887
|
-
case "basic": {
|
|
3888
|
-
const sep = restValue.indexOf(":");
|
|
3889
|
-
if (sep <= 0 || sep >= restValue.length - 1) {
|
|
3890
|
-
return { ok: false, reason: "basic requires <username>:<password>" };
|
|
3891
|
-
}
|
|
3892
|
-
return {
|
|
3893
|
-
ok: true,
|
|
3894
|
-
value: { type: "basic", username: restValue.slice(0, sep), password: restValue.slice(sep + 1) }
|
|
3895
|
-
};
|
|
3896
|
-
}
|
|
3897
|
-
default:
|
|
3898
|
-
return { ok: false, reason: `unknown auth type '${type}' (expected bearer|basic|header|query)` };
|
|
3899
|
-
}
|
|
3900
|
-
}
|
|
3901
|
-
function parseJsonOrThrow(raw, label) {
|
|
3902
|
-
try {
|
|
3903
|
-
return JSON.parse(raw);
|
|
3904
|
-
} catch (err2) {
|
|
3905
|
-
throw new Error(`${label} is not valid JSON: ${err2.message}`);
|
|
3906
|
-
}
|
|
3907
|
-
}
|
|
3908
3510
|
function stripMcpHeadersForParsing(input) {
|
|
3909
3511
|
const mcpHeaders = /* @__PURE__ */ new Map();
|
|
3910
3512
|
if (input === null || typeof input !== "object" || Array.isArray(input)) {
|
|
@@ -4400,6 +4002,82 @@ async function runWhoamiCmd(io2, argv) {
|
|
|
4400
4002
|
}
|
|
4401
4003
|
}
|
|
4402
4004
|
|
|
4005
|
+
// dist/host/redeem.js
|
|
4006
|
+
function messageForStatus(status2, serverMessage) {
|
|
4007
|
+
switch (status2) {
|
|
4008
|
+
case 404:
|
|
4009
|
+
return "coupon code not found";
|
|
4010
|
+
case 403:
|
|
4011
|
+
return "this coupon can't be redeemed by this workspace";
|
|
4012
|
+
case 409:
|
|
4013
|
+
return "coupon already redeemed";
|
|
4014
|
+
case 400:
|
|
4015
|
+
return serverMessage ? `invalid input: ${serverMessage}` : "invalid input";
|
|
4016
|
+
case 401:
|
|
4017
|
+
return "not authorized \u2014 check --api-token, or run `aex login`";
|
|
4018
|
+
default:
|
|
4019
|
+
return serverMessage ? `redeem failed: ${serverMessage}` : `redeem failed (HTTP ${status2})`;
|
|
4020
|
+
}
|
|
4021
|
+
}
|
|
4022
|
+
async function runRedeemCmd(io2, argv) {
|
|
4023
|
+
if (await refuseInsideManagedRun(io2, "redeem"))
|
|
4024
|
+
return USAGE_ERR;
|
|
4025
|
+
const common = await resolveCommonHostFlags(io2, argv);
|
|
4026
|
+
if (!common.ok) {
|
|
4027
|
+
io2.stderr(`${common.reason}
|
|
4028
|
+
`);
|
|
4029
|
+
return USAGE_ERR;
|
|
4030
|
+
}
|
|
4031
|
+
const positional = common.rest.filter((arg) => !arg.startsWith("--"));
|
|
4032
|
+
if (positional.length !== 1) {
|
|
4033
|
+
io2.stderr("usage: aex redeem <code> [common flags]\n");
|
|
4034
|
+
return USAGE_ERR;
|
|
4035
|
+
}
|
|
4036
|
+
const code = positional[0];
|
|
4037
|
+
const base = common.flags.aexUrl.replace(/\/+$/, "");
|
|
4038
|
+
const url = `${base}/billing/redeem`;
|
|
4039
|
+
let response;
|
|
4040
|
+
try {
|
|
4041
|
+
response = await io2.fetchImpl(url, {
|
|
4042
|
+
method: "POST",
|
|
4043
|
+
headers: {
|
|
4044
|
+
accept: "application/json",
|
|
4045
|
+
"content-type": "application/json",
|
|
4046
|
+
authorization: `Bearer ${common.flags.apiToken}`
|
|
4047
|
+
},
|
|
4048
|
+
body: JSON.stringify({ code })
|
|
4049
|
+
});
|
|
4050
|
+
} catch (err2) {
|
|
4051
|
+
io2.stderr(`redeem failed: ${err2 instanceof Error ? err2.message : String(err2)}
|
|
4052
|
+
`);
|
|
4053
|
+
return RUNTIME_ERR;
|
|
4054
|
+
}
|
|
4055
|
+
if (common.flags.debug) {
|
|
4056
|
+
io2.stderr(`[aex] POST /billing/redeem -> ${response.status}
|
|
4057
|
+
`);
|
|
4058
|
+
}
|
|
4059
|
+
const text = await response.text();
|
|
4060
|
+
let body = {};
|
|
4061
|
+
try {
|
|
4062
|
+
if (text.length > 0)
|
|
4063
|
+
body = JSON.parse(text);
|
|
4064
|
+
} catch {
|
|
4065
|
+
body = {};
|
|
4066
|
+
}
|
|
4067
|
+
if (!response.ok) {
|
|
4068
|
+
const serverMessage = body && typeof body === "object" && typeof body.message === "string" ? body.message : void 0;
|
|
4069
|
+
io2.stderr(`${messageForStatus(response.status, serverMessage)}
|
|
4070
|
+
`);
|
|
4071
|
+
return RUNTIME_ERR;
|
|
4072
|
+
}
|
|
4073
|
+
const ok = body;
|
|
4074
|
+
const amountUsd = typeof ok.amountUsd === "number" ? ok.amountUsd : 0;
|
|
4075
|
+
const newBalanceUsd = typeof ok.newBalanceUsd === "number" ? ok.newBalanceUsd : 0;
|
|
4076
|
+
io2.stdout(`Redeemed $${amountUsd.toFixed(2)}. New balance: $${newBalanceUsd.toFixed(2)}.
|
|
4077
|
+
`);
|
|
4078
|
+
return SUCCESS;
|
|
4079
|
+
}
|
|
4080
|
+
|
|
4403
4081
|
// dist/host/debug.js
|
|
4404
4082
|
import { dirname, resolve as resolvePath3 } from "node:path";
|
|
4405
4083
|
function status(source, state, opts = {}) {
|
|
@@ -5649,8 +5327,6 @@ async function dispatch(io2, args) {
|
|
|
5649
5327
|
const sub = args[0];
|
|
5650
5328
|
const rest = args.slice(1);
|
|
5651
5329
|
switch (sub) {
|
|
5652
|
-
case "proxy":
|
|
5653
|
-
return runProxy(io2, rest);
|
|
5654
5330
|
case "run":
|
|
5655
5331
|
return runRunCmd(io2, rest);
|
|
5656
5332
|
case "status":
|
|
@@ -5680,6 +5356,8 @@ async function dispatch(io2, args) {
|
|
|
5680
5356
|
return runDeleteAssetCmd(io2, rest);
|
|
5681
5357
|
case "whoami":
|
|
5682
5358
|
return runWhoamiCmd(io2, rest);
|
|
5359
|
+
case "redeem":
|
|
5360
|
+
return runRedeemCmd(io2, rest);
|
|
5683
5361
|
case "login":
|
|
5684
5362
|
return runLoginCmd(io2, rest);
|
|
5685
5363
|
case "logout":
|
|
@@ -5704,26 +5382,6 @@ async function dispatch(io2, args) {
|
|
|
5704
5382
|
}
|
|
5705
5383
|
}
|
|
5706
5384
|
async function printGlobalHelp(io2) {
|
|
5707
|
-
const manifest = await tryReadManifest(io2);
|
|
5708
|
-
if (manifest) {
|
|
5709
|
-
io2.stdout("aex \u2014 in-container CLI for managed run sessions\n\n");
|
|
5710
|
-
io2.stdout("Usage:\n");
|
|
5711
|
-
io2.stdout(" aex proxy <endpoint-name> [flags]\n");
|
|
5712
|
-
io2.stdout(" aex proxy --help\n\n");
|
|
5713
|
-
if (manifest.endpoints.length === 0) {
|
|
5714
|
-
io2.stdout("This run declared no proxy endpoints.\n");
|
|
5715
|
-
} else {
|
|
5716
|
-
io2.stdout("Declared proxy endpoints for this run:\n");
|
|
5717
|
-
for (const ep of manifest.endpoints) {
|
|
5718
|
-
io2.stdout(` \u2022 ${formatProxyEndpointSummary(ep)}
|
|
5719
|
-
`);
|
|
5720
|
-
}
|
|
5721
|
-
}
|
|
5722
|
-
io2.stdout(`
|
|
5723
|
-
Protocol version: ${manifest.protocolVersion}
|
|
5724
|
-
`);
|
|
5725
|
-
return SUCCESS;
|
|
5726
|
-
}
|
|
5727
5385
|
io2.stdout("aex \u2014 unified CLI for the aex platform (mirrors the SDK 1:1)\n\n");
|
|
5728
5386
|
io2.stdout("Usage:\n");
|
|
5729
5387
|
io2.stdout(" aex run --config <run.json> --<provider>-api-key K --api-token T [flags]\n");
|
|
@@ -5740,6 +5398,7 @@ Protocol version: ${manifest.protocolVersion}
|
|
|
5740
5398
|
io2.stdout(" aex delete <session-id> --api-token T\n");
|
|
5741
5399
|
io2.stdout(" aex delete-asset <assetId|hash> --api-token T\n");
|
|
5742
5400
|
io2.stdout(" aex whoami --api-token T\n");
|
|
5401
|
+
io2.stdout(" aex redeem <code> --api-token T Redeem a coupon code into the workspace prepaid balance\n");
|
|
5743
5402
|
io2.stdout(" aex login --api-token T [--aex-url U] Persist token + url (then other verbs need no --api-token)\n");
|
|
5744
5403
|
io2.stdout(" aex logout Clear the stored token\n");
|
|
5745
5404
|
io2.stdout(" aex auth status Show the resolved config (token never printed)\n");
|
|
@@ -5767,8 +5426,6 @@ Protocol version: ${manifest.protocolVersion}
|
|
|
5767
5426
|
io2.stdout(" --mcp name=url MCP server entry (repeatable)\n");
|
|
5768
5427
|
io2.stdout(" --mcp-auth name=Hdr:Val Auth header on the matching --mcp; routed into vaulted secrets (repeatable)\n");
|
|
5769
5428
|
io2.stdout(" --metadata key=value Submission metadata entry (repeatable)\n");
|
|
5770
|
-
io2.stdout(" --proxy-endpoint '<json>' PlatformProxyEndpoint JSON (repeatable)\n");
|
|
5771
|
-
io2.stdout(" --proxy-auth name=<spec> bearer:tok | basic:u:p | header:v | query:v (repeatable)\n");
|
|
5772
5429
|
io2.stdout(" --runtime-size <size> managed runtime preset\n");
|
|
5773
5430
|
io2.stdout(" --run-timeout <dur> Server-side run deadline (e.g. 1h); distinct from --timeout\n");
|
|
5774
5431
|
io2.stdout(" --idempotency-key <key> Optional; defaults to a fresh UUID\n");
|