@aexhq/sdk 0.35.0 → 0.37.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 +17 -16
- package/dist/_contracts/event-envelope.d.ts +22 -1
- package/dist/_contracts/event-envelope.js +26 -2
- package/dist/_contracts/event-stream-client.js +7 -1
- package/dist/_contracts/index.d.ts +3 -4
- package/dist/_contracts/index.js +1 -4
- package/dist/_contracts/operations.d.ts +31 -1
- package/dist/_contracts/operations.js +64 -1
- package/dist/_contracts/run-config.d.ts +2 -4
- 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 +14 -25
- package/dist/_contracts/run-unit.js +56 -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-sizes.d.ts +2 -2
- package/dist/_contracts/runtime-sizes.js +5 -5
- package/dist/_contracts/runtime-types.d.ts +123 -4
- package/dist/_contracts/stable.d.ts +1 -1
- package/dist/_contracts/stable.js +1 -1
- package/dist/_contracts/submission.d.ts +8 -76
- package/dist/_contracts/submission.js +5 -472
- package/dist/cli.mjs +574 -511
- package/dist/cli.mjs.sha256 +1 -1
- package/dist/client.d.ts +69 -25
- package/dist/client.js +338 -68
- package/dist/client.js.map +1 -1
- package/dist/index.d.ts +8 -16
- package/dist/index.js +5 -17
- package/dist/index.js.map +1 -1
- 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/authentication.md +92 -0
- package/docs/billing.md +112 -0
- package/docs/concepts/agent-tools.md +4 -4
- package/docs/concepts/composition.md +8 -14
- package/docs/concepts/providers-and-runtimes.md +4 -1
- package/docs/concepts/runs.md +2 -1
- package/docs/concepts/subagents.md +85 -0
- package/docs/credentials.md +78 -96
- package/docs/defaults.md +9 -15
- package/docs/errors.md +132 -0
- package/docs/events.md +44 -32
- package/docs/limits-and-quotas.md +30 -17
- package/docs/limits.md +4 -8
- package/docs/mcp.md +5 -6
- package/docs/networking.md +75 -59
- package/docs/outputs.md +4 -7
- package/docs/public-surface.json +4 -4
- package/docs/quickstart.md +12 -13
- package/docs/run-config.md +7 -4
- package/docs/secrets.md +6 -1
- package/docs/skills.md +3 -3
- package/docs/vision-skills.md +52 -101
- package/docs/webhooks.md +132 -0
- package/examples/feature-tour.ts +4 -21
- 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" },
|
|
@@ -156,6 +128,46 @@ var MODEL_PROVIDER_IDS = {
|
|
|
156
128
|
}
|
|
157
129
|
};
|
|
158
130
|
var RUN_MODELS = Object.keys(MODEL_PROVIDER_IDS);
|
|
131
|
+
var Models = {
|
|
132
|
+
/** Claude Haiku 4.5 — Anthropic. */
|
|
133
|
+
CLAUDE_HAIKU_4_5: "claude-haiku-4-5",
|
|
134
|
+
/** Claude 3.5 Haiku (latest) — Anthropic. */
|
|
135
|
+
CLAUDE_3_5_HAIKU_LATEST: "claude-3-5-haiku-latest",
|
|
136
|
+
/** Claude 3.5 Sonnet (latest) — Anthropic. */
|
|
137
|
+
CLAUDE_3_5_SONNET_LATEST: "claude-3-5-sonnet-latest",
|
|
138
|
+
/** Claude Sonnet 4.6 — Anthropic (1M context, reasoning-capable). */
|
|
139
|
+
CLAUDE_SONNET_4_6: "claude-sonnet-4-6",
|
|
140
|
+
/** DeepSeek V4 Flash — DeepSeek (non-thinking, fast). */
|
|
141
|
+
DEEPSEEK_V4_FLASH: "deepseek-v4-flash",
|
|
142
|
+
/** DeepSeek V4 Pro — DeepSeek (reasoning-heavy). */
|
|
143
|
+
DEEPSEEK_V4_PRO: "deepseek-v4-pro",
|
|
144
|
+
/** GPT-4.1 — OpenAI. */
|
|
145
|
+
GPT_4_1: "gpt-4.1",
|
|
146
|
+
/** GPT-4o mini — OpenAI, or via OpenRouter (`provider: Providers.OPENROUTER`). */
|
|
147
|
+
GPT_4O_MINI: "gpt-4o-mini",
|
|
148
|
+
/** GPT-4o — via OpenRouter (`provider: Providers.OPENROUTER`). */
|
|
149
|
+
GPT_4O: "gpt-4o",
|
|
150
|
+
/** Gemini 2.0 Flash — Gemini, or via OpenRouter (`provider: Providers.OPENROUTER`). */
|
|
151
|
+
GEMINI_2_0_FLASH: "gemini-2.0-flash",
|
|
152
|
+
/** Gemini 2.5 Flash — Gemini. */
|
|
153
|
+
GEMINI_2_5_FLASH: "gemini-2.5-flash",
|
|
154
|
+
/** Mistral Large (latest) — Mistral. */
|
|
155
|
+
MISTRAL_LARGE_LATEST: "mistral-large-latest",
|
|
156
|
+
/** Mistral Small (latest) — Mistral. */
|
|
157
|
+
MISTRAL_SMALL_LATEST: "mistral-small-latest",
|
|
158
|
+
/**
|
|
159
|
+
* Doubao Seed 1.8 — ByteDance, via the official Ark API. Default routes
|
|
160
|
+
* through the international BytePlus gateway (`Providers.DOUBAO`); pair with
|
|
161
|
+
* `Providers.DOUBAO_CN` for the China Volcengine gateway.
|
|
162
|
+
*/
|
|
163
|
+
DOUBAO_SEED_PRO: "doubao-seed-pro",
|
|
164
|
+
/**
|
|
165
|
+
* Doubao Seed 1.6 Flash — ByteDance, via the official Ark API (fast/cheap).
|
|
166
|
+
* Default `Providers.DOUBAO` (international); pair with `Providers.DOUBAO_CN`
|
|
167
|
+
* for China.
|
|
168
|
+
*/
|
|
169
|
+
DOUBAO_SEED_FLASH: "doubao-seed-flash"
|
|
170
|
+
};
|
|
159
171
|
var PROVIDERS_BY_MODEL = (() => {
|
|
160
172
|
const map = {};
|
|
161
173
|
for (const [model, providers] of Object.entries(MODEL_PROVIDER_IDS)) {
|
|
@@ -199,6 +211,15 @@ var TERMINAL_RUN_STATUSES = [
|
|
|
199
211
|
"cleanup_failed"
|
|
200
212
|
];
|
|
201
213
|
var terminalRunStatuses = new Set(TERMINAL_RUN_STATUSES);
|
|
214
|
+
var CLEANUP_STATUSES = [
|
|
215
|
+
"not_started",
|
|
216
|
+
"pending",
|
|
217
|
+
"running",
|
|
218
|
+
"succeeded",
|
|
219
|
+
"failed_retryable",
|
|
220
|
+
"failed_terminal",
|
|
221
|
+
"skipped"
|
|
222
|
+
];
|
|
202
223
|
|
|
203
224
|
// ../contracts/dist/run-config.js
|
|
204
225
|
var SKILL_BUNDLE_LIMITS = {
|
|
@@ -392,7 +413,6 @@ function parseRunRequestConfig(input) {
|
|
|
392
413
|
"environment",
|
|
393
414
|
"runtimeSize",
|
|
394
415
|
"timeout",
|
|
395
|
-
"proxyEndpoints",
|
|
396
416
|
"metadata"
|
|
397
417
|
]);
|
|
398
418
|
for (const key of Object.keys(record)) {
|
|
@@ -412,14 +432,13 @@ function parseRunRequestConfig(input) {
|
|
|
412
432
|
...system !== void 0 ? { system } : {},
|
|
413
433
|
prompt,
|
|
414
434
|
...mcpServers !== void 0 ? { mcpServers } : {},
|
|
415
|
-
// environment /
|
|
416
|
-
//
|
|
435
|
+
// environment / metadata: passed through as-is — the BFF revalidates
|
|
436
|
+
// them via `parseRunSubmissionRequest`,
|
|
417
437
|
// so duplicating the heavyweight parsers here would mean two sources
|
|
418
438
|
// of truth. The CLI surfaces structural errors at submission time.
|
|
419
439
|
...record.environment !== void 0 ? { environment: record.environment } : {},
|
|
420
440
|
...record.runtimeSize !== void 0 ? { runtimeSize: record.runtimeSize } : {},
|
|
421
441
|
...record.timeout !== void 0 ? { timeout: record.timeout } : {},
|
|
422
|
-
...record.proxyEndpoints !== void 0 ? { proxyEndpoints: record.proxyEndpoints } : {},
|
|
423
442
|
...record.metadata !== void 0 ? { metadata: record.metadata } : {}
|
|
424
443
|
};
|
|
425
444
|
}
|
|
@@ -475,8 +494,8 @@ var RUNTIME_SIZE_PRESETS = {
|
|
|
475
494
|
};
|
|
476
495
|
var RUNTIME_SIZES = Object.keys(RUNTIME_SIZE_PRESETS);
|
|
477
496
|
var DEFAULT_RUNTIME_SIZE = "shared-0.25x-1gb";
|
|
478
|
-
var DEFAULT_RUN_TIMEOUT_MS = 60 * 60 * 1e3;
|
|
479
|
-
var MAX_RUN_TIMEOUT_MS =
|
|
497
|
+
var DEFAULT_RUN_TIMEOUT_MS = 8 * 60 * 60 * 1e3;
|
|
498
|
+
var MAX_RUN_TIMEOUT_MS = 8 * 60 * 60 * 1e3;
|
|
480
499
|
var MIN_RUN_TIMEOUT_MS = 60 * 1e3;
|
|
481
500
|
var RUN_PROCESS_KILL_GRACE_MS = 60 * 1e3;
|
|
482
501
|
var RUN_TERMINAL_GRACE_MS = 90 * 1e3;
|
|
@@ -489,7 +508,6 @@ var RUNTIME_SECURITY_PROFILE_CONFIG = Object.freeze({
|
|
|
489
508
|
allowOpenNetworking: false,
|
|
490
509
|
allowRuntimePackages: false,
|
|
491
510
|
allowCustomerEnvVars: true,
|
|
492
|
-
allowProxyEndpoints: true,
|
|
493
511
|
allowMcpServers: true
|
|
494
512
|
}),
|
|
495
513
|
standard: Object.freeze({
|
|
@@ -498,7 +516,6 @@ var RUNTIME_SECURITY_PROFILE_CONFIG = Object.freeze({
|
|
|
498
516
|
allowOpenNetworking: true,
|
|
499
517
|
allowRuntimePackages: true,
|
|
500
518
|
allowCustomerEnvVars: true,
|
|
501
|
-
allowProxyEndpoints: true,
|
|
502
519
|
allowMcpServers: true
|
|
503
520
|
}),
|
|
504
521
|
developer: Object.freeze({
|
|
@@ -507,12 +524,12 @@ var RUNTIME_SECURITY_PROFILE_CONFIG = Object.freeze({
|
|
|
507
524
|
allowOpenNetworking: true,
|
|
508
525
|
allowRuntimePackages: true,
|
|
509
526
|
allowCustomerEnvVars: true,
|
|
510
|
-
allowProxyEndpoints: true,
|
|
511
527
|
allowMcpServers: true
|
|
512
528
|
})
|
|
513
529
|
});
|
|
514
530
|
|
|
515
531
|
// ../contracts/dist/submission.js
|
|
532
|
+
var PLATFORM_PACKAGE_ECOSYSTEMS = ["apt", "npm", "pip"];
|
|
516
533
|
var RUN_PROVIDERS = [
|
|
517
534
|
"anthropic",
|
|
518
535
|
"deepseek",
|
|
@@ -524,9 +541,6 @@ var RUN_PROVIDERS = [
|
|
|
524
541
|
"doubao-cn"
|
|
525
542
|
];
|
|
526
543
|
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
544
|
var BUILTIN_TOOL_NAMES = [
|
|
531
545
|
"bash",
|
|
532
546
|
"read_file",
|
|
@@ -566,12 +580,17 @@ var AEX_EVENT_TYPES = [
|
|
|
566
580
|
// off-the-shelf AG-UI client filters logs out by `channel`.
|
|
567
581
|
"LOG"
|
|
568
582
|
];
|
|
583
|
+
var AEX_SESSION_PARKED_NAMES = ["aex.session.idle", "aex.session.error", "aex.session.suspended"];
|
|
584
|
+
function isSessionParked(e) {
|
|
585
|
+
const name = customName(e);
|
|
586
|
+
return name !== null && AEX_SESSION_PARKED_NAMES.includes(name);
|
|
587
|
+
}
|
|
569
588
|
function customName(e) {
|
|
570
589
|
return e.type === "CUSTOM" ? str(e.data.name) || null : null;
|
|
571
590
|
}
|
|
572
591
|
var AEX_RUN_SETTLED_NAME = "aex.run.settled";
|
|
573
592
|
function isRunSettled(e) {
|
|
574
|
-
return customName(e) === AEX_RUN_SETTLED_NAME;
|
|
593
|
+
return customName(e) === AEX_RUN_SETTLED_NAME || isSessionParked(e);
|
|
575
594
|
}
|
|
576
595
|
function channelOf(e) {
|
|
577
596
|
return e.channel ?? "event";
|
|
@@ -629,7 +648,7 @@ function str(v) {
|
|
|
629
648
|
var encoder = new TextEncoder();
|
|
630
649
|
|
|
631
650
|
// ../contracts/dist/event-stream-client.js
|
|
632
|
-
var isTerminalType = (e) => e.type === "RUN_FINISHED" || e.type === "RUN_ERROR";
|
|
651
|
+
var isTerminalType = (e) => e.type === "RUN_FINISHED" || e.type === "RUN_ERROR" || isSessionParked(e);
|
|
633
652
|
var COORDINATOR_PING = "aex:ping";
|
|
634
653
|
var DEFAULT_IDLE_TIMEOUT_MS = 45e3;
|
|
635
654
|
var DEFAULT_PING_INTERVAL_MS = 15e3;
|
|
@@ -787,6 +806,191 @@ function sleep(ms, signal) {
|
|
|
787
806
|
});
|
|
788
807
|
}
|
|
789
808
|
|
|
809
|
+
// ../contracts/dist/run-unit.js
|
|
810
|
+
function parseRunUnitSubmission(input) {
|
|
811
|
+
if (!input || typeof input !== "object" || Array.isArray(input)) {
|
|
812
|
+
return fallbackFlat();
|
|
813
|
+
}
|
|
814
|
+
const value = input;
|
|
815
|
+
if (value.kind === "submission") {
|
|
816
|
+
return parseFlatProjection(value);
|
|
817
|
+
}
|
|
818
|
+
return fallbackFlat();
|
|
819
|
+
}
|
|
820
|
+
function parseFlatProjection(value) {
|
|
821
|
+
const submissionRaw = isRecord(value.submission) ? value.submission : {};
|
|
822
|
+
const outputsRaw = isRecord(submissionRaw.outputs) ? submissionRaw.outputs : {};
|
|
823
|
+
const allowedDirs = toOptionalStringArray(outputsRaw.allowedDirs);
|
|
824
|
+
const deniedDirs = toOptionalStringArray(outputsRaw.deniedDirs);
|
|
825
|
+
const captureTimeoutMs = toOptionalPositiveInteger(outputsRaw.captureTimeoutMs);
|
|
826
|
+
const maxFileBytes = toOptionalPositiveInteger(outputsRaw.maxFileBytes);
|
|
827
|
+
const maxTotalBytes = toOptionalPositiveInteger(outputsRaw.maxTotalBytes);
|
|
828
|
+
const maxFiles = toOptionalPositiveInteger(outputsRaw.maxFiles);
|
|
829
|
+
const submission = {
|
|
830
|
+
model: coerceRunUnitModel(submissionRaw.model),
|
|
831
|
+
...typeof submissionRaw.system === "string" ? { system: submissionRaw.system } : {},
|
|
832
|
+
prompt: toStringArray(submissionRaw.prompt),
|
|
833
|
+
agentsMd: [],
|
|
834
|
+
files: [],
|
|
835
|
+
mcpServers: toMcpServerRefArray(submissionRaw.mcpServers),
|
|
836
|
+
tools: [],
|
|
837
|
+
...parseEnvironment(submissionRaw.environment) ? { environment: parseEnvironment(submissionRaw.environment) } : {},
|
|
838
|
+
...parseSecurityProfile(submissionRaw.securityProfile) ? { securityProfile: parseSecurityProfile(submissionRaw.securityProfile) } : {},
|
|
839
|
+
...isJsonRecord(submissionRaw.metadata) ? { metadata: submissionRaw.metadata } : {},
|
|
840
|
+
...allowedDirs || deniedDirs || captureTimeoutMs !== void 0 || maxFileBytes !== void 0 || maxTotalBytes !== void 0 || maxFiles !== void 0 ? {
|
|
841
|
+
outputs: {
|
|
842
|
+
...allowedDirs ? { allowedDirs } : {},
|
|
843
|
+
...deniedDirs ? { deniedDirs } : {},
|
|
844
|
+
...captureTimeoutMs !== void 0 ? { captureTimeoutMs } : {},
|
|
845
|
+
...maxFileBytes !== void 0 ? { maxFileBytes } : {},
|
|
846
|
+
...maxTotalBytes !== void 0 ? { maxTotalBytes } : {},
|
|
847
|
+
...maxFiles !== void 0 ? { maxFiles } : {}
|
|
848
|
+
}
|
|
849
|
+
} : {}
|
|
850
|
+
};
|
|
851
|
+
return {
|
|
852
|
+
kind: "submission",
|
|
853
|
+
submission
|
|
854
|
+
};
|
|
855
|
+
}
|
|
856
|
+
function parseSecurityProfile(value) {
|
|
857
|
+
return value === "strict" || value === "standard" || value === "developer" ? value : void 0;
|
|
858
|
+
}
|
|
859
|
+
function toOptionalPositiveInteger(value) {
|
|
860
|
+
return typeof value === "number" && Number.isInteger(value) && value > 0 ? value : void 0;
|
|
861
|
+
}
|
|
862
|
+
function fallbackFlat() {
|
|
863
|
+
return {
|
|
864
|
+
kind: "submission",
|
|
865
|
+
submission: {
|
|
866
|
+
model: Models.CLAUDE_HAIKU_4_5,
|
|
867
|
+
prompt: [],
|
|
868
|
+
agentsMd: [],
|
|
869
|
+
files: [],
|
|
870
|
+
mcpServers: [],
|
|
871
|
+
tools: []
|
|
872
|
+
}
|
|
873
|
+
};
|
|
874
|
+
}
|
|
875
|
+
function isRecord(value) {
|
|
876
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
877
|
+
}
|
|
878
|
+
function normalizeRunUnit(raw) {
|
|
879
|
+
const r = isRecord(raw) ? raw : {};
|
|
880
|
+
const eventsRaw = isRecord(r.events) ? r.events : {};
|
|
881
|
+
const str3 = (v) => typeof v === "string" ? v : void 0;
|
|
882
|
+
const arr = (v) => Array.isArray(v) ? v : [];
|
|
883
|
+
return {
|
|
884
|
+
id: str3(r.id) ?? "",
|
|
885
|
+
workspaceId: str3(r.workspaceId) ?? "",
|
|
886
|
+
status: str3(r.status) ?? "unknown",
|
|
887
|
+
...str3(r.lifecyclePhase) ? { lifecyclePhase: r.lifecyclePhase } : {},
|
|
888
|
+
cleanupStatus: CLEANUP_STATUSES.includes(r.cleanupStatus) ? r.cleanupStatus : "not_started",
|
|
889
|
+
createdAt: str3(r.createdAt) ?? "",
|
|
890
|
+
updatedAt: str3(r.updatedAt) ?? "",
|
|
891
|
+
...str3(r.startedAt) ? { startedAt: r.startedAt } : {},
|
|
892
|
+
...str3(r.terminalAt) ? { terminalAt: r.terminalAt } : {},
|
|
893
|
+
...str3(r.deletedAt) ? { deletedAt: r.deletedAt } : {},
|
|
894
|
+
attemptCount: typeof r.attemptCount === "number" ? r.attemptCount : Array.isArray(r.attempts) ? r.attempts.length : 0,
|
|
895
|
+
submission: parseRunUnitSubmission(r.submission),
|
|
896
|
+
...isRecord(r.capsSnapshot) ? { capsSnapshot: r.capsSnapshot } : {},
|
|
897
|
+
attempts: arr(r.attempts),
|
|
898
|
+
events: {
|
|
899
|
+
entries: arr(eventsRaw.entries),
|
|
900
|
+
totalCount: typeof eventsRaw.totalCount === "number" ? eventsRaw.totalCount : 0,
|
|
901
|
+
truncated: eventsRaw.truncated === true,
|
|
902
|
+
...str3(eventsRaw.nextCursor) ? { nextCursor: eventsRaw.nextCursor } : {}
|
|
903
|
+
},
|
|
904
|
+
rawEventPages: arr(r.rawEventPages),
|
|
905
|
+
outputs: arr(r.outputs),
|
|
906
|
+
outputCaptureFailures: arr(r.outputCaptureFailures),
|
|
907
|
+
...isRecord(r.costTelemetry) ? { costTelemetry: r.costTelemetry } : {},
|
|
908
|
+
...isRecord(r.runtimeManifest) ? { runtimeManifest: r.runtimeManifest } : {}
|
|
909
|
+
};
|
|
910
|
+
}
|
|
911
|
+
function coerceRunUnitModel(value) {
|
|
912
|
+
if (typeof value !== "string")
|
|
913
|
+
return Models.CLAUDE_HAIKU_4_5;
|
|
914
|
+
try {
|
|
915
|
+
return parseRunModel(value, "run unit submission.model");
|
|
916
|
+
} catch {
|
|
917
|
+
return Models.CLAUDE_HAIKU_4_5;
|
|
918
|
+
}
|
|
919
|
+
}
|
|
920
|
+
function isJsonRecord(value) {
|
|
921
|
+
return isRecord(value);
|
|
922
|
+
}
|
|
923
|
+
function toStringArray(value) {
|
|
924
|
+
if (!Array.isArray(value)) {
|
|
925
|
+
return [];
|
|
926
|
+
}
|
|
927
|
+
return value.filter((item) => typeof item === "string");
|
|
928
|
+
}
|
|
929
|
+
function toOptionalStringArray(value) {
|
|
930
|
+
if (!Array.isArray(value) || value.length === 0) {
|
|
931
|
+
return void 0;
|
|
932
|
+
}
|
|
933
|
+
const filtered = value.filter((item) => typeof item === "string");
|
|
934
|
+
return filtered.length === 0 ? void 0 : filtered;
|
|
935
|
+
}
|
|
936
|
+
function toMcpServerRefArray(value) {
|
|
937
|
+
if (!Array.isArray(value)) {
|
|
938
|
+
return [];
|
|
939
|
+
}
|
|
940
|
+
const out = [];
|
|
941
|
+
for (let i2 = 0; i2 < value.length; i2++) {
|
|
942
|
+
try {
|
|
943
|
+
out.push(parseMcpServerRef(value[i2], `submission.mcpServers[${i2}]`));
|
|
944
|
+
} catch {
|
|
945
|
+
}
|
|
946
|
+
}
|
|
947
|
+
return out;
|
|
948
|
+
}
|
|
949
|
+
function parseEnvironment(value) {
|
|
950
|
+
if (!isRecord(value)) {
|
|
951
|
+
return void 0;
|
|
952
|
+
}
|
|
953
|
+
const env = {};
|
|
954
|
+
if (isRecord(value.networking)) {
|
|
955
|
+
const mode = value.networking.mode;
|
|
956
|
+
const allowedHosts = value.networking.allowedHosts;
|
|
957
|
+
if (mode === "limited" || mode === "open") {
|
|
958
|
+
env.networking = {
|
|
959
|
+
mode,
|
|
960
|
+
...Array.isArray(allowedHosts) ? { allowedHosts: toStringArray(allowedHosts) } : {}
|
|
961
|
+
};
|
|
962
|
+
}
|
|
963
|
+
}
|
|
964
|
+
if (Array.isArray(value.packages)) {
|
|
965
|
+
const pkgs = value.packages.filter(isRecord).map((p) => {
|
|
966
|
+
const r = p;
|
|
967
|
+
if (typeof r.name !== "string")
|
|
968
|
+
return null;
|
|
969
|
+
const ecosystem = typeof r.ecosystem === "string" && PLATFORM_PACKAGE_ECOSYSTEMS.includes(r.ecosystem) ? r.ecosystem : "apt";
|
|
970
|
+
return {
|
|
971
|
+
name: r.name,
|
|
972
|
+
...typeof r.version === "string" ? { version: r.version } : {},
|
|
973
|
+
ecosystem
|
|
974
|
+
};
|
|
975
|
+
}).filter((p) => p !== null);
|
|
976
|
+
if (pkgs.length > 0) {
|
|
977
|
+
env.packages = pkgs;
|
|
978
|
+
}
|
|
979
|
+
}
|
|
980
|
+
if (isRecord(value.envVars)) {
|
|
981
|
+
const out = {};
|
|
982
|
+
for (const [k, v] of Object.entries(value.envVars)) {
|
|
983
|
+
if (typeof v === "string") {
|
|
984
|
+
out[k] = v;
|
|
985
|
+
}
|
|
986
|
+
}
|
|
987
|
+
if (Object.keys(out).length > 0) {
|
|
988
|
+
env.envVars = out;
|
|
989
|
+
}
|
|
990
|
+
}
|
|
991
|
+
return env.networking || env.packages || env.envVars ? env : void 0;
|
|
992
|
+
}
|
|
993
|
+
|
|
790
994
|
// ../contracts/dist/runtime-manifest.js
|
|
791
995
|
var RUNTIME_PATHS = Object.freeze({
|
|
792
996
|
skillsRoot: "/workspace/skills",
|
|
@@ -1365,6 +1569,8 @@ __export(operations_exports, {
|
|
|
1365
1569
|
cancelRun: () => cancelRun,
|
|
1366
1570
|
cancelSession: () => cancelSession,
|
|
1367
1571
|
classifyOutput: () => classifyOutput,
|
|
1572
|
+
createBillingCheckout: () => createBillingCheckout,
|
|
1573
|
+
createBillingPortal: () => createBillingPortal,
|
|
1368
1574
|
createOutputLink: () => createOutputLink,
|
|
1369
1575
|
createSecret: () => createSecret,
|
|
1370
1576
|
createSession: () => createSession,
|
|
@@ -1384,6 +1590,8 @@ __export(operations_exports, {
|
|
|
1384
1590
|
findOutput: () => findOutput,
|
|
1385
1591
|
findOutputs: () => findOutputs,
|
|
1386
1592
|
getAgentsMd: () => getAgentsMd,
|
|
1593
|
+
getBilling: () => getBilling,
|
|
1594
|
+
getBillingLedger: () => getBillingLedger,
|
|
1387
1595
|
getCoordinatorTicket: () => getCoordinatorTicket,
|
|
1388
1596
|
getFile: () => getFile,
|
|
1389
1597
|
getRun: () => getRun,
|
|
@@ -1393,6 +1601,7 @@ __export(operations_exports, {
|
|
|
1393
1601
|
getSecretValue: () => getSecretValue,
|
|
1394
1602
|
getSession: () => getSession,
|
|
1395
1603
|
getSessionCoordinatorTicket: () => getSessionCoordinatorTicket,
|
|
1604
|
+
getWebhookSigningSecret: () => getWebhookSigningSecret,
|
|
1396
1605
|
listAgentsMd: () => listAgentsMd,
|
|
1397
1606
|
listFiles: () => listFiles,
|
|
1398
1607
|
listOutputs: () => listOutputs,
|
|
@@ -1400,6 +1609,7 @@ __export(operations_exports, {
|
|
|
1400
1609
|
listRuns: () => listRuns,
|
|
1401
1610
|
listSecrets: () => listSecrets,
|
|
1402
1611
|
listSessionEvents: () => listSessionEvents,
|
|
1612
|
+
listSessionMessages: () => listSessionMessages,
|
|
1403
1613
|
listSessionOutputs: () => listSessionOutputs,
|
|
1404
1614
|
listSessions: () => listSessions,
|
|
1405
1615
|
normalizeOutputLinkExpiresIn: () => normalizeOutputLinkExpiresIn,
|
|
@@ -2138,7 +2348,7 @@ async function getRun(http, runId) {
|
|
|
2138
2348
|
return hasRun(result) ? result.run : result;
|
|
2139
2349
|
}
|
|
2140
2350
|
async function getRunUnit(http, runId) {
|
|
2141
|
-
return http.request(`/api/runs/${encodeURIComponent(runId)}`);
|
|
2351
|
+
return normalizeRunUnit(await http.request(`/api/runs/${encodeURIComponent(runId)}`));
|
|
2142
2352
|
}
|
|
2143
2353
|
async function listRuns(http, query) {
|
|
2144
2354
|
const params = {};
|
|
@@ -2188,6 +2398,16 @@ async function sendSessionMessage(http, sessionId, request, options) {
|
|
|
2188
2398
|
body: JSON.stringify(request)
|
|
2189
2399
|
});
|
|
2190
2400
|
}
|
|
2401
|
+
async function listSessionMessages(http, sessionId, query) {
|
|
2402
|
+
const params = {};
|
|
2403
|
+
if (query?.limit !== void 0)
|
|
2404
|
+
params.limit = String(query.limit);
|
|
2405
|
+
if (query?.cursor !== void 0)
|
|
2406
|
+
params.cursor = query.cursor;
|
|
2407
|
+
if (query?.since !== void 0)
|
|
2408
|
+
params.since = query.since;
|
|
2409
|
+
return http.request(`/api/sessions/${encodeURIComponent(sessionId)}/messages`, {}, params);
|
|
2410
|
+
}
|
|
2191
2411
|
async function suspendSession(http, sessionId, options) {
|
|
2192
2412
|
const headers = idempotencyHeaders(options);
|
|
2193
2413
|
return http.request(`/api/sessions/${encodeURIComponent(sessionId)}/suspend`, { method: "POST", ...headers ? { headers } : {} });
|
|
@@ -2411,6 +2631,30 @@ async function deleteWorkspaceAsset(http, hash) {
|
|
|
2411
2631
|
async function whoami(http) {
|
|
2412
2632
|
return http.request("/api/whoami");
|
|
2413
2633
|
}
|
|
2634
|
+
async function getBilling(http) {
|
|
2635
|
+
return http.request("/api/billing");
|
|
2636
|
+
}
|
|
2637
|
+
async function createBillingCheckout(http, request) {
|
|
2638
|
+
return http.request("/api/billing/checkout", {
|
|
2639
|
+
method: "POST",
|
|
2640
|
+
body: JSON.stringify(request)
|
|
2641
|
+
});
|
|
2642
|
+
}
|
|
2643
|
+
async function createBillingPortal(http, request = {}) {
|
|
2644
|
+
return http.request("/api/billing/portal", {
|
|
2645
|
+
method: "POST",
|
|
2646
|
+
body: JSON.stringify(request)
|
|
2647
|
+
});
|
|
2648
|
+
}
|
|
2649
|
+
async function getBillingLedger(http, query) {
|
|
2650
|
+
const params = {};
|
|
2651
|
+
if (query?.limit !== void 0)
|
|
2652
|
+
params.limit = String(query.limit);
|
|
2653
|
+
return http.request("/api/billing/ledger", {}, params);
|
|
2654
|
+
}
|
|
2655
|
+
async function getWebhookSigningSecret(http) {
|
|
2656
|
+
return http.request("/api/webhook/signing-secret", { method: "POST" });
|
|
2657
|
+
}
|
|
2414
2658
|
async function collectArtifactBytes(http, runId, items, zipPrefix, namespace2) {
|
|
2415
2659
|
const entries = [];
|
|
2416
2660
|
const captured = [];
|
|
@@ -2677,7 +2921,7 @@ function jsonlEntry(path, events) {
|
|
|
2677
2921
|
}
|
|
2678
2922
|
function extractSubmissionSnapshot(run) {
|
|
2679
2923
|
const raw = run.submission;
|
|
2680
|
-
if (!
|
|
2924
|
+
if (!isRecord2(raw) || raw.kind !== "submission" || !isRecord2(raw.submission)) {
|
|
2681
2925
|
return void 0;
|
|
2682
2926
|
}
|
|
2683
2927
|
return {
|
|
@@ -2686,9 +2930,9 @@ function extractSubmissionSnapshot(run) {
|
|
|
2686
2930
|
}
|
|
2687
2931
|
function extractCostTelemetry(run) {
|
|
2688
2932
|
const raw = run.costTelemetry;
|
|
2689
|
-
return
|
|
2933
|
+
return isRecord2(raw) ? raw : void 0;
|
|
2690
2934
|
}
|
|
2691
|
-
function
|
|
2935
|
+
function isRecord2(value) {
|
|
2692
2936
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
2693
2937
|
}
|
|
2694
2938
|
async function submitRun(http, request) {
|
|
@@ -2800,34 +3044,8 @@ async function uploadWorkspaceAsset(http, input) {
|
|
|
2800
3044
|
});
|
|
2801
3045
|
}
|
|
2802
3046
|
|
|
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
3047
|
// dist/internal.js
|
|
2829
3048
|
var AEX_INDEX_PATH = "/mnt/session/uploads/aex/index.json";
|
|
2830
|
-
var AEX_RUN_TOKEN_PATH = "/mnt/session/uploads/aex/run-token";
|
|
2831
3049
|
|
|
2832
3050
|
// dist/host/common.js
|
|
2833
3051
|
var SUCCESS = { code: 0 };
|
|
@@ -2835,7 +3053,7 @@ var USAGE_ERR = { code: 2 };
|
|
|
2835
3053
|
var RUNTIME_ERR = { code: 1 };
|
|
2836
3054
|
var TIMEOUT_ERR = { code: 3 };
|
|
2837
3055
|
var TERMINAL_STATUSES = new Set(TERMINAL_RUN_STATUSES);
|
|
2838
|
-
function
|
|
3056
|
+
function isSessionParked2(status2) {
|
|
2839
3057
|
return status2 === "idle" || status2 === "suspended" || status2 === "error" || TERMINAL_STATUSES.has(status2);
|
|
2840
3058
|
}
|
|
2841
3059
|
function isSessionOk(status2) {
|
|
@@ -2922,6 +3140,8 @@ function describeApiError(err2) {
|
|
|
2922
3140
|
return { code: "error", message: err2 instanceof Error ? err2.message : String(err2) };
|
|
2923
3141
|
}
|
|
2924
3142
|
function remedyForStatus(status2) {
|
|
3143
|
+
if (status2 === 400)
|
|
3144
|
+
return "malformed request \u2014 if this is an auth failure, check --api-token or run `aex login`";
|
|
2925
3145
|
if (status2 === 401)
|
|
2926
3146
|
return "check --api-token, or run `aex login`";
|
|
2927
3147
|
if (status2 === 403)
|
|
@@ -2986,7 +3206,7 @@ async function refuseInsideManagedRun(io2, verb) {
|
|
|
2986
3206
|
try {
|
|
2987
3207
|
await io2.readFile(AEX_INDEX_PATH);
|
|
2988
3208
|
io2.stderr(`\`aex ${verb}\` is a host command and cannot run inside a managed run container.
|
|
2989
|
-
|
|
3209
|
+
Make HTTP calls from your code and pass credentials through secrets.
|
|
2990
3210
|
`);
|
|
2991
3211
|
return true;
|
|
2992
3212
|
} catch (err2) {
|
|
@@ -3171,285 +3391,6 @@ async function runOutputsSyncCmd(io2, dirs) {
|
|
|
3171
3391
|
return SUCCESS;
|
|
3172
3392
|
}
|
|
3173
3393
|
|
|
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
3394
|
// dist/host/run-cmd.js
|
|
3454
3395
|
import { resolve as resolvePath } from "node:path";
|
|
3455
3396
|
var DEFAULT_SESSION_IDLE_TTL = "3m";
|
|
@@ -3616,6 +3557,10 @@ async function runRunCmd(io2, argv) {
|
|
|
3616
3557
|
return USAGE_ERR;
|
|
3617
3558
|
}
|
|
3618
3559
|
rest = proxyAuthFlags.remaining;
|
|
3560
|
+
if (proxyEndpointFlags.values.length > 0 || Object.keys(proxyAuthFlags.entries).length > 0) {
|
|
3561
|
+
io2.stderr("--proxy-endpoint and --proxy-auth are no longer supported; make HTTP calls from your code and pass credentials via secrets.\n");
|
|
3562
|
+
return USAGE_ERR;
|
|
3563
|
+
}
|
|
3619
3564
|
const positional = rest.filter((a) => !a.startsWith("--"));
|
|
3620
3565
|
const unknownFlags = rest.filter((a) => a.startsWith("--"));
|
|
3621
3566
|
if (unknownFlags.length > 0) {
|
|
@@ -3727,35 +3672,6 @@ async function runRunCmd(io2, argv) {
|
|
|
3727
3672
|
for (const name of mcpHeaderBag.keys()) {
|
|
3728
3673
|
if (!mcpServersForSubmission.some((m) => m.name === name)) {
|
|
3729
3674
|
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
3675
|
`);
|
|
3760
3676
|
return USAGE_ERR;
|
|
3761
3677
|
}
|
|
@@ -3774,8 +3690,7 @@ async function runRunCmd(io2, argv) {
|
|
|
3774
3690
|
const hasAdditionalProviderKeys = Object.keys(providerKeyValues).some((p) => p !== provider);
|
|
3775
3691
|
const secrets = {
|
|
3776
3692
|
apiKeys: hasAdditionalProviderKeys ? providerKeyValues : { [provider]: providerKeyValues[provider] },
|
|
3777
|
-
...mcpServerSecrets.length > 0 ? { mcpServers: mcpServerSecrets } : {}
|
|
3778
|
-
...proxyAuth.length > 0 ? { proxyEndpointAuth: proxyAuth } : {}
|
|
3693
|
+
...mcpServerSecrets.length > 0 ? { mcpServers: mcpServerSecrets } : {}
|
|
3779
3694
|
};
|
|
3780
3695
|
const request = {
|
|
3781
3696
|
provider,
|
|
@@ -3784,8 +3699,7 @@ async function runRunCmd(io2, argv) {
|
|
|
3784
3699
|
retention: { idleTtl: DEFAULT_SESSION_IDLE_TTL },
|
|
3785
3700
|
...runtimeSizeFlag.value ? { runtimeSize: runtimeSizeFlag.value } : runConfig.runtimeSize ? { runtimeSize: runConfig.runtimeSize } : {},
|
|
3786
3701
|
...runTimeoutFlag.value ? { timeout: runTimeoutFlag.value } : runConfig.timeout ? { timeout: runConfig.timeout } : {},
|
|
3787
|
-
...webhookFlag.value ? { webhook: { url: webhookFlag.value } } : {}
|
|
3788
|
-
...proxyEndpoints.length > 0 ? { proxyEndpoints } : {}
|
|
3702
|
+
...webhookFlag.value ? { webhook: { url: webhookFlag.value } } : {}
|
|
3789
3703
|
};
|
|
3790
3704
|
const createKey = idempotency.value ?? generateIdempotencyKey();
|
|
3791
3705
|
const messageKey = `${createKey}:message`;
|
|
@@ -3817,7 +3731,7 @@ async function runRunCmd(io2, argv) {
|
|
|
3817
3731
|
const seen = /* @__PURE__ */ new Set();
|
|
3818
3732
|
let currentStatus = accepted.session.status;
|
|
3819
3733
|
const deadline = followTimeoutMs === null ? Number.POSITIVE_INFINITY : Date.now() + followTimeoutMs;
|
|
3820
|
-
while (!
|
|
3734
|
+
while (!isSessionParked2(currentStatus)) {
|
|
3821
3735
|
await sleep2(2e3);
|
|
3822
3736
|
try {
|
|
3823
3737
|
const events = await operations_exports.listSessionEvents(http, session.id);
|
|
@@ -3838,7 +3752,7 @@ async function runRunCmd(io2, argv) {
|
|
|
3838
3752
|
io2.stderr(`(transient) status poll failed: ${err2.message}
|
|
3839
3753
|
`);
|
|
3840
3754
|
}
|
|
3841
|
-
if (!
|
|
3755
|
+
if (!isSessionParked2(currentStatus) && Date.now() >= deadline) {
|
|
3842
3756
|
emitJsonError(io2, "run_follow_timeout", `timed out after ${followTimeoutMs}ms following session`, {
|
|
3843
3757
|
sessionId: session.id,
|
|
3844
3758
|
hint: `aex status ${session.id} | aex events ${session.id} | aex download ${session.id}`
|
|
@@ -3864,47 +3778,6 @@ async function runRunCmd(io2, argv) {
|
|
|
3864
3778
|
return RUNTIME_ERR;
|
|
3865
3779
|
}
|
|
3866
3780
|
}
|
|
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
3781
|
function stripMcpHeadersForParsing(input) {
|
|
3909
3782
|
const mcpHeaders = /* @__PURE__ */ new Map();
|
|
3910
3783
|
if (input === null || typeof input !== "object" || Array.isArray(input)) {
|
|
@@ -4075,7 +3948,7 @@ async function runWaitCmd(io2, argv) {
|
|
|
4075
3948
|
await sleep3(intervalMs);
|
|
4076
3949
|
continue;
|
|
4077
3950
|
}
|
|
4078
|
-
if (
|
|
3951
|
+
if (isSessionParked2(session.status)) {
|
|
4079
3952
|
io2.stdout(JSON.stringify(session) + "\n");
|
|
4080
3953
|
return isSessionOk(session.status) ? SUCCESS : RUNTIME_ERR;
|
|
4081
3954
|
}
|
|
@@ -4155,7 +4028,7 @@ async function runEventsCmd(io2, argv) {
|
|
|
4155
4028
|
}
|
|
4156
4029
|
try {
|
|
4157
4030
|
const session = await operations_exports.getSession(http, sessionId);
|
|
4158
|
-
if (
|
|
4031
|
+
if (isSessionParked2(session.status)) {
|
|
4159
4032
|
return SUCCESS;
|
|
4160
4033
|
}
|
|
4161
4034
|
} catch (err2) {
|
|
@@ -4400,25 +4273,26 @@ async function runWhoamiCmd(io2, argv) {
|
|
|
4400
4273
|
}
|
|
4401
4274
|
}
|
|
4402
4275
|
|
|
4403
|
-
// dist/host/
|
|
4404
|
-
function
|
|
4405
|
-
|
|
4406
|
-
|
|
4407
|
-
|
|
4408
|
-
|
|
4409
|
-
|
|
4410
|
-
|
|
4411
|
-
|
|
4412
|
-
|
|
4413
|
-
|
|
4414
|
-
|
|
4415
|
-
|
|
4416
|
-
|
|
4417
|
-
|
|
4276
|
+
// dist/host/billing.js
|
|
4277
|
+
function usd(value) {
|
|
4278
|
+
return typeof value === "number" && Number.isFinite(value) ? `$${value.toFixed(2)}` : "-";
|
|
4279
|
+
}
|
|
4280
|
+
function isPaidPlanKey(value) {
|
|
4281
|
+
return value === "pro" || value === "team";
|
|
4282
|
+
}
|
|
4283
|
+
function parseLimit(io2, raw) {
|
|
4284
|
+
if (raw === void 0)
|
|
4285
|
+
return { ok: true, limit: void 0 };
|
|
4286
|
+
const limit = Number(raw);
|
|
4287
|
+
if (!Number.isInteger(limit) || limit < 1) {
|
|
4288
|
+
io2.stderr(`--limit must be a positive integer (got: ${raw})
|
|
4289
|
+
`);
|
|
4290
|
+
return { ok: false };
|
|
4418
4291
|
}
|
|
4292
|
+
return { ok: true, limit };
|
|
4419
4293
|
}
|
|
4420
|
-
async function
|
|
4421
|
-
if (await refuseInsideManagedRun(io2, "
|
|
4294
|
+
async function runBillingCmd(io2, argv) {
|
|
4295
|
+
if (await refuseInsideManagedRun(io2, "billing"))
|
|
4422
4296
|
return USAGE_ERR;
|
|
4423
4297
|
const common = await resolveCommonHostFlags(io2, argv);
|
|
4424
4298
|
if (!common.ok) {
|
|
@@ -4426,54 +4300,255 @@ async function runRedeemCmd(io2, argv) {
|
|
|
4426
4300
|
`);
|
|
4427
4301
|
return USAGE_ERR;
|
|
4428
4302
|
}
|
|
4429
|
-
|
|
4430
|
-
|
|
4431
|
-
|
|
4303
|
+
if (common.rest[0] === "ledger") {
|
|
4304
|
+
return runBillingLedger(io2, common.rest.slice(1), common.flags);
|
|
4305
|
+
}
|
|
4306
|
+
if (common.rest[0] === "upgrade") {
|
|
4307
|
+
return runBillingUpgrade(io2, common.rest.slice(1), common.flags);
|
|
4308
|
+
}
|
|
4309
|
+
if (common.rest[0] === "portal") {
|
|
4310
|
+
return runBillingPortal(io2, common.rest.slice(1), common.flags);
|
|
4311
|
+
}
|
|
4312
|
+
const { present: json, remaining } = takeBooleanFlag(common.rest, "--json");
|
|
4313
|
+
if (remaining.length > 0) {
|
|
4314
|
+
io2.stderr(`unexpected arguments: ${remaining.join(" ")}
|
|
4315
|
+
`);
|
|
4316
|
+
io2.stderr("usage: aex billing [--json] | aex billing ledger [--limit N] | aex billing upgrade pro|team | aex billing portal [common flags]\n");
|
|
4432
4317
|
return USAGE_ERR;
|
|
4433
4318
|
}
|
|
4434
|
-
const
|
|
4435
|
-
const base = common.flags.aexUrl.replace(/\/+$/, "");
|
|
4436
|
-
const url = `${base}/billing/redeem`;
|
|
4437
|
-
let response;
|
|
4319
|
+
const http = makeHttpClient(io2, common.flags);
|
|
4438
4320
|
try {
|
|
4439
|
-
|
|
4440
|
-
|
|
4441
|
-
|
|
4442
|
-
|
|
4443
|
-
|
|
4444
|
-
|
|
4445
|
-
|
|
4446
|
-
|
|
4321
|
+
const billing = await operations_exports.getBilling(http);
|
|
4322
|
+
if (json) {
|
|
4323
|
+
io2.stdout(JSON.stringify(billing) + "\n");
|
|
4324
|
+
return SUCCESS;
|
|
4325
|
+
}
|
|
4326
|
+
io2.stdout(`Balance: ${usd(billing.balanceUsd)}
|
|
4327
|
+
`);
|
|
4328
|
+
io2.stdout(`Month spend: ${usd(billing.monthSpendUsd)}
|
|
4329
|
+
`);
|
|
4330
|
+
io2.stdout(`Spend cap: ${usd(billing.spendCapUsd)}
|
|
4331
|
+
`);
|
|
4332
|
+
io2.stdout(`Plan: ${billing.planKey} (subscription: ${billing.subscriptionStatus})
|
|
4333
|
+
`);
|
|
4334
|
+
return SUCCESS;
|
|
4335
|
+
} catch (err2) {
|
|
4336
|
+
const d = describeApiError(err2);
|
|
4337
|
+
return emitJsonError(io2, "billing_failed", d.message, {
|
|
4338
|
+
...d.status !== void 0 ? { status: d.status } : {},
|
|
4339
|
+
...d.remedy ? { remedy: d.remedy } : {}
|
|
4447
4340
|
});
|
|
4341
|
+
}
|
|
4342
|
+
}
|
|
4343
|
+
async function runBillingUpgrade(io2, argv, flags) {
|
|
4344
|
+
const { present: json, remaining: rest1 } = takeBooleanFlag(argv, "--json");
|
|
4345
|
+
const { value: successUrl, remaining: rest2 } = takeOptionFlag(rest1, "--success-url");
|
|
4346
|
+
const { value: cancelUrl, remaining: rest3 } = takeOptionFlag(rest2, "--cancel-url");
|
|
4347
|
+
const { value: idempotencyKey, remaining } = takeOptionFlag(rest3, "--idempotency-key");
|
|
4348
|
+
const planKey = remaining[0];
|
|
4349
|
+
if (!isPaidPlanKey(planKey) || remaining.length !== 1) {
|
|
4350
|
+
io2.stderr("usage: aex billing upgrade pro|team [--success-url URL] [--cancel-url URL] [--idempotency-key KEY] [--json] [common flags]\n");
|
|
4351
|
+
return USAGE_ERR;
|
|
4352
|
+
}
|
|
4353
|
+
const http = makeHttpClient(io2, flags);
|
|
4354
|
+
try {
|
|
4355
|
+
const session = await operations_exports.createBillingCheckout(http, {
|
|
4356
|
+
planKey,
|
|
4357
|
+
...successUrl !== void 0 ? { successUrl } : {},
|
|
4358
|
+
...cancelUrl !== void 0 ? { cancelUrl } : {},
|
|
4359
|
+
...idempotencyKey !== void 0 ? { idempotencyKey } : {}
|
|
4360
|
+
});
|
|
4361
|
+
io2.stdout(json ? `${JSON.stringify(session)}
|
|
4362
|
+
` : `${session.url}
|
|
4363
|
+
`);
|
|
4364
|
+
return SUCCESS;
|
|
4448
4365
|
} catch (err2) {
|
|
4449
|
-
|
|
4366
|
+
const d = describeApiError(err2);
|
|
4367
|
+
return emitJsonError(io2, "billing_checkout_failed", d.message, {
|
|
4368
|
+
...d.status !== void 0 ? { status: d.status } : {},
|
|
4369
|
+
...d.remedy ? { remedy: d.remedy } : {}
|
|
4370
|
+
});
|
|
4371
|
+
}
|
|
4372
|
+
}
|
|
4373
|
+
async function runBillingPortal(io2, argv, flags) {
|
|
4374
|
+
const { present: json, remaining: rest1 } = takeBooleanFlag(argv, "--json");
|
|
4375
|
+
const { value: returnUrl, remaining } = takeOptionFlag(rest1, "--return-url");
|
|
4376
|
+
if (remaining.length > 0) {
|
|
4377
|
+
io2.stderr(`unexpected arguments: ${remaining.join(" ")}
|
|
4450
4378
|
`);
|
|
4451
|
-
return
|
|
4379
|
+
io2.stderr("usage: aex billing portal [--return-url URL] [--json] [common flags]\n");
|
|
4380
|
+
return USAGE_ERR;
|
|
4452
4381
|
}
|
|
4453
|
-
|
|
4454
|
-
|
|
4382
|
+
const http = makeHttpClient(io2, flags);
|
|
4383
|
+
try {
|
|
4384
|
+
const session = await operations_exports.createBillingPortal(http, returnUrl !== void 0 ? { returnUrl } : void 0);
|
|
4385
|
+
io2.stdout(json ? `${JSON.stringify(session)}
|
|
4386
|
+
` : `${session.url}
|
|
4455
4387
|
`);
|
|
4388
|
+
return SUCCESS;
|
|
4389
|
+
} catch (err2) {
|
|
4390
|
+
const d = describeApiError(err2);
|
|
4391
|
+
return emitJsonError(io2, "billing_portal_failed", d.message, {
|
|
4392
|
+
...d.status !== void 0 ? { status: d.status } : {},
|
|
4393
|
+
...d.remedy ? { remedy: d.remedy } : {}
|
|
4394
|
+
});
|
|
4456
4395
|
}
|
|
4457
|
-
|
|
4458
|
-
|
|
4396
|
+
}
|
|
4397
|
+
async function runBillingLedger(io2, argv, flags) {
|
|
4398
|
+
const { value: rawLimit, remaining } = takeOptionFlag(argv, "--limit");
|
|
4399
|
+
if (remaining.length > 0) {
|
|
4400
|
+
io2.stderr(`unexpected arguments: ${remaining.join(" ")}
|
|
4401
|
+
`);
|
|
4402
|
+
io2.stderr("usage: aex billing ledger [--limit N] [common flags]\n");
|
|
4403
|
+
return USAGE_ERR;
|
|
4404
|
+
}
|
|
4405
|
+
const parsed = parseLimit(io2, rawLimit);
|
|
4406
|
+
if (!parsed.ok)
|
|
4407
|
+
return USAGE_ERR;
|
|
4408
|
+
const http = makeHttpClient(io2, flags);
|
|
4459
4409
|
try {
|
|
4460
|
-
|
|
4461
|
-
|
|
4462
|
-
|
|
4463
|
-
|
|
4410
|
+
const page = await operations_exports.getBillingLedger(http, parsed.limit !== void 0 ? { limit: parsed.limit } : void 0);
|
|
4411
|
+
io2.stdout(JSON.stringify(page.entries) + "\n");
|
|
4412
|
+
return SUCCESS;
|
|
4413
|
+
} catch (err2) {
|
|
4414
|
+
const d = describeApiError(err2);
|
|
4415
|
+
return emitJsonError(io2, "billing_ledger_failed", d.message, {
|
|
4416
|
+
...d.status !== void 0 ? { status: d.status } : {},
|
|
4417
|
+
...d.remedy ? { remedy: d.remedy } : {}
|
|
4418
|
+
});
|
|
4464
4419
|
}
|
|
4465
|
-
|
|
4466
|
-
|
|
4467
|
-
|
|
4420
|
+
}
|
|
4421
|
+
|
|
4422
|
+
// dist/host/webhooks-cmd.js
|
|
4423
|
+
async function runWebhooksCmd(io2, argv) {
|
|
4424
|
+
if (await refuseInsideManagedRun(io2, "webhooks"))
|
|
4425
|
+
return USAGE_ERR;
|
|
4426
|
+
const common = await resolveCommonHostFlags(io2, argv);
|
|
4427
|
+
if (!common.ok) {
|
|
4428
|
+
io2.stderr(`${common.reason}
|
|
4468
4429
|
`);
|
|
4469
|
-
return
|
|
4430
|
+
return USAGE_ERR;
|
|
4431
|
+
}
|
|
4432
|
+
const [sub, ...rest] = common.rest;
|
|
4433
|
+
if (sub !== "secret") {
|
|
4434
|
+
io2.stderr("usage: aex webhooks secret [common flags]\n");
|
|
4435
|
+
return USAGE_ERR;
|
|
4436
|
+
}
|
|
4437
|
+
const { present: rotate, remaining } = takeBooleanFlag(rest, "--rotate");
|
|
4438
|
+
if (rotate) {
|
|
4439
|
+
io2.stderr("--rotate is not supported: the hosted API reveals (or creates on first use) the workspace webhook signing secret but does not rotate it. Run `aex webhooks secret` to reveal the current value.\n");
|
|
4440
|
+
return USAGE_ERR;
|
|
4470
4441
|
}
|
|
4471
|
-
|
|
4472
|
-
|
|
4473
|
-
const newBalanceUsd = typeof ok.newBalanceUsd === "number" ? ok.newBalanceUsd : 0;
|
|
4474
|
-
io2.stdout(`Redeemed $${amountUsd.toFixed(2)}. New balance: $${newBalanceUsd.toFixed(2)}.
|
|
4442
|
+
if (remaining.length > 0) {
|
|
4443
|
+
io2.stderr(`unexpected arguments: ${remaining.join(" ")}
|
|
4475
4444
|
`);
|
|
4476
|
-
|
|
4445
|
+
io2.stderr("usage: aex webhooks secret [common flags]\n");
|
|
4446
|
+
return USAGE_ERR;
|
|
4447
|
+
}
|
|
4448
|
+
const http = makeHttpClient(io2, common.flags);
|
|
4449
|
+
try {
|
|
4450
|
+
const { whsec } = await operations_exports.getWebhookSigningSecret(http);
|
|
4451
|
+
io2.stdout(`${whsec}
|
|
4452
|
+
`);
|
|
4453
|
+
return SUCCESS;
|
|
4454
|
+
} catch (err2) {
|
|
4455
|
+
const d = describeApiError(err2);
|
|
4456
|
+
return emitJsonError(io2, "webhooks_secret_failed", d.message, {
|
|
4457
|
+
...d.status !== void 0 ? { status: d.status } : {},
|
|
4458
|
+
...d.remedy ? { remedy: d.remedy } : {}
|
|
4459
|
+
});
|
|
4460
|
+
}
|
|
4461
|
+
}
|
|
4462
|
+
|
|
4463
|
+
// dist/host/list-cmds.js
|
|
4464
|
+
function parseLimit2(io2, raw) {
|
|
4465
|
+
if (raw === void 0)
|
|
4466
|
+
return { ok: true, limit: void 0 };
|
|
4467
|
+
const limit = Number(raw);
|
|
4468
|
+
if (!Number.isInteger(limit) || limit < 1) {
|
|
4469
|
+
io2.stderr(`--limit must be a positive integer (got: ${raw})
|
|
4470
|
+
`);
|
|
4471
|
+
return { ok: false };
|
|
4472
|
+
}
|
|
4473
|
+
return { ok: true, limit };
|
|
4474
|
+
}
|
|
4475
|
+
async function runRunsCmd(io2, argv) {
|
|
4476
|
+
if (await refuseInsideManagedRun(io2, "runs"))
|
|
4477
|
+
return USAGE_ERR;
|
|
4478
|
+
const common = await resolveCommonHostFlags(io2, argv);
|
|
4479
|
+
if (!common.ok) {
|
|
4480
|
+
io2.stderr(`${common.reason}
|
|
4481
|
+
`);
|
|
4482
|
+
return USAGE_ERR;
|
|
4483
|
+
}
|
|
4484
|
+
const { value: rawLimit, remaining: afterLimit } = takeOptionFlag(common.rest, "--limit");
|
|
4485
|
+
const { value: since, remaining } = takeOptionFlag(afterLimit, "--since");
|
|
4486
|
+
if (remaining.length > 0) {
|
|
4487
|
+
io2.stderr(`unexpected arguments: ${remaining.join(" ")}
|
|
4488
|
+
`);
|
|
4489
|
+
io2.stderr("usage: aex runs [--limit N] [--since ISO-8601] [common flags]\n");
|
|
4490
|
+
return USAGE_ERR;
|
|
4491
|
+
}
|
|
4492
|
+
const parsed = parseLimit2(io2, rawLimit);
|
|
4493
|
+
if (!parsed.ok)
|
|
4494
|
+
return USAGE_ERR;
|
|
4495
|
+
const sinceMs = since !== void 0 ? Date.parse(since) : void 0;
|
|
4496
|
+
if (sinceMs !== void 0 && Number.isNaN(sinceMs)) {
|
|
4497
|
+
io2.stderr(`--since must be an ISO-8601 timestamp (got: ${since})
|
|
4498
|
+
`);
|
|
4499
|
+
return USAGE_ERR;
|
|
4500
|
+
}
|
|
4501
|
+
const http = makeHttpClient(io2, common.flags);
|
|
4502
|
+
try {
|
|
4503
|
+
const page = await operations_exports.listRuns(http, {
|
|
4504
|
+
...parsed.limit !== void 0 ? { limit: parsed.limit } : {},
|
|
4505
|
+
...since !== void 0 ? { since } : {}
|
|
4506
|
+
});
|
|
4507
|
+
const runs = sinceMs === void 0 ? page.runs : page.runs.filter((run) => {
|
|
4508
|
+
const created = Date.parse(run.createdAt);
|
|
4509
|
+
return !Number.isNaN(created) && created >= sinceMs;
|
|
4510
|
+
});
|
|
4511
|
+
io2.stdout(JSON.stringify({ ...page, runs }) + "\n");
|
|
4512
|
+
return SUCCESS;
|
|
4513
|
+
} catch (err2) {
|
|
4514
|
+
const d = describeApiError(err2);
|
|
4515
|
+
return emitJsonError(io2, "runs_failed", d.message, {
|
|
4516
|
+
...d.status !== void 0 ? { status: d.status } : {},
|
|
4517
|
+
...d.remedy ? { remedy: d.remedy } : {}
|
|
4518
|
+
});
|
|
4519
|
+
}
|
|
4520
|
+
}
|
|
4521
|
+
async function runSessionsCmd(io2, argv) {
|
|
4522
|
+
if (await refuseInsideManagedRun(io2, "sessions"))
|
|
4523
|
+
return USAGE_ERR;
|
|
4524
|
+
const common = await resolveCommonHostFlags(io2, argv);
|
|
4525
|
+
if (!common.ok) {
|
|
4526
|
+
io2.stderr(`${common.reason}
|
|
4527
|
+
`);
|
|
4528
|
+
return USAGE_ERR;
|
|
4529
|
+
}
|
|
4530
|
+
const { value: rawLimit, remaining } = takeOptionFlag(common.rest, "--limit");
|
|
4531
|
+
if (remaining.length > 0) {
|
|
4532
|
+
io2.stderr(`unexpected arguments: ${remaining.join(" ")}
|
|
4533
|
+
`);
|
|
4534
|
+
io2.stderr("usage: aex sessions [--limit N] [common flags]\n");
|
|
4535
|
+
return USAGE_ERR;
|
|
4536
|
+
}
|
|
4537
|
+
const parsed = parseLimit2(io2, rawLimit);
|
|
4538
|
+
if (!parsed.ok)
|
|
4539
|
+
return USAGE_ERR;
|
|
4540
|
+
const http = makeHttpClient(io2, common.flags);
|
|
4541
|
+
try {
|
|
4542
|
+
const page = await operations_exports.listSessions(http, parsed.limit !== void 0 ? { limit: parsed.limit } : void 0);
|
|
4543
|
+
io2.stdout(JSON.stringify(page) + "\n");
|
|
4544
|
+
return SUCCESS;
|
|
4545
|
+
} catch (err2) {
|
|
4546
|
+
const d = describeApiError(err2);
|
|
4547
|
+
return emitJsonError(io2, "sessions_failed", d.message, {
|
|
4548
|
+
...d.status !== void 0 ? { status: d.status } : {},
|
|
4549
|
+
...d.remedy ? { remedy: d.remedy } : {}
|
|
4550
|
+
});
|
|
4551
|
+
}
|
|
4477
4552
|
}
|
|
4478
4553
|
|
|
4479
4554
|
// dist/host/debug.js
|
|
@@ -5543,7 +5618,7 @@ async function runTailCmd(io2, argv) {
|
|
|
5543
5618
|
}
|
|
5544
5619
|
if (isSessionOk(finalStatus))
|
|
5545
5620
|
return SUCCESS;
|
|
5546
|
-
if (
|
|
5621
|
+
if (isSessionParked2(finalStatus))
|
|
5547
5622
|
return RUNTIME_ERR;
|
|
5548
5623
|
io2.stderr(JSON.stringify({
|
|
5549
5624
|
error: "tail_ended_before_terminal",
|
|
@@ -5725,8 +5800,6 @@ async function dispatch(io2, args) {
|
|
|
5725
5800
|
const sub = args[0];
|
|
5726
5801
|
const rest = args.slice(1);
|
|
5727
5802
|
switch (sub) {
|
|
5728
|
-
case "proxy":
|
|
5729
|
-
return runProxy(io2, rest);
|
|
5730
5803
|
case "run":
|
|
5731
5804
|
return runRunCmd(io2, rest);
|
|
5732
5805
|
case "status":
|
|
@@ -5754,10 +5827,16 @@ async function dispatch(io2, args) {
|
|
|
5754
5827
|
return runDeleteCmd(io2, rest);
|
|
5755
5828
|
case "delete-asset":
|
|
5756
5829
|
return runDeleteAssetCmd(io2, rest);
|
|
5830
|
+
case "runs":
|
|
5831
|
+
return runRunsCmd(io2, rest);
|
|
5832
|
+
case "sessions":
|
|
5833
|
+
return runSessionsCmd(io2, rest);
|
|
5757
5834
|
case "whoami":
|
|
5758
5835
|
return runWhoamiCmd(io2, rest);
|
|
5759
|
-
case "
|
|
5760
|
-
return
|
|
5836
|
+
case "billing":
|
|
5837
|
+
return runBillingCmd(io2, rest);
|
|
5838
|
+
case "webhooks":
|
|
5839
|
+
return runWebhooksCmd(io2, rest);
|
|
5761
5840
|
case "login":
|
|
5762
5841
|
return runLoginCmd(io2, rest);
|
|
5763
5842
|
case "logout":
|
|
@@ -5782,26 +5861,6 @@ async function dispatch(io2, args) {
|
|
|
5782
5861
|
}
|
|
5783
5862
|
}
|
|
5784
5863
|
async function printGlobalHelp(io2) {
|
|
5785
|
-
const manifest = await tryReadManifest(io2);
|
|
5786
|
-
if (manifest) {
|
|
5787
|
-
io2.stdout("aex \u2014 in-container CLI for managed run sessions\n\n");
|
|
5788
|
-
io2.stdout("Usage:\n");
|
|
5789
|
-
io2.stdout(" aex proxy <endpoint-name> [flags]\n");
|
|
5790
|
-
io2.stdout(" aex proxy --help\n\n");
|
|
5791
|
-
if (manifest.endpoints.length === 0) {
|
|
5792
|
-
io2.stdout("This run declared no proxy endpoints.\n");
|
|
5793
|
-
} else {
|
|
5794
|
-
io2.stdout("Declared proxy endpoints for this run:\n");
|
|
5795
|
-
for (const ep of manifest.endpoints) {
|
|
5796
|
-
io2.stdout(` \u2022 ${formatProxyEndpointSummary(ep)}
|
|
5797
|
-
`);
|
|
5798
|
-
}
|
|
5799
|
-
}
|
|
5800
|
-
io2.stdout(`
|
|
5801
|
-
Protocol version: ${manifest.protocolVersion}
|
|
5802
|
-
`);
|
|
5803
|
-
return SUCCESS;
|
|
5804
|
-
}
|
|
5805
5864
|
io2.stdout("aex \u2014 unified CLI for the aex platform (mirrors the SDK 1:1)\n\n");
|
|
5806
5865
|
io2.stdout("Usage:\n");
|
|
5807
5866
|
io2.stdout(" aex run --config <run.json> --<provider>-api-key K --api-token T [flags]\n");
|
|
@@ -5817,8 +5876,14 @@ Protocol version: ${manifest.protocolVersion}
|
|
|
5817
5876
|
io2.stdout(" aex cancel <session-id> --api-token T\n");
|
|
5818
5877
|
io2.stdout(" aex delete <session-id> --api-token T\n");
|
|
5819
5878
|
io2.stdout(" aex delete-asset <assetId|hash> --api-token T\n");
|
|
5879
|
+
io2.stdout(" aex runs [--limit N] [--since ISO] --api-token T List the workspace's runs (newest first, JSON)\n");
|
|
5880
|
+
io2.stdout(" aex sessions [--limit N] --api-token T List the workspace's sessions (newest first, JSON)\n");
|
|
5820
5881
|
io2.stdout(" aex whoami --api-token T\n");
|
|
5821
|
-
io2.stdout(" aex
|
|
5882
|
+
io2.stdout(" aex billing [--json] --api-token T Show prepaid balance, month spend, and spend cap\n");
|
|
5883
|
+
io2.stdout(" aex billing ledger [--limit N] --api-token T Recent credit-ledger entries (newest first, JSON)\n");
|
|
5884
|
+
io2.stdout(" aex billing upgrade pro|team --api-token T Create a hosted checkout session and print its URL\n");
|
|
5885
|
+
io2.stdout(" aex billing portal --api-token T Create a hosted billing portal session and print its URL\n");
|
|
5886
|
+
io2.stdout(" aex webhooks secret --api-token T Reveal (create on first use) the webhook signing secret\n");
|
|
5822
5887
|
io2.stdout(" aex login --api-token T [--aex-url U] Persist token + url (then other verbs need no --api-token)\n");
|
|
5823
5888
|
io2.stdout(" aex logout Clear the stored token\n");
|
|
5824
5889
|
io2.stdout(" aex auth status Show the resolved config (token never printed)\n");
|
|
@@ -5846,10 +5911,8 @@ Protocol version: ${manifest.protocolVersion}
|
|
|
5846
5911
|
io2.stdout(" --mcp name=url MCP server entry (repeatable)\n");
|
|
5847
5912
|
io2.stdout(" --mcp-auth name=Hdr:Val Auth header on the matching --mcp; routed into vaulted secrets (repeatable)\n");
|
|
5848
5913
|
io2.stdout(" --metadata key=value Submission metadata entry (repeatable)\n");
|
|
5849
|
-
io2.stdout(" --proxy-endpoint '<json>' PlatformProxyEndpoint JSON (repeatable)\n");
|
|
5850
|
-
io2.stdout(" --proxy-auth name=<spec> bearer:tok | basic:u:p | header:v | query:v (repeatable)\n");
|
|
5851
5914
|
io2.stdout(" --runtime-size <size> managed runtime preset\n");
|
|
5852
|
-
io2.stdout(" --run-timeout <dur> Server-side run deadline (e.g. 1h); distinct from --timeout\n");
|
|
5915
|
+
io2.stdout(" --run-timeout <dur> Server-side run deadline (e.g. 1h, max 8h); distinct from --timeout\n");
|
|
5853
5916
|
io2.stdout(" --idempotency-key <key> Optional; defaults to a fresh UUID\n");
|
|
5854
5917
|
io2.stdout(" --webhook <url> Optional per-run callback URL (https); receives the terminal run.finished event\n");
|
|
5855
5918
|
io2.stdout(" --follow Poll events to stdout until the run terminates\n");
|