@finalai/final-agent-provider 0.6.4 → 0.8.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 (106) hide show
  1. package/HOSTING.md +4 -4
  2. package/README.md +113 -2
  3. package/dist/modules/authoring-final-channel.mjs +2 -2
  4. package/dist/modules/authoring-final-channel.mjs.map +2 -2
  5. package/dist/modules/channel-factories.d.mts +5 -7
  6. package/dist/modules/channel-factories.mjs +4 -50
  7. package/dist/modules/channel-factories.mjs.map +2 -2
  8. package/dist/modules/channels/channel-utils.d.mts +132 -0
  9. package/dist/modules/channels/channel-utils.mjs +445 -0
  10. package/dist/modules/channels/channel-utils.mjs.map +7 -0
  11. package/dist/modules/channels/delivery.d.mts +5 -5
  12. package/dist/modules/channels/delivery.mjs.map +1 -1
  13. package/dist/modules/channels/direct-messaging.d.mts +2 -2
  14. package/dist/modules/channels/direct-messaging.mjs.map +2 -2
  15. package/dist/modules/channels/discord-dispatch.d.mts +17 -0
  16. package/dist/modules/channels/discord-dispatch.mjs +139 -0
  17. package/dist/modules/channels/discord-dispatch.mjs.map +7 -0
  18. package/dist/modules/channels/discord-gateway.d.mts +19 -0
  19. package/dist/modules/channels/discord-gateway.mjs +233 -0
  20. package/dist/modules/channels/discord-gateway.mjs.map +7 -0
  21. package/dist/modules/channels/discord.d.mts +9 -0
  22. package/dist/modules/channels/discord.mjs +904 -0
  23. package/dist/modules/channels/discord.mjs.map +7 -0
  24. package/dist/modules/channels/fake-platform.d.mts +2 -7
  25. package/dist/modules/channels/fake-platform.mjs +2 -38
  26. package/dist/modules/channels/fake-platform.mjs.map +2 -2
  27. package/dist/modules/channels/github.d.mts +5 -0
  28. package/dist/modules/channels/github.mjs +720 -0
  29. package/dist/modules/channels/github.mjs.map +7 -0
  30. package/dist/modules/channels/group-messaging.d.mts +2 -2
  31. package/dist/modules/channels/group-messaging.mjs.map +2 -2
  32. package/dist/modules/channels/index.d.mts +7 -3
  33. package/dist/modules/channels/index.mjs +7 -3
  34. package/dist/modules/channels/index.mjs.map +2 -2
  35. package/dist/modules/channels/linear.d.mts +4 -0
  36. package/dist/modules/channels/linear.mjs +621 -0
  37. package/dist/modules/channels/linear.mjs.map +7 -0
  38. package/dist/modules/channels/messaging-channel.d.mts +3 -3
  39. package/dist/modules/channels/messaging-channel.mjs +2 -2
  40. package/dist/modules/channels/messaging-channel.mjs.map +2 -2
  41. package/dist/modules/channels/phone.d.mts +8 -0
  42. package/dist/modules/channels/phone.mjs +382 -0
  43. package/dist/modules/channels/phone.mjs.map +7 -0
  44. package/dist/modules/channels/projection.mjs.map +1 -1
  45. package/dist/modules/channels/reply-receipts.d.mts +31 -0
  46. package/dist/modules/channels/reply-receipts.mjs +63 -0
  47. package/dist/modules/channels/reply-receipts.mjs.map +7 -0
  48. package/dist/modules/channels/routing.d.mts +1 -0
  49. package/dist/modules/channels/routing.mjs +5 -1
  50. package/dist/modules/channels/routing.mjs.map +2 -2
  51. package/dist/modules/channels/slack.d.mts +7 -0
  52. package/dist/modules/channels/slack.mjs +1134 -0
  53. package/dist/modules/channels/slack.mjs.map +7 -0
  54. package/dist/modules/channels/voice-recording.d.mts +7 -0
  55. package/dist/modules/channels/voice-recording.mjs +49 -0
  56. package/dist/modules/channels/voice-recording.mjs.map +7 -0
  57. package/dist/modules/channels/voice.d.mts +33 -0
  58. package/dist/modules/channels/voice.mjs +851 -0
  59. package/dist/modules/channels/voice.mjs.map +7 -0
  60. package/dist/modules/channels/webhook.d.mts +5 -0
  61. package/dist/modules/channels/webhook.mjs +76 -0
  62. package/dist/modules/channels/webhook.mjs.map +7 -0
  63. package/dist/modules/harnesses/acp-describe.mjs +1 -1
  64. package/dist/modules/harnesses/acp-describe.mjs.map +2 -2
  65. package/dist/modules/harnesses/fidelity.mjs +17 -17
  66. package/dist/modules/harnesses/fidelity.mjs.map +2 -2
  67. package/dist/modules/harnesses/remote-url.mjs.map +1 -1
  68. package/dist/modules/runtime/remote-host.mjs.map +1 -1
  69. package/dist/modules/sandboxes/build-scripts.mjs.map +1 -1
  70. package/dist/modules/sandboxes/bytes.d.mts +1 -0
  71. package/dist/modules/sandboxes/bytes.mjs +7 -1
  72. package/dist/modules/sandboxes/bytes.mjs.map +2 -2
  73. package/dist/modules/sandboxes/computer.mjs +5 -1
  74. package/dist/modules/sandboxes/computer.mjs.map +2 -2
  75. package/dist/modules/sandboxes/computers-api-transport.d.mts +1 -1
  76. package/dist/modules/sandboxes/computers-api-transport.mjs +8 -0
  77. package/dist/modules/sandboxes/computers-api-transport.mjs.map +2 -2
  78. package/dist/modules/sandboxes/device-api.mjs +8 -0
  79. package/dist/modules/sandboxes/device-api.mjs.map +2 -2
  80. package/dist/modules/sandboxes/device.mjs +6 -0
  81. package/dist/modules/sandboxes/device.mjs.map +2 -2
  82. package/dist/modules/sandboxes/paths.mjs.map +1 -1
  83. package/dist/modules/sandboxes/session.d.mts +1 -0
  84. package/dist/modules/sandboxes/session.mjs +106 -36
  85. package/dist/modules/sandboxes/session.mjs.map +3 -3
  86. package/dist/modules/sandboxes/testing/conformance.mjs +3 -0
  87. package/dist/modules/sandboxes/testing/conformance.mjs.map +2 -2
  88. package/dist/modules/sandboxes/testing/fake-machine.mjs +11 -0
  89. package/dist/modules/sandboxes/testing/fake-machine.mjs.map +2 -2
  90. package/dist/modules/sandboxes/transport.d.mts +1 -0
  91. package/dist/modules/sandboxes/transport.mjs.map +2 -2
  92. package/dist/modules/testing/harness.mjs +2 -2
  93. package/dist/modules/testing/harness.mjs.map +1 -1
  94. package/package.json +45 -19
  95. package/dist/modules/channels/address-context.d.mts +0 -7
  96. package/dist/modules/channels/address-context.mjs +0 -80
  97. package/dist/modules/channels/address-context.mjs.map +0 -7
  98. package/dist/modules/channels/agent-events.d.mts +0 -103
  99. package/dist/modules/channels/agent-events.mjs +0 -341
  100. package/dist/modules/channels/agent-events.mjs.map +0 -7
  101. package/dist/modules/channels/agent-schedules.d.mts +0 -25
  102. package/dist/modules/channels/agent-schedules.mjs +0 -96
  103. package/dist/modules/channels/agent-schedules.mjs.map +0 -7
  104. package/dist/modules/channels/service-input.d.mts +0 -22
  105. package/dist/modules/channels/service-input.mjs +0 -32
  106. package/dist/modules/channels/service-input.mjs.map +0 -7
@@ -1,4 +1,4 @@
1
- import type { ComputersApiClientIface } from "./computers-api.mjs";
1
+ import { type ComputersApiClientIface } from "./computers-api.mjs";
2
2
  import type { SandboxTransportIface } from "./transport.mjs";
3
3
  export declare const DEFAULT_EXEC_USER = "user";
4
4
  export interface CreateComputersApiTransportArgsIface {
@@ -1,7 +1,12 @@
1
1
  import { SandboxEntryType } from "@finalai/agent-provider/sandbox";
2
2
  import { decodeBase64, encodeBase64 } from "./bytes.mjs";
3
+ import {
4
+ isComputersApiError,
5
+ isComputersApiStatus
6
+ } from "./computers-api.mjs";
3
7
  import { shellQuote } from "./paths.mjs";
4
8
  const FILE_CHUNK_BYTES = 1024 * 1024;
9
+ const PROCESS_GONE_MESSAGE = /process not found|stale boot id/i;
5
10
  const OUTPUT_WAIT_MS = 25e3;
6
11
  const DEFAULT_EXEC_USER = "user";
7
12
  const toOutput = (output) => ({
@@ -186,6 +191,9 @@ const createComputersApiTransport = (args) => {
186
191
  });
187
192
  }
188
193
  },
194
+ // Managed processes run in the computer and are found again by id and
195
+ // boot until it boots again or is deleted.
196
+ processGone: (cause) => isComputersApiStatus(cause, 404) || isComputersApiStatus(cause, 409) && isComputersApiError(cause) && PROCESS_GONE_MESSAGE.test(cause.message),
189
197
  close: () => void 0
190
198
  };
191
199
  };
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../../src/sandboxes/computers-api-transport.ts"],
4
- "sourcesContent": ["import { SandboxEntryType } from '@finalai/agent-provider/sandbox';\nimport { decodeBase64, encodeBase64 } from \"./bytes.mjs\";\nimport type {\n ComputerProcessOutputIface,\n ComputersApiClientIface,\n ExecBodyIface,\n} from \"./computers-api.mjs\";\nimport { shellQuote } from \"./paths.mjs\";\nimport type {\n SandboxTransportIface,\n TransportDirEntryIface,\n TransportOutputIface,\n TransportStatIface,\n} from \"./transport.mjs\";\n\n// The public Computers API as a sandbox transport: files are ranged base64 reads and\n// replace-then-append writes; processes are managed processes with offset-polled\n// output. The API has no stat, list or remove, so those run as one short command.\n\nconst FILE_CHUNK_BYTES = 1024 * 1024;\n// The service caps a long-poll at 30 s.\nconst OUTPUT_WAIT_MS = 25_000;\nexport const DEFAULT_EXEC_USER = 'user';\n\nconst toOutput = (output: ComputerProcessOutputIface): TransportOutputIface => ({\n stdout: {\n data: decodeBase64(output.stdout.dataB64),\n nextOffset: output.stdout.nextOffset,\n eof: output.stdout.eof,\n },\n stderr: {\n data: decodeBase64(output.stderr.dataB64),\n nextOffset: output.stderr.nextOffset,\n eof: output.stderr.eof,\n },\n exited: output.state === 'exited',\n exitCode: output.result?.exitCode ?? null,\n exitSignal: output.result?.signal ?? null,\n});\n\nconst statTypes = new Map([\n ['regular file', SandboxEntryType.File],\n ['regular empty file', SandboxEntryType.File],\n ['directory', SandboxEntryType.Directory],\n ['symbolic link', SandboxEntryType.Symlink],\n]);\nconst findTypes = new Map([\n ['f', SandboxEntryType.File],\n ['d', SandboxEntryType.Directory],\n ['l', SandboxEntryType.Symlink],\n]);\n\nexport interface CreateComputersApiTransportArgsIface {\n client: ComputersApiClientIface;\n computerId: string;\n user?: string;\n // How long a call waits for a waking computer to accept processes.\n readyTimeoutMs?: number;\n}\n\nexport const createComputersApiTransport = (\n args: CreateComputersApiTransportArgsIface,\n): SandboxTransportIface => {\n const user = args.user ?? DEFAULT_EXEC_USER;\n const readyTimeoutMs = args.readyTimeoutMs ?? 120_000;\n\n // A short helper command, read to completion.\n const capture = async (\n script: string,\n ): Promise<{ exitCode: number | null; stdout: string; stderr: string }> => {\n const result = await args.client.run(args.computerId, {\n command: script,\n cwd: '/',\n user,\n readyTimeoutMs,\n autoResume: false,\n timeoutMs: 60_000,\n });\n let output = toOutput(result);\n const stdout: Uint8Array[] = [output.stdout.data];\n const stderr: Uint8Array[] = [output.stderr.data];\n while (!(output.exited && output.stdout.eof && output.stderr.eof)) {\n output = toOutput(\n await args.client.output({\n computerId: args.computerId,\n processId: result.id,\n bootId: result.bootId,\n stdoutOffset: output.stdout.nextOffset,\n stderrOffset: output.stderr.nextOffset,\n waitMs: OUTPUT_WAIT_MS,\n }),\n );\n stdout.push(output.stdout.data);\n stderr.push(output.stderr.data);\n }\n const decode = (chunks: Uint8Array[]): string => {\n const decoder = new TextDecoder();\n return (\n chunks.map((chunk) => decoder.decode(chunk, { stream: true })).join('') + decoder.decode()\n );\n };\n return { exitCode: output.exitCode, stdout: decode(stdout), stderr: decode(stderr) };\n };\n\n const failIfNonZero = (\n label: string,\n result: { exitCode: number | null; stderr: string },\n ): void => {\n if (result.exitCode !== 0)\n throw new Error(`${label}: ${result.stderr.trim() || `exit ${result.exitCode}`}`);\n };\n\n return {\n kind: 'computers-api',\n fileChunkBytes: FILE_CHUNK_BYTES,\n outputWaitMs: OUTPUT_WAIT_MS,\n stat: async ({ path }): Promise<TransportStatIface | null> => {\n const quoted = shellQuote(path);\n const result = await capture(\n `if [ ! -e ${quoted} ] && [ ! -L ${quoted} ]; then echo missing; exit 0; fi; stat -c '%F|%s|%Y|%a' -- ${quoted}`,\n );\n failIfNonZero(`stat ${path}`, result);\n const line = result.stdout.trim();\n if (line === 'missing') return null;\n const [kind, size, mtime, mode] = line.split('|');\n return {\n type: statTypes.get(kind ?? '') ?? SandboxEntryType.Other,\n size: Number(size ?? 0),\n modifiedAtMs: mtime == null ? null : Number(mtime) * 1000,\n mode: mode == null ? null : Number.parseInt(mode, 8),\n };\n },\n readDir: async ({ path }): Promise<TransportDirEntryIface[]> => {\n const quoted = shellQuote(path);\n const result = await capture(\n `[ -d ${quoted} ] || { echo 'Not a directory' >&2; exit 2; }; find ${quoted} -mindepth 1 -maxdepth 1 -printf '%y\\\\t%s\\\\t%f\\\\0'`,\n );\n failIfNonZero(`list ${path}`, result);\n return result.stdout\n .split('\\0')\n .filter((entry) => entry !== '')\n .map((entry) => {\n const [kind, size, ...name] = entry.split('\\t');\n return {\n name: name.join('\\t'),\n type: findTypes.get(kind ?? '') ?? SandboxEntryType.Other,\n size: size == null ? null : Number(size),\n };\n });\n },\n readChunk: async ({ path, offset, length, signal }) => {\n const read = await args.client.readFile({\n computerId: args.computerId,\n path,\n offset,\n length,\n signal,\n });\n return { bytes: decodeBase64(read.dataB64), eof: read.eof };\n },\n writeChunk: async ({ path, offset, bytes, signal }) => {\n await args.client.writeFile({\n computerId: args.computerId,\n path,\n dataB64: encodeBase64(bytes),\n append: offset > 0,\n signal,\n });\n },\n createDirectory: async ({ path }) => {\n failIfNonZero(`mkdir ${path}`, await capture(`mkdir -p -- ${shellQuote(path)}`));\n },\n remove: async ({ path, recursive, force }) => {\n const quoted = shellQuote(path);\n const flags = `${recursive ? 'r' : ''}${force ? 'f' : ''}`;\n const removeDirectory = recursive ? `rm -${flags} -- ${quoted}` : `rmdir -- ${quoted}`;\n const removeFile = `rm ${force ? '-f ' : ''}-- ${quoted}`;\n failIfNonZero(\n `remove ${path}`,\n await capture(\n `if [ -d ${quoted} ] && [ ! -L ${quoted} ]; then ${removeDirectory}; else ${removeFile}; fi`,\n ),\n );\n },\n exec: async ({ command, cwd, env, timeoutMs }) => {\n const body: ExecBodyIface = { command, cwd, env, user, readyTimeoutMs, autoResume: false };\n if (timeoutMs != null) body.timeoutMs = timeoutMs;\n return args.client.exec(args.computerId, body);\n },\n output: async ({ process, stdoutOffset, stderrOffset, waitMs, signal }) =>\n toOutput(\n await args.client.output({\n computerId: args.computerId,\n processId: process.id,\n bootId: process.bootId,\n stdoutOffset,\n stderrOffset,\n waitMs,\n signal,\n }),\n ),\n input: async ({ process, data, eof, signal, terminate }) => {\n if (terminate === true) {\n await args.client.terminate({\n computerId: args.computerId,\n processId: process.id,\n bootId: process.bootId,\n });\n return;\n }\n const base = { bootId: process.bootId };\n if (data != null && data.byteLength > 0) {\n await args.client.input({\n computerId: args.computerId,\n processId: process.id,\n body: { ...base, dataB64: encodeBase64(data) },\n });\n }\n if (signal != null) {\n await args.client.input({\n computerId: args.computerId,\n processId: process.id,\n body: { ...base, signal },\n });\n }\n if (eof === true) {\n await args.client.input({\n computerId: args.computerId,\n processId: process.id,\n body: { ...base, eof: true },\n });\n }\n },\n close: () => undefined,\n };\n};\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import { SandboxEntryType } from '@finalai/agent-provider/sandbox';\nimport { decodeBase64, encodeBase64 } from \"./bytes.mjs\";\nimport {\n isComputersApiError,\n isComputersApiStatus,\n type ComputerProcessOutputIface,\n type ComputersApiClientIface,\n type ExecBodyIface,\n} from \"./computers-api.mjs\";\nimport { shellQuote } from \"./paths.mjs\";\nimport type {\n SandboxTransportIface,\n TransportDirEntryIface,\n TransportOutputIface,\n TransportStatIface,\n} from \"./transport.mjs\";\n\n// The public Computers API as a sandbox transport: files are ranged base64 reads and\n// replace-then-append writes; processes are managed processes with offset-polled\n// output. The API has no stat, list or remove, so those run as one short command.\n\nconst FILE_CHUNK_BYTES = 1024 * 1024;\n// The guest agent's answers (409) for an unknown process and one from an earlier boot.\nconst PROCESS_GONE_MESSAGE = /process not found|stale boot id/i;\n// The service caps a long-poll at 30 s.\nconst OUTPUT_WAIT_MS = 25_000;\nexport const DEFAULT_EXEC_USER = 'user';\n\nconst toOutput = (output: ComputerProcessOutputIface): TransportOutputIface => ({\n stdout: {\n data: decodeBase64(output.stdout.dataB64),\n nextOffset: output.stdout.nextOffset,\n eof: output.stdout.eof,\n },\n stderr: {\n data: decodeBase64(output.stderr.dataB64),\n nextOffset: output.stderr.nextOffset,\n eof: output.stderr.eof,\n },\n exited: output.state === 'exited',\n exitCode: output.result?.exitCode ?? null,\n exitSignal: output.result?.signal ?? null,\n});\n\nconst statTypes = new Map([\n ['regular file', SandboxEntryType.File],\n ['regular empty file', SandboxEntryType.File],\n ['directory', SandboxEntryType.Directory],\n ['symbolic link', SandboxEntryType.Symlink],\n]);\nconst findTypes = new Map([\n ['f', SandboxEntryType.File],\n ['d', SandboxEntryType.Directory],\n ['l', SandboxEntryType.Symlink],\n]);\n\nexport interface CreateComputersApiTransportArgsIface {\n client: ComputersApiClientIface;\n computerId: string;\n user?: string;\n // How long a call waits for a waking computer to accept processes.\n readyTimeoutMs?: number;\n}\n\nexport const createComputersApiTransport = (\n args: CreateComputersApiTransportArgsIface,\n): SandboxTransportIface => {\n const user = args.user ?? DEFAULT_EXEC_USER;\n const readyTimeoutMs = args.readyTimeoutMs ?? 120_000;\n\n // A short helper command, read to completion.\n const capture = async (\n script: string,\n ): Promise<{ exitCode: number | null; stdout: string; stderr: string }> => {\n const result = await args.client.run(args.computerId, {\n command: script,\n cwd: '/',\n user,\n readyTimeoutMs,\n autoResume: false,\n timeoutMs: 60_000,\n });\n let output = toOutput(result);\n const stdout: Uint8Array[] = [output.stdout.data];\n const stderr: Uint8Array[] = [output.stderr.data];\n while (!(output.exited && output.stdout.eof && output.stderr.eof)) {\n output = toOutput(\n await args.client.output({\n computerId: args.computerId,\n processId: result.id,\n bootId: result.bootId,\n stdoutOffset: output.stdout.nextOffset,\n stderrOffset: output.stderr.nextOffset,\n waitMs: OUTPUT_WAIT_MS,\n }),\n );\n stdout.push(output.stdout.data);\n stderr.push(output.stderr.data);\n }\n const decode = (chunks: Uint8Array[]): string => {\n const decoder = new TextDecoder();\n return (\n chunks.map((chunk) => decoder.decode(chunk, { stream: true })).join('') + decoder.decode()\n );\n };\n return { exitCode: output.exitCode, stdout: decode(stdout), stderr: decode(stderr) };\n };\n\n const failIfNonZero = (\n label: string,\n result: { exitCode: number | null; stderr: string },\n ): void => {\n if (result.exitCode !== 0)\n throw new Error(`${label}: ${result.stderr.trim() || `exit ${result.exitCode}`}`);\n };\n\n return {\n kind: 'computers-api',\n fileChunkBytes: FILE_CHUNK_BYTES,\n outputWaitMs: OUTPUT_WAIT_MS,\n stat: async ({ path }): Promise<TransportStatIface | null> => {\n const quoted = shellQuote(path);\n const result = await capture(\n `if [ ! -e ${quoted} ] && [ ! -L ${quoted} ]; then echo missing; exit 0; fi; stat -c '%F|%s|%Y|%a' -- ${quoted}`,\n );\n failIfNonZero(`stat ${path}`, result);\n const line = result.stdout.trim();\n if (line === 'missing') return null;\n const [kind, size, mtime, mode] = line.split('|');\n return {\n type: statTypes.get(kind ?? '') ?? SandboxEntryType.Other,\n size: Number(size ?? 0),\n modifiedAtMs: mtime == null ? null : Number(mtime) * 1000,\n mode: mode == null ? null : Number.parseInt(mode, 8),\n };\n },\n readDir: async ({ path }): Promise<TransportDirEntryIface[]> => {\n const quoted = shellQuote(path);\n const result = await capture(\n `[ -d ${quoted} ] || { echo 'Not a directory' >&2; exit 2; }; find ${quoted} -mindepth 1 -maxdepth 1 -printf '%y\\\\t%s\\\\t%f\\\\0'`,\n );\n failIfNonZero(`list ${path}`, result);\n return result.stdout\n .split('\\0')\n .filter((entry) => entry !== '')\n .map((entry) => {\n const [kind, size, ...name] = entry.split('\\t');\n return {\n name: name.join('\\t'),\n type: findTypes.get(kind ?? '') ?? SandboxEntryType.Other,\n size: size == null ? null : Number(size),\n };\n });\n },\n readChunk: async ({ path, offset, length, signal }) => {\n const read = await args.client.readFile({\n computerId: args.computerId,\n path,\n offset,\n length,\n signal,\n });\n return { bytes: decodeBase64(read.dataB64), eof: read.eof };\n },\n writeChunk: async ({ path, offset, bytes, signal }) => {\n await args.client.writeFile({\n computerId: args.computerId,\n path,\n dataB64: encodeBase64(bytes),\n append: offset > 0,\n signal,\n });\n },\n createDirectory: async ({ path }) => {\n failIfNonZero(`mkdir ${path}`, await capture(`mkdir -p -- ${shellQuote(path)}`));\n },\n remove: async ({ path, recursive, force }) => {\n const quoted = shellQuote(path);\n const flags = `${recursive ? 'r' : ''}${force ? 'f' : ''}`;\n const removeDirectory = recursive ? `rm -${flags} -- ${quoted}` : `rmdir -- ${quoted}`;\n const removeFile = `rm ${force ? '-f ' : ''}-- ${quoted}`;\n failIfNonZero(\n `remove ${path}`,\n await capture(\n `if [ -d ${quoted} ] && [ ! -L ${quoted} ]; then ${removeDirectory}; else ${removeFile}; fi`,\n ),\n );\n },\n exec: async ({ command, cwd, env, timeoutMs }) => {\n const body: ExecBodyIface = { command, cwd, env, user, readyTimeoutMs, autoResume: false };\n if (timeoutMs != null) body.timeoutMs = timeoutMs;\n return args.client.exec(args.computerId, body);\n },\n output: async ({ process, stdoutOffset, stderrOffset, waitMs, signal }) =>\n toOutput(\n await args.client.output({\n computerId: args.computerId,\n processId: process.id,\n bootId: process.bootId,\n stdoutOffset,\n stderrOffset,\n waitMs,\n signal,\n }),\n ),\n input: async ({ process, data, eof, signal, terminate }) => {\n if (terminate === true) {\n await args.client.terminate({\n computerId: args.computerId,\n processId: process.id,\n bootId: process.bootId,\n });\n return;\n }\n const base = { bootId: process.bootId };\n if (data != null && data.byteLength > 0) {\n await args.client.input({\n computerId: args.computerId,\n processId: process.id,\n body: { ...base, dataB64: encodeBase64(data) },\n });\n }\n if (signal != null) {\n await args.client.input({\n computerId: args.computerId,\n processId: process.id,\n body: { ...base, signal },\n });\n }\n if (eof === true) {\n await args.client.input({\n computerId: args.computerId,\n processId: process.id,\n body: { ...base, eof: true },\n });\n }\n },\n // Managed processes run in the computer and are found again by id and\n // boot until it boots again or is deleted.\n processGone: (cause) =>\n isComputersApiStatus(cause, 404) ||\n (isComputersApiStatus(cause, 409) &&\n isComputersApiError(cause) &&\n PROCESS_GONE_MESSAGE.test(cause.message)),\n close: () => undefined,\n };\n};\n"],
5
+ "mappings": "AAAA,SAAS,wBAAwB;AACjC,SAAS,cAAc,oBAAoB;AAC3C;AAAA,EACE;AAAA,EACA;AAAA,OAIK;AACP,SAAS,kBAAkB;AAY3B,MAAM,mBAAmB,OAAO;AAEhC,MAAM,uBAAuB;AAE7B,MAAM,iBAAiB;AAChB,MAAM,oBAAoB;AAEjC,MAAM,WAAW,CAAC,YAA8D;AAAA,EAC9E,QAAQ;AAAA,IACN,MAAM,aAAa,OAAO,OAAO,OAAO;AAAA,IACxC,YAAY,OAAO,OAAO;AAAA,IAC1B,KAAK,OAAO,OAAO;AAAA,EACrB;AAAA,EACA,QAAQ;AAAA,IACN,MAAM,aAAa,OAAO,OAAO,OAAO;AAAA,IACxC,YAAY,OAAO,OAAO;AAAA,IAC1B,KAAK,OAAO,OAAO;AAAA,EACrB;AAAA,EACA,QAAQ,OAAO,UAAU;AAAA,EACzB,UAAU,OAAO,QAAQ,YAAY;AAAA,EACrC,YAAY,OAAO,QAAQ,UAAU;AACvC;AAEA,MAAM,YAAY,oBAAI,IAAI;AAAA,EACxB,CAAC,gBAAgB,iBAAiB,IAAI;AAAA,EACtC,CAAC,sBAAsB,iBAAiB,IAAI;AAAA,EAC5C,CAAC,aAAa,iBAAiB,SAAS;AAAA,EACxC,CAAC,iBAAiB,iBAAiB,OAAO;AAC5C,CAAC;AACD,MAAM,YAAY,oBAAI,IAAI;AAAA,EACxB,CAAC,KAAK,iBAAiB,IAAI;AAAA,EAC3B,CAAC,KAAK,iBAAiB,SAAS;AAAA,EAChC,CAAC,KAAK,iBAAiB,OAAO;AAChC,CAAC;AAUM,MAAM,8BAA8B,CACzC,SAC0B;AAC1B,QAAM,OAAO,KAAK,QAAQ;AAC1B,QAAM,iBAAiB,KAAK,kBAAkB;AAG9C,QAAM,UAAU,OACd,WACyE;AACzE,UAAM,SAAS,MAAM,KAAK,OAAO,IAAI,KAAK,YAAY;AAAA,MACpD,SAAS;AAAA,MACT,KAAK;AAAA,MACL;AAAA,MACA;AAAA,MACA,YAAY;AAAA,MACZ,WAAW;AAAA,IACb,CAAC;AACD,QAAI,SAAS,SAAS,MAAM;AAC5B,UAAM,SAAuB,CAAC,OAAO,OAAO,IAAI;AAChD,UAAM,SAAuB,CAAC,OAAO,OAAO,IAAI;AAChD,WAAO,EAAE,OAAO,UAAU,OAAO,OAAO,OAAO,OAAO,OAAO,MAAM;AACjE,eAAS;AAAA,QACP,MAAM,KAAK,OAAO,OAAO;AAAA,UACvB,YAAY,KAAK;AAAA,UACjB,WAAW,OAAO;AAAA,UAClB,QAAQ,OAAO;AAAA,UACf,cAAc,OAAO,OAAO;AAAA,UAC5B,cAAc,OAAO,OAAO;AAAA,UAC5B,QAAQ;AAAA,QACV,CAAC;AAAA,MACH;AACA,aAAO,KAAK,OAAO,OAAO,IAAI;AAC9B,aAAO,KAAK,OAAO,OAAO,IAAI;AAAA,IAChC;AACA,UAAM,SAAS,CAAC,WAAiC;AAC/C,YAAM,UAAU,IAAI,YAAY;AAChC,aACE,OAAO,IAAI,CAAC,UAAU,QAAQ,OAAO,OAAO,EAAE,QAAQ,KAAK,CAAC,CAAC,EAAE,KAAK,EAAE,IAAI,QAAQ,OAAO;AAAA,IAE7F;AACA,WAAO,EAAE,UAAU,OAAO,UAAU,QAAQ,OAAO,MAAM,GAAG,QAAQ,OAAO,MAAM,EAAE;AAAA,EACrF;AAEA,QAAM,gBAAgB,CACpB,OACA,WACS;AACT,QAAI,OAAO,aAAa;AACtB,YAAM,IAAI,MAAM,GAAG,KAAK,KAAK,OAAO,OAAO,KAAK,KAAK,QAAQ,OAAO,QAAQ,EAAE,EAAE;AAAA,EACpF;AAEA,SAAO;AAAA,IACL,MAAM;AAAA,IACN,gBAAgB;AAAA,IAChB,cAAc;AAAA,IACd,MAAM,OAAO,EAAE,KAAK,MAA0C;AAC5D,YAAM,SAAS,WAAW,IAAI;AAC9B,YAAM,SAAS,MAAM;AAAA,QACnB,aAAa,MAAM,gBAAgB,MAAM,+DAA+D,MAAM;AAAA,MAChH;AACA,oBAAc,QAAQ,IAAI,IAAI,MAAM;AACpC,YAAM,OAAO,OAAO,OAAO,KAAK;AAChC,UAAI,SAAS,UAAW,QAAO;AAC/B,YAAM,CAAC,MAAM,MAAM,OAAO,IAAI,IAAI,KAAK,MAAM,GAAG;AAChD,aAAO;AAAA,QACL,MAAM,UAAU,IAAI,QAAQ,EAAE,KAAK,iBAAiB;AAAA,QACpD,MAAM,OAAO,QAAQ,CAAC;AAAA,QACtB,cAAc,SAAS,OAAO,OAAO,OAAO,KAAK,IAAI;AAAA,QACrD,MAAM,QAAQ,OAAO,OAAO,OAAO,SAAS,MAAM,CAAC;AAAA,MACrD;AAAA,IACF;AAAA,IACA,SAAS,OAAO,EAAE,KAAK,MAAyC;AAC9D,YAAM,SAAS,WAAW,IAAI;AAC9B,YAAM,SAAS,MAAM;AAAA,QACnB,QAAQ,MAAM,uDAAuD,MAAM;AAAA,MAC7E;AACA,oBAAc,QAAQ,IAAI,IAAI,MAAM;AACpC,aAAO,OAAO,OACX,MAAM,IAAI,EACV,OAAO,CAAC,UAAU,UAAU,EAAE,EAC9B,IAAI,CAAC,UAAU;AACd,cAAM,CAAC,MAAM,MAAM,GAAG,IAAI,IAAI,MAAM,MAAM,GAAI;AAC9C,eAAO;AAAA,UACL,MAAM,KAAK,KAAK,GAAI;AAAA,UACpB,MAAM,UAAU,IAAI,QAAQ,EAAE,KAAK,iBAAiB;AAAA,UACpD,MAAM,QAAQ,OAAO,OAAO,OAAO,IAAI;AAAA,QACzC;AAAA,MACF,CAAC;AAAA,IACL;AAAA,IACA,WAAW,OAAO,EAAE,MAAM,QAAQ,QAAQ,OAAO,MAAM;AACrD,YAAM,OAAO,MAAM,KAAK,OAAO,SAAS;AAAA,QACtC,YAAY,KAAK;AAAA,QACjB;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,MACF,CAAC;AACD,aAAO,EAAE,OAAO,aAAa,KAAK,OAAO,GAAG,KAAK,KAAK,IAAI;AAAA,IAC5D;AAAA,IACA,YAAY,OAAO,EAAE,MAAM,QAAQ,OAAO,OAAO,MAAM;AACrD,YAAM,KAAK,OAAO,UAAU;AAAA,QAC1B,YAAY,KAAK;AAAA,QACjB;AAAA,QACA,SAAS,aAAa,KAAK;AAAA,QAC3B,QAAQ,SAAS;AAAA,QACjB;AAAA,MACF,CAAC;AAAA,IACH;AAAA,IACA,iBAAiB,OAAO,EAAE,KAAK,MAAM;AACnC,oBAAc,SAAS,IAAI,IAAI,MAAM,QAAQ,eAAe,WAAW,IAAI,CAAC,EAAE,CAAC;AAAA,IACjF;AAAA,IACA,QAAQ,OAAO,EAAE,MAAM,WAAW,MAAM,MAAM;AAC5C,YAAM,SAAS,WAAW,IAAI;AAC9B,YAAM,QAAQ,GAAG,YAAY,MAAM,EAAE,GAAG,QAAQ,MAAM,EAAE;AACxD,YAAM,kBAAkB,YAAY,OAAO,KAAK,OAAO,MAAM,KAAK,YAAY,MAAM;AACpF,YAAM,aAAa,MAAM,QAAQ,QAAQ,EAAE,MAAM,MAAM;AACvD;AAAA,QACE,UAAU,IAAI;AAAA,QACd,MAAM;AAAA,UACJ,WAAW,MAAM,gBAAgB,MAAM,YAAY,eAAe,UAAU,UAAU;AAAA,QACxF;AAAA,MACF;AAAA,IACF;AAAA,IACA,MAAM,OAAO,EAAE,SAAS,KAAK,KAAK,UAAU,MAAM;AAChD,YAAM,OAAsB,EAAE,SAAS,KAAK,KAAK,MAAM,gBAAgB,YAAY,MAAM;AACzF,UAAI,aAAa,KAAM,MAAK,YAAY;AACxC,aAAO,KAAK,OAAO,KAAK,KAAK,YAAY,IAAI;AAAA,IAC/C;AAAA,IACA,QAAQ,OAAO,EAAE,SAAS,cAAc,cAAc,QAAQ,OAAO,MACnE;AAAA,MACE,MAAM,KAAK,OAAO,OAAO;AAAA,QACvB,YAAY,KAAK;AAAA,QACjB,WAAW,QAAQ;AAAA,QACnB,QAAQ,QAAQ;AAAA,QAChB;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,MACF,CAAC;AAAA,IACH;AAAA,IACF,OAAO,OAAO,EAAE,SAAS,MAAM,KAAK,QAAQ,UAAU,MAAM;AAC1D,UAAI,cAAc,MAAM;AACtB,cAAM,KAAK,OAAO,UAAU;AAAA,UAC1B,YAAY,KAAK;AAAA,UACjB,WAAW,QAAQ;AAAA,UACnB,QAAQ,QAAQ;AAAA,QAClB,CAAC;AACD;AAAA,MACF;AACA,YAAM,OAAO,EAAE,QAAQ,QAAQ,OAAO;AACtC,UAAI,QAAQ,QAAQ,KAAK,aAAa,GAAG;AACvC,cAAM,KAAK,OAAO,MAAM;AAAA,UACtB,YAAY,KAAK;AAAA,UACjB,WAAW,QAAQ;AAAA,UACnB,MAAM,EAAE,GAAG,MAAM,SAAS,aAAa,IAAI,EAAE;AAAA,QAC/C,CAAC;AAAA,MACH;AACA,UAAI,UAAU,MAAM;AAClB,cAAM,KAAK,OAAO,MAAM;AAAA,UACtB,YAAY,KAAK;AAAA,UACjB,WAAW,QAAQ;AAAA,UACnB,MAAM,EAAE,GAAG,MAAM,OAAO;AAAA,QAC1B,CAAC;AAAA,MACH;AACA,UAAI,QAAQ,MAAM;AAChB,cAAM,KAAK,OAAO,MAAM;AAAA,UACtB,YAAY,KAAK;AAAA,UACjB,WAAW,QAAQ;AAAA,UACnB,MAAM,EAAE,GAAG,MAAM,KAAK,KAAK;AAAA,QAC7B,CAAC;AAAA,MACH;AAAA,IACF;AAAA;AAAA;AAAA,IAGA,aAAa,CAAC,UACZ,qBAAqB,OAAO,GAAG,KAC9B,qBAAqB,OAAO,GAAG,KAC9B,oBAAoB,KAAK,KACzB,qBAAqB,KAAK,MAAM,OAAO;AAAA,IAC3C,OAAO,MAAM;AAAA,EACf;AACF;",
6
6
  "names": []
7
7
  }
@@ -104,6 +104,7 @@ const screenSchema = z.object({ url: z.string(), token: z.string(), expiresAt: z
104
104
  const emptySchema = z.unknown();
105
105
  const DEVICE_API_FILE_CHUNK_BYTES = 4 * 1024 * 1024;
106
106
  const DEVICE_API_OUTPUT_WAIT_MS = 15e3;
107
+ const DEVICE_PROCESS_GONE_MESSAGE = /unknown process|belongs to another device runtime|consumed output has expired/i;
107
108
  var DeviceApiClientErrorCode = /* @__PURE__ */ ((DeviceApiClientErrorCode2) => {
108
109
  DeviceApiClientErrorCode2["CredentialMissing"] = "credential_missing";
109
110
  DeviceApiClientErrorCode2["NoActingUser"] = "no_acting_user";
@@ -308,6 +309,13 @@ const createDeviceApiClient = (config) => {
308
309
  });
309
310
  }
310
311
  },
312
+ // Lease processes run on the Device and are found again by id and boot
313
+ // while the lease generation lasts.
314
+ processGone: (cause) => {
315
+ if (!(cause instanceof Error)) return false;
316
+ const status = deviceApiStatusOf(cause);
317
+ return status === 404 || status === 502 && DEVICE_PROCESS_GONE_MESSAGE.test(cause.message);
318
+ },
311
319
  close: () => void 0
312
320
  };
313
321
  };
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../../src/sandboxes/device-api.ts"],
4
- "sourcesContent": ["import {\n deviceEgressCreateRequestSchema,\n deviceEgressWorkspaceIdSchema,\n deviceEgressEnrollmentSchema,\n deviceEgressLeaseSchema,\n deviceEgressWorkspaceSchema,\n workspaceNetworkPolicySchema,\n deviceWorkspaceNetworkStateSchema,\n type WorkspaceNetworkPolicyIface,\n} from '@finalai/agent-protocol/device-egress';\nimport {\n ProcessInspectionOperation,\n processInspectionResultSchema,\n type ProcessInspectionRequestIface,\n type ProcessInspectionResultIface,\n} from '@finalai/agent-protocol/process-inspection';\nimport { jsonObjectSchema, jsonValueSchema, type JsonValue } from '@finalai/agent-provider';\nimport {\n SandboxEntryType,\n type FinalPlatformAccessIface,\n type SandboxActingUserIface,\n type SandboxCredentialsIface,\n} from '@finalai/agent-provider/sandbox';\nimport * as z from 'zod';\nimport { decodeBase64, encodeBase64 } from \"./bytes.mjs\";\nimport { DEVICE_API_ACTING_USER_HEADER } from \"./environment.mjs\";\nimport type {\n SandboxTransportIface,\n TransportDirEntryIface,\n TransportOutputIface,\n TransportStatIface,\n} from \"./transport.mjs\";\n\n// A client of the Device API, authenticated with the context's\n// `credentials.deviceAccess`. Device operations also name the acting user; the API\n// enforces ownership independently of the token.\n\n// The Device API's header naming the user a request acts for (a Final user id).\nexport { DEVICE_API_ACTING_USER_HEADER } from \"./environment.mjs\";\n\n// The organization, credentials and user a call acts for; the user is read on each\n// call. Workspace networking also calls with no user (admission, policy\n// persistence and cleanup), which needs service access from `deviceAccess`.\nexport interface DeviceApiCallerIface {\n organizationId: string;\n credentials?: SandboxCredentialsIface;\n actingUser: SandboxActingUserIface;\n}\n\n// Transport options; the API origin and token come from the caller's credentials.\nexport interface DeviceApiConfigIface {\n fetch?: DeviceApiFetchIface;\n}\n\nexport interface DeviceApiFetchIface {\n (input: string, init: RequestInit): Promise<Response>;\n}\n\nexport enum DeviceApiLeaseAccess {\n Read = 'read',\n Write = 'write',\n}\n\nexport enum DeviceApiCapability {\n Files = 'files',\n Process = 'process',\n ComputerUse = 'computer-use',\n LocalMcp = 'local-mcp',\n}\n\nexport const DEVICE_API_COMPUTER_USE_SERVER = 'computer-use';\n\n// Unknown values from a newer API read as absent rather than failing the call.\nconst tolerantEnum = <T extends Record<string, string>>(values: T) =>\n z.string().transform((value): T[keyof T] | null => {\n const parsed = z.nativeEnum(values).safeParse(value);\n return parsed.success ? parsed.data : null;\n });\n\nconst deviceSchema = z.object({\n id: z.string(),\n organizationId: z.string(),\n displayName: z.string(),\n os: z.string(),\n online: z.boolean(),\n writable: z.boolean(),\n allowProcesses: z.boolean(),\n computerUseReady: z.boolean(),\n screenReady: z.boolean(),\n});\nexport type DeviceApiDeviceIface = z.infer<typeof deviceSchema>;\n\nconst leaseSchema = z.object({\n lease: z.string(),\n deviceId: z.string(),\n generation: z.number(),\n workspaceRoot: z.string(),\n platform: z.string(),\n access: z.nativeEnum(DeviceApiLeaseAccess),\n capabilities: z.array(tolerantEnum(DeviceApiCapability)),\n expiresAt: z.string(),\n});\nexport interface DeviceApiLeaseIface {\n lease: string;\n deviceId: string;\n generation: number;\n workspaceRoot: string;\n platform: string;\n access: DeviceApiLeaseAccess;\n capabilities: DeviceApiCapability[];\n expiresAtMs: number;\n}\n\ninterface ProcessInputBodyIface {\n bootId: string;\n dataBase64?: string;\n eof?: boolean;\n}\n\nconst errorBodySchema = z.object({ error: z.object({ code: z.string(), message: z.string() }) });\nconst statBodySchema = z.object({\n stat: z\n .object({\n type: tolerantEnum(SandboxEntryType),\n size: z.number(),\n modifiedAtMs: z.number().nullable(),\n mode: z.number().nullable(),\n })\n .nullable(),\n});\nconst dirBodySchema = z.object({\n entries: z.array(\n z.object({\n name: z.string(),\n type: tolerantEnum(SandboxEntryType),\n size: z.number().nullable(),\n }),\n ),\n});\nconst processSchema = z.object({ id: z.string(), bootId: z.string() });\nconst outputStreamSchema = z.object({\n dataBase64: z.string(),\n nextOffset: z.number(),\n eof: z.boolean(),\n});\nconst outputSchema = z.object({\n stdout: outputStreamSchema,\n stderr: outputStreamSchema,\n exited: z.boolean(),\n exitCode: z.number().nullable(),\n exitSignal: z.string().nullable(),\n});\nconst devicesSchema = z.object({ devices: z.array(deviceSchema) });\nconst serversSchema = z.object({ servers: z.array(z.string()) });\n// A Device server's tool as the API recorded it; checked against the tool\n// descriptor contract where the provider hands it on.\nconst catalogToolSchema = jsonObjectSchema;\nconst mcpCatalogSchema = z.object({\n computerUse: z.object({ tools: z.array(catalogToolSchema) }).nullable(),\n localServers: z\n .object({\n servers: z.array(\n z.object({ name: z.string(), tools: z.array(catalogToolSchema).nullable() }),\n ),\n })\n .nullable(),\n});\nexport type DeviceApiMcpCatalogIface = z.infer<typeof mcpCatalogSchema>;\nconst pipeReadSchema = z.object({ dataBase64: z.string().optional() });\nconst screenSchema = z.object({ url: z.string(), token: z.string(), expiresAt: z.string() });\nconst emptySchema = z.unknown();\n\n// One ranged read or write; the API splits it into the Device's own chunks.\nexport const DEVICE_API_FILE_CHUNK_BYTES = 4 * 1024 * 1024;\n// The API long-polls the Device for output up to this long.\nexport const DEVICE_API_OUTPUT_WAIT_MS = 15_000;\n\nexport enum DeviceApiClientErrorCode {\n // The host granted no access for this user or trusted service call.\n CredentialMissing = 'credential_missing',\n // The session acts for no user, and a Device is only used for its owner.\n NoActingUser = 'no_acting_user',\n EgressEnrollmentLost = 'egress_enrollment_lost',\n}\n\nexport interface DeviceApiErrorIface extends Error {\n status: number | null;\n code: string;\n}\n\nconst apiError = (status: number, code: string, message: string): DeviceApiErrorIface =>\n Object.assign(new Error(`Device API ${status} ${code}: ${message}`), { status, code });\n\nconst credentialMissing = (actingUserId: string | null): DeviceApiErrorIface =>\n Object.assign(\n new Error(\n `Device API access is unavailable ${actingUserId == null ? 'for workspace networking (no acting user)' : 'for this acting user'}: the host's credentials.deviceAccess granted none`,\n ),\n { status: null, code: DeviceApiClientErrorCode.CredentialMissing },\n );\n\nconst noActingUser = (): DeviceApiErrorIface =>\n Object.assign(\n new Error(\n 'this session acts for no user, and a Final Device is only used by sessions acting for its owner',\n ),\n { status: null, code: DeviceApiClientErrorCode.NoActingUser },\n );\n\nconst statusSchema = z.object({ status: z.number() });\nexport const deviceApiCodeOf = (cause: unknown): string | null =>\n z.object({ code: z.string() }).safeParse(cause).data?.code ?? null;\n\nexport const deviceApiStatusOf = (cause: Error): number | null =>\n statusSchema.safeParse(cause).data?.status ?? null;\n\nconst parseJson = (text: string): JsonValue => {\n try {\n return jsonValueSchema.parse(JSON.parse(text));\n } catch {\n return null;\n }\n};\n\nconst leaseOf = (raw: z.infer<typeof leaseSchema>): DeviceApiLeaseIface => ({\n lease: raw.lease,\n deviceId: raw.deviceId,\n generation: raw.generation,\n workspaceRoot: raw.workspaceRoot,\n platform: raw.platform,\n access: raw.access,\n capabilities: raw.capabilities.filter((capability) => capability != null),\n expiresAtMs: Date.parse(raw.expiresAt),\n});\n\nexport interface DeviceApiClientIface {\n egress: {\n networkState(args: {\n organizationId: string;\n credentials?: SandboxCredentialsIface;\n workspaceId: string;\n }): Promise<z.infer<typeof deviceWorkspaceNetworkStateSchema>>;\n setNetworkPolicy(args: {\n caller: DeviceApiCallerIface;\n workspaceId: string;\n policy: WorkspaceNetworkPolicyIface;\n initializeIfMissing?: boolean;\n }): Promise<void>;\n workspace(args: {\n caller: DeviceApiCallerIface;\n workspaceId: string;\n }): Promise<z.infer<typeof deviceEgressWorkspaceSchema>>;\n create(args: {\n caller: DeviceApiCallerIface;\n workspaceId: string;\n deviceIds: string[];\n dnsResolvers?: string[];\n }): Promise<z.infer<typeof deviceEgressEnrollmentSchema>>;\n renew(args: {\n caller: DeviceApiCallerIface;\n leaseId: string;\n }): Promise<z.infer<typeof deviceEgressLeaseSchema>>;\n activate(args: {\n caller: DeviceApiCallerIface;\n leaseId: string;\n }): Promise<z.infer<typeof deviceEgressLeaseSchema>>;\n revoke(args: {\n caller: DeviceApiCallerIface;\n leaseId: string;\n workspaceId: string;\n }): Promise<void>;\n disable(args: { caller: DeviceApiCallerIface; workspaceId: string }): Promise<void>;\n suspend(args: { caller: DeviceApiCallerIface; workspaceId: string }): Promise<void>;\n };\n releaseWorkspaceLeases(args: {\n caller: DeviceApiCallerIface;\n deviceId: string;\n bindingId: string;\n }): Promise<void>;\n inspectProcesses(args: {\n caller: DeviceApiCallerIface;\n deviceId: string;\n bindingId: string;\n request: ProcessInspectionRequestIface;\n }): Promise<ProcessInspectionResultIface>;\n getDevice(args: {\n caller: DeviceApiCallerIface;\n deviceId: string;\n }): Promise<DeviceApiDeviceIface | null>;\n // The Devices of the user the call acts for.\n listDevices(args: { caller: DeviceApiCallerIface }): Promise<DeviceApiDeviceIface[]>;\n resolvePairing(args: {\n caller: DeviceApiCallerIface;\n code: string;\n }): Promise<DeviceApiDeviceIface | null>;\n lease(args: {\n caller: DeviceApiCallerIface;\n deviceId: string;\n sessionId: string;\n bindingId: string;\n access: DeviceApiLeaseAccess;\n ttlMs: number;\n afterGeneration?: number;\n }): Promise<DeviceApiLeaseIface>;\n recoverLease(args: {\n caller: DeviceApiCallerIface;\n deviceId: string;\n sessionId: string;\n bindingId: string;\n access: DeviceApiLeaseAccess;\n }): Promise<DeviceApiLeaseIface>;\n renew(args: {\n caller: DeviceApiCallerIface;\n lease: string;\n ttlMs: number;\n }): Promise<DeviceApiLeaseIface>;\n release(args: { caller: DeviceApiCallerIface; lease: string }): Promise<void>;\n // The sandbox transport over one lease; `lease()` is the current handle.\n transport(args: {\n caller: DeviceApiCallerIface;\n lease: () => Promise<string>;\n }): SandboxTransportIface;\n localMcpServers(args: { caller: DeviceApiCallerIface; lease: string }): Promise<string[]>;\n // What the Device's MCP servers last listed through the API, without a lease.\n mcpCatalog(args: {\n caller: DeviceApiCallerIface;\n deviceId: string;\n }): Promise<DeviceApiMcpCatalogIface>;\n pipe(args: {\n caller: DeviceApiCallerIface;\n lease: string;\n server: string;\n action: 'open' | 'write' | 'read' | 'close';\n clientId: string;\n dataBase64?: string;\n signal?: AbortSignal;\n }): Promise<string>;\n screen(args: {\n caller: DeviceApiCallerIface;\n deviceId: string;\n sessionId: string;\n viewOnly?: boolean;\n }): Promise<{ url: string; token: string; expiresAt: string }>;\n}\n\nexport const createDeviceApiClient = (config: {\n api: DeviceApiConfigIface | (() => DeviceApiConfigIface);\n fetch?: DeviceApiFetchIface;\n}): DeviceApiClientIface => {\n const readApi = () => (typeof config.api === 'function' ? config.api() : config.api);\n const failure = async (response: Response): Promise<DeviceApiErrorIface> => {\n // Read as text so proxy and load balancer error pages survive.\n const text = await response.text().catch(() => '');\n const body = errorBodySchema.safeParse(parseJson(text));\n return body.success\n ? apiError(response.status, body.data.error.code, body.data.error.message)\n : apiError(response.status, 'http', text.slice(0, 200) || response.statusText);\n };\n\n const accessFor = async (args: {\n caller: DeviceApiCallerIface;\n actingUserId: string | null;\n refresh: boolean;\n }): Promise<FinalPlatformAccessIface> => {\n const access = await args.caller.credentials?.deviceAccess({\n actingUserId: args.actingUserId,\n refresh: args.refresh,\n });\n if (access == null) throw credentialMissing(args.actingUserId);\n return access;\n };\n\n // One authenticated call for the user it acts for; rejected access is asked for\n // again once, in case it expired.\n const send = async (args: {\n caller: DeviceApiCallerIface;\n method: string;\n path: string;\n query?: Record<string, string>;\n body?: BodyInit;\n contentType?: string;\n signal?: AbortSignal;\n anonymous?: boolean;\n }): Promise<Response> => {\n const api = readApi();\n const actingUserId = await args.caller.actingUser.current();\n if (actingUserId == null && !args.anonymous) throw noActingUser();\n const attempt = async (refresh: boolean): Promise<Response> => {\n const access = await accessFor({ caller: args.caller, actingUserId, refresh });\n const url = new URL(`${access.baseUrl.replace(/\\/+$/, '')}${args.path}`);\n for (const [key, value] of Object.entries(args.query ?? {})) url.searchParams.set(key, value);\n const headers = new Headers({ authorization: `Bearer ${access.token}` });\n if (actingUserId != null) headers.set(DEVICE_API_ACTING_USER_HEADER, actingUserId);\n if (args.contentType != null) headers.set('content-type', args.contentType);\n return (config.fetch ?? api.fetch ?? fetch)(url.toString(), {\n method: args.method,\n headers,\n body: args.body,\n signal: args.signal,\n });\n };\n let response = await attempt(false);\n if (response.status === 401) {\n await response.text().catch(() => '');\n response = await attempt(true);\n }\n return response;\n };\n\n const json = async <T extends z.ZodType>(\n schema: T,\n args: Parameters<typeof send>[0] & { json?: unknown },\n ): Promise<z.infer<T>> => {\n const response = await send({\n ...args,\n body: args.json === undefined ? args.body : JSON.stringify(args.json),\n contentType: args.json === undefined ? args.contentType : 'application/json',\n });\n if (!response.ok) throw await failure(response);\n const text = await response.text();\n return schema.parse(text === '' ? null : parseJson(text));\n };\n\n // A 404 reads as absent.\n const orNull = async <T>(work: Promise<T>): Promise<T | null> => {\n try {\n return await work;\n } catch (cause) {\n if (cause instanceof Error && deviceApiStatusOf(cause) === 404) return null;\n throw cause;\n }\n };\n\n const leasePath = (lease: string, rest: string): string =>\n `/v1/leases/${encodeURIComponent(lease)}${rest}`;\n\n const transport: DeviceApiClientIface['transport'] = ({ caller, lease }) => {\n const call = async <T extends z.ZodType>(\n schema: T,\n args: Omit<Parameters<typeof json>[1], 'caller' | 'path'> & { path: string },\n ): Promise<z.infer<T>> =>\n json(schema, { ...args, caller, path: leasePath(await lease(), args.path) });\n const processPath = (id: string, rest: string): string =>\n `/processes/${encodeURIComponent(id)}${rest}`;\n return {\n kind: 'device-api',\n fileChunkBytes: DEVICE_API_FILE_CHUNK_BYTES,\n outputWaitMs: DEVICE_API_OUTPUT_WAIT_MS,\n stat: async ({ path, signal }): Promise<TransportStatIface | null> => {\n const { stat } = await call(statBodySchema, {\n method: 'GET',\n path: '/files/stat',\n query: { path },\n signal,\n });\n return stat == null ? null : { ...stat, type: stat.type ?? SandboxEntryType.Other };\n },\n readDir: async ({ path, signal }): Promise<TransportDirEntryIface[]> =>\n (\n await call(dirBodySchema, { method: 'GET', path: '/files/dir', query: { path }, signal })\n ).entries.map((entry) => ({ ...entry, type: entry.type ?? SandboxEntryType.Other })),\n readChunk: async ({ path, offset, length, signal }) => {\n const response = await send({\n caller,\n method: 'GET',\n path: leasePath(await lease(), '/files/content'),\n query: { path, offset: String(offset), length: String(length) },\n signal,\n });\n if (!response.ok) throw await failure(response);\n const bytes = new Uint8Array(await response.arrayBuffer());\n return { bytes, eof: bytes.byteLength < length };\n },\n writeChunk: async ({ path, offset, bytes, signal }) => {\n await call(emptySchema, {\n method: 'PUT',\n path: '/files/content',\n query: { path, offset: String(offset) },\n body: new Blob([bytes.slice()]),\n contentType: 'application/octet-stream',\n signal,\n });\n },\n createDirectory: async ({ path, signal }) => {\n await call(emptySchema, {\n method: 'POST',\n path: '/files/directories',\n json: { path },\n signal,\n });\n },\n remove: async ({ path, recursive, force, signal }) => {\n await call(emptySchema, {\n method: 'DELETE',\n path: '/files',\n query: { path, recursive: String(recursive), force: String(force) },\n signal,\n });\n },\n exec: async ({ id, command, cwd, env, timeoutMs, signal }) =>\n call(processSchema, {\n method: 'POST',\n path: '/processes',\n json: { id, command, cwd, env, timeoutMs },\n signal,\n }),\n output: async ({ process, stdoutOffset, stderrOffset, waitMs, signal }) => {\n const output = await call(outputSchema, {\n method: 'POST',\n path: processPath(process.id, '/output'),\n json: { bootId: process.bootId, stdoutOffset, stderrOffset, waitMs },\n signal,\n });\n const stream = (value: z.infer<typeof outputStreamSchema>) => ({\n data: decodeBase64(value.dataBase64),\n nextOffset: value.nextOffset,\n eof: value.eof,\n });\n const result: TransportOutputIface = {\n stdout: stream(output.stdout),\n stderr: stream(output.stderr),\n exited: output.exited,\n exitCode: output.exitCode,\n exitSignal: output.exitSignal,\n };\n return result;\n },\n input: async ({ process, data, eof, signal, terminate, abortSignal }) => {\n if (terminate === true || signal != null) {\n await call(emptySchema, {\n method: 'POST',\n path: processPath(process.id, '/kill'),\n json:\n terminate === true ? { bootId: process.bootId } : { bootId: process.bootId, signal },\n signal: abortSignal,\n });\n if (terminate === true) return;\n }\n if ((data != null && data.byteLength > 0) || eof === true) {\n const body: ProcessInputBodyIface = {\n bootId: process.bootId,\n };\n if (data != null && data.byteLength > 0) body.dataBase64 = encodeBase64(data);\n if (eof === true) body.eof = true;\n await call(emptySchema, {\n method: 'POST',\n path: processPath(process.id, '/input'),\n json: body,\n signal: abortSignal,\n });\n }\n },\n close: () => undefined,\n };\n };\n\n return {\n egress: {\n networkState: ({ organizationId, credentials, workspaceId }) =>\n json(deviceWorkspaceNetworkStateSchema, {\n caller: { organizationId, credentials, actingUser: { current: async () => null } },\n anonymous: true,\n method: 'GET',\n path: `/v1/egress/workspaces/${encodeURIComponent(deviceEgressWorkspaceIdSchema.parse(workspaceId))}/network-state`,\n signal: AbortSignal.timeout(30_000),\n }),\n setNetworkPolicy: async ({ caller, workspaceId, policy, initializeIfMissing }) => {\n const userId = await caller.actingUser.current();\n const anonymous = userId == null;\n const resolvedCaller = { ...caller, actingUser: { current: async () => userId } };\n const result = await json(z.object({ ok: z.boolean() }), {\n caller: resolvedCaller,\n method: initializeIfMissing === true ? 'POST' : 'PUT',\n anonymous,\n path: `/v1/egress/workspaces/${encodeURIComponent(deviceEgressWorkspaceIdSchema.parse(workspaceId))}/${initializeIfMissing === true ? 'network-state/initialize' : anonymous ? 'network-state' : 'network-policy'}`,\n json: workspaceNetworkPolicySchema.parse(policy),\n signal: AbortSignal.timeout(30_000),\n });\n if (!result.ok) throw new Error('Device API did not save the workspace network policy');\n },\n workspace: ({ caller, workspaceId }) =>\n json(deviceEgressWorkspaceSchema, {\n caller,\n method: 'GET',\n path: `/v1/egress/workspaces/${encodeURIComponent(deviceEgressWorkspaceIdSchema.parse(workspaceId))}`,\n signal: AbortSignal.timeout(30_000),\n }),\n create: ({ caller, ...input }) =>\n json(deviceEgressEnrollmentSchema, {\n caller,\n method: 'POST',\n path: '/v1/egress/leases',\n json: deviceEgressCreateRequestSchema.parse(input),\n signal: AbortSignal.timeout(180_000),\n }),\n renew: ({ caller, leaseId }) =>\n json(deviceEgressLeaseSchema, {\n caller,\n method: 'POST',\n path: `/v1/egress/leases/${encodeURIComponent(leaseId)}/renew`,\n signal: AbortSignal.timeout(180_000),\n }),\n activate: ({ caller, leaseId }) =>\n json(deviceEgressLeaseSchema, {\n caller,\n method: 'POST',\n path: `/v1/egress/leases/${encodeURIComponent(leaseId)}/activate`,\n signal: AbortSignal.timeout(60_000),\n }),\n revoke: async ({ caller, leaseId, workspaceId }) => {\n await json(emptySchema, {\n caller,\n method: 'DELETE',\n json: { workspaceId },\n path: `/v1/egress/leases/${encodeURIComponent(leaseId)}`,\n signal: AbortSignal.timeout(60_000),\n });\n },\n suspend: async ({\n caller,\n workspaceId,\n }: {\n caller: DeviceApiCallerIface;\n workspaceId: string;\n }) => {\n const userId = await caller.actingUser.current();\n const anonymous = userId == null;\n const resolvedCaller = { ...caller, actingUser: { current: async () => userId } };\n await json(emptySchema, {\n caller: resolvedCaller,\n anonymous,\n method: 'POST',\n path: `/v1/egress/workspaces/${encodeURIComponent(deviceEgressWorkspaceIdSchema.parse(workspaceId))}/${anonymous ? 'network-state/suspend' : 'suspend'}`,\n signal: AbortSignal.timeout(60_000),\n });\n },\n disable: async ({ caller, workspaceId }) => {\n await json(emptySchema, {\n caller,\n method: 'DELETE',\n path: `/v1/egress/workspaces/${encodeURIComponent(deviceEgressWorkspaceIdSchema.parse(workspaceId))}`,\n signal: AbortSignal.timeout(60_000),\n });\n },\n },\n releaseWorkspaceLeases: async ({ caller, deviceId, bindingId }) => {\n const result = await json(z.object({ released: z.boolean() }), {\n caller,\n method: 'DELETE',\n path:\n '/v1/devices/' +\n encodeURIComponent(deviceId) +\n '/workspaces/' +\n encodeURIComponent(bindingId) +\n '/leases',\n });\n if (!result.released) throw new Error('The Device did not release its workspace leases');\n },\n inspectProcesses: ({ caller, deviceId, bindingId, request }) => {\n const suffix =\n request.operation === ProcessInspectionOperation.Available\n ? '/available'\n : 'processId' in request\n ? '/' + encodeURIComponent(request.processId)\n : '';\n const query: Record<string, string> = {};\n if (bindingId != null) query.bindingId = bindingId;\n if ('bootId' in request) query.bootId = request.bootId;\n if ('cursor' in request && request.cursor != null) query.cursor = request.cursor;\n if ('limit' in request && request.limit != null) query.limit = String(request.limit);\n return json(processInspectionResultSchema, {\n caller,\n method: request.operation === ProcessInspectionOperation.Stop ? 'DELETE' : 'GET',\n path: '/v1/devices/' + encodeURIComponent(deviceId) + '/processes' + suffix,\n query,\n });\n },\n getDevice: ({ caller, deviceId }) =>\n orNull(\n json(deviceSchema, {\n caller,\n method: 'GET',\n path: `/v1/devices/${encodeURIComponent(deviceId)}`,\n }),\n ),\n listDevices: async ({ caller }) =>\n (await json(devicesSchema, { caller, method: 'GET', path: '/v1/devices' })).devices,\n resolvePairing: ({ caller, code }) =>\n orNull(\n json(deviceSchema, {\n caller,\n method: 'POST',\n path: '/v1/pairings/resolve',\n json: { code },\n }),\n ),\n lease: async ({ caller, deviceId, sessionId, bindingId, access, ttlMs, afterGeneration }) =>\n leaseOf(\n await json(leaseSchema, {\n caller,\n method: 'POST',\n path: `/v1/devices/${encodeURIComponent(deviceId)}/leases`,\n json: { sessionId, bindingId, access, ttlMs, afterGeneration },\n }),\n ),\n recoverLease: async ({ caller, deviceId, sessionId, bindingId, access }) =>\n leaseOf(\n await json(leaseSchema, {\n caller,\n method: 'POST',\n path: `/v1/devices/${encodeURIComponent(deviceId)}/leases/recover`,\n json: { sessionId, bindingId, access },\n }),\n ),\n renew: async ({ caller, lease, ttlMs }) =>\n leaseOf(\n await json(leaseSchema, {\n caller,\n method: 'POST',\n path: leasePath(lease, '/renew'),\n json: { ttlMs },\n }),\n ),\n release: async ({ caller, lease }) => {\n await json(emptySchema, { caller, method: 'DELETE', path: leasePath(lease, '') });\n },\n transport,\n mcpCatalog: ({ caller, deviceId }) =>\n json(mcpCatalogSchema, {\n caller,\n method: 'GET',\n path: `/v1/devices/${encodeURIComponent(deviceId)}/mcp`,\n }),\n localMcpServers: async ({ caller, lease }) =>\n (await json(serversSchema, { caller, method: 'GET', path: leasePath(lease, '/mcp') }))\n .servers,\n pipe: async ({ caller, lease, server, action, clientId, dataBase64, signal }) =>\n (\n await json(pipeReadSchema, {\n caller,\n method: 'POST',\n path: leasePath(lease, `/mcp/${encodeURIComponent(server)}/${action}`),\n json: dataBase64 == null ? { clientId } : { clientId, dataBase64 },\n signal,\n })\n ).dataBase64 ?? '',\n screen: ({ caller, deviceId, sessionId, viewOnly }) =>\n json(screenSchema, {\n caller,\n method: 'POST',\n path: `/v1/devices/${encodeURIComponent(deviceId)}/screen`,\n json: { sessionId, viewOnly },\n }),\n };\n};\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import {\n deviceEgressCreateRequestSchema,\n deviceEgressWorkspaceIdSchema,\n deviceEgressEnrollmentSchema,\n deviceEgressLeaseSchema,\n deviceEgressWorkspaceSchema,\n workspaceNetworkPolicySchema,\n deviceWorkspaceNetworkStateSchema,\n type WorkspaceNetworkPolicyIface,\n} from '@finalai/agent-protocol/device-egress';\nimport {\n ProcessInspectionOperation,\n processInspectionResultSchema,\n type ProcessInspectionRequestIface,\n type ProcessInspectionResultIface,\n} from '@finalai/agent-protocol/process-inspection';\nimport { jsonObjectSchema, jsonValueSchema, type JsonValue } from '@finalai/agent-provider';\nimport {\n SandboxEntryType,\n type FinalPlatformAccessIface,\n type SandboxActingUserIface,\n type SandboxCredentialsIface,\n} from '@finalai/agent-provider/sandbox';\nimport * as z from 'zod';\nimport { decodeBase64, encodeBase64 } from \"./bytes.mjs\";\nimport { DEVICE_API_ACTING_USER_HEADER } from \"./environment.mjs\";\nimport type {\n SandboxTransportIface,\n TransportDirEntryIface,\n TransportOutputIface,\n TransportStatIface,\n} from \"./transport.mjs\";\n\n// A client of the Device API, authenticated with the context's\n// `credentials.deviceAccess`. Device operations also name the acting user; the API\n// enforces ownership independently of the token.\n\n// The Device API's header naming the user a request acts for (a Final user id).\nexport { DEVICE_API_ACTING_USER_HEADER } from \"./environment.mjs\";\n\n// The organization, credentials and user a call acts for; the user is read on each\n// call. Workspace networking also calls with no user (admission, policy\n// persistence and cleanup), which needs service access from `deviceAccess`.\nexport interface DeviceApiCallerIface {\n organizationId: string;\n credentials?: SandboxCredentialsIface;\n actingUser: SandboxActingUserIface;\n}\n\n// Transport options; the API origin and token come from the caller's credentials.\nexport interface DeviceApiConfigIface {\n fetch?: DeviceApiFetchIface;\n}\n\nexport interface DeviceApiFetchIface {\n (input: string, init: RequestInit): Promise<Response>;\n}\n\nexport enum DeviceApiLeaseAccess {\n Read = 'read',\n Write = 'write',\n}\n\nexport enum DeviceApiCapability {\n Files = 'files',\n Process = 'process',\n ComputerUse = 'computer-use',\n LocalMcp = 'local-mcp',\n}\n\nexport const DEVICE_API_COMPUTER_USE_SERVER = 'computer-use';\n\n// Unknown values from a newer API read as absent rather than failing the call.\nconst tolerantEnum = <T extends Record<string, string>>(values: T) =>\n z.string().transform((value): T[keyof T] | null => {\n const parsed = z.nativeEnum(values).safeParse(value);\n return parsed.success ? parsed.data : null;\n });\n\nconst deviceSchema = z.object({\n id: z.string(),\n organizationId: z.string(),\n displayName: z.string(),\n os: z.string(),\n online: z.boolean(),\n writable: z.boolean(),\n allowProcesses: z.boolean(),\n computerUseReady: z.boolean(),\n screenReady: z.boolean(),\n});\nexport type DeviceApiDeviceIface = z.infer<typeof deviceSchema>;\n\nconst leaseSchema = z.object({\n lease: z.string(),\n deviceId: z.string(),\n generation: z.number(),\n workspaceRoot: z.string(),\n platform: z.string(),\n access: z.nativeEnum(DeviceApiLeaseAccess),\n capabilities: z.array(tolerantEnum(DeviceApiCapability)),\n expiresAt: z.string(),\n});\nexport interface DeviceApiLeaseIface {\n lease: string;\n deviceId: string;\n generation: number;\n workspaceRoot: string;\n platform: string;\n access: DeviceApiLeaseAccess;\n capabilities: DeviceApiCapability[];\n expiresAtMs: number;\n}\n\ninterface ProcessInputBodyIface {\n bootId: string;\n dataBase64?: string;\n eof?: boolean;\n}\n\nconst errorBodySchema = z.object({ error: z.object({ code: z.string(), message: z.string() }) });\nconst statBodySchema = z.object({\n stat: z\n .object({\n type: tolerantEnum(SandboxEntryType),\n size: z.number(),\n modifiedAtMs: z.number().nullable(),\n mode: z.number().nullable(),\n })\n .nullable(),\n});\nconst dirBodySchema = z.object({\n entries: z.array(\n z.object({\n name: z.string(),\n type: tolerantEnum(SandboxEntryType),\n size: z.number().nullable(),\n }),\n ),\n});\nconst processSchema = z.object({ id: z.string(), bootId: z.string() });\nconst outputStreamSchema = z.object({\n dataBase64: z.string(),\n nextOffset: z.number(),\n eof: z.boolean(),\n});\nconst outputSchema = z.object({\n stdout: outputStreamSchema,\n stderr: outputStreamSchema,\n exited: z.boolean(),\n exitCode: z.number().nullable(),\n exitSignal: z.string().nullable(),\n});\nconst devicesSchema = z.object({ devices: z.array(deviceSchema) });\nconst serversSchema = z.object({ servers: z.array(z.string()) });\n// A Device server's tool as the API recorded it; checked against the tool\n// descriptor contract where the provider hands it on.\nconst catalogToolSchema = jsonObjectSchema;\nconst mcpCatalogSchema = z.object({\n computerUse: z.object({ tools: z.array(catalogToolSchema) }).nullable(),\n localServers: z\n .object({\n servers: z.array(\n z.object({ name: z.string(), tools: z.array(catalogToolSchema).nullable() }),\n ),\n })\n .nullable(),\n});\nexport type DeviceApiMcpCatalogIface = z.infer<typeof mcpCatalogSchema>;\nconst pipeReadSchema = z.object({ dataBase64: z.string().optional() });\nconst screenSchema = z.object({ url: z.string(), token: z.string(), expiresAt: z.string() });\nconst emptySchema = z.unknown();\n\n// One ranged read or write; the API splits it into the Device's own chunks.\nexport const DEVICE_API_FILE_CHUNK_BYTES = 4 * 1024 * 1024;\n// The API long-polls the Device for output up to this long.\nexport const DEVICE_API_OUTPUT_WAIT_MS = 15_000;\n// How the Device reports a lease process it no longer has (relayed as a 502):\n// unknown in this lease, from an earlier runtime, or retired after its output\n// was read to the end.\nconst DEVICE_PROCESS_GONE_MESSAGE =\n /unknown process|belongs to another device runtime|consumed output has expired/i;\n\nexport enum DeviceApiClientErrorCode {\n // The host granted no access for this user or trusted service call.\n CredentialMissing = 'credential_missing',\n // The session acts for no user, and a Device is only used for its owner.\n NoActingUser = 'no_acting_user',\n EgressEnrollmentLost = 'egress_enrollment_lost',\n}\n\nexport interface DeviceApiErrorIface extends Error {\n status: number | null;\n code: string;\n}\n\nconst apiError = (status: number, code: string, message: string): DeviceApiErrorIface =>\n Object.assign(new Error(`Device API ${status} ${code}: ${message}`), { status, code });\n\nconst credentialMissing = (actingUserId: string | null): DeviceApiErrorIface =>\n Object.assign(\n new Error(\n `Device API access is unavailable ${actingUserId == null ? 'for workspace networking (no acting user)' : 'for this acting user'}: the host's credentials.deviceAccess granted none`,\n ),\n { status: null, code: DeviceApiClientErrorCode.CredentialMissing },\n );\n\nconst noActingUser = (): DeviceApiErrorIface =>\n Object.assign(\n new Error(\n 'this session acts for no user, and a Final Device is only used by sessions acting for its owner',\n ),\n { status: null, code: DeviceApiClientErrorCode.NoActingUser },\n );\n\nconst statusSchema = z.object({ status: z.number() });\nexport const deviceApiCodeOf = (cause: unknown): string | null =>\n z.object({ code: z.string() }).safeParse(cause).data?.code ?? null;\n\nexport const deviceApiStatusOf = (cause: Error): number | null =>\n statusSchema.safeParse(cause).data?.status ?? null;\n\nconst parseJson = (text: string): JsonValue => {\n try {\n return jsonValueSchema.parse(JSON.parse(text));\n } catch {\n return null;\n }\n};\n\nconst leaseOf = (raw: z.infer<typeof leaseSchema>): DeviceApiLeaseIface => ({\n lease: raw.lease,\n deviceId: raw.deviceId,\n generation: raw.generation,\n workspaceRoot: raw.workspaceRoot,\n platform: raw.platform,\n access: raw.access,\n capabilities: raw.capabilities.filter((capability) => capability != null),\n expiresAtMs: Date.parse(raw.expiresAt),\n});\n\nexport interface DeviceApiClientIface {\n egress: {\n networkState(args: {\n organizationId: string;\n credentials?: SandboxCredentialsIface;\n workspaceId: string;\n }): Promise<z.infer<typeof deviceWorkspaceNetworkStateSchema>>;\n setNetworkPolicy(args: {\n caller: DeviceApiCallerIface;\n workspaceId: string;\n policy: WorkspaceNetworkPolicyIface;\n initializeIfMissing?: boolean;\n }): Promise<void>;\n workspace(args: {\n caller: DeviceApiCallerIface;\n workspaceId: string;\n }): Promise<z.infer<typeof deviceEgressWorkspaceSchema>>;\n create(args: {\n caller: DeviceApiCallerIface;\n workspaceId: string;\n deviceIds: string[];\n dnsResolvers?: string[];\n }): Promise<z.infer<typeof deviceEgressEnrollmentSchema>>;\n renew(args: {\n caller: DeviceApiCallerIface;\n leaseId: string;\n }): Promise<z.infer<typeof deviceEgressLeaseSchema>>;\n activate(args: {\n caller: DeviceApiCallerIface;\n leaseId: string;\n }): Promise<z.infer<typeof deviceEgressLeaseSchema>>;\n revoke(args: {\n caller: DeviceApiCallerIface;\n leaseId: string;\n workspaceId: string;\n }): Promise<void>;\n disable(args: { caller: DeviceApiCallerIface; workspaceId: string }): Promise<void>;\n suspend(args: { caller: DeviceApiCallerIface; workspaceId: string }): Promise<void>;\n };\n releaseWorkspaceLeases(args: {\n caller: DeviceApiCallerIface;\n deviceId: string;\n bindingId: string;\n }): Promise<void>;\n inspectProcesses(args: {\n caller: DeviceApiCallerIface;\n deviceId: string;\n bindingId: string;\n request: ProcessInspectionRequestIface;\n }): Promise<ProcessInspectionResultIface>;\n getDevice(args: {\n caller: DeviceApiCallerIface;\n deviceId: string;\n }): Promise<DeviceApiDeviceIface | null>;\n // The Devices of the user the call acts for.\n listDevices(args: { caller: DeviceApiCallerIface }): Promise<DeviceApiDeviceIface[]>;\n resolvePairing(args: {\n caller: DeviceApiCallerIface;\n code: string;\n }): Promise<DeviceApiDeviceIface | null>;\n lease(args: {\n caller: DeviceApiCallerIface;\n deviceId: string;\n sessionId: string;\n bindingId: string;\n access: DeviceApiLeaseAccess;\n ttlMs: number;\n afterGeneration?: number;\n }): Promise<DeviceApiLeaseIface>;\n recoverLease(args: {\n caller: DeviceApiCallerIface;\n deviceId: string;\n sessionId: string;\n bindingId: string;\n access: DeviceApiLeaseAccess;\n }): Promise<DeviceApiLeaseIface>;\n renew(args: {\n caller: DeviceApiCallerIface;\n lease: string;\n ttlMs: number;\n }): Promise<DeviceApiLeaseIface>;\n release(args: { caller: DeviceApiCallerIface; lease: string }): Promise<void>;\n // The sandbox transport over one lease; `lease()` is the current handle.\n transport(args: {\n caller: DeviceApiCallerIface;\n lease: () => Promise<string>;\n }): SandboxTransportIface;\n localMcpServers(args: { caller: DeviceApiCallerIface; lease: string }): Promise<string[]>;\n // What the Device's MCP servers last listed through the API, without a lease.\n mcpCatalog(args: {\n caller: DeviceApiCallerIface;\n deviceId: string;\n }): Promise<DeviceApiMcpCatalogIface>;\n pipe(args: {\n caller: DeviceApiCallerIface;\n lease: string;\n server: string;\n action: 'open' | 'write' | 'read' | 'close';\n clientId: string;\n dataBase64?: string;\n signal?: AbortSignal;\n }): Promise<string>;\n screen(args: {\n caller: DeviceApiCallerIface;\n deviceId: string;\n sessionId: string;\n viewOnly?: boolean;\n }): Promise<{ url: string; token: string; expiresAt: string }>;\n}\n\nexport const createDeviceApiClient = (config: {\n api: DeviceApiConfigIface | (() => DeviceApiConfigIface);\n fetch?: DeviceApiFetchIface;\n}): DeviceApiClientIface => {\n const readApi = () => (typeof config.api === 'function' ? config.api() : config.api);\n const failure = async (response: Response): Promise<DeviceApiErrorIface> => {\n // Read as text so proxy and load balancer error pages survive.\n const text = await response.text().catch(() => '');\n const body = errorBodySchema.safeParse(parseJson(text));\n return body.success\n ? apiError(response.status, body.data.error.code, body.data.error.message)\n : apiError(response.status, 'http', text.slice(0, 200) || response.statusText);\n };\n\n const accessFor = async (args: {\n caller: DeviceApiCallerIface;\n actingUserId: string | null;\n refresh: boolean;\n }): Promise<FinalPlatformAccessIface> => {\n const access = await args.caller.credentials?.deviceAccess({\n actingUserId: args.actingUserId,\n refresh: args.refresh,\n });\n if (access == null) throw credentialMissing(args.actingUserId);\n return access;\n };\n\n // One authenticated call for the user it acts for; rejected access is asked for\n // again once, in case it expired.\n const send = async (args: {\n caller: DeviceApiCallerIface;\n method: string;\n path: string;\n query?: Record<string, string>;\n body?: BodyInit;\n contentType?: string;\n signal?: AbortSignal;\n anonymous?: boolean;\n }): Promise<Response> => {\n const api = readApi();\n const actingUserId = await args.caller.actingUser.current();\n if (actingUserId == null && !args.anonymous) throw noActingUser();\n const attempt = async (refresh: boolean): Promise<Response> => {\n const access = await accessFor({ caller: args.caller, actingUserId, refresh });\n const url = new URL(`${access.baseUrl.replace(/\\/+$/, '')}${args.path}`);\n for (const [key, value] of Object.entries(args.query ?? {})) url.searchParams.set(key, value);\n const headers = new Headers({ authorization: `Bearer ${access.token}` });\n if (actingUserId != null) headers.set(DEVICE_API_ACTING_USER_HEADER, actingUserId);\n if (args.contentType != null) headers.set('content-type', args.contentType);\n return (config.fetch ?? api.fetch ?? fetch)(url.toString(), {\n method: args.method,\n headers,\n body: args.body,\n signal: args.signal,\n });\n };\n let response = await attempt(false);\n if (response.status === 401) {\n await response.text().catch(() => '');\n response = await attempt(true);\n }\n return response;\n };\n\n const json = async <T extends z.ZodType>(\n schema: T,\n args: Parameters<typeof send>[0] & { json?: unknown },\n ): Promise<z.infer<T>> => {\n const response = await send({\n ...args,\n body: args.json === undefined ? args.body : JSON.stringify(args.json),\n contentType: args.json === undefined ? args.contentType : 'application/json',\n });\n if (!response.ok) throw await failure(response);\n const text = await response.text();\n return schema.parse(text === '' ? null : parseJson(text));\n };\n\n // A 404 reads as absent.\n const orNull = async <T>(work: Promise<T>): Promise<T | null> => {\n try {\n return await work;\n } catch (cause) {\n if (cause instanceof Error && deviceApiStatusOf(cause) === 404) return null;\n throw cause;\n }\n };\n\n const leasePath = (lease: string, rest: string): string =>\n `/v1/leases/${encodeURIComponent(lease)}${rest}`;\n\n const transport: DeviceApiClientIface['transport'] = ({ caller, lease }) => {\n const call = async <T extends z.ZodType>(\n schema: T,\n args: Omit<Parameters<typeof json>[1], 'caller' | 'path'> & { path: string },\n ): Promise<z.infer<T>> =>\n json(schema, { ...args, caller, path: leasePath(await lease(), args.path) });\n const processPath = (id: string, rest: string): string =>\n `/processes/${encodeURIComponent(id)}${rest}`;\n return {\n kind: 'device-api',\n fileChunkBytes: DEVICE_API_FILE_CHUNK_BYTES,\n outputWaitMs: DEVICE_API_OUTPUT_WAIT_MS,\n stat: async ({ path, signal }): Promise<TransportStatIface | null> => {\n const { stat } = await call(statBodySchema, {\n method: 'GET',\n path: '/files/stat',\n query: { path },\n signal,\n });\n return stat == null ? null : { ...stat, type: stat.type ?? SandboxEntryType.Other };\n },\n readDir: async ({ path, signal }): Promise<TransportDirEntryIface[]> =>\n (\n await call(dirBodySchema, { method: 'GET', path: '/files/dir', query: { path }, signal })\n ).entries.map((entry) => ({ ...entry, type: entry.type ?? SandboxEntryType.Other })),\n readChunk: async ({ path, offset, length, signal }) => {\n const response = await send({\n caller,\n method: 'GET',\n path: leasePath(await lease(), '/files/content'),\n query: { path, offset: String(offset), length: String(length) },\n signal,\n });\n if (!response.ok) throw await failure(response);\n const bytes = new Uint8Array(await response.arrayBuffer());\n return { bytes, eof: bytes.byteLength < length };\n },\n writeChunk: async ({ path, offset, bytes, signal }) => {\n await call(emptySchema, {\n method: 'PUT',\n path: '/files/content',\n query: { path, offset: String(offset) },\n body: new Blob([bytes.slice()]),\n contentType: 'application/octet-stream',\n signal,\n });\n },\n createDirectory: async ({ path, signal }) => {\n await call(emptySchema, {\n method: 'POST',\n path: '/files/directories',\n json: { path },\n signal,\n });\n },\n remove: async ({ path, recursive, force, signal }) => {\n await call(emptySchema, {\n method: 'DELETE',\n path: '/files',\n query: { path, recursive: String(recursive), force: String(force) },\n signal,\n });\n },\n exec: async ({ id, command, cwd, env, timeoutMs, signal }) =>\n call(processSchema, {\n method: 'POST',\n path: '/processes',\n json: { id, command, cwd, env, timeoutMs },\n signal,\n }),\n output: async ({ process, stdoutOffset, stderrOffset, waitMs, signal }) => {\n const output = await call(outputSchema, {\n method: 'POST',\n path: processPath(process.id, '/output'),\n json: { bootId: process.bootId, stdoutOffset, stderrOffset, waitMs },\n signal,\n });\n const stream = (value: z.infer<typeof outputStreamSchema>) => ({\n data: decodeBase64(value.dataBase64),\n nextOffset: value.nextOffset,\n eof: value.eof,\n });\n const result: TransportOutputIface = {\n stdout: stream(output.stdout),\n stderr: stream(output.stderr),\n exited: output.exited,\n exitCode: output.exitCode,\n exitSignal: output.exitSignal,\n };\n return result;\n },\n input: async ({ process, data, eof, signal, terminate, abortSignal }) => {\n if (terminate === true || signal != null) {\n await call(emptySchema, {\n method: 'POST',\n path: processPath(process.id, '/kill'),\n json:\n terminate === true ? { bootId: process.bootId } : { bootId: process.bootId, signal },\n signal: abortSignal,\n });\n if (terminate === true) return;\n }\n if ((data != null && data.byteLength > 0) || eof === true) {\n const body: ProcessInputBodyIface = {\n bootId: process.bootId,\n };\n if (data != null && data.byteLength > 0) body.dataBase64 = encodeBase64(data);\n if (eof === true) body.eof = true;\n await call(emptySchema, {\n method: 'POST',\n path: processPath(process.id, '/input'),\n json: body,\n signal: abortSignal,\n });\n }\n },\n // Lease processes run on the Device and are found again by id and boot\n // while the lease generation lasts.\n processGone: (cause) => {\n if (!(cause instanceof Error)) return false;\n const status = deviceApiStatusOf(cause);\n return (\n status === 404 || (status === 502 && DEVICE_PROCESS_GONE_MESSAGE.test(cause.message))\n );\n },\n close: () => undefined,\n };\n };\n\n return {\n egress: {\n networkState: ({ organizationId, credentials, workspaceId }) =>\n json(deviceWorkspaceNetworkStateSchema, {\n caller: { organizationId, credentials, actingUser: { current: async () => null } },\n anonymous: true,\n method: 'GET',\n path: `/v1/egress/workspaces/${encodeURIComponent(deviceEgressWorkspaceIdSchema.parse(workspaceId))}/network-state`,\n signal: AbortSignal.timeout(30_000),\n }),\n setNetworkPolicy: async ({ caller, workspaceId, policy, initializeIfMissing }) => {\n const userId = await caller.actingUser.current();\n const anonymous = userId == null;\n const resolvedCaller = { ...caller, actingUser: { current: async () => userId } };\n const result = await json(z.object({ ok: z.boolean() }), {\n caller: resolvedCaller,\n method: initializeIfMissing === true ? 'POST' : 'PUT',\n anonymous,\n path: `/v1/egress/workspaces/${encodeURIComponent(deviceEgressWorkspaceIdSchema.parse(workspaceId))}/${initializeIfMissing === true ? 'network-state/initialize' : anonymous ? 'network-state' : 'network-policy'}`,\n json: workspaceNetworkPolicySchema.parse(policy),\n signal: AbortSignal.timeout(30_000),\n });\n if (!result.ok) throw new Error('Device API did not save the workspace network policy');\n },\n workspace: ({ caller, workspaceId }) =>\n json(deviceEgressWorkspaceSchema, {\n caller,\n method: 'GET',\n path: `/v1/egress/workspaces/${encodeURIComponent(deviceEgressWorkspaceIdSchema.parse(workspaceId))}`,\n signal: AbortSignal.timeout(30_000),\n }),\n create: ({ caller, ...input }) =>\n json(deviceEgressEnrollmentSchema, {\n caller,\n method: 'POST',\n path: '/v1/egress/leases',\n json: deviceEgressCreateRequestSchema.parse(input),\n signal: AbortSignal.timeout(180_000),\n }),\n renew: ({ caller, leaseId }) =>\n json(deviceEgressLeaseSchema, {\n caller,\n method: 'POST',\n path: `/v1/egress/leases/${encodeURIComponent(leaseId)}/renew`,\n signal: AbortSignal.timeout(180_000),\n }),\n activate: ({ caller, leaseId }) =>\n json(deviceEgressLeaseSchema, {\n caller,\n method: 'POST',\n path: `/v1/egress/leases/${encodeURIComponent(leaseId)}/activate`,\n signal: AbortSignal.timeout(60_000),\n }),\n revoke: async ({ caller, leaseId, workspaceId }) => {\n await json(emptySchema, {\n caller,\n method: 'DELETE',\n json: { workspaceId },\n path: `/v1/egress/leases/${encodeURIComponent(leaseId)}`,\n signal: AbortSignal.timeout(60_000),\n });\n },\n suspend: async ({\n caller,\n workspaceId,\n }: {\n caller: DeviceApiCallerIface;\n workspaceId: string;\n }) => {\n const userId = await caller.actingUser.current();\n const anonymous = userId == null;\n const resolvedCaller = { ...caller, actingUser: { current: async () => userId } };\n await json(emptySchema, {\n caller: resolvedCaller,\n anonymous,\n method: 'POST',\n path: `/v1/egress/workspaces/${encodeURIComponent(deviceEgressWorkspaceIdSchema.parse(workspaceId))}/${anonymous ? 'network-state/suspend' : 'suspend'}`,\n signal: AbortSignal.timeout(60_000),\n });\n },\n disable: async ({ caller, workspaceId }) => {\n await json(emptySchema, {\n caller,\n method: 'DELETE',\n path: `/v1/egress/workspaces/${encodeURIComponent(deviceEgressWorkspaceIdSchema.parse(workspaceId))}`,\n signal: AbortSignal.timeout(60_000),\n });\n },\n },\n releaseWorkspaceLeases: async ({ caller, deviceId, bindingId }) => {\n const result = await json(z.object({ released: z.boolean() }), {\n caller,\n method: 'DELETE',\n path:\n '/v1/devices/' +\n encodeURIComponent(deviceId) +\n '/workspaces/' +\n encodeURIComponent(bindingId) +\n '/leases',\n });\n if (!result.released) throw new Error('The Device did not release its workspace leases');\n },\n inspectProcesses: ({ caller, deviceId, bindingId, request }) => {\n const suffix =\n request.operation === ProcessInspectionOperation.Available\n ? '/available'\n : 'processId' in request\n ? '/' + encodeURIComponent(request.processId)\n : '';\n const query: Record<string, string> = {};\n if (bindingId != null) query.bindingId = bindingId;\n if ('bootId' in request) query.bootId = request.bootId;\n if ('cursor' in request && request.cursor != null) query.cursor = request.cursor;\n if ('limit' in request && request.limit != null) query.limit = String(request.limit);\n return json(processInspectionResultSchema, {\n caller,\n method: request.operation === ProcessInspectionOperation.Stop ? 'DELETE' : 'GET',\n path: '/v1/devices/' + encodeURIComponent(deviceId) + '/processes' + suffix,\n query,\n });\n },\n getDevice: ({ caller, deviceId }) =>\n orNull(\n json(deviceSchema, {\n caller,\n method: 'GET',\n path: `/v1/devices/${encodeURIComponent(deviceId)}`,\n }),\n ),\n listDevices: async ({ caller }) =>\n (await json(devicesSchema, { caller, method: 'GET', path: '/v1/devices' })).devices,\n resolvePairing: ({ caller, code }) =>\n orNull(\n json(deviceSchema, {\n caller,\n method: 'POST',\n path: '/v1/pairings/resolve',\n json: { code },\n }),\n ),\n lease: async ({ caller, deviceId, sessionId, bindingId, access, ttlMs, afterGeneration }) =>\n leaseOf(\n await json(leaseSchema, {\n caller,\n method: 'POST',\n path: `/v1/devices/${encodeURIComponent(deviceId)}/leases`,\n json: { sessionId, bindingId, access, ttlMs, afterGeneration },\n }),\n ),\n recoverLease: async ({ caller, deviceId, sessionId, bindingId, access }) =>\n leaseOf(\n await json(leaseSchema, {\n caller,\n method: 'POST',\n path: `/v1/devices/${encodeURIComponent(deviceId)}/leases/recover`,\n json: { sessionId, bindingId, access },\n }),\n ),\n renew: async ({ caller, lease, ttlMs }) =>\n leaseOf(\n await json(leaseSchema, {\n caller,\n method: 'POST',\n path: leasePath(lease, '/renew'),\n json: { ttlMs },\n }),\n ),\n release: async ({ caller, lease }) => {\n await json(emptySchema, { caller, method: 'DELETE', path: leasePath(lease, '') });\n },\n transport,\n mcpCatalog: ({ caller, deviceId }) =>\n json(mcpCatalogSchema, {\n caller,\n method: 'GET',\n path: `/v1/devices/${encodeURIComponent(deviceId)}/mcp`,\n }),\n localMcpServers: async ({ caller, lease }) =>\n (await json(serversSchema, { caller, method: 'GET', path: leasePath(lease, '/mcp') }))\n .servers,\n pipe: async ({ caller, lease, server, action, clientId, dataBase64, signal }) =>\n (\n await json(pipeReadSchema, {\n caller,\n method: 'POST',\n path: leasePath(lease, `/mcp/${encodeURIComponent(server)}/${action}`),\n json: dataBase64 == null ? { clientId } : { clientId, dataBase64 },\n signal,\n })\n ).dataBase64 ?? '',\n screen: ({ caller, deviceId, sessionId, viewOnly }) =>\n json(screenSchema, {\n caller,\n method: 'POST',\n path: `/v1/devices/${encodeURIComponent(deviceId)}/screen`,\n json: { sessionId, viewOnly },\n }),\n };\n};\n"],
5
+ "mappings": "AAAA;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OAEK;AACP;AAAA,EACE;AAAA,EACA;AAAA,OAGK;AACP,SAAS,kBAAkB,uBAAuC;AAClE;AAAA,EACE;AAAA,OAIK;AACP,YAAY,OAAO;AACnB,SAAS,cAAc,oBAAoB;AAC3C,SAAS,qCAAqC;AAa9C,SAAS,iCAAAA,sCAAqC;AAoBvC,IAAK,uBAAL,kBAAKC,0BAAL;AACL,EAAAA,sBAAA,UAAO;AACP,EAAAA,sBAAA,WAAQ;AAFE,SAAAA;AAAA,GAAA;AAKL,IAAK,sBAAL,kBAAKC,yBAAL;AACL,EAAAA,qBAAA,WAAQ;AACR,EAAAA,qBAAA,aAAU;AACV,EAAAA,qBAAA,iBAAc;AACd,EAAAA,qBAAA,cAAW;AAJD,SAAAA;AAAA,GAAA;AAOL,MAAM,iCAAiC;AAG9C,MAAM,eAAe,CAAmC,WACtD,EAAE,OAAO,EAAE,UAAU,CAAC,UAA6B;AACjD,QAAM,SAAS,EAAE,WAAW,MAAM,EAAE,UAAU,KAAK;AACnD,SAAO,OAAO,UAAU,OAAO,OAAO;AACxC,CAAC;AAEH,MAAM,eAAe,EAAE,OAAO;AAAA,EAC5B,IAAI,EAAE,OAAO;AAAA,EACb,gBAAgB,EAAE,OAAO;AAAA,EACzB,aAAa,EAAE,OAAO;AAAA,EACtB,IAAI,EAAE,OAAO;AAAA,EACb,QAAQ,EAAE,QAAQ;AAAA,EAClB,UAAU,EAAE,QAAQ;AAAA,EACpB,gBAAgB,EAAE,QAAQ;AAAA,EAC1B,kBAAkB,EAAE,QAAQ;AAAA,EAC5B,aAAa,EAAE,QAAQ;AACzB,CAAC;AAGD,MAAM,cAAc,EAAE,OAAO;AAAA,EAC3B,OAAO,EAAE,OAAO;AAAA,EAChB,UAAU,EAAE,OAAO;AAAA,EACnB,YAAY,EAAE,OAAO;AAAA,EACrB,eAAe,EAAE,OAAO;AAAA,EACxB,UAAU,EAAE,OAAO;AAAA,EACnB,QAAQ,EAAE,WAAW,oBAAoB;AAAA,EACzC,cAAc,EAAE,MAAM,aAAa,mBAAmB,CAAC;AAAA,EACvD,WAAW,EAAE,OAAO;AACtB,CAAC;AAkBD,MAAM,kBAAkB,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,GAAG,SAAS,EAAE,OAAO,EAAE,CAAC,EAAE,CAAC;AAC/F,MAAM,iBAAiB,EAAE,OAAO;AAAA,EAC9B,MAAM,EACH,OAAO;AAAA,IACN,MAAM,aAAa,gBAAgB;AAAA,IACnC,MAAM,EAAE,OAAO;AAAA,IACf,cAAc,EAAE,OAAO,EAAE,SAAS;AAAA,IAClC,MAAM,EAAE,OAAO,EAAE,SAAS;AAAA,EAC5B,CAAC,EACA,SAAS;AACd,CAAC;AACD,MAAM,gBAAgB,EAAE,OAAO;AAAA,EAC7B,SAAS,EAAE;AAAA,IACT,EAAE,OAAO;AAAA,MACP,MAAM,EAAE,OAAO;AAAA,MACf,MAAM,aAAa,gBAAgB;AAAA,MACnC,MAAM,EAAE,OAAO,EAAE,SAAS;AAAA,IAC5B,CAAC;AAAA,EACH;AACF,CAAC;AACD,MAAM,gBAAgB,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,GAAG,QAAQ,EAAE,OAAO,EAAE,CAAC;AACrE,MAAM,qBAAqB,EAAE,OAAO;AAAA,EAClC,YAAY,EAAE,OAAO;AAAA,EACrB,YAAY,EAAE,OAAO;AAAA,EACrB,KAAK,EAAE,QAAQ;AACjB,CAAC;AACD,MAAM,eAAe,EAAE,OAAO;AAAA,EAC5B,QAAQ;AAAA,EACR,QAAQ;AAAA,EACR,QAAQ,EAAE,QAAQ;AAAA,EAClB,UAAU,EAAE,OAAO,EAAE,SAAS;AAAA,EAC9B,YAAY,EAAE,OAAO,EAAE,SAAS;AAClC,CAAC;AACD,MAAM,gBAAgB,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,YAAY,EAAE,CAAC;AACjE,MAAM,gBAAgB,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,CAAC;AAG/D,MAAM,oBAAoB;AAC1B,MAAM,mBAAmB,EAAE,OAAO;AAAA,EAChC,aAAa,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,iBAAiB,EAAE,CAAC,EAAE,SAAS;AAAA,EACtE,cAAc,EACX,OAAO;AAAA,IACN,SAAS,EAAE;AAAA,MACT,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,GAAG,OAAO,EAAE,MAAM,iBAAiB,EAAE,SAAS,EAAE,CAAC;AAAA,IAC7E;AAAA,EACF,CAAC,EACA,SAAS;AACd,CAAC;AAED,MAAM,iBAAiB,EAAE,OAAO,EAAE,YAAY,EAAE,OAAO,EAAE,SAAS,EAAE,CAAC;AACrE,MAAM,eAAe,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO,GAAG,OAAO,EAAE,OAAO,GAAG,WAAW,EAAE,OAAO,EAAE,CAAC;AAC3F,MAAM,cAAc,EAAE,QAAQ;AAGvB,MAAM,8BAA8B,IAAI,OAAO;AAE/C,MAAM,4BAA4B;AAIzC,MAAM,8BACJ;AAEK,IAAK,2BAAL,kBAAKC,8BAAL;AAEL,EAAAA,0BAAA,uBAAoB;AAEpB,EAAAA,0BAAA,kBAAe;AACf,EAAAA,0BAAA,0BAAuB;AALb,SAAAA;AAAA,GAAA;AAaZ,MAAM,WAAW,CAAC,QAAgB,MAAc,YAC9C,OAAO,OAAO,IAAI,MAAM,cAAc,MAAM,IAAI,IAAI,KAAK,OAAO,EAAE,GAAG,EAAE,QAAQ,KAAK,CAAC;AAEvF,MAAM,oBAAoB,CAAC,iBACzB,OAAO;AAAA,EACL,IAAI;AAAA,IACF,oCAAoC,gBAAgB,OAAO,8CAA8C,sBAAsB;AAAA,EACjI;AAAA,EACA,EAAE,QAAQ,MAAM,MAAM,6CAA2C;AACnE;AAEF,MAAM,eAAe,MACnB,OAAO;AAAA,EACL,IAAI;AAAA,IACF;AAAA,EACF;AAAA,EACA,EAAE,QAAQ,MAAM,MAAM,oCAAsC;AAC9D;AAEF,MAAM,eAAe,EAAE,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,CAAC;AAC7C,MAAM,kBAAkB,CAAC,UAC9B,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,EAAE,UAAU,KAAK,EAAE,MAAM,QAAQ;AAEzD,MAAM,oBAAoB,CAAC,UAChC,aAAa,UAAU,KAAK,EAAE,MAAM,UAAU;AAEhD,MAAM,YAAY,CAAC,SAA4B;AAC7C,MAAI;AACF,WAAO,gBAAgB,MAAM,KAAK,MAAM,IAAI,CAAC;AAAA,EAC/C,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEA,MAAM,UAAU,CAAC,SAA2D;AAAA,EAC1E,OAAO,IAAI;AAAA,EACX,UAAU,IAAI;AAAA,EACd,YAAY,IAAI;AAAA,EAChB,eAAe,IAAI;AAAA,EACnB,UAAU,IAAI;AAAA,EACd,QAAQ,IAAI;AAAA,EACZ,cAAc,IAAI,aAAa,OAAO,CAAC,eAAe,cAAc,IAAI;AAAA,EACxE,aAAa,KAAK,MAAM,IAAI,SAAS;AACvC;AAgHO,MAAM,wBAAwB,CAAC,WAGV;AAC1B,QAAM,UAAU,MAAO,OAAO,OAAO,QAAQ,aAAa,OAAO,IAAI,IAAI,OAAO;AAChF,QAAM,UAAU,OAAO,aAAqD;AAE1E,UAAM,OAAO,MAAM,SAAS,KAAK,EAAE,MAAM,MAAM,EAAE;AACjD,UAAM,OAAO,gBAAgB,UAAU,UAAU,IAAI,CAAC;AACtD,WAAO,KAAK,UACR,SAAS,SAAS,QAAQ,KAAK,KAAK,MAAM,MAAM,KAAK,KAAK,MAAM,OAAO,IACvE,SAAS,SAAS,QAAQ,QAAQ,KAAK,MAAM,GAAG,GAAG,KAAK,SAAS,UAAU;AAAA,EACjF;AAEA,QAAM,YAAY,OAAO,SAIgB;AACvC,UAAM,SAAS,MAAM,KAAK,OAAO,aAAa,aAAa;AAAA,MACzD,cAAc,KAAK;AAAA,MACnB,SAAS,KAAK;AAAA,IAChB,CAAC;AACD,QAAI,UAAU,KAAM,OAAM,kBAAkB,KAAK,YAAY;AAC7D,WAAO;AAAA,EACT;AAIA,QAAM,OAAO,OAAO,SASK;AACvB,UAAM,MAAM,QAAQ;AACpB,UAAM,eAAe,MAAM,KAAK,OAAO,WAAW,QAAQ;AAC1D,QAAI,gBAAgB,QAAQ,CAAC,KAAK,UAAW,OAAM,aAAa;AAChE,UAAM,UAAU,OAAO,YAAwC;AAC7D,YAAM,SAAS,MAAM,UAAU,EAAE,QAAQ,KAAK,QAAQ,cAAc,QAAQ,CAAC;AAC7E,YAAM,MAAM,IAAI,IAAI,GAAG,OAAO,QAAQ,QAAQ,QAAQ,EAAE,CAAC,GAAG,KAAK,IAAI,EAAE;AACvE,iBAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,KAAK,SAAS,CAAC,CAAC,EAAG,KAAI,aAAa,IAAI,KAAK,KAAK;AAC5F,YAAM,UAAU,IAAI,QAAQ,EAAE,eAAe,UAAU,OAAO,KAAK,GAAG,CAAC;AACvE,UAAI,gBAAgB,KAAM,SAAQ,IAAI,+BAA+B,YAAY;AACjF,UAAI,KAAK,eAAe,KAAM,SAAQ,IAAI,gBAAgB,KAAK,WAAW;AAC1E,cAAQ,OAAO,SAAS,IAAI,SAAS,OAAO,IAAI,SAAS,GAAG;AAAA,QAC1D,QAAQ,KAAK;AAAA,QACb;AAAA,QACA,MAAM,KAAK;AAAA,QACX,QAAQ,KAAK;AAAA,MACf,CAAC;AAAA,IACH;AACA,QAAI,WAAW,MAAM,QAAQ,KAAK;AAClC,QAAI,SAAS,WAAW,KAAK;AAC3B,YAAM,SAAS,KAAK,EAAE,MAAM,MAAM,EAAE;AACpC,iBAAW,MAAM,QAAQ,IAAI;AAAA,IAC/B;AACA,WAAO;AAAA,EACT;AAEA,QAAM,OAAO,OACX,QACA,SACwB;AACxB,UAAM,WAAW,MAAM,KAAK;AAAA,MAC1B,GAAG;AAAA,MACH,MAAM,KAAK,SAAS,SAAY,KAAK,OAAO,KAAK,UAAU,KAAK,IAAI;AAAA,MACpE,aAAa,KAAK,SAAS,SAAY,KAAK,cAAc;AAAA,IAC5D,CAAC;AACD,QAAI,CAAC,SAAS,GAAI,OAAM,MAAM,QAAQ,QAAQ;AAC9C,UAAM,OAAO,MAAM,SAAS,KAAK;AACjC,WAAO,OAAO,MAAM,SAAS,KAAK,OAAO,UAAU,IAAI,CAAC;AAAA,EAC1D;AAGA,QAAM,SAAS,OAAU,SAAwC;AAC/D,QAAI;AACF,aAAO,MAAM;AAAA,IACf,SAAS,OAAO;AACd,UAAI,iBAAiB,SAAS,kBAAkB,KAAK,MAAM,IAAK,QAAO;AACvE,YAAM;AAAA,IACR;AAAA,EACF;AAEA,QAAM,YAAY,CAAC,OAAe,SAChC,cAAc,mBAAmB,KAAK,CAAC,GAAG,IAAI;AAEhD,QAAM,YAA+C,CAAC,EAAE,QAAQ,MAAM,MAAM;AAC1E,UAAM,OAAO,OACX,QACA,SAEA,KAAK,QAAQ,EAAE,GAAG,MAAM,QAAQ,MAAM,UAAU,MAAM,MAAM,GAAG,KAAK,IAAI,EAAE,CAAC;AAC7E,UAAM,cAAc,CAAC,IAAY,SAC/B,cAAc,mBAAmB,EAAE,CAAC,GAAG,IAAI;AAC7C,WAAO;AAAA,MACL,MAAM;AAAA,MACN,gBAAgB;AAAA,MAChB,cAAc;AAAA,MACd,MAAM,OAAO,EAAE,MAAM,OAAO,MAA0C;AACpE,cAAM,EAAE,KAAK,IAAI,MAAM,KAAK,gBAAgB;AAAA,UAC1C,QAAQ;AAAA,UACR,MAAM;AAAA,UACN,OAAO,EAAE,KAAK;AAAA,UACd;AAAA,QACF,CAAC;AACD,eAAO,QAAQ,OAAO,OAAO,EAAE,GAAG,MAAM,MAAM,KAAK,QAAQ,iBAAiB,MAAM;AAAA,MACpF;AAAA,MACA,SAAS,OAAO,EAAE,MAAM,OAAO,OAE3B,MAAM,KAAK,eAAe,EAAE,QAAQ,OAAO,MAAM,cAAc,OAAO,EAAE,KAAK,GAAG,OAAO,CAAC,GACxF,QAAQ,IAAI,CAAC,WAAW,EAAE,GAAG,OAAO,MAAM,MAAM,QAAQ,iBAAiB,MAAM,EAAE;AAAA,MACrF,WAAW,OAAO,EAAE,MAAM,QAAQ,QAAQ,OAAO,MAAM;AACrD,cAAM,WAAW,MAAM,KAAK;AAAA,UAC1B;AAAA,UACA,QAAQ;AAAA,UACR,MAAM,UAAU,MAAM,MAAM,GAAG,gBAAgB;AAAA,UAC/C,OAAO,EAAE,MAAM,QAAQ,OAAO,MAAM,GAAG,QAAQ,OAAO,MAAM,EAAE;AAAA,UAC9D;AAAA,QACF,CAAC;AACD,YAAI,CAAC,SAAS,GAAI,OAAM,MAAM,QAAQ,QAAQ;AAC9C,cAAM,QAAQ,IAAI,WAAW,MAAM,SAAS,YAAY,CAAC;AACzD,eAAO,EAAE,OAAO,KAAK,MAAM,aAAa,OAAO;AAAA,MACjD;AAAA,MACA,YAAY,OAAO,EAAE,MAAM,QAAQ,OAAO,OAAO,MAAM;AACrD,cAAM,KAAK,aAAa;AAAA,UACtB,QAAQ;AAAA,UACR,MAAM;AAAA,UACN,OAAO,EAAE,MAAM,QAAQ,OAAO,MAAM,EAAE;AAAA,UACtC,MAAM,IAAI,KAAK,CAAC,MAAM,MAAM,CAAC,CAAC;AAAA,UAC9B,aAAa;AAAA,UACb;AAAA,QACF,CAAC;AAAA,MACH;AAAA,MACA,iBAAiB,OAAO,EAAE,MAAM,OAAO,MAAM;AAC3C,cAAM,KAAK,aAAa;AAAA,UACtB,QAAQ;AAAA,UACR,MAAM;AAAA,UACN,MAAM,EAAE,KAAK;AAAA,UACb;AAAA,QACF,CAAC;AAAA,MACH;AAAA,MACA,QAAQ,OAAO,EAAE,MAAM,WAAW,OAAO,OAAO,MAAM;AACpD,cAAM,KAAK,aAAa;AAAA,UACtB,QAAQ;AAAA,UACR,MAAM;AAAA,UACN,OAAO,EAAE,MAAM,WAAW,OAAO,SAAS,GAAG,OAAO,OAAO,KAAK,EAAE;AAAA,UAClE;AAAA,QACF,CAAC;AAAA,MACH;AAAA,MACA,MAAM,OAAO,EAAE,IAAI,SAAS,KAAK,KAAK,WAAW,OAAO,MACtD,KAAK,eAAe;AAAA,QAClB,QAAQ;AAAA,QACR,MAAM;AAAA,QACN,MAAM,EAAE,IAAI,SAAS,KAAK,KAAK,UAAU;AAAA,QACzC;AAAA,MACF,CAAC;AAAA,MACH,QAAQ,OAAO,EAAE,SAAS,cAAc,cAAc,QAAQ,OAAO,MAAM;AACzE,cAAM,SAAS,MAAM,KAAK,cAAc;AAAA,UACtC,QAAQ;AAAA,UACR,MAAM,YAAY,QAAQ,IAAI,SAAS;AAAA,UACvC,MAAM,EAAE,QAAQ,QAAQ,QAAQ,cAAc,cAAc,OAAO;AAAA,UACnE;AAAA,QACF,CAAC;AACD,cAAM,SAAS,CAAC,WAA+C;AAAA,UAC7D,MAAM,aAAa,MAAM,UAAU;AAAA,UACnC,YAAY,MAAM;AAAA,UAClB,KAAK,MAAM;AAAA,QACb;AACA,cAAM,SAA+B;AAAA,UACnC,QAAQ,OAAO,OAAO,MAAM;AAAA,UAC5B,QAAQ,OAAO,OAAO,MAAM;AAAA,UAC5B,QAAQ,OAAO;AAAA,UACf,UAAU,OAAO;AAAA,UACjB,YAAY,OAAO;AAAA,QACrB;AACA,eAAO;AAAA,MACT;AAAA,MACA,OAAO,OAAO,EAAE,SAAS,MAAM,KAAK,QAAQ,WAAW,YAAY,MAAM;AACvE,YAAI,cAAc,QAAQ,UAAU,MAAM;AACxC,gBAAM,KAAK,aAAa;AAAA,YACtB,QAAQ;AAAA,YACR,MAAM,YAAY,QAAQ,IAAI,OAAO;AAAA,YACrC,MACE,cAAc,OAAO,EAAE,QAAQ,QAAQ,OAAO,IAAI,EAAE,QAAQ,QAAQ,QAAQ,OAAO;AAAA,YACrF,QAAQ;AAAA,UACV,CAAC;AACD,cAAI,cAAc,KAAM;AAAA,QAC1B;AACA,YAAK,QAAQ,QAAQ,KAAK,aAAa,KAAM,QAAQ,MAAM;AACzD,gBAAM,OAA8B;AAAA,YAClC,QAAQ,QAAQ;AAAA,UAClB;AACA,cAAI,QAAQ,QAAQ,KAAK,aAAa,EAAG,MAAK,aAAa,aAAa,IAAI;AAC5E,cAAI,QAAQ,KAAM,MAAK,MAAM;AAC7B,gBAAM,KAAK,aAAa;AAAA,YACtB,QAAQ;AAAA,YACR,MAAM,YAAY,QAAQ,IAAI,QAAQ;AAAA,YACtC,MAAM;AAAA,YACN,QAAQ;AAAA,UACV,CAAC;AAAA,QACH;AAAA,MACF;AAAA;AAAA;AAAA,MAGA,aAAa,CAAC,UAAU;AACtB,YAAI,EAAE,iBAAiB,OAAQ,QAAO;AACtC,cAAM,SAAS,kBAAkB,KAAK;AACtC,eACE,WAAW,OAAQ,WAAW,OAAO,4BAA4B,KAAK,MAAM,OAAO;AAAA,MAEvF;AAAA,MACA,OAAO,MAAM;AAAA,IACf;AAAA,EACF;AAEA,SAAO;AAAA,IACL,QAAQ;AAAA,MACN,cAAc,CAAC,EAAE,gBAAgB,aAAa,YAAY,MACxD,KAAK,mCAAmC;AAAA,QACtC,QAAQ,EAAE,gBAAgB,aAAa,YAAY,EAAE,SAAS,YAAY,KAAK,EAAE;AAAA,QACjF,WAAW;AAAA,QACX,QAAQ;AAAA,QACR,MAAM,yBAAyB,mBAAmB,8BAA8B,MAAM,WAAW,CAAC,CAAC;AAAA,QACnG,QAAQ,YAAY,QAAQ,GAAM;AAAA,MACpC,CAAC;AAAA,MACH,kBAAkB,OAAO,EAAE,QAAQ,aAAa,QAAQ,oBAAoB,MAAM;AAChF,cAAM,SAAS,MAAM,OAAO,WAAW,QAAQ;AAC/C,cAAM,YAAY,UAAU;AAC5B,cAAM,iBAAiB,EAAE,GAAG,QAAQ,YAAY,EAAE,SAAS,YAAY,OAAO,EAAE;AAChF,cAAM,SAAS,MAAM,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC,GAAG;AAAA,UACvD,QAAQ;AAAA,UACR,QAAQ,wBAAwB,OAAO,SAAS;AAAA,UAChD;AAAA,UACA,MAAM,yBAAyB,mBAAmB,8BAA8B,MAAM,WAAW,CAAC,CAAC,IAAI,wBAAwB,OAAO,6BAA6B,YAAY,kBAAkB,gBAAgB;AAAA,UACjN,MAAM,6BAA6B,MAAM,MAAM;AAAA,UAC/C,QAAQ,YAAY,QAAQ,GAAM;AAAA,QACpC,CAAC;AACD,YAAI,CAAC,OAAO,GAAI,OAAM,IAAI,MAAM,sDAAsD;AAAA,MACxF;AAAA,MACA,WAAW,CAAC,EAAE,QAAQ,YAAY,MAChC,KAAK,6BAA6B;AAAA,QAChC;AAAA,QACA,QAAQ;AAAA,QACR,MAAM,yBAAyB,mBAAmB,8BAA8B,MAAM,WAAW,CAAC,CAAC;AAAA,QACnG,QAAQ,YAAY,QAAQ,GAAM;AAAA,MACpC,CAAC;AAAA,MACH,QAAQ,CAAC,EAAE,QAAQ,GAAG,MAAM,MAC1B,KAAK,8BAA8B;AAAA,QACjC;AAAA,QACA,QAAQ;AAAA,QACR,MAAM;AAAA,QACN,MAAM,gCAAgC,MAAM,KAAK;AAAA,QACjD,QAAQ,YAAY,QAAQ,IAAO;AAAA,MACrC,CAAC;AAAA,MACH,OAAO,CAAC,EAAE,QAAQ,QAAQ,MACxB,KAAK,yBAAyB;AAAA,QAC5B;AAAA,QACA,QAAQ;AAAA,QACR,MAAM,qBAAqB,mBAAmB,OAAO,CAAC;AAAA,QACtD,QAAQ,YAAY,QAAQ,IAAO;AAAA,MACrC,CAAC;AAAA,MACH,UAAU,CAAC,EAAE,QAAQ,QAAQ,MAC3B,KAAK,yBAAyB;AAAA,QAC5B;AAAA,QACA,QAAQ;AAAA,QACR,MAAM,qBAAqB,mBAAmB,OAAO,CAAC;AAAA,QACtD,QAAQ,YAAY,QAAQ,GAAM;AAAA,MACpC,CAAC;AAAA,MACH,QAAQ,OAAO,EAAE,QAAQ,SAAS,YAAY,MAAM;AAClD,cAAM,KAAK,aAAa;AAAA,UACtB;AAAA,UACA,QAAQ;AAAA,UACR,MAAM,EAAE,YAAY;AAAA,UACpB,MAAM,qBAAqB,mBAAmB,OAAO,CAAC;AAAA,UACtD,QAAQ,YAAY,QAAQ,GAAM;AAAA,QACpC,CAAC;AAAA,MACH;AAAA,MACA,SAAS,OAAO;AAAA,QACd;AAAA,QACA;AAAA,MACF,MAGM;AACJ,cAAM,SAAS,MAAM,OAAO,WAAW,QAAQ;AAC/C,cAAM,YAAY,UAAU;AAC5B,cAAM,iBAAiB,EAAE,GAAG,QAAQ,YAAY,EAAE,SAAS,YAAY,OAAO,EAAE;AAChF,cAAM,KAAK,aAAa;AAAA,UACtB,QAAQ;AAAA,UACR;AAAA,UACA,QAAQ;AAAA,UACR,MAAM,yBAAyB,mBAAmB,8BAA8B,MAAM,WAAW,CAAC,CAAC,IAAI,YAAY,0BAA0B,SAAS;AAAA,UACtJ,QAAQ,YAAY,QAAQ,GAAM;AAAA,QACpC,CAAC;AAAA,MACH;AAAA,MACA,SAAS,OAAO,EAAE,QAAQ,YAAY,MAAM;AAC1C,cAAM,KAAK,aAAa;AAAA,UACtB;AAAA,UACA,QAAQ;AAAA,UACR,MAAM,yBAAyB,mBAAmB,8BAA8B,MAAM,WAAW,CAAC,CAAC;AAAA,UACnG,QAAQ,YAAY,QAAQ,GAAM;AAAA,QACpC,CAAC;AAAA,MACH;AAAA,IACF;AAAA,IACA,wBAAwB,OAAO,EAAE,QAAQ,UAAU,UAAU,MAAM;AACjE,YAAM,SAAS,MAAM,KAAK,EAAE,OAAO,EAAE,UAAU,EAAE,QAAQ,EAAE,CAAC,GAAG;AAAA,QAC7D;AAAA,QACA,QAAQ;AAAA,QACR,MACE,iBACA,mBAAmB,QAAQ,IAC3B,iBACA,mBAAmB,SAAS,IAC5B;AAAA,MACJ,CAAC;AACD,UAAI,CAAC,OAAO,SAAU,OAAM,IAAI,MAAM,iDAAiD;AAAA,IACzF;AAAA,IACA,kBAAkB,CAAC,EAAE,QAAQ,UAAU,WAAW,QAAQ,MAAM;AAC9D,YAAM,SACJ,QAAQ,cAAc,2BAA2B,YAC7C,eACA,eAAe,UACb,MAAM,mBAAmB,QAAQ,SAAS,IAC1C;AACR,YAAM,QAAgC,CAAC;AACvC,UAAI,aAAa,KAAM,OAAM,YAAY;AACzC,UAAI,YAAY,QAAS,OAAM,SAAS,QAAQ;AAChD,UAAI,YAAY,WAAW,QAAQ,UAAU,KAAM,OAAM,SAAS,QAAQ;AAC1E,UAAI,WAAW,WAAW,QAAQ,SAAS,KAAM,OAAM,QAAQ,OAAO,QAAQ,KAAK;AACnF,aAAO,KAAK,+BAA+B;AAAA,QACzC;AAAA,QACA,QAAQ,QAAQ,cAAc,2BAA2B,OAAO,WAAW;AAAA,QAC3E,MAAM,iBAAiB,mBAAmB,QAAQ,IAAI,eAAe;AAAA,QACrE;AAAA,MACF,CAAC;AAAA,IACH;AAAA,IACA,WAAW,CAAC,EAAE,QAAQ,SAAS,MAC7B;AAAA,MACE,KAAK,cAAc;AAAA,QACjB;AAAA,QACA,QAAQ;AAAA,QACR,MAAM,eAAe,mBAAmB,QAAQ,CAAC;AAAA,MACnD,CAAC;AAAA,IACH;AAAA,IACF,aAAa,OAAO,EAAE,OAAO,OAC1B,MAAM,KAAK,eAAe,EAAE,QAAQ,QAAQ,OAAO,MAAM,cAAc,CAAC,GAAG;AAAA,IAC9E,gBAAgB,CAAC,EAAE,QAAQ,KAAK,MAC9B;AAAA,MACE,KAAK,cAAc;AAAA,QACjB;AAAA,QACA,QAAQ;AAAA,QACR,MAAM;AAAA,QACN,MAAM,EAAE,KAAK;AAAA,MACf,CAAC;AAAA,IACH;AAAA,IACF,OAAO,OAAO,EAAE,QAAQ,UAAU,WAAW,WAAW,QAAQ,OAAO,gBAAgB,MACrF;AAAA,MACE,MAAM,KAAK,aAAa;AAAA,QACtB;AAAA,QACA,QAAQ;AAAA,QACR,MAAM,eAAe,mBAAmB,QAAQ,CAAC;AAAA,QACjD,MAAM,EAAE,WAAW,WAAW,QAAQ,OAAO,gBAAgB;AAAA,MAC/D,CAAC;AAAA,IACH;AAAA,IACF,cAAc,OAAO,EAAE,QAAQ,UAAU,WAAW,WAAW,OAAO,MACpE;AAAA,MACE,MAAM,KAAK,aAAa;AAAA,QACtB;AAAA,QACA,QAAQ;AAAA,QACR,MAAM,eAAe,mBAAmB,QAAQ,CAAC;AAAA,QACjD,MAAM,EAAE,WAAW,WAAW,OAAO;AAAA,MACvC,CAAC;AAAA,IACH;AAAA,IACF,OAAO,OAAO,EAAE,QAAQ,OAAO,MAAM,MACnC;AAAA,MACE,MAAM,KAAK,aAAa;AAAA,QACtB;AAAA,QACA,QAAQ;AAAA,QACR,MAAM,UAAU,OAAO,QAAQ;AAAA,QAC/B,MAAM,EAAE,MAAM;AAAA,MAChB,CAAC;AAAA,IACH;AAAA,IACF,SAAS,OAAO,EAAE,QAAQ,MAAM,MAAM;AACpC,YAAM,KAAK,aAAa,EAAE,QAAQ,QAAQ,UAAU,MAAM,UAAU,OAAO,EAAE,EAAE,CAAC;AAAA,IAClF;AAAA,IACA;AAAA,IACA,YAAY,CAAC,EAAE,QAAQ,SAAS,MAC9B,KAAK,kBAAkB;AAAA,MACrB;AAAA,MACA,QAAQ;AAAA,MACR,MAAM,eAAe,mBAAmB,QAAQ,CAAC;AAAA,IACnD,CAAC;AAAA,IACH,iBAAiB,OAAO,EAAE,QAAQ,MAAM,OACrC,MAAM,KAAK,eAAe,EAAE,QAAQ,QAAQ,OAAO,MAAM,UAAU,OAAO,MAAM,EAAE,CAAC,GACjF;AAAA,IACL,MAAM,OAAO,EAAE,QAAQ,OAAO,QAAQ,QAAQ,UAAU,YAAY,OAAO,OAEvE,MAAM,KAAK,gBAAgB;AAAA,MACzB;AAAA,MACA,QAAQ;AAAA,MACR,MAAM,UAAU,OAAO,QAAQ,mBAAmB,MAAM,CAAC,IAAI,MAAM,EAAE;AAAA,MACrE,MAAM,cAAc,OAAO,EAAE,SAAS,IAAI,EAAE,UAAU,WAAW;AAAA,MACjE;AAAA,IACF,CAAC,GACD,cAAc;AAAA,IAClB,QAAQ,CAAC,EAAE,QAAQ,UAAU,WAAW,SAAS,MAC/C,KAAK,cAAc;AAAA,MACjB;AAAA,MACA,QAAQ;AAAA,MACR,MAAM,eAAe,mBAAmB,QAAQ,CAAC;AAAA,MACjD,MAAM,EAAE,WAAW,SAAS;AAAA,IAC9B,CAAC;AAAA,EACL;AACF;",
6
6
  "names": ["DEVICE_API_ACTING_USER_HEADER", "DeviceApiLeaseAccess", "DeviceApiCapability", "DeviceApiClientErrorCode"]
7
7
  }
@@ -130,6 +130,8 @@ const createDeviceSandboxProvider = (config) => {
130
130
  randomUuid,
131
131
  paths,
132
132
  commands: commandEncoderFor(platform),
133
+ // Lease processes end with the lease generation; a new one knows none.
134
+ processScope: () => String(current.generation),
133
135
  network: {
134
136
  ports: [],
135
137
  getPortEndpoint: async () => {
@@ -145,6 +147,8 @@ const createDeviceSandboxProvider = (config) => {
145
147
  const computerUse = offered.has(DeviceApiCapability.ComputerUse);
146
148
  const capabilities = [SandboxCapability.Files];
147
149
  if (processes) capabilities.push(SandboxCapability.Process);
150
+ if (processes && access !== SandboxAccess.Read)
151
+ capabilities.push(SandboxCapability.DurableProcesses);
148
152
  if (localMcp) capabilities.push(SandboxCapability.LocalMcp);
149
153
  if (computerUse) capabilities.push(SandboxCapability.ComputerUse);
150
154
  if (device.screenReady) capabilities.push(SandboxCapability.Screen);
@@ -186,6 +190,7 @@ const createDeviceSandboxProvider = (config) => {
186
190
  });
187
191
  };
188
192
  const sandbox = { ...session, capabilities };
193
+ if (!processes) delete sandbox.attachProcess;
189
194
  if (computerUse) {
190
195
  sandbox.computerUse = async () => channelEndpoint(DEVICE_COMPUTER_USE_SERVER);
191
196
  }
@@ -258,6 +263,7 @@ const createDeviceSandboxProvider = (config) => {
258
263
  if (device.writable && device.allowProcesses) {
259
264
  offered.push(
260
265
  SandboxCapability.Process,
266
+ SandboxCapability.DurableProcesses,
261
267
  SandboxCapability.LocalMcp,
262
268
  SandboxCapability.ComputerUse
263
269
  );
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../../src/sandboxes/device.ts"],
4
- "sourcesContent": ["import { ProcessInspectionOperation } from '@finalai/agent-protocol/process-inspection';\nimport {\n SandboxAccess,\n toolDescriptorSchema,\n type JsonObject,\n type JsonValue,\n type ToolDescriptorIface,\n} from '@finalai/agent-provider';\nimport {\n defineSandboxProvider,\n SandboxCapability,\n type McpChannelEndpointIface,\n type NetworkSandboxSessionIface,\n type SandboxProviderHandleIface,\n type SandboxProviderIface,\n type SandboxProviderImplementationIface,\n type SandboxStartContextIface,\n} from '@finalai/agent-provider/sandbox';\nimport * as z from 'zod';\nimport { commandEncoderFor } from \"./commands.mjs\";\nimport {\n createDeviceApiClient,\n DEVICE_API_COMPUTER_USE_SERVER,\n DeviceApiCapability,\n DeviceApiLeaseAccess,\n type DeviceApiCallerIface,\n type DeviceApiConfigIface,\n type DeviceApiDeviceIface,\n type DeviceApiFetchIface,\n type DeviceApiLeaseIface,\n} from \"./device-api.mjs\";\nimport { computerOpenOptionsSchema, deviceEnvironmentSchema } from \"./environment.mjs\";\nimport { createMcpPipe } from \"./mcp-pipe.mjs\";\nimport { sandboxPathsFor, SandboxPlatform } from \"./paths.mjs\";\nimport { createTransportSession, sessionForAccess } from \"./session.mjs\";\n\nexport { DEVICE_API_ACTING_USER_HEADER, DeviceApiClientErrorCode } from \"./device-api.mjs\";\nexport type { DeviceApiConfigIface, DeviceApiFetchIface } from \"./device-api.mjs\";\nexport { DEVICE_SANDBOX_SPECIFIER } from \"./environment.mjs\";\nexport type { FinalPlatformAccessIface } from '@finalai/agent-provider/sandbox';\nexport { SandboxPlatform } from \"./paths.mjs\";\n\n// The `device` sandbox: a user's own computer running Final Device. The\n// provider is a client of the Device API, the Device's backend, exactly as a\n// vendor provider is a client of its vendor's API: it\n// leases a workspace there and drives files, processes, computer use and the\n// screen through that API with host-provided credentials. It knows nothing of how\n// the Device API reaches the Device (DEVICE_DIRECT_ENDPOINT.md). A Device is one\n// person's machine: every call names the user the session acts for\n// (ctx.actingUser, read per call since it changes between turns), and the Device\n// API refuses a Device that user does not own.\n\nexport interface DeviceSandboxProviderConfigIface {\n // Transport options; the Device API origin and token come from each context's\n // `credentials.deviceAccess`.\n api: DeviceApiConfigIface;\n fetch?: DeviceApiFetchIface;\n // Device leases last at most an hour; renewed while in use.\n leaseTtlMs?: number;\n // How long start and resume wait for an offline Device to connect (default 0:\n // an offline Device fails at once); polled from 500 ms, doubling to 5 s.\n onlineWaitMs?: number;\n sleep?: (ms: number) => Promise<void>;\n log?: (message: string, fields?: Record<string, string | number | boolean | null>) => void;\n randomUuid?: () => string;\n now?: () => number;\n}\n\nconst deviceArtifactSchema = z.object({ version: z.literal(1), deviceId: z.string() });\nconst deviceStateSchema = z.object({\n version: z.literal(1),\n deviceId: z.string(),\n generation: z.number().int().min(1),\n access: z.nativeEnum(SandboxAccess),\n});\nexport type DeviceSandboxArtifact = z.infer<typeof deviceArtifactSchema>;\nexport type DeviceSandboxState = z.infer<typeof deviceStateSchema>;\n\nexport const DEVICE_COMPUTER_USE_SERVER = DEVICE_API_COMPUTER_USE_SERVER;\n\nexport interface DeviceSandboxSessionIface extends NetworkSandboxSessionIface {\n readonly capabilities: readonly SandboxCapability[];\n}\n\nexport type DeviceSandboxProviderIface = SandboxProviderIface<\n JsonValue,\n JsonValue,\n DeviceSandboxArtifact,\n DeviceSandboxState,\n DeviceSandboxSessionIface\n>;\n\n// The Device API's recorded tools as tool descriptors; one that does not fit\n// the contract is left out.\nconst descriptorsOf = (tools: readonly JsonObject[]): ToolDescriptorIface[] =>\n tools.flatMap((tool) => {\n const parsed = toolDescriptorSchema.safeParse({\n ...tool,\n description: tool.description ?? tool.title ?? tool.name,\n });\n return parsed.success ? [parsed.data] : [];\n });\n\nconst LEASE_RENEW_MARGIN_MS = 5 * 60_000;\nconst ONLINE_POLL_MS = 500;\nconst ONLINE_POLL_MAX_MS = 5_000;\nconst MAX_LEASE_TTL_MS = 60 * 60_000;\nconst MIN_LEASE_TTL_MS = 60_000;\n\nconst platformOf = (platform: string): SandboxPlatform =>\n platform === 'windows' ? SandboxPlatform.Windows : SandboxPlatform.Posix;\n\nexport const createDeviceSandboxProvider = (\n config: DeviceSandboxProviderConfigIface,\n): DeviceSandboxProviderIface => {\n const randomUuid = config.randomUuid ?? (() => crypto.randomUUID());\n const now = config.now ?? (() => Date.now());\n const log = config.log ?? (() => undefined);\n const leaseTtlMs = Math.max(\n MIN_LEASE_TTL_MS,\n Math.min(config.leaseTtlMs ?? 15 * 60_000, MAX_LEASE_TTL_MS),\n );\n const sleep =\n config.sleep ?? ((ms: number) => new Promise<void>((resolve) => setTimeout(resolve, ms)));\n const onlineWaitMs = config.onlineWaitMs ?? 0;\n const api = createDeviceApiClient({ api: config.api, fetch: config.fetch });\n\n // A Device runs when it is connected to the Device API; nothing is leased before.\n const awaitOnline = async (\n caller: DeviceApiCallerIface,\n deviceId: string,\n timeoutMs: number,\n ): Promise<DeviceApiDeviceIface> => {\n const deadline = now() + timeoutMs;\n let pollMs = ONLINE_POLL_MS;\n for (;;) {\n const device = await api.getDevice({ caller, deviceId });\n if (device == null) throw new Error(`device ${deviceId} was not found`);\n if (device.online) return device;\n const left = deadline - now();\n if (left <= 0) throw new Error(`${device.displayName} is not connected`);\n await sleep(Math.min(pollMs, left));\n pollMs = Math.min(pollMs * 2, ONLINE_POLL_MAX_MS);\n }\n };\n\n const attach = async (args: {\n ctx: SandboxStartContextIface;\n deviceId: string;\n afterGeneration: number | null;\n passive?: boolean;\n access: SandboxAccess;\n }): Promise<{\n handle: SandboxProviderHandleIface<DeviceSandboxSessionIface>;\n generation: number;\n }> => {\n const { ctx, access } = args;\n const caller: DeviceApiCallerIface = {\n organizationId: ctx.session.organizationId,\n credentials: ctx.credentials,\n actingUser: ctx.actingUser,\n };\n const bindingId = ctx.session.bindingId;\n // The provider's awaitRunning, before the lease.\n const device = await awaitOnline(caller, args.deviceId, onlineWaitMs);\n // Processes need the Device's write lease, so execute access does too.\n if (access !== SandboxAccess.Read && !device.writable) {\n throw new Error(`${device.displayName} does not permit writes`);\n }\n const leaseAccess =\n access === SandboxAccess.Read ? DeviceApiLeaseAccess.Read : DeviceApiLeaseAccess.Write;\n let current: DeviceApiLeaseIface =\n args.passive === true\n ? await api.recoverLease({\n caller,\n deviceId: device.id,\n sessionId: ctx.session.id,\n bindingId,\n access: leaseAccess,\n })\n : await api.lease({\n caller,\n deviceId: device.id,\n sessionId: ctx.session.id,\n bindingId,\n access: leaseAccess,\n ttlMs: leaseTtlMs,\n afterGeneration: args.afterGeneration ?? undefined,\n });\n if (\n args.passive === true &&\n (current.deviceId !== device.id ||\n current.access !== leaseAccess ||\n current.generation < (args.afterGeneration ?? 0) ||\n current.expiresAtMs <= now())\n )\n throw new Error('The existing Device lease is unavailable');\n let renewing: Promise<DeviceApiLeaseIface> | null = null;\n // The current lease handle, renewed shortly before it lapses.\n const lease = async (): Promise<string> => {\n if (current.expiresAtMs - now() < LEASE_RENEW_MARGIN_MS) {\n renewing ??= (\n args.passive === true\n ? api.recoverLease({\n caller,\n deviceId: device.id,\n sessionId: ctx.session.id,\n bindingId,\n access: leaseAccess,\n })\n : api.renew({ caller, lease: current.lease, ttlMs: leaseTtlMs })\n ).finally(() => {\n renewing = null;\n });\n current = await renewing;\n }\n return current.lease;\n };\n let released = false;\n const release = async (): Promise<void> => {\n if (released) return;\n released = true;\n await api.release({ caller, lease: current.lease });\n };\n\n const platform = platformOf(current.platform);\n const paths = sandboxPathsFor(platform);\n const session = createTransportSession({\n id: `${device.id}:${bindingId}`,\n description: `${device.displayName} (Final Device)`,\n workspaceRoot: current.workspaceRoot,\n transport: api.transport({ caller, lease }),\n baseEnv: async () => ({}),\n randomUuid,\n paths,\n commands: commandEncoderFor(platform),\n network: {\n ports: [],\n getPortEndpoint: async () => {\n throw new Error('Final Device sandboxes expose no ports');\n },\n stop: release,\n destroy: release,\n },\n });\n\n const offered = new Set(current.capabilities);\n const processes = offered.has(DeviceApiCapability.Process);\n const localMcp = offered.has(DeviceApiCapability.LocalMcp);\n const computerUse = offered.has(DeviceApiCapability.ComputerUse);\n const capabilities = [SandboxCapability.Files];\n if (processes) capabilities.push(SandboxCapability.Process);\n if (localMcp) capabilities.push(SandboxCapability.LocalMcp);\n if (computerUse) capabilities.push(SandboxCapability.ComputerUse);\n if (device.screenReady) capabilities.push(SandboxCapability.Screen);\n\n // The Device's computer-use server, or one of its local MCP servers, is a byte\n // pipe in the Device API (`/v1/leases/:lease/mcp/:server/{open,write,read,close}`):\n // a channel endpoint whoever runs this handle opens in process.\n const channelEndpoint = (server: string): McpChannelEndpointIface => ({\n name: server,\n connect: async () => {\n const pipe = openMcpPipe(server);\n return {\n send: (message, options) => pipe.send(message, options?.abortSignal),\n receive: (options) => pipe.receive(options?.abortSignal),\n close: () => pipe.close(),\n };\n },\n });\n const openMcpPipe = (server: string) => {\n const clientId = randomUuid();\n const request = async (\n action: 'open' | 'write' | 'read' | 'close',\n dataBase64?: string,\n signal?: AbortSignal,\n ): Promise<string> =>\n api.pipe({\n caller,\n lease: await lease(),\n server,\n action,\n clientId,\n dataBase64,\n signal,\n });\n return createMcpPipe({\n wire: {\n open: async (signal) => {\n await request('open', undefined, signal);\n },\n write: async (data, signal) => {\n await request('write', data, signal);\n },\n read: (signal) => request('read', undefined, signal),\n close: async () => {\n await request('close').catch(() => undefined);\n },\n },\n });\n };\n const sandbox: DeviceSandboxSessionIface = { ...session, capabilities };\n if (computerUse) {\n sandbox.computerUse = async () => channelEndpoint(DEVICE_COMPUTER_USE_SERVER);\n }\n if (localMcp) {\n sandbox.localMcp = async () =>\n (await api.localMcpServers({ caller, lease: await lease() })).map(channelEndpoint);\n }\n if (device.screenReady) {\n sandbox.screen = (options) =>\n api.screen({\n caller,\n deviceId: device.id,\n sessionId: randomUuid(),\n viewOnly: options?.viewOnly ?? true,\n });\n }\n log('device_sandbox.attached', { deviceId: device.id, generation: current.generation });\n return {\n generation: current.generation,\n handle: {\n // The Device enforces the read lease too; the view refuses before a round trip.\n sandbox: sessionForAccess(sandbox, access),\n onSandboxStop: release,\n onSandboxDelete: release,\n onRuntimeShutdown: async () => undefined,\n },\n };\n };\n\n const environment = (\n rawOptions?: JsonValue,\n ): SandboxProviderImplementationIface<\n JsonValue,\n DeviceSandboxArtifact,\n DeviceSandboxState,\n DeviceSandboxSessionIface\n > => {\n const parsed = deviceEnvironmentSchema.safeParse(rawOptions ?? {});\n if (!parsed.success) throw new Error(`invalid device environment: ${parsed.error.message}`);\n const options = parsed.data;\n // The Device the environment names; the Device API checks on every call\n // that the acting user owns it.\n const resolveDeviceId = async (caller: DeviceApiCallerIface): Promise<string> => {\n if ('deviceId' in options) return options.deviceId;\n if ('pairing' in options) {\n const device = await api.resolvePairing({ caller, code: options.pairing });\n if (device == null) throw new Error('the Final Device pairing code is unknown or expired');\n return device.id;\n }\n // An unnamed binding uses the only Device of the user the session acts\n // for (the API lists only that user's Devices), never another member's.\n const devices = await api.listDevices({ caller });\n const [only] = devices;\n if (devices.length !== 1 || only == null) {\n throw new Error(\n devices.length === 0\n ? 'the user this session acts for has no Final Device'\n : 'the user this session acts for has several Final Devices; name one by id or pairing code',\n );\n }\n return only.id;\n };\n return {\n processes: async (ctx, rawState, request) => {\n const state = deviceStateSchema.parse(rawState);\n if (\n request.operation === ProcessInspectionOperation.Stop &&\n state.access === SandboxAccess.Read\n )\n throw new Error('stopping processes requires execute access');\n return api.inspectProcesses({\n caller: ctx,\n deviceId: state.deviceId,\n bindingId: ctx.bindingId,\n request,\n });\n },\n // What a lease on this Device grants, known from the registry without\n // leasing (the Device API's rule: processes, local MCP and computer use with\n // a write lease on a Device that allows processes). The computer-use\n // driver's readiness is checked when leased.\n capabilities: async (ctx) => {\n const device = await api.getDevice({\n caller: ctx,\n deviceId: await resolveDeviceId(ctx),\n });\n if (device == null) return null;\n const offered = [SandboxCapability.Files];\n if (device.writable && device.allowProcesses) {\n offered.push(\n SandboxCapability.Process,\n SandboxCapability.LocalMcp,\n SandboxCapability.ComputerUse,\n );\n }\n if (device.screenReady) offered.push(SandboxCapability.Screen);\n return offered;\n },\n // What the Device's servers last listed through the Device API (it records\n // them from the MCP pipes), so the projection lists them without leasing.\n // A Device the API has never seen list gives unknown; its first lease does.\n mcpCatalog: async (ctx) => {\n const catalog = await api.mcpCatalog({\n caller: ctx,\n deviceId: await resolveDeviceId(ctx),\n });\n const local = catalog.localServers;\n const localMcp: Record<string, ToolDescriptorIface[]> = {};\n let localKnown = local != null;\n for (const server of local?.servers ?? []) {\n if (server.tools == null) localKnown = false;\n else localMcp[server.name] = descriptorsOf(server.tools);\n }\n return {\n computerUse:\n catalog.computerUse == null ? null : descriptorsOf(catalog.computerUse.tools),\n localMcp: localKnown ? localMcp : null,\n };\n },\n awaitRunning: async (ctx, rawState, { timeoutMs }) => {\n const { deviceId } = deviceStateSchema.pick({ deviceId: true }).parse(rawState);\n await awaitOnline(\n {\n organizationId: ctx.session.organizationId,\n credentials: ctx.credentials,\n actingUser: ctx.actingUser,\n },\n deviceId,\n timeoutMs,\n );\n },\n artifactKey: async (ctx) => `device:${await resolveDeviceId(ctx)}`,\n prepare: async (ctx) => ({ version: 1, deviceId: await resolveDeviceId(ctx) }),\n start: async (ctx, openOptions, rawArtifact) => {\n const artifact = deviceArtifactSchema.parse(rawArtifact);\n const access = computerOpenOptionsSchema.parse(openOptions ?? {}).access;\n const { handle, generation } = await attach({\n ctx,\n deviceId: artifact.deviceId,\n afterGeneration: null,\n access,\n });\n return { handle, state: { version: 1, deviceId: artifact.deviceId, generation, access } };\n },\n // A Device never takes a lease back at an old generation once it lapsed,\n // so every attach leases a later one.\n resume: async (ctx, _artifact, rawState) => {\n const state = deviceStateSchema.parse(rawState);\n return (\n await attach({\n ctx,\n deviceId: state.deviceId,\n afterGeneration: state.generation,\n access: state.access,\n })\n ).handle;\n },\n resumePassive: async (ctx, _artifact, rawState) => {\n const state = deviceStateSchema.parse(rawState);\n return (\n await attach({\n ctx,\n deviceId: state.deviceId,\n afterGeneration: state.generation,\n access: state.access,\n passive: true,\n })\n ).handle;\n },\n onSessionEnd: async (ctx, _artifact, rawState) => {\n const state = deviceStateSchema.parse(rawState);\n await api.releaseWorkspaceLeases({\n caller: {\n organizationId: ctx.session.organizationId,\n credentials: ctx.credentials,\n actingUser: ctx.actingUser,\n },\n deviceId: state.deviceId,\n bindingId: ctx.session.bindingId,\n });\n },\n // The lease lapses on its own; the next generation retires its processes.\n park: async (_ctx, _artifact, rawState) => deviceStateSchema.parse(rawState),\n };\n };\n\n return defineSandboxProvider({\n name: 'device',\n stateProtocolVersion: 1,\n environment,\n });\n};\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import { ProcessInspectionOperation } from '@finalai/agent-protocol/process-inspection';\nimport {\n SandboxAccess,\n toolDescriptorSchema,\n type JsonObject,\n type JsonValue,\n type ToolDescriptorIface,\n} from '@finalai/agent-provider';\nimport {\n defineSandboxProvider,\n SandboxCapability,\n type McpChannelEndpointIface,\n type NetworkSandboxSessionIface,\n type SandboxProviderHandleIface,\n type SandboxProviderIface,\n type SandboxProviderImplementationIface,\n type SandboxStartContextIface,\n} from '@finalai/agent-provider/sandbox';\nimport * as z from 'zod';\nimport { commandEncoderFor } from \"./commands.mjs\";\nimport {\n createDeviceApiClient,\n DEVICE_API_COMPUTER_USE_SERVER,\n DeviceApiCapability,\n DeviceApiLeaseAccess,\n type DeviceApiCallerIface,\n type DeviceApiConfigIface,\n type DeviceApiDeviceIface,\n type DeviceApiFetchIface,\n type DeviceApiLeaseIface,\n} from \"./device-api.mjs\";\nimport { computerOpenOptionsSchema, deviceEnvironmentSchema } from \"./environment.mjs\";\nimport { createMcpPipe } from \"./mcp-pipe.mjs\";\nimport { sandboxPathsFor, SandboxPlatform } from \"./paths.mjs\";\nimport { createTransportSession, sessionForAccess } from \"./session.mjs\";\n\nexport { DEVICE_API_ACTING_USER_HEADER, DeviceApiClientErrorCode } from \"./device-api.mjs\";\nexport type { DeviceApiConfigIface, DeviceApiFetchIface } from \"./device-api.mjs\";\nexport { DEVICE_SANDBOX_SPECIFIER } from \"./environment.mjs\";\nexport type { FinalPlatformAccessIface } from '@finalai/agent-provider/sandbox';\nexport { SandboxPlatform } from \"./paths.mjs\";\n\n// The `device` sandbox: a user's own computer running Final Device. The\n// provider is a client of the Device API, the Device's backend, exactly as a\n// vendor provider is a client of its vendor's API: it\n// leases a workspace there and drives files, processes, computer use and the\n// screen through that API with host-provided credentials. It knows nothing of how\n// the Device API reaches the Device (DEVICE_DIRECT_ENDPOINT.md). A Device is one\n// person's machine: every call names the user the session acts for\n// (ctx.actingUser, read per call since it changes between turns), and the Device\n// API refuses a Device that user does not own.\n\nexport interface DeviceSandboxProviderConfigIface {\n // Transport options; the Device API origin and token come from each context's\n // `credentials.deviceAccess`.\n api: DeviceApiConfigIface;\n fetch?: DeviceApiFetchIface;\n // Device leases last at most an hour; renewed while in use.\n leaseTtlMs?: number;\n // How long start and resume wait for an offline Device to connect (default 0:\n // an offline Device fails at once); polled from 500 ms, doubling to 5 s.\n onlineWaitMs?: number;\n sleep?: (ms: number) => Promise<void>;\n log?: (message: string, fields?: Record<string, string | number | boolean | null>) => void;\n randomUuid?: () => string;\n now?: () => number;\n}\n\nconst deviceArtifactSchema = z.object({ version: z.literal(1), deviceId: z.string() });\nconst deviceStateSchema = z.object({\n version: z.literal(1),\n deviceId: z.string(),\n generation: z.number().int().min(1),\n access: z.nativeEnum(SandboxAccess),\n});\nexport type DeviceSandboxArtifact = z.infer<typeof deviceArtifactSchema>;\nexport type DeviceSandboxState = z.infer<typeof deviceStateSchema>;\n\nexport const DEVICE_COMPUTER_USE_SERVER = DEVICE_API_COMPUTER_USE_SERVER;\n\nexport interface DeviceSandboxSessionIface extends NetworkSandboxSessionIface {\n readonly capabilities: readonly SandboxCapability[];\n}\n\nexport type DeviceSandboxProviderIface = SandboxProviderIface<\n JsonValue,\n JsonValue,\n DeviceSandboxArtifact,\n DeviceSandboxState,\n DeviceSandboxSessionIface\n>;\n\n// The Device API's recorded tools as tool descriptors; one that does not fit\n// the contract is left out.\nconst descriptorsOf = (tools: readonly JsonObject[]): ToolDescriptorIface[] =>\n tools.flatMap((tool) => {\n const parsed = toolDescriptorSchema.safeParse({\n ...tool,\n description: tool.description ?? tool.title ?? tool.name,\n });\n return parsed.success ? [parsed.data] : [];\n });\n\nconst LEASE_RENEW_MARGIN_MS = 5 * 60_000;\nconst ONLINE_POLL_MS = 500;\nconst ONLINE_POLL_MAX_MS = 5_000;\nconst MAX_LEASE_TTL_MS = 60 * 60_000;\nconst MIN_LEASE_TTL_MS = 60_000;\n\nconst platformOf = (platform: string): SandboxPlatform =>\n platform === 'windows' ? SandboxPlatform.Windows : SandboxPlatform.Posix;\n\nexport const createDeviceSandboxProvider = (\n config: DeviceSandboxProviderConfigIface,\n): DeviceSandboxProviderIface => {\n const randomUuid = config.randomUuid ?? (() => crypto.randomUUID());\n const now = config.now ?? (() => Date.now());\n const log = config.log ?? (() => undefined);\n const leaseTtlMs = Math.max(\n MIN_LEASE_TTL_MS,\n Math.min(config.leaseTtlMs ?? 15 * 60_000, MAX_LEASE_TTL_MS),\n );\n const sleep =\n config.sleep ?? ((ms: number) => new Promise<void>((resolve) => setTimeout(resolve, ms)));\n const onlineWaitMs = config.onlineWaitMs ?? 0;\n const api = createDeviceApiClient({ api: config.api, fetch: config.fetch });\n\n // A Device runs when it is connected to the Device API; nothing is leased before.\n const awaitOnline = async (\n caller: DeviceApiCallerIface,\n deviceId: string,\n timeoutMs: number,\n ): Promise<DeviceApiDeviceIface> => {\n const deadline = now() + timeoutMs;\n let pollMs = ONLINE_POLL_MS;\n for (;;) {\n const device = await api.getDevice({ caller, deviceId });\n if (device == null) throw new Error(`device ${deviceId} was not found`);\n if (device.online) return device;\n const left = deadline - now();\n if (left <= 0) throw new Error(`${device.displayName} is not connected`);\n await sleep(Math.min(pollMs, left));\n pollMs = Math.min(pollMs * 2, ONLINE_POLL_MAX_MS);\n }\n };\n\n const attach = async (args: {\n ctx: SandboxStartContextIface;\n deviceId: string;\n afterGeneration: number | null;\n passive?: boolean;\n access: SandboxAccess;\n }): Promise<{\n handle: SandboxProviderHandleIface<DeviceSandboxSessionIface>;\n generation: number;\n }> => {\n const { ctx, access } = args;\n const caller: DeviceApiCallerIface = {\n organizationId: ctx.session.organizationId,\n credentials: ctx.credentials,\n actingUser: ctx.actingUser,\n };\n const bindingId = ctx.session.bindingId;\n // The provider's awaitRunning, before the lease.\n const device = await awaitOnline(caller, args.deviceId, onlineWaitMs);\n // Processes need the Device's write lease, so execute access does too.\n if (access !== SandboxAccess.Read && !device.writable) {\n throw new Error(`${device.displayName} does not permit writes`);\n }\n const leaseAccess =\n access === SandboxAccess.Read ? DeviceApiLeaseAccess.Read : DeviceApiLeaseAccess.Write;\n let current: DeviceApiLeaseIface =\n args.passive === true\n ? await api.recoverLease({\n caller,\n deviceId: device.id,\n sessionId: ctx.session.id,\n bindingId,\n access: leaseAccess,\n })\n : await api.lease({\n caller,\n deviceId: device.id,\n sessionId: ctx.session.id,\n bindingId,\n access: leaseAccess,\n ttlMs: leaseTtlMs,\n afterGeneration: args.afterGeneration ?? undefined,\n });\n if (\n args.passive === true &&\n (current.deviceId !== device.id ||\n current.access !== leaseAccess ||\n current.generation < (args.afterGeneration ?? 0) ||\n current.expiresAtMs <= now())\n )\n throw new Error('The existing Device lease is unavailable');\n let renewing: Promise<DeviceApiLeaseIface> | null = null;\n // The current lease handle, renewed shortly before it lapses.\n const lease = async (): Promise<string> => {\n if (current.expiresAtMs - now() < LEASE_RENEW_MARGIN_MS) {\n renewing ??= (\n args.passive === true\n ? api.recoverLease({\n caller,\n deviceId: device.id,\n sessionId: ctx.session.id,\n bindingId,\n access: leaseAccess,\n })\n : api.renew({ caller, lease: current.lease, ttlMs: leaseTtlMs })\n ).finally(() => {\n renewing = null;\n });\n current = await renewing;\n }\n return current.lease;\n };\n let released = false;\n const release = async (): Promise<void> => {\n if (released) return;\n released = true;\n await api.release({ caller, lease: current.lease });\n };\n\n const platform = platformOf(current.platform);\n const paths = sandboxPathsFor(platform);\n const session = createTransportSession({\n id: `${device.id}:${bindingId}`,\n description: `${device.displayName} (Final Device)`,\n workspaceRoot: current.workspaceRoot,\n transport: api.transport({ caller, lease }),\n baseEnv: async () => ({}),\n randomUuid,\n paths,\n commands: commandEncoderFor(platform),\n // Lease processes end with the lease generation; a new one knows none.\n processScope: () => String(current.generation),\n network: {\n ports: [],\n getPortEndpoint: async () => {\n throw new Error('Final Device sandboxes expose no ports');\n },\n stop: release,\n destroy: release,\n },\n });\n\n const offered = new Set(current.capabilities);\n const processes = offered.has(DeviceApiCapability.Process);\n const localMcp = offered.has(DeviceApiCapability.LocalMcp);\n const computerUse = offered.has(DeviceApiCapability.ComputerUse);\n const capabilities = [SandboxCapability.Files];\n if (processes) capabilities.push(SandboxCapability.Process);\n if (processes && access !== SandboxAccess.Read)\n capabilities.push(SandboxCapability.DurableProcesses);\n if (localMcp) capabilities.push(SandboxCapability.LocalMcp);\n if (computerUse) capabilities.push(SandboxCapability.ComputerUse);\n if (device.screenReady) capabilities.push(SandboxCapability.Screen);\n\n // The Device's computer-use server, or one of its local MCP servers, is a byte\n // pipe in the Device API (`/v1/leases/:lease/mcp/:server/{open,write,read,close}`):\n // a channel endpoint whoever runs this handle opens in process.\n const channelEndpoint = (server: string): McpChannelEndpointIface => ({\n name: server,\n connect: async () => {\n const pipe = openMcpPipe(server);\n return {\n send: (message, options) => pipe.send(message, options?.abortSignal),\n receive: (options) => pipe.receive(options?.abortSignal),\n close: () => pipe.close(),\n };\n },\n });\n const openMcpPipe = (server: string) => {\n const clientId = randomUuid();\n const request = async (\n action: 'open' | 'write' | 'read' | 'close',\n dataBase64?: string,\n signal?: AbortSignal,\n ): Promise<string> =>\n api.pipe({\n caller,\n lease: await lease(),\n server,\n action,\n clientId,\n dataBase64,\n signal,\n });\n return createMcpPipe({\n wire: {\n open: async (signal) => {\n await request('open', undefined, signal);\n },\n write: async (data, signal) => {\n await request('write', data, signal);\n },\n read: (signal) => request('read', undefined, signal),\n close: async () => {\n await request('close').catch(() => undefined);\n },\n },\n });\n };\n const sandbox: DeviceSandboxSessionIface = { ...session, capabilities };\n // Without process access there is nothing to attach to.\n if (!processes) delete sandbox.attachProcess;\n if (computerUse) {\n sandbox.computerUse = async () => channelEndpoint(DEVICE_COMPUTER_USE_SERVER);\n }\n if (localMcp) {\n sandbox.localMcp = async () =>\n (await api.localMcpServers({ caller, lease: await lease() })).map(channelEndpoint);\n }\n if (device.screenReady) {\n sandbox.screen = (options) =>\n api.screen({\n caller,\n deviceId: device.id,\n sessionId: randomUuid(),\n viewOnly: options?.viewOnly ?? true,\n });\n }\n log('device_sandbox.attached', { deviceId: device.id, generation: current.generation });\n return {\n generation: current.generation,\n handle: {\n // The Device enforces the read lease too; the view refuses before a round trip.\n sandbox: sessionForAccess(sandbox, access),\n onSandboxStop: release,\n onSandboxDelete: release,\n onRuntimeShutdown: async () => undefined,\n },\n };\n };\n\n const environment = (\n rawOptions?: JsonValue,\n ): SandboxProviderImplementationIface<\n JsonValue,\n DeviceSandboxArtifact,\n DeviceSandboxState,\n DeviceSandboxSessionIface\n > => {\n const parsed = deviceEnvironmentSchema.safeParse(rawOptions ?? {});\n if (!parsed.success) throw new Error(`invalid device environment: ${parsed.error.message}`);\n const options = parsed.data;\n // The Device the environment names; the Device API checks on every call\n // that the acting user owns it.\n const resolveDeviceId = async (caller: DeviceApiCallerIface): Promise<string> => {\n if ('deviceId' in options) return options.deviceId;\n if ('pairing' in options) {\n const device = await api.resolvePairing({ caller, code: options.pairing });\n if (device == null) throw new Error('the Final Device pairing code is unknown or expired');\n return device.id;\n }\n // An unnamed binding uses the only Device of the user the session acts\n // for (the API lists only that user's Devices), never another member's.\n const devices = await api.listDevices({ caller });\n const [only] = devices;\n if (devices.length !== 1 || only == null) {\n throw new Error(\n devices.length === 0\n ? 'the user this session acts for has no Final Device'\n : 'the user this session acts for has several Final Devices; name one by id or pairing code',\n );\n }\n return only.id;\n };\n return {\n processes: async (ctx, rawState, request) => {\n const state = deviceStateSchema.parse(rawState);\n if (\n request.operation === ProcessInspectionOperation.Stop &&\n state.access === SandboxAccess.Read\n )\n throw new Error('stopping processes requires execute access');\n return api.inspectProcesses({\n caller: ctx,\n deviceId: state.deviceId,\n bindingId: ctx.bindingId,\n request,\n });\n },\n // What a lease on this Device grants, known from the registry without\n // leasing (the Device API's rule: processes, local MCP and computer use with\n // a write lease on a Device that allows processes). The computer-use\n // driver's readiness is checked when leased.\n capabilities: async (ctx) => {\n const device = await api.getDevice({\n caller: ctx,\n deviceId: await resolveDeviceId(ctx),\n });\n if (device == null) return null;\n const offered = [SandboxCapability.Files];\n if (device.writable && device.allowProcesses) {\n offered.push(\n SandboxCapability.Process,\n SandboxCapability.DurableProcesses,\n SandboxCapability.LocalMcp,\n SandboxCapability.ComputerUse,\n );\n }\n if (device.screenReady) offered.push(SandboxCapability.Screen);\n return offered;\n },\n // What the Device's servers last listed through the Device API (it records\n // them from the MCP pipes), so the projection lists them without leasing.\n // A Device the API has never seen list gives unknown; its first lease does.\n mcpCatalog: async (ctx) => {\n const catalog = await api.mcpCatalog({\n caller: ctx,\n deviceId: await resolveDeviceId(ctx),\n });\n const local = catalog.localServers;\n const localMcp: Record<string, ToolDescriptorIface[]> = {};\n let localKnown = local != null;\n for (const server of local?.servers ?? []) {\n if (server.tools == null) localKnown = false;\n else localMcp[server.name] = descriptorsOf(server.tools);\n }\n return {\n computerUse:\n catalog.computerUse == null ? null : descriptorsOf(catalog.computerUse.tools),\n localMcp: localKnown ? localMcp : null,\n };\n },\n awaitRunning: async (ctx, rawState, { timeoutMs }) => {\n const { deviceId } = deviceStateSchema.pick({ deviceId: true }).parse(rawState);\n await awaitOnline(\n {\n organizationId: ctx.session.organizationId,\n credentials: ctx.credentials,\n actingUser: ctx.actingUser,\n },\n deviceId,\n timeoutMs,\n );\n },\n artifactKey: async (ctx) => `device:${await resolveDeviceId(ctx)}`,\n prepare: async (ctx) => ({ version: 1, deviceId: await resolveDeviceId(ctx) }),\n start: async (ctx, openOptions, rawArtifact) => {\n const artifact = deviceArtifactSchema.parse(rawArtifact);\n const access = computerOpenOptionsSchema.parse(openOptions ?? {}).access;\n const { handle, generation } = await attach({\n ctx,\n deviceId: artifact.deviceId,\n afterGeneration: null,\n access,\n });\n return { handle, state: { version: 1, deviceId: artifact.deviceId, generation, access } };\n },\n // A Device never takes a lease back at an old generation once it lapsed,\n // so every attach leases a later one.\n resume: async (ctx, _artifact, rawState) => {\n const state = deviceStateSchema.parse(rawState);\n return (\n await attach({\n ctx,\n deviceId: state.deviceId,\n afterGeneration: state.generation,\n access: state.access,\n })\n ).handle;\n },\n resumePassive: async (ctx, _artifact, rawState) => {\n const state = deviceStateSchema.parse(rawState);\n return (\n await attach({\n ctx,\n deviceId: state.deviceId,\n afterGeneration: state.generation,\n access: state.access,\n passive: true,\n })\n ).handle;\n },\n onSessionEnd: async (ctx, _artifact, rawState) => {\n const state = deviceStateSchema.parse(rawState);\n await api.releaseWorkspaceLeases({\n caller: {\n organizationId: ctx.session.organizationId,\n credentials: ctx.credentials,\n actingUser: ctx.actingUser,\n },\n deviceId: state.deviceId,\n bindingId: ctx.session.bindingId,\n });\n },\n // The lease lapses on its own; the next generation retires its processes.\n park: async (_ctx, _artifact, rawState) => deviceStateSchema.parse(rawState),\n };\n };\n\n return defineSandboxProvider({\n name: 'device',\n stateProtocolVersion: 1,\n environment,\n });\n};\n"],
5
+ "mappings": "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",
6
6
  "names": ["SandboxPlatform"]
7
7
  }
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../../src/sandboxes/paths.ts"],
4
- "sourcesContent": ["import { quoteShellArgument } from '@finalai/computers/shell';\nimport { posix, win32 } from 'node:path';\n\n// Sandbox paths, by the sandbox's platform: computers and Unix Devices are\n// POSIX; a Windows Device's workspace is a drive path (`C:\\Users\\me\\Final\\chat`).\n// Resolving with the wrong flavour turns the root into a relative path under this\n// process's cwd, so every operation would land outside the workspace.\n\nexport enum SandboxPlatform {\n Posix = 'posix',\n Windows = 'windows',\n}\n\nexport interface SandboxPathsIface {\n readonly platform: SandboxPlatform;\n readonly separator: string;\n // Absolute, normalized, without a trailing separator (except a root).\n resolve(root: string, path: string): string;\n join(...parts: string[]): string;\n dirname(path: string): string;\n basename(path: string): string;\n // Whether `path` is `root` or below it.\n isWithin(root: string, path: string): boolean;\n}\n\nconst posixPaths: SandboxPathsIface = {\n platform: SandboxPlatform.Posix,\n separator: '/',\n resolve: (root, path) => {\n const resolved = posix.resolve(root, path);\n return resolved === '/' ? resolved : resolved.replace(/\\/+$/, '');\n },\n join: (...parts) => posix.join(...parts),\n dirname: (path) => posix.dirname(path),\n basename: (path) => posix.basename(path),\n isWithin: (root, path) => {\n const relative = posix.relative(root, path);\n return (\n relative === '' ||\n (relative !== '..' && !relative.startsWith('../') && !posix.isAbsolute(relative))\n );\n },\n};\n\nconst DRIVE_ROOT = /^[A-Za-z]:\\\\$/;\n\n// `\\\\server\\share` and `\\\\?\\` / `\\\\.\\` device paths.\nexport const isUncPath = (path: string): boolean => /^[\\\\/]{2}/.test(path);\n\nexport const isWindowsDrivePath = (path: string): boolean => /^[A-Za-z]:[\\\\/]/.test(path);\n\nconst refuseUnc = (path: string): string => {\n if (isUncPath(path))\n throw new Error(`UNC paths are not supported in a Device workspace: ${path}`);\n return path;\n};\n\nconst windowsPaths: SandboxPathsIface = {\n platform: SandboxPlatform.Windows,\n separator: '\\\\',\n resolve: (root, path) => {\n refuseUnc(path);\n const resolved = refuseUnc(win32.resolve(refuseUnc(root), path));\n return DRIVE_ROOT.test(resolved) ? resolved : resolved.replace(/\\\\+$/, '');\n },\n join: (...parts) => win32.join(...parts),\n dirname: (path) => win32.dirname(path),\n basename: (path) => win32.basename(path),\n // win32.relative compares case-insensitively and across separators; a\n // different drive comes back absolute.\n isWithin: (root, path) => {\n if (isUncPath(root) || isUncPath(path)) return false;\n const relative = win32.relative(root, path);\n return (\n relative === '' ||\n (relative !== '..' && !relative.startsWith('..\\\\') && !win32.isAbsolute(relative))\n );\n },\n};\n\nexport const sandboxPathsFor = (platform: SandboxPlatform): SandboxPathsIface =>\n platform === SandboxPlatform.Windows ? windowsPaths : posixPaths;\n\n// A platform a Device did not report, from the shape of its workspace root.\nexport const platformOfRoot = (root: string): SandboxPlatform =>\n isWindowsDrivePath(root) || isUncPath(root) ? SandboxPlatform.Windows : SandboxPlatform.Posix;\n\nexport const POSIX_PATHS = posixPaths;\n\n// Preserve arguments through both POSIX shells and a Unix Device's fish shell.\nexport const shellQuote = quoteShellArgument;\n"],
4
+ "sourcesContent": ["import { quoteShellArgument } from '@finalai/computers/shell';\nimport { posix, win32 } from 'node:path';\n\n// Sandbox paths, by the sandbox's platform: computers and Unix Devices are\n// POSIX; a Windows Device's workspace is a drive path (`C:\\workspaces\\chat`).\n// Resolving with the wrong flavour turns the root into a relative path under this\n// process's cwd, so every operation would land outside the workspace.\n\nexport enum SandboxPlatform {\n Posix = 'posix',\n Windows = 'windows',\n}\n\nexport interface SandboxPathsIface {\n readonly platform: SandboxPlatform;\n readonly separator: string;\n // Absolute, normalized, without a trailing separator (except a root).\n resolve(root: string, path: string): string;\n join(...parts: string[]): string;\n dirname(path: string): string;\n basename(path: string): string;\n // Whether `path` is `root` or below it.\n isWithin(root: string, path: string): boolean;\n}\n\nconst posixPaths: SandboxPathsIface = {\n platform: SandboxPlatform.Posix,\n separator: '/',\n resolve: (root, path) => {\n const resolved = posix.resolve(root, path);\n return resolved === '/' ? resolved : resolved.replace(/\\/+$/, '');\n },\n join: (...parts) => posix.join(...parts),\n dirname: (path) => posix.dirname(path),\n basename: (path) => posix.basename(path),\n isWithin: (root, path) => {\n const relative = posix.relative(root, path);\n return (\n relative === '' ||\n (relative !== '..' && !relative.startsWith('../') && !posix.isAbsolute(relative))\n );\n },\n};\n\nconst DRIVE_ROOT = /^[A-Za-z]:\\\\$/;\n\n// `\\\\server\\share` and `\\\\?\\` / `\\\\.\\` device paths.\nexport const isUncPath = (path: string): boolean => /^[\\\\/]{2}/.test(path);\n\nexport const isWindowsDrivePath = (path: string): boolean => /^[A-Za-z]:[\\\\/]/.test(path);\n\nconst refuseUnc = (path: string): string => {\n if (isUncPath(path))\n throw new Error(`UNC paths are not supported in a Device workspace: ${path}`);\n return path;\n};\n\nconst windowsPaths: SandboxPathsIface = {\n platform: SandboxPlatform.Windows,\n separator: '\\\\',\n resolve: (root, path) => {\n refuseUnc(path);\n const resolved = refuseUnc(win32.resolve(refuseUnc(root), path));\n return DRIVE_ROOT.test(resolved) ? resolved : resolved.replace(/\\\\+$/, '');\n },\n join: (...parts) => win32.join(...parts),\n dirname: (path) => win32.dirname(path),\n basename: (path) => win32.basename(path),\n // win32.relative compares case-insensitively and across separators; a\n // different drive comes back absolute.\n isWithin: (root, path) => {\n if (isUncPath(root) || isUncPath(path)) return false;\n const relative = win32.relative(root, path);\n return (\n relative === '' ||\n (relative !== '..' && !relative.startsWith('..\\\\') && !win32.isAbsolute(relative))\n );\n },\n};\n\nexport const sandboxPathsFor = (platform: SandboxPlatform): SandboxPathsIface =>\n platform === SandboxPlatform.Windows ? windowsPaths : posixPaths;\n\n// A platform a Device did not report, from the shape of its workspace root.\nexport const platformOfRoot = (root: string): SandboxPlatform =>\n isWindowsDrivePath(root) || isUncPath(root) ? SandboxPlatform.Windows : SandboxPlatform.Posix;\n\nexport const POSIX_PATHS = posixPaths;\n\n// Preserve arguments through both POSIX shells and a Unix Device's fish shell.\nexport const shellQuote = quoteShellArgument;\n"],
5
5
  "mappings": "AAAA,SAAS,0BAA0B;AACnC,SAAS,OAAO,aAAa;AAOtB,IAAK,kBAAL,kBAAKA,qBAAL;AACL,EAAAA,iBAAA,WAAQ;AACR,EAAAA,iBAAA,aAAU;AAFA,SAAAA;AAAA,GAAA;AAiBZ,MAAM,aAAgC;AAAA,EACpC,UAAU;AAAA,EACV,WAAW;AAAA,EACX,SAAS,CAAC,MAAM,SAAS;AACvB,UAAM,WAAW,MAAM,QAAQ,MAAM,IAAI;AACzC,WAAO,aAAa,MAAM,WAAW,SAAS,QAAQ,QAAQ,EAAE;AAAA,EAClE;AAAA,EACA,MAAM,IAAI,UAAU,MAAM,KAAK,GAAG,KAAK;AAAA,EACvC,SAAS,CAAC,SAAS,MAAM,QAAQ,IAAI;AAAA,EACrC,UAAU,CAAC,SAAS,MAAM,SAAS,IAAI;AAAA,EACvC,UAAU,CAAC,MAAM,SAAS;AACxB,UAAM,WAAW,MAAM,SAAS,MAAM,IAAI;AAC1C,WACE,aAAa,MACZ,aAAa,QAAQ,CAAC,SAAS,WAAW,KAAK,KAAK,CAAC,MAAM,WAAW,QAAQ;AAAA,EAEnF;AACF;AAEA,MAAM,aAAa;AAGZ,MAAM,YAAY,CAAC,SAA0B,YAAY,KAAK,IAAI;AAElE,MAAM,qBAAqB,CAAC,SAA0B,kBAAkB,KAAK,IAAI;AAExF,MAAM,YAAY,CAAC,SAAyB;AAC1C,MAAI,UAAU,IAAI;AAChB,UAAM,IAAI,MAAM,sDAAsD,IAAI,EAAE;AAC9E,SAAO;AACT;AAEA,MAAM,eAAkC;AAAA,EACtC,UAAU;AAAA,EACV,WAAW;AAAA,EACX,SAAS,CAAC,MAAM,SAAS;AACvB,cAAU,IAAI;AACd,UAAM,WAAW,UAAU,MAAM,QAAQ,UAAU,IAAI,GAAG,IAAI,CAAC;AAC/D,WAAO,WAAW,KAAK,QAAQ,IAAI,WAAW,SAAS,QAAQ,QAAQ,EAAE;AAAA,EAC3E;AAAA,EACA,MAAM,IAAI,UAAU,MAAM,KAAK,GAAG,KAAK;AAAA,EACvC,SAAS,CAAC,SAAS,MAAM,QAAQ,IAAI;AAAA,EACrC,UAAU,CAAC,SAAS,MAAM,SAAS,IAAI;AAAA;AAAA;AAAA,EAGvC,UAAU,CAAC,MAAM,SAAS;AACxB,QAAI,UAAU,IAAI,KAAK,UAAU,IAAI,EAAG,QAAO;AAC/C,UAAM,WAAW,MAAM,SAAS,MAAM,IAAI;AAC1C,WACE,aAAa,MACZ,aAAa,QAAQ,CAAC,SAAS,WAAW,MAAM,KAAK,CAAC,MAAM,WAAW,QAAQ;AAAA,EAEpF;AACF;AAEO,MAAM,kBAAkB,CAAC,aAC9B,aAAa,0BAA0B,eAAe;AAGjD,MAAM,iBAAiB,CAAC,SAC7B,mBAAmB,IAAI,KAAK,UAAU,IAAI,IAAI,0BAA0B;AAEnE,MAAM,cAAc;AAGpB,MAAM,aAAa;",
6
6
  "names": ["SandboxPlatform"]
7
7
  }
@@ -25,6 +25,7 @@ export interface CreateTransportSessionArgsIface {
25
25
  network: TransportSessionNetworkIface;
26
26
  paths?: SandboxPathsIface;
27
27
  commands?: SandboxCommandEncoderIface;
28
+ processScope?: () => string;
28
29
  }
29
30
  export declare const createTransportSession: (args: CreateTransportSessionArgsIface) => NetworkSandboxSessionIface;
30
31
  export declare const readOnlySession: <S extends NetworkSandboxSessionIface>(session: S) => S;