@aexhq/sdk 0.13.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (112) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +160 -0
  3. package/dist/_contracts/connection-ticket.d.ts +21 -0
  4. package/dist/_contracts/connection-ticket.js +49 -0
  5. package/dist/_contracts/event-envelope.d.ts +276 -0
  6. package/dist/_contracts/event-envelope.js +324 -0
  7. package/dist/_contracts/event-stream-client.d.ts +47 -0
  8. package/dist/_contracts/event-stream-client.js +141 -0
  9. package/dist/_contracts/http.d.ts +35 -0
  10. package/dist/_contracts/http.js +114 -0
  11. package/dist/_contracts/index.d.ts +28 -0
  12. package/dist/_contracts/index.js +29 -0
  13. package/dist/_contracts/managed-key.d.ts +74 -0
  14. package/dist/_contracts/managed-key.js +110 -0
  15. package/dist/_contracts/operations.d.ts +237 -0
  16. package/dist/_contracts/operations.js +632 -0
  17. package/dist/_contracts/provider-support.d.ts +220 -0
  18. package/dist/_contracts/provider-support.js +90 -0
  19. package/dist/_contracts/proxy-protocol.d.ts +257 -0
  20. package/dist/_contracts/proxy-protocol.js +234 -0
  21. package/dist/_contracts/proxy-validation.d.ts +19 -0
  22. package/dist/_contracts/proxy-validation.js +51 -0
  23. package/dist/_contracts/run-artifacts.d.ts +47 -0
  24. package/dist/_contracts/run-artifacts.js +101 -0
  25. package/dist/_contracts/run-config.d.ts +304 -0
  26. package/dist/_contracts/run-config.js +659 -0
  27. package/dist/_contracts/run-cost.d.ts +125 -0
  28. package/dist/_contracts/run-cost.js +616 -0
  29. package/dist/_contracts/run-custody.d.ts +226 -0
  30. package/dist/_contracts/run-custody.js +465 -0
  31. package/dist/_contracts/run-record.d.ts +127 -0
  32. package/dist/_contracts/run-record.js +177 -0
  33. package/dist/_contracts/run-retention.d.ts +213 -0
  34. package/dist/_contracts/run-retention.js +484 -0
  35. package/dist/_contracts/run-unit.d.ts +194 -0
  36. package/dist/_contracts/run-unit.js +215 -0
  37. package/dist/_contracts/runner-event.d.ts +114 -0
  38. package/dist/_contracts/runner-event.js +187 -0
  39. package/dist/_contracts/runtime-manifest.d.ts +106 -0
  40. package/dist/_contracts/runtime-manifest.js +98 -0
  41. package/dist/_contracts/runtime-security-profile.d.ts +27 -0
  42. package/dist/_contracts/runtime-security-profile.js +82 -0
  43. package/dist/_contracts/runtime-sizes.d.ts +144 -0
  44. package/dist/_contracts/runtime-sizes.js +136 -0
  45. package/dist/_contracts/runtime-types.d.ts +212 -0
  46. package/dist/_contracts/runtime-types.js +2 -0
  47. package/dist/_contracts/sdk-errors.d.ts +34 -0
  48. package/dist/_contracts/sdk-errors.js +52 -0
  49. package/dist/_contracts/sdk-secrets.d.ts +31 -0
  50. package/dist/_contracts/sdk-secrets.js +220 -0
  51. package/dist/_contracts/side-effect-audit.d.ts +129 -0
  52. package/dist/_contracts/side-effect-audit.js +494 -0
  53. package/dist/_contracts/sse.d.ts +74 -0
  54. package/dist/_contracts/sse.js +0 -0
  55. package/dist/_contracts/stable.d.ts +26 -0
  56. package/dist/_contracts/stable.js +44 -0
  57. package/dist/_contracts/status.d.ts +19 -0
  58. package/dist/_contracts/status.js +61 -0
  59. package/dist/_contracts/submission.d.ts +383 -0
  60. package/dist/_contracts/submission.js +1380 -0
  61. package/dist/agents-md.d.ts +46 -0
  62. package/dist/agents-md.js +83 -0
  63. package/dist/agents-md.js.map +1 -0
  64. package/dist/asset-upload.d.ts +66 -0
  65. package/dist/asset-upload.js +168 -0
  66. package/dist/asset-upload.js.map +1 -0
  67. package/dist/bundle.d.ts +33 -0
  68. package/dist/bundle.js +89 -0
  69. package/dist/bundle.js.map +1 -0
  70. package/dist/cli.mjs +4140 -0
  71. package/dist/cli.mjs.sha256 +1 -0
  72. package/dist/client.d.ts +460 -0
  73. package/dist/client.js +857 -0
  74. package/dist/client.js.map +1 -0
  75. package/dist/fetch-archive.d.ts +16 -0
  76. package/dist/fetch-archive.js +170 -0
  77. package/dist/fetch-archive.js.map +1 -0
  78. package/dist/file.d.ts +57 -0
  79. package/dist/file.js +153 -0
  80. package/dist/file.js.map +1 -0
  81. package/dist/index.d.ts +30 -0
  82. package/dist/index.js +34 -0
  83. package/dist/index.js.map +1 -0
  84. package/dist/mcp-server.d.ts +84 -0
  85. package/dist/mcp-server.js +114 -0
  86. package/dist/mcp-server.js.map +1 -0
  87. package/dist/node-fs.d.ts +12 -0
  88. package/dist/node-fs.js +44 -0
  89. package/dist/node-fs.js.map +1 -0
  90. package/dist/proxy-endpoint.d.ts +131 -0
  91. package/dist/proxy-endpoint.js +147 -0
  92. package/dist/proxy-endpoint.js.map +1 -0
  93. package/dist/skill.d.ts +117 -0
  94. package/dist/skill.js +169 -0
  95. package/dist/skill.js.map +1 -0
  96. package/dist/version.d.ts +9 -0
  97. package/dist/version.js +10 -0
  98. package/dist/version.js.map +1 -0
  99. package/docs/cleanup.md +38 -0
  100. package/docs/credentials.md +153 -0
  101. package/docs/events.md +76 -0
  102. package/docs/mcp.md +47 -0
  103. package/docs/outputs.md +157 -0
  104. package/docs/product-boundaries.md +57 -0
  105. package/docs/provider-runtime-capabilities.md +103 -0
  106. package/docs/quickstart.md +110 -0
  107. package/docs/release.md +99 -0
  108. package/docs/run-config.md +53 -0
  109. package/docs/run-record.md +39 -0
  110. package/docs/skills.md +139 -0
  111. package/docs/testing.md +29 -0
  112. package/package.json +47 -0
@@ -0,0 +1,234 @@
1
+ // Wire format between the in-container runtime bridge (mounted at
2
+ // `/mnt/session/uploads/aex/aex`, invoked through `node`) and
3
+ // the dashboard BFF proxy route
4
+ // (`POST /api/runs/:runId/proxy/:endpointName`).
5
+ //
6
+ // This module is the single source of truth for the request shape, the
7
+ // response shape, the error-code enum, and the protocol version header.
8
+ // CLI and BFF both import from here; drift becomes a build-time type error.
9
+ //
10
+ /**
11
+ * Wire-protocol version. Bumped on any breaking change to the request or
12
+ * response shape. The CLI sends this in the `X-Aex-Proxy-Protocol`
13
+ * header on every request; the BFF rejects mismatches with HTTP 426
14
+ * `unsupported_protocol`.
15
+ *
16
+ * Bumps are coordinated: CLI and BFF release together, the worker
17
+ * bundles the matching CLI artifact, and the e2e suite runs both with
18
+ * the new version.
19
+ */
20
+ export const PROXY_PROTOCOL_VERSION = "1";
21
+ export const PROXY_PROTOCOL_HEADER = "x-aex-proxy-protocol";
22
+ /**
23
+ * Default `User-Agent` the proxy attaches to every outbound request when
24
+ * the caller did not supply one via `allowHeaders`. Some upstreams reject
25
+ * requests that arrive without a meaningful UA — notably the Wikimedia
26
+ * family (Wikidata, Wikipedia, Wikimedia Commons), whose policy requires
27
+ * a contactable identifier and otherwise returns HTTP 403 with a
28
+ * `Please identify your user agent` body.
29
+ *
30
+ * Callers can override per request by listing `user-agent` in their
31
+ * endpoint's `allowHeaders` and setting it on the proxy call; the
32
+ * default only fires when nothing was forwarded.
33
+ *
34
+ * See <https://meta.wikimedia.org/wiki/User-Agent_policy>.
35
+ */
36
+ export const PROXY_DEFAULT_USER_AGENT = "aex-proxy/1.0 (+https://aex.dev/contact)";
37
+ export const PROXY_METHOD_HEADER = "x-aex-method";
38
+ export const PROXY_PATH_HEADER = "x-aex-path";
39
+ export const PROXY_QUERY_HEADER = "x-aex-query";
40
+ export const PROXY_HEADERS_HEADER = "x-aex-headers";
41
+ export const PROXY_RESPONSE_MODE_HEADER = "x-aex-response-mode";
42
+ export const PROXY_ALLOWED_METHODS = ["GET", "POST", "PUT", "PATCH", "DELETE", "HEAD"];
43
+ export const PROXY_RESPONSE_MODES = ["status_only", "headers_only", "full"];
44
+ /**
45
+ * Narrowing order: a request may only narrow below the policy ceiling.
46
+ * `status_only` is narrowest, `full` is widest. The BFF computes
47
+ * `narrowest(policyMode, headerMode)` and ignores escalation attempts,
48
+ * auditing them as `mode_clamped`.
49
+ */
50
+ const RESPONSE_MODE_WIDTH = {
51
+ status_only: 0,
52
+ headers_only: 1,
53
+ full: 2
54
+ };
55
+ /**
56
+ * Returns the narrower of the two response modes (lower width wins).
57
+ * Pure function so the CLI and BFF can both call it without import cycles.
58
+ */
59
+ export function narrowResponseMode(policy, requested) {
60
+ return RESPONSE_MODE_WIDTH[requested] < RESPONSE_MODE_WIDTH[policy] ? requested : policy;
61
+ }
62
+ /**
63
+ * Error codes returned by the proxy route. Stable strings — the CLI
64
+ * matches against them in scripts. Adding a new code is non-breaking;
65
+ * removing or renaming an existing code requires a protocol bump.
66
+ */
67
+ export const PROXY_ERROR_CODES = [
68
+ "unsupported_protocol",
69
+ "unauthorized",
70
+ "endpoint_not_found",
71
+ "policy_denied",
72
+ "rate_limited",
73
+ "budget_exceeded",
74
+ "ssrf_denied",
75
+ "upstream_timeout",
76
+ "upstream_error",
77
+ "exceeded_cap",
78
+ "bad_request",
79
+ "internal_error"
80
+ ];
81
+ /**
82
+ * Default caps for a proxy endpoint when the submission doesn't specify
83
+ * one. Conservative on purpose. Lives in the protocol module (next to the
84
+ * index-file shape) so {@link buildProxyIndexFile} can fill every optional
85
+ * cap with a concrete value; the submission parser re-exports it.
86
+ */
87
+ export const PROXY_ENDPOINT_DEFAULTS = {
88
+ allowHeaders: [],
89
+ responseMode: "headers_only",
90
+ maxRequestBytes: 64 * 1024,
91
+ maxResponseBytes: 1024 * 1024,
92
+ timeoutMs: 10_000,
93
+ perCallBudget: 60,
94
+ responseByteBudget: 1024 * 1024
95
+ };
96
+ /**
97
+ * Build the per-run {@link ProxyIndexFile} mounted into the container at
98
+ * `/mnt/session/uploads/aex/index.json`. Pure: applies
99
+ * {@link PROXY_ENDPOINT_DEFAULTS} so every optional cap is concrete, and
100
+ * carries ONLY the non-secret endpoint policy — auth values never appear.
101
+ *
102
+ * ALWAYS emits a file (the always-on surface). With zero endpoints OR no
103
+ * `proxyPublicBaseUrl`, `proxyBaseUrl` is `null` and `endpoints` is `[]`.
104
+ * Otherwise `proxyBaseUrl` is `<trimmed base>/api/runs/<runId>/proxy`, the
105
+ * prefix the in-container runtime bridge appends `/<endpointName>` to (proxy.ts).
106
+ */
107
+ export function buildProxyIndexFile(input) {
108
+ const endpoints = input.endpoints ?? [];
109
+ const base = input.proxyPublicBaseUrl?.trim() ?? "";
110
+ const haveBase = base.length > 0;
111
+ const proxyBaseUrl = endpoints.length > 0 && haveBase
112
+ ? `${base.replace(/\/+$/, "")}/api/runs/${input.runId}/proxy`
113
+ : null;
114
+ return {
115
+ protocolVersion: PROXY_PROTOCOL_VERSION,
116
+ runId: input.runId,
117
+ proxyBaseUrl,
118
+ endpoints: endpoints.map((e) => ({
119
+ name: e.name,
120
+ baseUrl: e.baseUrl,
121
+ authShape: e.authShape,
122
+ allowMethods: e.allowMethods,
123
+ allowPathPrefixes: e.allowPathPrefixes,
124
+ allowHeaders: e.allowHeaders ?? PROXY_ENDPOINT_DEFAULTS.allowHeaders,
125
+ responseMode: e.responseMode ?? PROXY_ENDPOINT_DEFAULTS.responseMode,
126
+ maxRequestBytes: e.maxRequestBytes ?? PROXY_ENDPOINT_DEFAULTS.maxRequestBytes,
127
+ maxResponseBytes: e.maxResponseBytes ?? PROXY_ENDPOINT_DEFAULTS.maxResponseBytes,
128
+ timeoutMs: e.timeoutMs ?? PROXY_ENDPOINT_DEFAULTS.timeoutMs,
129
+ perCallBudget: e.perCallBudget ?? PROXY_ENDPOINT_DEFAULTS.perCallBudget,
130
+ responseByteBudget: e.responseByteBudget ?? PROXY_ENDPOINT_DEFAULTS.responseByteBudget
131
+ }))
132
+ };
133
+ }
134
+ /**
135
+ * Header name (lowercase) that an upstream auth shape uses as its
136
+ * carrier. Returns `undefined` for query-based and keyless auth.
137
+ *
138
+ * Used by the submission parser to forbid `allowHeaders` from listing
139
+ * the auth header (avoids leaks via caller-supplied headers), and by
140
+ * the proxy route to strip any caller header that would collide with
141
+ * the auth carrier at request time.
142
+ */
143
+ export function authShapeHeaderName(shape) {
144
+ switch (shape.type) {
145
+ case "bearer":
146
+ case "basic":
147
+ return "authorization";
148
+ case "header":
149
+ return shape.name.toLowerCase();
150
+ case "query":
151
+ case "none":
152
+ return undefined;
153
+ }
154
+ }
155
+ /**
156
+ * Query-string key that an upstream query-based auth shape uses as its
157
+ * carrier. Returns `undefined` for non-query shapes (including "none").
158
+ */
159
+ export function authShapeQueryName(shape) {
160
+ return shape.type === "query" ? shape.name : undefined;
161
+ }
162
+ /**
163
+ * Inbound request headers every Aex proxy plane STRIPS before
164
+ * forwarding a runtime/runner request upstream. Three categories:
165
+ *
166
+ * - Credential carriers (`authorization`, `x-api-key`, `cookie`,
167
+ * `proxy-authorization`) — these belong to Aex's own auth gate
168
+ * (the per-run bearer) or to the caller, never the upstream. The
169
+ * legitimate upstream credential is injected server-side from the
170
+ * run's Vault bundle / endpoint auth shape AFTER this strip, so it is
171
+ * never sourced from an inbound header.
172
+ * - Hop-by-hop fields (RFC 7230 §6.1: `connection`, `keep-alive`,
173
+ * `transfer-encoding`, `te`, `trailer`, `upgrade`, `expect`,
174
+ * `proxy-authenticate`, `proxy-connection`) — must not survive a
175
+ * proxy hop.
176
+ * - Routing primitives a compromised runner could spoof to bypass an
177
+ * upstream's IP allowlist / rate-limit (`host`, `content-length`,
178
+ * `x-forwarded-*`, `x-real-ip`, `forwarded`).
179
+ *
180
+ * The api Worker provider-proxy and the dashboard MCP proxy strip exactly
181
+ * this set (both inject upstream auth separately — the provider key, or the
182
+ * Vault MCP-bundle headers, applied AFTER the strip). The dashboard
183
+ * customer HTTP proxy hard-denies this set MINUS `x-api-key`, because a
184
+ * customer endpoint may legitimately declare `x-api-key` as its auth
185
+ * carrier; it derives from this constant so the hop-by-hop + routing
186
+ * entries never drift. Keeping the membership here is the single source of
187
+ * truth that stops those surfaces diverging.
188
+ */
189
+ export const PROXY_STRIPPED_INBOUND_HEADERS = new Set([
190
+ // credential carriers
191
+ "authorization",
192
+ "x-api-key",
193
+ "cookie",
194
+ "proxy-authorization",
195
+ // hop-by-hop (RFC 7230 §6.1)
196
+ "connection",
197
+ "keep-alive",
198
+ "transfer-encoding",
199
+ "te",
200
+ "trailer",
201
+ "upgrade",
202
+ "expect",
203
+ "proxy-authenticate",
204
+ "proxy-connection",
205
+ // routing primitives a runner could spoof
206
+ "host",
207
+ "content-length",
208
+ "x-forwarded-for",
209
+ "x-forwarded-host",
210
+ "x-forwarded-proto",
211
+ "x-forwarded-port",
212
+ "x-real-ip",
213
+ "forwarded"
214
+ ]);
215
+ /**
216
+ * Status code → error code mapping used by the BFF to ensure the audit
217
+ * row's error code and the HTTP response line up. Kept here so callers
218
+ * can do a sanity check in tests.
219
+ */
220
+ export const PROXY_ERROR_HTTP_STATUS = {
221
+ unsupported_protocol: 426,
222
+ unauthorized: 401,
223
+ endpoint_not_found: 404,
224
+ policy_denied: 403,
225
+ rate_limited: 429,
226
+ budget_exceeded: 429,
227
+ ssrf_denied: 403,
228
+ upstream_timeout: 504,
229
+ upstream_error: 502,
230
+ exceeded_cap: 502,
231
+ bad_request: 400,
232
+ internal_error: 500
233
+ };
234
+ //# sourceMappingURL=proxy-protocol.js.map
@@ -0,0 +1,19 @@
1
+ import type { PlatformProxyEndpoint, PlatformProxyEndpointAuth } from "./submission.js";
2
+ /**
3
+ * Cross-validate a `proxyEndpoints` policy list against a
4
+ * `secrets.proxyEndpointAuth` value list. Throws on the first mismatch
5
+ * with an actionable, field-named error message.
6
+ *
7
+ * Mirrors the BFF's authoritative validator so misconfigured submissions
8
+ * fail fast in the SDK/CLI before going over the wire.
9
+ */
10
+ export declare function validateProxyAuth(endpoints: readonly PlatformProxyEndpoint[], auth: readonly PlatformProxyEndpointAuth[] | undefined): void;
11
+ /**
12
+ * Build an `allowedHosts` list for `environment.network` that includes
13
+ * the aex proxy host (and optionally Anthropic's MCP host) when the
14
+ * caller is hand-rolling networking.
15
+ */
16
+ export declare function buildPlatformAllowedHosts(input: {
17
+ readonly baseUrl: string;
18
+ readonly extraHosts?: readonly string[];
19
+ }): readonly string[];
@@ -0,0 +1,51 @@
1
+ /**
2
+ * Cross-validate a `proxyEndpoints` policy list against a
3
+ * `secrets.proxyEndpointAuth` value list. Throws on the first mismatch
4
+ * with an actionable, field-named error message.
5
+ *
6
+ * Mirrors the BFF's authoritative validator so misconfigured submissions
7
+ * fail fast in the SDK/CLI before going over the wire.
8
+ */
9
+ export function validateProxyAuth(endpoints, auth) {
10
+ const authList = auth ?? [];
11
+ const endpointNames = new Set(endpoints.map((e) => e.name));
12
+ const authNames = new Set();
13
+ for (const entry of authList) {
14
+ if (authNames.has(entry.name)) {
15
+ throw new Error(`secrets.proxyEndpointAuth contains duplicate name '${entry.name}'`);
16
+ }
17
+ authNames.add(entry.name);
18
+ if (!endpointNames.has(entry.name)) {
19
+ throw new Error(`secrets.proxyEndpointAuth[].name='${entry.name}' has no matching proxyEndpoints[].name`);
20
+ }
21
+ }
22
+ for (const endpoint of endpoints) {
23
+ const match = authList.find((a) => a.name === endpoint.name);
24
+ if (!match) {
25
+ throw new Error(`proxyEndpoints[].name='${endpoint.name}' is missing a matching secrets.proxyEndpointAuth entry`);
26
+ }
27
+ if (match.value.type !== endpoint.authShape.type) {
28
+ 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}'`);
29
+ }
30
+ }
31
+ }
32
+ /**
33
+ * Build an `allowedHosts` list for `environment.network` that includes
34
+ * the aex proxy host (and optionally Anthropic's MCP host) when the
35
+ * caller is hand-rolling networking.
36
+ */
37
+ export function buildPlatformAllowedHosts(input) {
38
+ const result = [];
39
+ try {
40
+ result.push(new URL(input.baseUrl).host);
41
+ }
42
+ catch {
43
+ throw new Error("buildPlatformAllowedHosts: baseUrl must be an absolute URL");
44
+ }
45
+ for (const host of input.extraHosts ?? []) {
46
+ if (!result.includes(host))
47
+ result.push(host);
48
+ }
49
+ return result;
50
+ }
51
+ //# sourceMappingURL=proxy-validation.js.map
@@ -0,0 +1,47 @@
1
+ /**
2
+ * Single source of truth for a run's artifact namespaces.
3
+ *
4
+ * Every run stores its artifacts under two sibling prefixes:
5
+ *
6
+ * runs/<runId>/outputs/<rel> — the run's real deliverables.
7
+ * runs/<runId>/logs/<rel> — platform diagnostics (`runtime/`,
8
+ * `host/`, `provider-proxy/`,
9
+ * `control-plane/`).
10
+ *
11
+ * The runner uploads every file with a workspace-relative path and the
12
+ * server decides the namespace from that path's prefix, so the split is
13
+ * owned here — the runner does not need to know about it. Diagnostics
14
+ * reach the upload route as workspace dotdirs (`.runtime-logs/...`,
15
+ * `.host-logs/...`, etc.); the stored path uses canonical log namespaces.
16
+ * Legacy diagnostic prefixes are normalized on read/write compatibility paths.
17
+ */
18
+ export declare const RUN_OUTPUTS_PREFIX = "outputs";
19
+ export declare const RUN_LOGS_PREFIX = "logs";
20
+ /**
21
+ * Relative-path prefixes that mark a stored artifact as a platform diagnostic
22
+ * rather than a run deliverable. Dotted forms are upload-time paths; legacy
23
+ * forms are accepted so old records normalize to the canonical namespace.
24
+ */
25
+ export declare const RUN_LOG_REL_PREFIXES: readonly [".runtime-logs/", ".host-logs/", ".provider-proxy/", ".control-plane/", ".anthropic-debug/", ".goose-logs/", ".fly-logs/", "runtime/", "host/", "provider-proxy/", "control-plane/", "anthropic-debug/", "goose-logs/", "fly-logs/"];
26
+ /** True when a workspace-relative artifact path belongs to the `logs` namespace. */
27
+ export declare function isRunLogRelPath(rel: string): boolean;
28
+ /**
29
+ * The artifact's path relative to its namespace prefix as stored. Diagnostics
30
+ * are canonicalized (`.runtime-logs/x` -> `runtime/x`,
31
+ * legacy `.goose-logs/x` -> `runtime/x`, legacy `.fly-logs/x` -> `host/x`).
32
+ */
33
+ export declare function runArtifactRel(rel: string): string;
34
+ /**
35
+ * Storage key for a run artifact uploaded with relative path `rel`, routing
36
+ * diagnostics into `logs/` and everything else into `outputs/`.
37
+ */
38
+ export declare function runArtifactKey(runId: string, rel: string): string;
39
+ /** The `assets` namespace under a run's prefix. */
40
+ export declare const RUN_ASSETS_PREFIX = "assets";
41
+ /**
42
+ * Storage key for a run's snapshotted asset, addressed by its content hash.
43
+ * At submit, each referenced shared-store asset is copied here so the run owns
44
+ * its bytes. Accepts a `sha256:<hex>` hash or a bare 64-hex digest; the stored
45
+ * suffix is the hex.
46
+ */
47
+ export declare function runAssetKey(runId: string, hash: string): string;
@@ -0,0 +1,101 @@
1
+ /**
2
+ * Single source of truth for a run's artifact namespaces.
3
+ *
4
+ * Every run stores its artifacts under two sibling prefixes:
5
+ *
6
+ * runs/<runId>/outputs/<rel> — the run's real deliverables.
7
+ * runs/<runId>/logs/<rel> — platform diagnostics (`runtime/`,
8
+ * `host/`, `provider-proxy/`,
9
+ * `control-plane/`).
10
+ *
11
+ * The runner uploads every file with a workspace-relative path and the
12
+ * server decides the namespace from that path's prefix, so the split is
13
+ * owned here — the runner does not need to know about it. Diagnostics
14
+ * reach the upload route as workspace dotdirs (`.runtime-logs/...`,
15
+ * `.host-logs/...`, etc.); the stored path uses canonical log namespaces.
16
+ * Legacy diagnostic prefixes are normalized on read/write compatibility paths.
17
+ */
18
+ export const RUN_OUTPUTS_PREFIX = "outputs";
19
+ export const RUN_LOGS_PREFIX = "logs";
20
+ /**
21
+ * Relative-path prefixes that mark a stored artifact as a platform diagnostic
22
+ * rather than a run deliverable. Dotted forms are upload-time paths; legacy
23
+ * forms are accepted so old records normalize to the canonical namespace.
24
+ */
25
+ export const RUN_LOG_REL_PREFIXES = [
26
+ ".runtime-logs/",
27
+ ".host-logs/",
28
+ ".provider-proxy/",
29
+ ".control-plane/",
30
+ ".anthropic-debug/",
31
+ ".goose-logs/",
32
+ ".fly-logs/",
33
+ "runtime/",
34
+ "host/",
35
+ "provider-proxy/",
36
+ "control-plane/",
37
+ "anthropic-debug/",
38
+ "goose-logs/",
39
+ "fly-logs/"
40
+ ];
41
+ /** True when a workspace-relative artifact path belongs to the `logs` namespace. */
42
+ export function isRunLogRelPath(rel) {
43
+ return RUN_LOG_REL_PREFIXES.some((prefix) => rel.startsWith(prefix));
44
+ }
45
+ /**
46
+ * The artifact's path relative to its namespace prefix as stored. Diagnostics
47
+ * are canonicalized (`.runtime-logs/x` -> `runtime/x`,
48
+ * legacy `.goose-logs/x` -> `runtime/x`, legacy `.fly-logs/x` -> `host/x`).
49
+ */
50
+ export function runArtifactRel(rel) {
51
+ if (rel.startsWith(".runtime-logs/"))
52
+ return `runtime/${rel.slice(".runtime-logs/".length)}`;
53
+ if (rel.startsWith("runtime/"))
54
+ return rel;
55
+ if (rel.startsWith(".host-logs/"))
56
+ return `host/${rel.slice(".host-logs/".length)}`;
57
+ if (rel.startsWith("host/"))
58
+ return rel;
59
+ if (rel.startsWith(".provider-proxy/"))
60
+ return `provider-proxy/${rel.slice(".provider-proxy/".length)}`;
61
+ if (rel.startsWith("provider-proxy/"))
62
+ return rel;
63
+ if (rel.startsWith(".control-plane/"))
64
+ return `control-plane/${rel.slice(".control-plane/".length)}`;
65
+ if (rel.startsWith("control-plane/"))
66
+ return rel;
67
+ if (rel.startsWith(".goose-logs/"))
68
+ return `runtime/${rel.slice(".goose-logs/".length)}`;
69
+ if (rel.startsWith("goose-logs/"))
70
+ return `runtime/${rel.slice("goose-logs/".length)}`;
71
+ if (rel.startsWith(".fly-logs/"))
72
+ return `host/${rel.slice(".fly-logs/".length)}`;
73
+ if (rel.startsWith("fly-logs/"))
74
+ return `host/${rel.slice("fly-logs/".length)}`;
75
+ if (rel.startsWith(".anthropic-debug/"))
76
+ return `provider-proxy/${rel.slice(".anthropic-debug/".length)}`;
77
+ if (rel.startsWith("anthropic-debug/"))
78
+ return `provider-proxy/${rel.slice("anthropic-debug/".length)}`;
79
+ return rel;
80
+ }
81
+ /**
82
+ * Storage key for a run artifact uploaded with relative path `rel`, routing
83
+ * diagnostics into `logs/` and everything else into `outputs/`.
84
+ */
85
+ export function runArtifactKey(runId, rel) {
86
+ const namespace = isRunLogRelPath(rel) ? RUN_LOGS_PREFIX : RUN_OUTPUTS_PREFIX;
87
+ return `runs/${runId}/${namespace}/${runArtifactRel(rel)}`;
88
+ }
89
+ /** The `assets` namespace under a run's prefix. */
90
+ export const RUN_ASSETS_PREFIX = "assets";
91
+ /**
92
+ * Storage key for a run's snapshotted asset, addressed by its content hash.
93
+ * At submit, each referenced shared-store asset is copied here so the run owns
94
+ * its bytes. Accepts a `sha256:<hex>` hash or a bare 64-hex digest; the stored
95
+ * suffix is the hex.
96
+ */
97
+ export function runAssetKey(runId, hash) {
98
+ const hex = hash.startsWith("sha256:") ? hash.slice("sha256:".length) : hash;
99
+ return `runs/${runId}/${RUN_ASSETS_PREFIX}/${hex}`;
100
+ }
101
+ //# sourceMappingURL=run-artifacts.js.map