agentfootprint 11.4.0 → 12.0.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.
Files changed (198) hide show
  1. package/CAPABILITIES.md +3 -1
  2. package/dist/adapters/code/agentcore.js +295 -214
  3. package/dist/adapters/code/agentcore.js.map +1 -1
  4. package/dist/adapters/code/agentcoreClient.js +178 -0
  5. package/dist/adapters/code/agentcoreClient.js.map +1 -0
  6. package/dist/adapters/code/agentcoreWire.js +348 -0
  7. package/dist/adapters/code/agentcoreWire.js.map +1 -0
  8. package/dist/adapters/code/fileName.js +100 -0
  9. package/dist/adapters/code/fileName.js.map +1 -0
  10. package/dist/adapters/code/local.js +529 -183
  11. package/dist/adapters/code/local.js.map +1 -1
  12. package/dist/adapters/code/output.js +140 -0
  13. package/dist/adapters/code/output.js.map +1 -0
  14. package/dist/adapters/mcp/agentcoreRuntime/invoke.js +7 -6
  15. package/dist/adapters/mcp/agentcoreRuntime/invoke.js.map +1 -1
  16. package/dist/adapters/mcp/agentcoreRuntime/sessionBusy.js +36 -2
  17. package/dist/adapters/mcp/agentcoreRuntime/sessionBusy.js.map +1 -1
  18. package/dist/adapters/mcp/agentcoreRuntime/transport.js +3 -1
  19. package/dist/adapters/mcp/agentcoreRuntime/transport.js.map +1 -1
  20. package/dist/core/codeRunnerTool.js +52 -7
  21. package/dist/core/codeRunnerTool.js.map +1 -1
  22. package/dist/doors/providers.js.map +1 -1
  23. package/dist/esm/adapters/code/agentcore.d.ts +65 -68
  24. package/dist/esm/adapters/code/agentcore.js +293 -212
  25. package/dist/esm/adapters/code/agentcore.js.map +1 -1
  26. package/dist/esm/adapters/code/agentcoreClient.d.ts +193 -0
  27. package/dist/esm/adapters/code/agentcoreClient.js +173 -0
  28. package/dist/esm/adapters/code/agentcoreClient.js.map +1 -0
  29. package/dist/esm/adapters/code/agentcoreWire.d.ts +119 -0
  30. package/dist/esm/adapters/code/agentcoreWire.js +334 -0
  31. package/dist/esm/adapters/code/agentcoreWire.js.map +1 -0
  32. package/dist/esm/adapters/code/fileName.d.ts +43 -0
  33. package/dist/esm/adapters/code/fileName.js +96 -0
  34. package/dist/esm/adapters/code/fileName.js.map +1 -0
  35. package/dist/esm/adapters/code/local.d.ts +91 -12
  36. package/dist/esm/adapters/code/local.js +528 -182
  37. package/dist/esm/adapters/code/local.js.map +1 -1
  38. package/dist/esm/adapters/code/output.d.ts +70 -0
  39. package/dist/esm/adapters/code/output.js +129 -0
  40. package/dist/esm/adapters/code/output.js.map +1 -0
  41. package/dist/esm/adapters/mcp/agentcoreRuntime/invoke.d.ts +7 -6
  42. package/dist/esm/adapters/mcp/agentcoreRuntime/invoke.js +7 -6
  43. package/dist/esm/adapters/mcp/agentcoreRuntime/invoke.js.map +1 -1
  44. package/dist/esm/adapters/mcp/agentcoreRuntime/sessionBusy.d.ts +32 -1
  45. package/dist/esm/adapters/mcp/agentcoreRuntime/sessionBusy.js +35 -1
  46. package/dist/esm/adapters/mcp/agentcoreRuntime/sessionBusy.js.map +1 -1
  47. package/dist/esm/adapters/mcp/agentcoreRuntime/transport.js +4 -2
  48. package/dist/esm/adapters/mcp/agentcoreRuntime/transport.js.map +1 -1
  49. package/dist/esm/core/codeRunnerTool.d.ts +15 -3
  50. package/dist/esm/core/codeRunnerTool.js +52 -7
  51. package/dist/esm/core/codeRunnerTool.js.map +1 -1
  52. package/dist/esm/doors/providers.d.ts +1 -1
  53. package/dist/esm/doors/providers.js.map +1 -1
  54. package/dist/esm/events/payloads.d.ts +144 -29
  55. package/dist/esm/index.d.ts +2 -0
  56. package/dist/esm/index.js +5 -0
  57. package/dist/esm/index.js.map +1 -1
  58. package/dist/esm/mcp/callLifetime.d.ts +57 -14
  59. package/dist/esm/mcp/callLifetime.js +67 -19
  60. package/dist/esm/mcp/callLifetime.js.map +1 -1
  61. package/dist/esm/mcp/callMarker.d.ts +43 -0
  62. package/dist/esm/mcp/callMarker.js +69 -0
  63. package/dist/esm/mcp/callMarker.js.map +1 -0
  64. package/dist/esm/mcp/connectionRefusals.js +7 -0
  65. package/dist/esm/mcp/connectionRefusals.js.map +1 -1
  66. package/dist/esm/mcp/index.d.ts +2 -0
  67. package/dist/esm/mcp/index.js +3 -0
  68. package/dist/esm/mcp/index.js.map +1 -1
  69. package/dist/esm/mcp/mcpClient.js +93 -26
  70. package/dist/esm/mcp/mcpClient.js.map +1 -1
  71. package/dist/esm/mcp/replay.d.ts +291 -0
  72. package/dist/esm/mcp/replay.js +405 -0
  73. package/dist/esm/mcp/replay.js.map +1 -0
  74. package/dist/esm/mcp/replayUnavailable.d.ts +68 -0
  75. package/dist/esm/mcp/replayUnavailable.js +87 -0
  76. package/dist/esm/mcp/replayUnavailable.js.map +1 -0
  77. package/dist/esm/mcp/requestLedger.d.ts +115 -32
  78. package/dist/esm/mcp/requestLedger.js +193 -52
  79. package/dist/esm/mcp/requestLedger.js.map +1 -1
  80. package/dist/esm/mcp/seriesEvidence.d.ts +73 -15
  81. package/dist/esm/mcp/seriesEvidence.js +114 -21
  82. package/dist/esm/mcp/seriesEvidence.js.map +1 -1
  83. package/dist/esm/mcp/throttleRetry.d.ts +86 -42
  84. package/dist/esm/mcp/throttleRetry.js +158 -50
  85. package/dist/esm/mcp/throttleRetry.js.map +1 -1
  86. package/dist/esm/mcp/toolResult.d.ts +6 -0
  87. package/dist/esm/mcp/toolResult.js +15 -0
  88. package/dist/esm/mcp/toolResult.js.map +1 -1
  89. package/dist/esm/mcp/types.d.ts +73 -8
  90. package/dist/esm/provider-contract/codeSandbox.d.ts +89 -0
  91. package/dist/esm/provider-contract/codeSandbox.js +119 -0
  92. package/dist/esm/provider-contract/codeSandbox.js.map +1 -0
  93. package/dist/esm/provider-contract/sessionExpired.d.ts +31 -0
  94. package/dist/esm/provider-contract/sessionExpired.js +40 -0
  95. package/dist/esm/provider-contract/sessionExpired.js.map +1 -0
  96. package/dist/esm/provider-contract/types.d.ts +166 -17
  97. package/dist/esm/provider-contract/types.js +9 -0
  98. package/dist/esm/provider-contract/types.js.map +1 -1
  99. package/dist/esm/redaction/knownStrings.js +16 -0
  100. package/dist/esm/redaction/knownStrings.js.map +1 -1
  101. package/dist/esm/tool-providers/index.d.ts +2 -2
  102. package/dist/esm/tool-providers/index.js +4 -0
  103. package/dist/esm/tool-providers/index.js.map +1 -1
  104. package/dist/esm/tools/requestEvidence.js +60 -0
  105. package/dist/esm/tools/requestEvidence.js.map +1 -1
  106. package/dist/index.js +12 -4
  107. package/dist/index.js.map +1 -1
  108. package/dist/mcp/callLifetime.js +66 -18
  109. package/dist/mcp/callLifetime.js.map +1 -1
  110. package/dist/mcp/callMarker.js +74 -0
  111. package/dist/mcp/callMarker.js.map +1 -0
  112. package/dist/mcp/connectionRefusals.js +7 -0
  113. package/dist/mcp/connectionRefusals.js.map +1 -1
  114. package/dist/mcp/index.js +5 -1
  115. package/dist/mcp/index.js.map +1 -1
  116. package/dist/mcp/mcpClient.js +91 -24
  117. package/dist/mcp/mcpClient.js.map +1 -1
  118. package/dist/mcp/replay.js +415 -0
  119. package/dist/mcp/replay.js.map +1 -0
  120. package/dist/mcp/replayUnavailable.js +92 -0
  121. package/dist/mcp/replayUnavailable.js.map +1 -0
  122. package/dist/mcp/requestLedger.js +193 -52
  123. package/dist/mcp/requestLedger.js.map +1 -1
  124. package/dist/mcp/seriesEvidence.js +116 -22
  125. package/dist/mcp/seriesEvidence.js.map +1 -1
  126. package/dist/mcp/throttleRetry.js +160 -51
  127. package/dist/mcp/throttleRetry.js.map +1 -1
  128. package/dist/mcp/toolResult.js +17 -1
  129. package/dist/mcp/toolResult.js.map +1 -1
  130. package/dist/provider-contract/codeSandbox.js +125 -0
  131. package/dist/provider-contract/codeSandbox.js.map +1 -0
  132. package/dist/provider-contract/sessionExpired.js +44 -0
  133. package/dist/provider-contract/sessionExpired.js.map +1 -0
  134. package/dist/provider-contract/types.js +12 -1
  135. package/dist/provider-contract/types.js.map +1 -1
  136. package/dist/redaction/knownStrings.js +16 -0
  137. package/dist/redaction/knownStrings.js.map +1 -1
  138. package/dist/tool-providers/index.js +5 -1
  139. package/dist/tool-providers/index.js.map +1 -1
  140. package/dist/tools/requestEvidence.js +60 -0
  141. package/dist/tools/requestEvidence.js.map +1 -1
  142. package/dist/types/adapters/code/agentcore.d.ts +65 -68
  143. package/dist/types/adapters/code/agentcore.d.ts.map +1 -1
  144. package/dist/types/adapters/code/agentcoreClient.d.ts +194 -0
  145. package/dist/types/adapters/code/agentcoreClient.d.ts.map +1 -0
  146. package/dist/types/adapters/code/agentcoreWire.d.ts +120 -0
  147. package/dist/types/adapters/code/agentcoreWire.d.ts.map +1 -0
  148. package/dist/types/adapters/code/fileName.d.ts +44 -0
  149. package/dist/types/adapters/code/fileName.d.ts.map +1 -0
  150. package/dist/types/adapters/code/local.d.ts +91 -12
  151. package/dist/types/adapters/code/local.d.ts.map +1 -1
  152. package/dist/types/adapters/code/output.d.ts +71 -0
  153. package/dist/types/adapters/code/output.d.ts.map +1 -0
  154. package/dist/types/adapters/mcp/agentcoreRuntime/invoke.d.ts +7 -6
  155. package/dist/types/adapters/mcp/agentcoreRuntime/invoke.d.ts.map +1 -1
  156. package/dist/types/adapters/mcp/agentcoreRuntime/sessionBusy.d.ts +32 -1
  157. package/dist/types/adapters/mcp/agentcoreRuntime/sessionBusy.d.ts.map +1 -1
  158. package/dist/types/adapters/mcp/agentcoreRuntime/transport.d.ts.map +1 -1
  159. package/dist/types/core/codeRunnerTool.d.ts +15 -3
  160. package/dist/types/core/codeRunnerTool.d.ts.map +1 -1
  161. package/dist/types/doors/providers.d.ts +1 -1
  162. package/dist/types/doors/providers.d.ts.map +1 -1
  163. package/dist/types/events/payloads.d.ts +144 -29
  164. package/dist/types/events/payloads.d.ts.map +1 -1
  165. package/dist/types/index.d.ts +2 -0
  166. package/dist/types/index.d.ts.map +1 -1
  167. package/dist/types/mcp/callLifetime.d.ts +57 -14
  168. package/dist/types/mcp/callLifetime.d.ts.map +1 -1
  169. package/dist/types/mcp/callMarker.d.ts +44 -0
  170. package/dist/types/mcp/callMarker.d.ts.map +1 -0
  171. package/dist/types/mcp/index.d.ts +2 -0
  172. package/dist/types/mcp/index.d.ts.map +1 -1
  173. package/dist/types/mcp/mcpClient.d.ts.map +1 -1
  174. package/dist/types/mcp/replay.d.ts +292 -0
  175. package/dist/types/mcp/replay.d.ts.map +1 -0
  176. package/dist/types/mcp/replayUnavailable.d.ts +69 -0
  177. package/dist/types/mcp/replayUnavailable.d.ts.map +1 -0
  178. package/dist/types/mcp/requestLedger.d.ts +115 -32
  179. package/dist/types/mcp/requestLedger.d.ts.map +1 -1
  180. package/dist/types/mcp/seriesEvidence.d.ts +73 -15
  181. package/dist/types/mcp/seriesEvidence.d.ts.map +1 -1
  182. package/dist/types/mcp/throttleRetry.d.ts +86 -42
  183. package/dist/types/mcp/throttleRetry.d.ts.map +1 -1
  184. package/dist/types/mcp/toolResult.d.ts +6 -0
  185. package/dist/types/mcp/toolResult.d.ts.map +1 -1
  186. package/dist/types/mcp/types.d.ts +73 -8
  187. package/dist/types/mcp/types.d.ts.map +1 -1
  188. package/dist/types/provider-contract/codeSandbox.d.ts +90 -0
  189. package/dist/types/provider-contract/codeSandbox.d.ts.map +1 -0
  190. package/dist/types/provider-contract/sessionExpired.d.ts +32 -0
  191. package/dist/types/provider-contract/sessionExpired.d.ts.map +1 -0
  192. package/dist/types/provider-contract/types.d.ts +166 -17
  193. package/dist/types/provider-contract/types.d.ts.map +1 -1
  194. package/dist/types/redaction/knownStrings.d.ts.map +1 -1
  195. package/dist/types/tool-providers/index.d.ts +2 -2
  196. package/dist/types/tool-providers/index.d.ts.map +1 -1
  197. package/dist/types/tools/requestEvidence.d.ts.map +1 -1
  198. package/package.json +1 -1
@@ -23,6 +23,7 @@
23
23
  import type { Tool } from '../tools/tools.js';
24
24
  import type { CredentialProvider } from '../identity/types.js';
25
25
  import type { RetryOnThrottle } from './throttleRetry.js';
26
+ import type { McpReplayOptions } from './replay.js';
26
27
  import type { FetchLike } from './gatewayTransport.js';
27
28
  /**
28
29
  * `stdio` transport — spawns a local subprocess and speaks MCP over
@@ -207,14 +208,17 @@ export interface McpClientOptions {
207
208
  * the transport's `retry` values as the call's overall limits and these as
208
209
  * limits on the 429 retries inside them.
209
210
  *
210
- * **What this assumes.** Automatic 429 retries assume the server rejected
211
- * the request before executing it. The saved response records that
212
- * assumption's basis (the server's 429), not proof that nothing ran: HTTP 429
213
- * says the request was rate-limited, nothing more (RFC 6585 §4). A tool with
214
- * side effects is retried on 429 like any other today — this retry has no
215
- * side-effect guard and sends no deduplication key — and
216
- * `retryOnThrottle: false` turns that off for this server. Nothing else is
217
- * retried: a 5xx or a timeout may be the record of work that ran.
211
+ * **Who may ask again is {@link McpClientOptions.replay}'s.** These
212
+ * options set the BUDGET of a call's retries; whether a tool call is sent
213
+ * again at all is the replay policy's. Under the default (`'compatibility'`)
214
+ * a 429 is repeated for every tool, ASSUMING the server refused it before
215
+ * running it — HTTP 429 says only that the request was rate-limited (RFC 6585
216
+ * §4) — and every such repeat records that assumption. A tool you declare as
217
+ * making changes is never repeated without a deduplication key, and
218
+ * `'app-authorized'` repeats only what you declare. `retryOnThrottle: false`
219
+ * turns 429 retries off for this server, and nothing else: a tool declared
220
+ * repeatable on `'network'`, and the `'app-authorized'` policy, keep their
221
+ * series and their record. A 5xx is an answer and is never repeated.
218
222
  *
219
223
  * **Why this is on by default.** Managed gateways rate-limit per principal by
220
224
  * design, and without this a designed, self-clearing condition reached the
@@ -223,6 +227,65 @@ export interface McpClientOptions {
223
227
  * Ignored for `stdio`, which has no HTTP status to read.
224
228
  */
225
229
  readonly retryOnThrottle?: RetryOnThrottle;
230
+ /**
231
+ * Who may send a tool call again, declared by YOU for this server's tools —
232
+ * never by the model, a tool's description or the server's annotations
233
+ * (`readOnlyHint`). Read once, here; a field it does not know is refused.
234
+ *
235
+ * ```ts
236
+ * const orders = await mcpClient({
237
+ * name: 'orders',
238
+ * transport: { transport: 'http', url },
239
+ * replay: {
240
+ * policy: 'app-authorized',
241
+ * tools: {
242
+ * search_orders: { on: ['throttle', 'network'] },
243
+ * create_order: { on: ['throttle'], changes: true },
244
+ * },
245
+ * deduplicates: { argument: 'idempotency_key' },
246
+ * },
247
+ * });
248
+ * ```
249
+ *
250
+ * - `policy: 'compatibility'` (the default, kept in 12.0) — today's
251
+ * behaviour, by name: a 429 is sent again for every tool, assuming the
252
+ * server refused it before running it. Each such retry records that
253
+ * assumption (`permission: { by: 'compatibility', assumes: 'refused-before-execution' }`).
254
+ * It gains none of the strict guarantees below.
255
+ * - `policy: 'app-authorized'` (opt-in, by name) — a 429
256
+ * (`'throttle'`) or a request that failed without an answer
257
+ * (`'network'`) is sent again only for a tool whose entry names it.
258
+ * - `changes: true` — the tool makes changes: never sent again
259
+ * automatically, under either policy, unless `deduplicates` is declared
260
+ * and the call carries the key. A key protects only when the server uses it.
261
+ *
262
+ * Under both policies the adapter you chose retries its own refusal —
263
+ * AgentCore Runtime's session-busy reply — within the budget, as its policy:
264
+ * each repeat records what it assumes, never proof that nothing ran. A
265
+ * repeat re-sends the SAME request: the same arguments, server and session,
266
+ * as the same identity. Each attempt's run record says what is known of its
267
+ * effect — `unknown` for anything sent that did not complete, `applied` when
268
+ * the call completed (never proof of a write) — and what permitted the next
269
+ * one. Under `'app-authorized'`, a received refusal or error (a 429, a 503,
270
+ * a JSON-RPC or tool error) reaches the caller as the server sent it, its
271
+ * effect still unknown; a call that genuinely lacked an answer somewhere —
272
+ * a request with no response, or one accepted over HTTP whose JSON-RPC
273
+ * answer never came — and then fails, fails as "may have run"
274
+ * (footprintjs's `UnknownEffectError`, its final error as the `cause`).
275
+ * Under `'compatibility'` the caller sees the error it always did.
276
+ *
277
+ * `'app-authorized'` needs each request matched to its call and each answer
278
+ * seen. A connection that cannot give both refuses each tool call BEFORE its
279
+ * request is sent, with `McpReplayUnavailableError` and a typed `reason`: an
280
+ * MCP SDK whose `connect` replaces the transport's `onmessage` handler
281
+ * (`'answers-unobserved'`), one that drops the params' `_meta`
282
+ * (`'request-unmatched'`), or a transport whose requests the library cannot
283
+ * watch, such as `stdio` (`'requests-unwatched'`). Connecting and listing
284
+ * tools still run; only the tool invocation is refused. An explicit
285
+ * `'app-authorized'` never falls back to `'compatibility'`. Under
286
+ * `'compatibility'`, `stdio` ignores it: it has no retry series.
287
+ */
288
+ readonly replay?: McpReplayOptions;
226
289
  /**
227
290
  * Pre-resolved SDK modules. Give these and the library never touches its Node
228
291
  * `require` loader — which is what lets a browser bundle speak MCP over
@@ -295,6 +358,8 @@ export interface McpConnectionOptions {
295
358
  readonly clientInfo?: undefined;
296
359
  /** @see McpClientOptions — never set on this arm. */
297
360
  readonly retryOnThrottle?: undefined;
361
+ /** @see McpClientOptions — never set on this arm. */
362
+ readonly replay?: undefined;
298
363
  /** @internal @see McpClientOptions — never set on this arm. */
299
364
  readonly _client?: undefined;
300
365
  }
@@ -0,0 +1,89 @@
1
+ /**
2
+ * The code-session port's refusals and its one path rule.
3
+ *
4
+ * Every adapter behind the `CodeSession` port refuses the same things with the
5
+ * same error, and reads a session path by the same rule, so a caller that
6
+ * swaps `localCodeRunner` for `agentCoreCodeRunner` catches the same names.
7
+ * The rule lives here, beside the port, rather than in either adapter: two
8
+ * copies of a path rule are two rules.
9
+ */
10
+ /** Why a code-session operation was refused. */
11
+ export type CodeSandboxRefusal =
12
+ /** The path is absolute, climbs above the working directory, or is not a path. */
13
+ 'path-refused'
14
+ /** A read found a file larger than its `maxBytes`. Nothing was returned. */
15
+ | 'file-too-large'
16
+ /** The backend answered a read with no file for the path. */
17
+ | 'file-not-returned'
18
+ /** The backend returned a file without saying which path it is. */
19
+ | 'uri-missing'
20
+ /** The backend returned a file for a path other than the one asked for. */
21
+ | 'uri-mismatch'
22
+ /** The backend returned several files for one path, or a file with both text and bytes, or neither. */
23
+ | 'content-ambiguous'
24
+ /** One request would be larger than the backend accepts in a single call. Nothing was sent. */
25
+ | 'request-too-large'
26
+ /** The backend did not confirm a write. */
27
+ | 'write-failed'
28
+ /** The caller's `timeoutMs` passed before the backend answered. */
29
+ | 'timed-out'
30
+ /** A process started, then the runtime reported an error for it. It was
31
+ * stopped; whether it finished, and what it changed, is unknown. */
32
+ | 'error-after-start'
33
+ /** The staged-input manifest could not be set where the next run reads it. */
34
+ | 'staged-inputs-unset';
35
+ /**
36
+ * A code-session operation refused — before anything was sent, or because
37
+ * what came back could not be trusted as the answer.
38
+ *
39
+ * Carries the path, sizes and limits as data. Never a file's contents and
40
+ * never a command's text: those are the two things a code session holds that
41
+ * an error message must not repeat, because error messages reach logs, traces
42
+ * and the model.
43
+ */
44
+ export declare class CodeSandboxError extends Error {
45
+ readonly code: "ERR_CODE_SANDBOX";
46
+ /** What was refused. */
47
+ readonly reason: CodeSandboxRefusal;
48
+ /** The session path involved, when there was one. */
49
+ readonly path?: string;
50
+ /** The size that was measured, in bytes, when the refusal is about size. */
51
+ readonly bytes?: number;
52
+ /** The limit that size was held to, in bytes. */
53
+ readonly limit?: number;
54
+ constructor(reason: CodeSandboxRefusal, message: string, details?: {
55
+ readonly path?: string;
56
+ readonly bytes?: number;
57
+ readonly limit?: number;
58
+ });
59
+ }
60
+ /**
61
+ * One session path, checked and put in canonical form — THE path rule every
62
+ * adapter applies before it reads a file.
63
+ *
64
+ * Refused, by name, before anything is sent:
65
+ * - an empty path, and one that names the working directory itself (`.`);
66
+ * - an absolute path (`/etc/passwd`) and a drive (`C:…`);
67
+ * - a leading `~`, which a shell would read as a home directory;
68
+ * - any backslash — a separator on one platform and an ordinary character
69
+ * on another, so `a\..\..\x` cannot be judged the same way everywhere;
70
+ * - a NUL, which ends a path early in the operating system's own calls;
71
+ * - a `..` that climbs above the working directory (`../x`, `a/../../x`).
72
+ *
73
+ * A `..` that stays inside is resolved here (`a/../b` → `b`), `.` and empty
74
+ * segments are dropped (`./out//a.csv` → `out/a.csv`), and the result never
75
+ * contains `..` at all — so no backend is ever handed a parent hop to
76
+ * interpret. Lexical, not physical: on the caller's own machine a symbolic
77
+ * link can still point elsewhere, which `localCodeRunner` checks separately.
78
+ *
79
+ * @throws CodeSandboxError with reason `'path-refused'`.
80
+ */
81
+ export declare function sandboxPath(path: string): string;
82
+ /**
83
+ * The one check of a `maxBytes` bound: a positive whole number, or a
84
+ * `TypeError` naming the option. A read with no bound, or with a bound of
85
+ * zero, is a programming error rather than a file that happened to be large.
86
+ */
87
+ export declare function readBound(options: {
88
+ readonly maxBytes?: unknown;
89
+ } | undefined): number;
@@ -0,0 +1,119 @@
1
+ /**
2
+ * The code-session port's refusals and its one path rule.
3
+ *
4
+ * Every adapter behind the `CodeSession` port refuses the same things with the
5
+ * same error, and reads a session path by the same rule, so a caller that
6
+ * swaps `localCodeRunner` for `agentCoreCodeRunner` catches the same names.
7
+ * The rule lives here, beside the port, rather than in either adapter: two
8
+ * copies of a path rule are two rules.
9
+ */
10
+ /**
11
+ * A code-session operation refused — before anything was sent, or because
12
+ * what came back could not be trusted as the answer.
13
+ *
14
+ * Carries the path, sizes and limits as data. Never a file's contents and
15
+ * never a command's text: those are the two things a code session holds that
16
+ * an error message must not repeat, because error messages reach logs, traces
17
+ * and the model.
18
+ */
19
+ export class CodeSandboxError extends Error {
20
+ code = 'ERR_CODE_SANDBOX';
21
+ /** What was refused. */
22
+ reason;
23
+ /** The session path involved, when there was one. */
24
+ path;
25
+ /** The size that was measured, in bytes, when the refusal is about size. */
26
+ bytes;
27
+ /** The limit that size was held to, in bytes. */
28
+ limit;
29
+ constructor(reason, message, details = {}) {
30
+ super(message);
31
+ this.name = 'CodeSandboxError';
32
+ this.reason = reason;
33
+ if (details.path !== undefined)
34
+ this.path = details.path;
35
+ if (details.bytes !== undefined)
36
+ this.bytes = details.bytes;
37
+ if (details.limit !== undefined)
38
+ this.limit = details.limit;
39
+ }
40
+ }
41
+ /** The longest stretch of a refused path a message quotes. */
42
+ const QUOTED_PATH_MAX = 200;
43
+ function quoted(path) {
44
+ const shown = path.length > QUOTED_PATH_MAX ? `${path.slice(0, QUOTED_PATH_MAX)}…` : path;
45
+ return JSON.stringify(shown);
46
+ }
47
+ function refused(path, why) {
48
+ return new CodeSandboxError('path-refused', `code session: the path ${quoted(path)} ${why}. A session path is relative to the ` +
49
+ "session's working directory and stays inside it — name the file as the session's code " +
50
+ 'would, for example `out/result.csv`.', { path });
51
+ }
52
+ /**
53
+ * One session path, checked and put in canonical form — THE path rule every
54
+ * adapter applies before it reads a file.
55
+ *
56
+ * Refused, by name, before anything is sent:
57
+ * - an empty path, and one that names the working directory itself (`.`);
58
+ * - an absolute path (`/etc/passwd`) and a drive (`C:…`);
59
+ * - a leading `~`, which a shell would read as a home directory;
60
+ * - any backslash — a separator on one platform and an ordinary character
61
+ * on another, so `a\..\..\x` cannot be judged the same way everywhere;
62
+ * - a NUL, which ends a path early in the operating system's own calls;
63
+ * - a `..` that climbs above the working directory (`../x`, `a/../../x`).
64
+ *
65
+ * A `..` that stays inside is resolved here (`a/../b` → `b`), `.` and empty
66
+ * segments are dropped (`./out//a.csv` → `out/a.csv`), and the result never
67
+ * contains `..` at all — so no backend is ever handed a parent hop to
68
+ * interpret. Lexical, not physical: on the caller's own machine a symbolic
69
+ * link can still point elsewhere, which `localCodeRunner` checks separately.
70
+ *
71
+ * @throws CodeSandboxError with reason `'path-refused'`.
72
+ */
73
+ export function sandboxPath(path) {
74
+ if (typeof path !== 'string') {
75
+ throw refused(String(path), 'is not a string');
76
+ }
77
+ if (path.length === 0)
78
+ throw refused(path, 'is empty');
79
+ if (path.includes('\0'))
80
+ throw refused(path, 'contains a NUL character');
81
+ if (path.includes('\\')) {
82
+ throw refused(path, 'contains a backslash, which is a separator on one platform and an ordinary character on another');
83
+ }
84
+ if (path.startsWith('/'))
85
+ throw refused(path, 'is absolute');
86
+ if (/^[A-Za-z]:/.test(path))
87
+ throw refused(path, 'names a drive');
88
+ if (path.startsWith('~'))
89
+ throw refused(path, "starts with '~', which a shell reads as a home directory");
90
+ const kept = [];
91
+ for (const segment of path.split('/')) {
92
+ if (segment === '' || segment === '.')
93
+ continue;
94
+ if (segment === '..') {
95
+ if (kept.length === 0)
96
+ throw refused(path, 'climbs above the working directory');
97
+ kept.pop();
98
+ continue;
99
+ }
100
+ kept.push(segment);
101
+ }
102
+ if (kept.length === 0)
103
+ throw refused(path, 'names the working directory itself, not a file');
104
+ return kept.join('/');
105
+ }
106
+ /**
107
+ * The one check of a `maxBytes` bound: a positive whole number, or a
108
+ * `TypeError` naming the option. A read with no bound, or with a bound of
109
+ * zero, is a programming error rather than a file that happened to be large.
110
+ */
111
+ export function readBound(options) {
112
+ const maxBytes = options?.maxBytes;
113
+ if (typeof maxBytes !== 'number' || !Number.isSafeInteger(maxBytes) || maxBytes <= 0) {
114
+ throw new TypeError('code session: readFile needs `maxBytes`, a positive whole number of bytes — a read names ' +
115
+ 'its bound, and a file over it is refused rather than cut.');
116
+ }
117
+ return maxBytes;
118
+ }
119
+ //# sourceMappingURL=codeSandbox.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"codeSandbox.js","sourceRoot":"","sources":["../../../src/provider-contract/codeSandbox.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,31 @@
1
+ /**
2
+ * `SessionExpiredError` — a remote session that is gone, said ONE way.
3
+ *
4
+ * A managed backend reaps its sessions on its own schedule (a timeout, a stop,
5
+ * a restart), and each service words that differently: AgentCore's Code
6
+ * Interpreter answers with a `ValidationException` saying the session is "not
7
+ * active", a stream error naming an inactive session, or a
8
+ * `ResourceNotFoundException` on a call that addresses nothing but the session.
9
+ * A caller that has to recognise all of those by message text will miss the
10
+ * next one. An adapter recognises them once and raises this instead, so "start
11
+ * a new session" is one `instanceof` away.
12
+ *
13
+ * Raised only on evidence that names the session. A "not found" that could be
14
+ * about something else in the session (a file a read asked for) is not taken
15
+ * as proof the session is gone.
16
+ *
17
+ * It names the session and the signal that said so — never the request that
18
+ * hit it. Nothing reconnects: the session's files and state are gone, and a
19
+ * session name is not an address (names are not unique), so the only honest
20
+ * next step is a new session.
21
+ */
22
+ export declare class SessionExpiredError extends Error {
23
+ readonly code: "ERR_SESSION_EXPIRED";
24
+ /** The adapter that raised it, e.g. `'agentCoreCodeRunner'`. */
25
+ readonly backend: string;
26
+ /** The backend's id for the session that is gone. */
27
+ readonly sessionId: string;
28
+ /** The service's own name for the signal that said so, e.g. `'ResourceNotFoundException'`. */
29
+ readonly evidence: string;
30
+ constructor(backend: string, sessionId: string, evidence: string);
31
+ }
@@ -0,0 +1,40 @@
1
+ /**
2
+ * `SessionExpiredError` — a remote session that is gone, said ONE way.
3
+ *
4
+ * A managed backend reaps its sessions on its own schedule (a timeout, a stop,
5
+ * a restart), and each service words that differently: AgentCore's Code
6
+ * Interpreter answers with a `ValidationException` saying the session is "not
7
+ * active", a stream error naming an inactive session, or a
8
+ * `ResourceNotFoundException` on a call that addresses nothing but the session.
9
+ * A caller that has to recognise all of those by message text will miss the
10
+ * next one. An adapter recognises them once and raises this instead, so "start
11
+ * a new session" is one `instanceof` away.
12
+ *
13
+ * Raised only on evidence that names the session. A "not found" that could be
14
+ * about something else in the session (a file a read asked for) is not taken
15
+ * as proof the session is gone.
16
+ *
17
+ * It names the session and the signal that said so — never the request that
18
+ * hit it. Nothing reconnects: the session's files and state are gone, and a
19
+ * session name is not an address (names are not unique), so the only honest
20
+ * next step is a new session.
21
+ */
22
+ export class SessionExpiredError extends Error {
23
+ code = 'ERR_SESSION_EXPIRED';
24
+ /** The adapter that raised it, e.g. `'agentCoreCodeRunner'`. */
25
+ backend;
26
+ /** The backend's id for the session that is gone. */
27
+ sessionId;
28
+ /** The service's own name for the signal that said so, e.g. `'ResourceNotFoundException'`. */
29
+ evidence;
30
+ constructor(backend, sessionId, evidence) {
31
+ super(`${backend}: session ${sessionId} is no longer active (${evidence}). The service ends a ` +
32
+ 'session at its timeout or when it is stopped, and its files and state end with it. ' +
33
+ 'Start a new session; nothing reconnects to this one.');
34
+ this.name = 'SessionExpiredError';
35
+ this.backend = backend;
36
+ this.sessionId = sessionId;
37
+ this.evidence = evidence;
38
+ }
39
+ }
40
+ //# sourceMappingURL=sessionExpired.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sessionExpired.js","sourceRoot":"","sources":["../../../src/provider-contract/sessionExpired.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,MAAM,OAAO,mBAAoB,SAAQ,KAAK;IACnC,IAAI,GAAG,qBAA8B,CAAC;IAC/C,gEAAgE;IACvD,OAAO,CAAS;IACzB,qDAAqD;IAC5C,SAAS,CAAS;IAC3B,8FAA8F;IACrF,QAAQ,CAAS;IAE1B,YAAY,OAAe,EAAE,SAAiB,EAAE,QAAgB;QAC9D,KAAK,CACH,GAAG,OAAO,aAAa,SAAS,yBAAyB,QAAQ,wBAAwB;YACvF,qFAAqF;YACrF,sDAAsD,CACzD,CAAC;QACF,IAAI,CAAC,IAAI,GAAG,qBAAqB,CAAC;QAClC,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;QACvB,IAAI,CAAC,SAAS,GAAG,SAAS,CAAC;QAC3B,IAAI,CAAC,QAAQ,GAAG,QAAQ,CAAC;IAC3B,CAAC;CACF"}
@@ -1165,6 +1165,42 @@ export interface CodeSession {
1165
1165
  * the accepted-and-silently-wrong failure.
1166
1166
  */
1167
1167
  stageInputs?(inputs: readonly CodeInput[]): Promise<readonly StagedCodeInput[]>;
1168
+ /**
1169
+ * OPTIONAL — read ONE file back out of the session, whole or not at all.
1170
+ *
1171
+ * `path` is relative to the session's working directory and may not leave
1172
+ * it. An absolute path, a `..` that climbs above the working directory, a
1173
+ * backslash, a leading `~` or a NUL is refused by name before anything is
1174
+ * sent (`CodeSandboxError`, reason `'path-refused'`) — one rule,
1175
+ * `sandboxPath`, shared by every adapter.
1176
+ *
1177
+ * The answer is the file the BACKEND returned for that path, paired to it
1178
+ * by what the backend said it returned. A file the adapter cannot pair with
1179
+ * the path it asked for is refused, never guessed at — a backend that
1180
+ * answers with another file, or with two, has not answered this read.
1181
+ *
1182
+ * `maxBytes` is required: a read names its bound. A file over it is refused
1183
+ * (reason `'file-too-large'`), never cut — a truncated file handed back as
1184
+ * the file is the silent success this port refuses everywhere else.
1185
+ *
1186
+ * Feature-detect with `canReadCodeFiles(session)`.
1187
+ */
1188
+ readFile?(path: string, options: CodeReadOptions): Promise<CodeFile>;
1189
+ /**
1190
+ * OPTIONAL — run ONE shell command in the session.
1191
+ *
1192
+ * It runs arbitrary shell, so an adapter offers it only when the runner was
1193
+ * built with `commands: true`; otherwise the member is ABSENT. Feature-detect
1194
+ * with `canRunCodeCommands(session)`. The command runs in the session's
1195
+ * working directory with the environment `execute` gets, staged-input
1196
+ * manifest included.
1197
+ *
1198
+ * The result says only what the backend reported. The exit status comes
1199
+ * from the backend or not at all: when it reported none, `exitCode` is
1200
+ * absent — unknown, never inferred from an error flag and never defaulted.
1201
+ * stdout and stderr are bounded, and a cut is stated on `truncated`.
1202
+ */
1203
+ runCommand?(command: string, options?: CodeCommandOptions): Promise<CodeCommandResult>;
1168
1204
  /**
1169
1205
  * Release the session.
1170
1206
  *
@@ -1177,13 +1213,138 @@ export interface CodeSession {
1177
1213
  /** Can this session accept staged inputs? The feature-detection law: read the
1178
1214
  * member, never assume it from the adapter's name. */
1179
1215
  export declare function canStageCodeInputs(session: CodeSession): session is CodeSession & Required<Pick<CodeSession, 'stageInputs'>>;
1216
+ /** Can this session read files back out? Read the member, never the adapter's name. */
1217
+ export declare function canReadCodeFiles(session: CodeSession): session is CodeSession & Required<Pick<CodeSession, 'readFile'>>;
1218
+ /** Can this session run shell commands? Absent unless the runner was built
1219
+ * with `commands: true`. Read the member, never the adapter's name. */
1220
+ export declare function canRunCodeCommands(session: CodeSession): session is CodeSession & Required<Pick<CodeSession, 'runCommand'>>;
1221
+ /** How one {@link CodeSession.readFile} is bounded. */
1222
+ export interface CodeReadOptions {
1223
+ /**
1224
+ * The most bytes this read may return. Required, and a positive whole
1225
+ * number: a file larger than this is refused, never cut.
1226
+ */
1227
+ readonly maxBytes: number;
1228
+ /** Stop waiting for the read. */
1229
+ readonly signal?: AbortSignal;
1230
+ }
1231
+ /** One file read back out of a code session — exactly as the backend returned it. */
1232
+ export interface CodeFile {
1233
+ /** The path that was read, in the canonical form the backend was asked for
1234
+ * (`./out//a.csv` → `out/a.csv`). */
1235
+ readonly path: string;
1236
+ /**
1237
+ * The contents. A string when the backend returned TEXT, bytes when it
1238
+ * returned BYTES — decided by which of the two the backend filled, never by
1239
+ * the file's name or extension. A backend that draws no such line
1240
+ * (`localCodeRunner`: a file on disk is bytes) returns bytes, and never
1241
+ * guesses an encoding.
1242
+ */
1243
+ readonly data: string | Uint8Array;
1244
+ /** The size of `data` in bytes (a string's UTF-8 length). */
1245
+ readonly bytes: number;
1246
+ /** The backend's own statement of the media type, when it made one. Never guessed. */
1247
+ readonly mediaType?: string;
1248
+ }
1249
+ /** How one {@link CodeSession.runCommand} is bounded. */
1250
+ export interface CodeCommandOptions {
1251
+ /**
1252
+ * Stop waiting after this many milliseconds. What happens to the command
1253
+ * depends on the backend, and the error says which: a local child process is
1254
+ * killed; a managed sandbox may keep running it.
1255
+ */
1256
+ readonly timeoutMs?: number;
1257
+ /** Stop waiting when this fires. */
1258
+ readonly signal?: AbortSignal;
1259
+ /** Per-stream ceiling for this command's output, in characters. The
1260
+ * runner's own `maxOutputChars` when absent. A cut is stated on `truncated`. */
1261
+ readonly maxOutputChars?: number;
1262
+ /**
1263
+ * A line the command prints when it reaches a point you care about — for
1264
+ * example `make && echo STEP_DONE` with `checkpoint: 'STEP_DONE'`. The
1265
+ * result then says, on `checkpointSeen`, whether stdout held that exact line,
1266
+ * read BEFORE any cut, so a marker printed past `maxOutputChars` is still
1267
+ * found.
1268
+ *
1269
+ * It proves the command reached that line and nothing more: not that it
1270
+ * exited cleanly, and not that anything after it ran. Its absence proves
1271
+ * nothing about why. One line, no line breaks.
1272
+ */
1273
+ readonly checkpoint?: string;
1274
+ }
1275
+ /** What one shell command produced — only what the backend reported. */
1276
+ export interface CodeCommandResult {
1277
+ readonly stdout: string;
1278
+ readonly stderr: string;
1279
+ /**
1280
+ * The exit status the backend reported. ABSENT when it reported none: the
1281
+ * outcome is unknown. Never inferred from {@link CodeCommandResult.isError},
1282
+ * never defaulted, never derived from the output.
1283
+ */
1284
+ readonly exitCode?: number;
1285
+ /**
1286
+ * The backend's own error flag, as it reported it (AgentCore's `isError`);
1287
+ * absent when it reported none. It is NOT an exit status — a command can
1288
+ * fail without it, and it can be set with no exit status at all.
1289
+ */
1290
+ readonly isError?: boolean;
1291
+ /** The signal that ended the command before it exited, when the runner knows
1292
+ * it (`'SIGKILL'`). There is no `exitCode` then, and none is made up. */
1293
+ readonly terminatedBy?: string;
1294
+ /** Present IFF output was cut — see {@link CodeTruncation}. */
1295
+ readonly truncated?: CodeTruncation;
1296
+ /** Present IFF a `checkpoint` was asked for: whether stdout held that line. */
1297
+ readonly checkpointSeen?: boolean;
1298
+ }
1299
+ /**
1300
+ * Present IFF output was cut, and then it says by how much.
1301
+ *
1302
+ * Load-bearing, not politeness. A runner exists so big data is computed
1303
+ * outside the context window instead of pasted into it; a runner that
1304
+ * quietly slices its own output to fit is the same bug wearing a different
1305
+ * hat, and the model would go on to reason over a truncated table it was
1306
+ * never told was truncated. An unstated slice is a silent success.
1307
+ */
1308
+ export interface CodeTruncation {
1309
+ readonly stdout?: boolean;
1310
+ readonly stderr?: boolean;
1311
+ /** The pre-truncation length, in characters, of whichever stream was cut. */
1312
+ readonly ofChars?: number;
1313
+ }
1180
1314
  /** What one execution produced. */
1181
1315
  export interface CodeResult {
1182
- /** Did the code run to completion without an error exit? */
1183
- readonly ok: boolean;
1316
+ /**
1317
+ * Did the code run to completion without an error exit? WHAT THE RUNNER
1318
+ * REPORTED, nothing more.
1319
+ *
1320
+ * `true` or `false` only when the backend said so: an exit status, or its
1321
+ * own error verdict. ABSENT when it reported neither — the outcome is
1322
+ * unknown, and an absent `ok` is never success. (Before this was optional,
1323
+ * `agentCoreCodeRunner` filled `true` from silence.) A `false` is told
1324
+ * apart by the fields below: a program that exited non-zero (`exitCode`), a
1325
+ * backend error with no exit status (`serviceError`, where the run is
1326
+ * unconfirmed), and a process ended before it exited (`terminatedBy`).
1327
+ */
1328
+ readonly ok?: boolean;
1184
1329
  readonly stdout: string;
1185
1330
  readonly stderr: string;
1331
+ /** The exit status — exactly when the runner reported one. Never inferred
1332
+ * from an error flag, never defaulted. */
1186
1333
  readonly exitCode?: number;
1334
+ /**
1335
+ * `true` when the backend flagged its answer as an error and reported NO
1336
+ * exit status: whether the code ran at all is not confirmed. That is not a
1337
+ * program that failed — a program that ran and failed has an `exitCode`.
1338
+ * `ok` is `false` alongside it.
1339
+ */
1340
+ readonly serviceError?: true;
1341
+ /**
1342
+ * The signal that ended the process before it exited, when the runner knows
1343
+ * it (`'SIGKILL'`): there is no exit status then, and none is made up. A
1344
+ * local child the operating system ended, or one the runner ended because
1345
+ * its output passed the buffer ceiling. `ok` is `false` alongside it.
1346
+ */
1347
+ readonly terminatedBy?: string;
1187
1348
  /** Files the run produced, described rather than inlined — the whole point is
1188
1349
  * that big data does not enter the window. All fields beyond the original
1189
1350
  * `{ name, bytes, uri? }` are ADDITIVE (9.22.0) and honest about absence:
@@ -1221,19 +1382,7 @@ export interface CodeResult {
1221
1382
  readonly data?: string | Uint8Array;
1222
1383
  readonly ref?: string;
1223
1384
  }[];
1224
- /**
1225
- * Present IFF output was cut, and then it says by how much.
1226
- *
1227
- * Load-bearing, not politeness. A runner exists so big data is computed
1228
- * outside the context window instead of pasted into it; a runner that
1229
- * quietly slices its own output to fit is the same bug wearing a different
1230
- * hat, and the model would go on to reason over a truncated table it was
1231
- * never told was truncated. An unstated slice is a silent success.
1232
- */
1233
- readonly truncated?: {
1234
- readonly stdout?: boolean;
1235
- readonly stderr?: boolean;
1236
- /** The pre-truncation length, in characters, of whichever stream was cut. */
1237
- readonly ofChars?: number;
1238
- };
1385
+ /** Present IFF output was cut — see {@link CodeTruncation}. An unstated
1386
+ * slice is a silent success. */
1387
+ readonly truncated?: CodeTruncation;
1239
1388
  }
@@ -50,4 +50,13 @@ export const STAGED_INPUTS_ENV = 'AF_STAGED_INPUTS';
50
50
  export function canStageCodeInputs(session) {
51
51
  return typeof session.stageInputs === 'function';
52
52
  }
53
+ /** Can this session read files back out? Read the member, never the adapter's name. */
54
+ export function canReadCodeFiles(session) {
55
+ return typeof session.readFile === 'function';
56
+ }
57
+ /** Can this session run shell commands? Absent unless the runner was built
58
+ * with `commands: true`. Read the member, never the adapter's name. */
59
+ export function canRunCodeCommands(session) {
60
+ return typeof session.runCommand === 'function';
61
+ }
53
62
  //# sourceMappingURL=types.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/provider-contract/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AA8OH;;;;GAIG;AACH,MAAM,CAAC,MAAM,2BAA2B,GAAwB,MAAM,CAAC,MAAM,CAAC;IAC5E,MAAM;IACN,WAAW;CACZ,CAAC,CAAC;AA0sBH;;;;;;GAMG;AACH,MAAM,UAAU,cAAc,CAC5B,OAAsC,EACtC,UAAgC;IAEhC,IAAI,CAAC,OAAO;QAAE,OAAO,KAAK,CAAC;IAC3B,IAAI,UAAU,KAAK,WAAW;QAAE,OAAO,IAAI,CAAC;IAC5C,OAAO,OAAO,CAAC,OAAO,EAAE,QAAQ,CAAC,UAAU,CAAC,KAAK,IAAI,CAAC;AACxD,CAAC;AAqID;;;;;;;;;GASG;AACH,MAAM,CAAC,MAAM,iBAAiB,GAAG,kBAAkB,CAAC;AAgGpD;uDACuD;AACvD,MAAM,UAAU,kBAAkB,CAChC,OAAoB;IAEpB,OAAO,OAAO,OAAO,CAAC,WAAW,KAAK,UAAU,CAAC;AACnD,CAAC"}
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/provider-contract/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AA8OH;;;;GAIG;AACH,MAAM,CAAC,MAAM,2BAA2B,GAAwB,MAAM,CAAC,MAAM,CAAC;IAC5E,MAAM;IACN,WAAW;CACZ,CAAC,CAAC;AA0sBH;;;;;;GAMG;AACH,MAAM,UAAU,cAAc,CAC5B,OAAsC,EACtC,UAAgC;IAEhC,IAAI,CAAC,OAAO;QAAE,OAAO,KAAK,CAAC;IAC3B,IAAI,UAAU,KAAK,WAAW;QAAE,OAAO,IAAI,CAAC;IAC5C,OAAO,OAAO,CAAC,OAAO,EAAE,QAAQ,CAAC,UAAU,CAAC,KAAK,IAAI,CAAC;AACxD,CAAC;AAqID;;;;;;;;;GASG;AACH,MAAM,CAAC,MAAM,iBAAiB,GAAG,kBAAkB,CAAC;AAoIpD;uDACuD;AACvD,MAAM,UAAU,kBAAkB,CAChC,OAAoB;IAEpB,OAAO,OAAO,OAAO,CAAC,WAAW,KAAK,UAAU,CAAC;AACnD,CAAC;AAED,uFAAuF;AACvF,MAAM,UAAU,gBAAgB,CAC9B,OAAoB;IAEpB,OAAO,OAAO,OAAO,CAAC,QAAQ,KAAK,UAAU,CAAC;AAChD,CAAC;AAED;wEACwE;AACxE,MAAM,UAAU,kBAAkB,CAChC,OAAoB;IAEpB,OAAO,OAAO,OAAO,CAAC,UAAU,KAAK,UAAU,CAAC;AAClD,CAAC"}