hyperbrane 0.1.2 → 0.2.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 (287) hide show
  1. package/README.md +67 -25
  2. package/dist/agent/agentClient.d.ts +5 -0
  3. package/dist/agent/agentClient.js +4 -0
  4. package/dist/agent/agentService.d.ts +9 -37
  5. package/dist/agent/agentService.js +62 -322
  6. package/dist/agent/agentStorage.d.ts +1 -20
  7. package/dist/agent/agentStorage.js +0 -30
  8. package/dist/agent/api.d.ts +80 -151
  9. package/dist/agent/api.js +1 -8
  10. package/dist/agent/client.d.ts +3 -1
  11. package/dist/agent/client.js +2 -3
  12. package/dist/agent/control.d.ts +23 -0
  13. package/dist/agent/control.js +479 -0
  14. package/dist/agent/hostTranscript.d.ts +0 -6
  15. package/dist/agent/hostTranscript.js +3 -14
  16. package/dist/agent/session/backend.d.ts +17 -32
  17. package/dist/agent/session/claude/home.d.ts +0 -1
  18. package/dist/agent/session/claude/home.js +0 -1
  19. package/dist/agent/session/claude/provision.d.ts +10 -0
  20. package/dist/agent/session/claude/provision.js +17 -0
  21. package/dist/agent/session/claude/transcript.d.ts +2 -7
  22. package/dist/agent/session/claude/transcript.js +68 -14
  23. package/dist/agent/session/client.d.ts +1 -10
  24. package/dist/agent/session/client.js +0 -3
  25. package/dist/agent/session/codex/provision.d.ts +14 -0
  26. package/dist/agent/session/codex/provision.js +25 -0
  27. package/dist/agent/session/fileTranscript.d.ts +6 -49
  28. package/dist/agent/session/fileTranscript.js +26 -82
  29. package/dist/agent/session/install.d.ts +5 -0
  30. package/dist/agent/session/install.js +35 -0
  31. package/dist/agent/session/sessionStorage.d.ts +4 -35
  32. package/dist/agent/session/sessionStorage.js +10 -16
  33. package/dist/agent/session/sharedConnection.d.ts +0 -8
  34. package/dist/agent/session/sharedConnection.js +0 -7
  35. package/dist/agent/session/storedTranscripts.d.ts +1 -6
  36. package/dist/agent/session/storedTranscripts.js +0 -3
  37. package/dist/agent/session/worker/jsonRpc.d.ts +2 -13
  38. package/dist/agent/session/worker/jsonRpc.js +2 -11
  39. package/dist/agent/session/worker/protocol.d.ts +26 -20
  40. package/dist/agent/session/worker/protocol.js +29 -18
  41. package/dist/agent/session/worker/workerParams.d.ts +0 -5
  42. package/dist/agent/session/worker/workerParams.js +14 -14
  43. package/dist/agent/session/workerConnection.d.ts +2 -13
  44. package/dist/agent/session/workerConnection.js +7 -12
  45. package/dist/agent/session/workerGatewayConnection.d.ts +18 -0
  46. package/dist/agent/session/workerGatewayConnection.js +86 -0
  47. package/dist/agent/vendor-types/manifest.json +87 -0
  48. package/dist/agent/workerBundle.d.ts +4 -19
  49. package/dist/agent/workerBundle.generated.js +1 -1
  50. package/dist/agent/workerBundle.js +3 -30
  51. package/dist/agent/workerReplacement.d.ts +3 -0
  52. package/dist/agent/workerReplacement.js +49 -0
  53. package/dist/cli/agent.js +31 -16
  54. package/dist/cli/command.d.ts +10 -11
  55. package/dist/cli/command.js +0 -4
  56. package/dist/cli/dimension.js +6 -6
  57. package/dist/cli/gateway.js +3 -6
  58. package/dist/cli/main.js +14 -31
  59. package/dist/cli/streamPrinter.d.ts +2 -10
  60. package/dist/cli/streamPrinter.js +16 -46
  61. package/dist/cli/table.d.ts +0 -3
  62. package/dist/cli/table.js +0 -4
  63. package/dist/dimension/api.d.ts +39 -27
  64. package/dist/dimension/api.js +28 -47
  65. package/dist/dimension/client.d.ts +5 -0
  66. package/dist/dimension/client.js +4 -0
  67. package/dist/dimension/control.d.ts +21 -0
  68. package/dist/dimension/control.js +328 -0
  69. package/dist/dimension/image.d.ts +0 -5
  70. package/dist/dimension/image.js +0 -8
  71. package/dist/dimension/imageFiles.generated.js +1 -1
  72. package/dist/dimension/paths.d.ts +5 -4
  73. package/dist/dimension/paths.js +15 -6
  74. package/dist/dimension/service.d.ts +8 -24
  75. package/dist/dimension/service.js +60 -228
  76. package/dist/dimension/transport-worker.d.ts +1 -0
  77. package/dist/dimension/transport-worker.js +151 -0
  78. package/dist/dimension/transportBundle.d.ts +2 -0
  79. package/dist/dimension/transportBundle.generated.d.ts +1 -0
  80. package/dist/dimension/transportBundle.generated.js +2 -0
  81. package/dist/dimension/transportBundle.js +4 -0
  82. package/dist/dimension/transportClient.d.ts +10 -0
  83. package/dist/dimension/transportClient.js +115 -0
  84. package/dist/dimension/transportProtocol.d.ts +53 -0
  85. package/dist/dimension/transportProtocol.js +8 -0
  86. package/dist/index.d.ts +5 -9
  87. package/dist/index.js +5 -19
  88. package/dist/lib/control.d.ts +8 -0
  89. package/dist/lib/control.js +62 -0
  90. package/dist/lib/docker.d.ts +0 -22
  91. package/dist/lib/docker.js +0 -10
  92. package/dist/lib/image.d.ts +0 -3
  93. package/dist/lib/image.js +0 -2
  94. package/dist/lib/jsonDirectory.d.ts +0 -13
  95. package/dist/lib/jsonDirectory.js +10 -15
  96. package/dist/lib/scriptBundle.d.ts +6 -0
  97. package/dist/lib/scriptBundle.js +28 -0
  98. package/dist/lib/sh.d.ts +2 -0
  99. package/dist/lib/sh.js +8 -0
  100. package/dist/lib/sleep.d.ts +0 -1
  101. package/dist/lib/sleep.js +0 -1
  102. package/dist/lib/streamFetch.d.ts +15 -0
  103. package/dist/lib/streamFetch.js +150 -0
  104. package/dist/lib/tar.d.ts +0 -1
  105. package/dist/lib/tar.js +5 -11
  106. package/dist/portal-gateway/api.d.ts +13 -44
  107. package/dist/portal-gateway/api.js +1 -3
  108. package/dist/portal-gateway/control.d.ts +42 -0
  109. package/dist/portal-gateway/control.js +657 -0
  110. package/dist/portal-gateway/gatewayClient.d.ts +5 -0
  111. package/dist/portal-gateway/gatewayClient.js +4 -0
  112. package/dist/portal-gateway/gatewayService.d.ts +8 -38
  113. package/dist/portal-gateway/gatewayService.js +68 -254
  114. package/dist/portal-gateway/image.d.ts +0 -1
  115. package/dist/portal-gateway/image.js +0 -2
  116. package/dist/portal-gateway/imageFiles.generated.js +2 -2
  117. package/dist/portal-gateway/portalClient.d.ts +5 -0
  118. package/dist/portal-gateway/portalClient.js +4 -0
  119. package/dist/portal-gateway/portalService.d.ts +5 -47
  120. package/dist/portal-gateway/portalService.js +19 -349
  121. package/dist/portal-gateway/transport-worker.d.ts +1 -0
  122. package/dist/portal-gateway/transport-worker.js +205 -0
  123. package/dist/portal-gateway/transportBundle.d.ts +2 -0
  124. package/dist/portal-gateway/transportBundle.generated.d.ts +1 -0
  125. package/dist/portal-gateway/transportBundle.generated.js +2 -0
  126. package/dist/portal-gateway/transportBundle.js +4 -0
  127. package/dist/portal-gateway/upstream.d.ts +0 -81
  128. package/dist/portal-gateway/upstream.js +0 -1
  129. package/dist/sandbox/api.d.ts +121 -187
  130. package/dist/sandbox/api.js +5 -7
  131. package/dist/sandbox/client.d.ts +2 -0
  132. package/dist/sandbox/client.js +4 -0
  133. package/dist/sandbox/data-endpoints/dataEndpoints.d.ts +13 -0
  134. package/dist/sandbox/data-endpoints/dataEndpoints.js +100 -0
  135. package/dist/sandbox/data-endpoints/firewalledPorts.d.ts +4 -0
  136. package/dist/sandbox/data-endpoints/firewalledPorts.js +28 -0
  137. package/dist/sandbox/lib/httpOverStream.d.ts +3 -0
  138. package/dist/sandbox/lib/httpOverStream.js +21 -0
  139. package/dist/sandbox/lib/remoteFileOperations.d.ts +10 -0
  140. package/dist/sandbox/lib/remoteFileOperations.js +70 -0
  141. package/dist/sandbox/lib/shellCommand.d.ts +3 -0
  142. package/dist/sandbox/lib/shellCommand.js +7 -0
  143. package/dist/sandbox/providers/boat/boatService.d.ts +2 -0
  144. package/dist/sandbox/providers/boat/boatService.js +321 -0
  145. package/dist/sandbox/providers/exedev/exeDevService.d.ts +2 -0
  146. package/dist/sandbox/providers/exedev/exeDevService.js +127 -0
  147. package/dist/sandbox/providers/exedev/exeDevToken.d.ts +1 -0
  148. package/dist/sandbox/providers/exedev/exeDevToken.js +54 -0
  149. package/dist/sandbox/providers/local/localService.d.ts +2 -0
  150. package/dist/sandbox/providers/local/localService.js +219 -0
  151. package/dist/sandbox/providers/ssh/sshService.d.ts +2 -0
  152. package/dist/sandbox/providers/ssh/sshService.js +82 -0
  153. package/dist/sandbox/providers/ssh/sshTransport.d.ts +12 -0
  154. package/dist/sandbox/providers/ssh/sshTransport.js +216 -0
  155. package/dist/sandbox/service.d.ts +2 -0
  156. package/dist/sandbox/service.js +18 -0
  157. package/dist/sandbox/storage/descriptors.d.ts +6 -0
  158. package/dist/sandbox/storage/descriptors.js +25 -0
  159. package/dist/sandbox/storage/sandboxStorage.d.ts +11 -0
  160. package/dist/sandbox/storage/sandboxStorage.js +42 -0
  161. package/dist/upstreams/anthropic.d.ts +0 -5
  162. package/dist/upstreams/anthropic.js +1 -8
  163. package/dist/upstreams/index.d.ts +2 -6
  164. package/dist/upstreams/index.js +0 -4
  165. package/dist/upstreams/openai.d.ts +0 -5
  166. package/dist/upstreams/openai.js +1 -13
  167. package/package.json +12 -4
  168. package/dist/agent/gatewaySignIns.d.ts +0 -5
  169. package/dist/agent/gatewaySignIns.js +0 -11
  170. package/dist/agent/session/codex/home.d.ts +0 -2
  171. package/dist/agent/session/codex/home.js +0 -4
  172. package/dist/agent/session/codex/messages.d.ts +0 -30
  173. package/dist/agent/session/codex/messages.js +0 -135
  174. package/dist/agent/session/codex/transcript.d.ts +0 -12
  175. package/dist/agent/session/codex/transcript.js +0 -22
  176. package/dist/agent/session/sdkMessages.d.ts +0 -15
  177. package/dist/agent/session/sdkMessages.js +0 -28
  178. package/dist/agent/session/workerSseConnection.d.ts +0 -31
  179. package/dist/agent/session/workerSseConnection.js +0 -76
  180. package/dist/agent/vendor-types/codex/app-server/AbsolutePathBuf.d.ts +0 -10
  181. package/dist/agent/vendor-types/codex/app-server/AbsolutePathBuf.js +0 -2
  182. package/dist/agent/vendor-types/codex/app-server/FunctionCallOutputBody.d.ts +0 -2
  183. package/dist/agent/vendor-types/codex/app-server/FunctionCallOutputBody.js +0 -2
  184. package/dist/agent/vendor-types/codex/app-server/FunctionCallOutputContentItem.d.ts +0 -22
  185. package/dist/agent/vendor-types/codex/app-server/FunctionCallOutputContentItem.js +0 -2
  186. package/dist/agent/vendor-types/codex/app-server/ImageDetail.d.ts +0 -1
  187. package/dist/agent/vendor-types/codex/app-server/ImageDetail.js +0 -2
  188. package/dist/agent/vendor-types/codex/app-server/ImageGenerationFailure.d.ts +0 -5
  189. package/dist/agent/vendor-types/codex/app-server/ImageGenerationFailure.js +0 -2
  190. package/dist/agent/vendor-types/codex/app-server/ImageGenerationItem.d.ts +0 -11
  191. package/dist/agent/vendor-types/codex/app-server/ImageGenerationItem.js +0 -2
  192. package/dist/agent/vendor-types/codex/app-server/LegacyAppPathString.d.ts +0 -23
  193. package/dist/agent/vendor-types/codex/app-server/LegacyAppPathString.js +0 -2
  194. package/dist/agent/vendor-types/codex/app-server/MessagePhase.d.ts +0 -7
  195. package/dist/agent/vendor-types/codex/app-server/MessagePhase.js +0 -2
  196. package/dist/agent/vendor-types/codex/app-server/ReasoningEffort.d.ts +0 -4
  197. package/dist/agent/vendor-types/codex/app-server/ReasoningEffort.js +0 -2
  198. package/dist/agent/vendor-types/codex/app-server/SleepItem.d.ts +0 -7
  199. package/dist/agent/vendor-types/codex/app-server/SleepItem.js +0 -2
  200. package/dist/agent/vendor-types/codex/app-server/WebSearchItem.d.ts +0 -14
  201. package/dist/agent/vendor-types/codex/app-server/WebSearchItem.js +0 -2
  202. package/dist/agent/vendor-types/codex/app-server/serde_json/JsonValue.d.ts +0 -3
  203. package/dist/agent/vendor-types/codex/app-server/serde_json/JsonValue.js +0 -2
  204. package/dist/agent/vendor-types/codex/app-server/v2/AgentMessageDelivery.d.ts +0 -1
  205. package/dist/agent/vendor-types/codex/app-server/v2/AgentMessageDelivery.js +0 -2
  206. package/dist/agent/vendor-types/codex/app-server/v2/AsyncUserInputQuestion.d.ts +0 -4
  207. package/dist/agent/vendor-types/codex/app-server/v2/AsyncUserInputQuestion.js +0 -2
  208. package/dist/agent/vendor-types/codex/app-server/v2/ByteRange.d.ts +0 -4
  209. package/dist/agent/vendor-types/codex/app-server/v2/ByteRange.js +0 -2
  210. package/dist/agent/vendor-types/codex/app-server/v2/CollabAgentState.d.ts +0 -5
  211. package/dist/agent/vendor-types/codex/app-server/v2/CollabAgentState.js +0 -2
  212. package/dist/agent/vendor-types/codex/app-server/v2/CollabAgentStatus.d.ts +0 -1
  213. package/dist/agent/vendor-types/codex/app-server/v2/CollabAgentStatus.js +0 -2
  214. package/dist/agent/vendor-types/codex/app-server/v2/CollabAgentTool.d.ts +0 -1
  215. package/dist/agent/vendor-types/codex/app-server/v2/CollabAgentTool.js +0 -2
  216. package/dist/agent/vendor-types/codex/app-server/v2/CollabAgentToolCallStatus.d.ts +0 -1
  217. package/dist/agent/vendor-types/codex/app-server/v2/CollabAgentToolCallStatus.js +0 -2
  218. package/dist/agent/vendor-types/codex/app-server/v2/CommandAction.d.ts +0 -19
  219. package/dist/agent/vendor-types/codex/app-server/v2/CommandAction.js +0 -2
  220. package/dist/agent/vendor-types/codex/app-server/v2/CommandExecutionSource.d.ts +0 -1
  221. package/dist/agent/vendor-types/codex/app-server/v2/CommandExecutionSource.js +0 -2
  222. package/dist/agent/vendor-types/codex/app-server/v2/CommandExecutionStatus.d.ts +0 -1
  223. package/dist/agent/vendor-types/codex/app-server/v2/CommandExecutionStatus.js +0 -2
  224. package/dist/agent/vendor-types/codex/app-server/v2/DynamicToolCallOutputContentItem.d.ts +0 -10
  225. package/dist/agent/vendor-types/codex/app-server/v2/DynamicToolCallOutputContentItem.js +0 -2
  226. package/dist/agent/vendor-types/codex/app-server/v2/DynamicToolCallStatus.d.ts +0 -1
  227. package/dist/agent/vendor-types/codex/app-server/v2/DynamicToolCallStatus.js +0 -2
  228. package/dist/agent/vendor-types/codex/app-server/v2/FileUpdateChange.d.ts +0 -6
  229. package/dist/agent/vendor-types/codex/app-server/v2/FileUpdateChange.js +0 -2
  230. package/dist/agent/vendor-types/codex/app-server/v2/HookPromptFragment.d.ts +0 -4
  231. package/dist/agent/vendor-types/codex/app-server/v2/HookPromptFragment.js +0 -2
  232. package/dist/agent/vendor-types/codex/app-server/v2/McpAppDisplayMode.d.ts +0 -1
  233. package/dist/agent/vendor-types/codex/app-server/v2/McpAppDisplayMode.js +0 -2
  234. package/dist/agent/vendor-types/codex/app-server/v2/McpAppUi.d.ts +0 -8
  235. package/dist/agent/vendor-types/codex/app-server/v2/McpAppUi.js +0 -2
  236. package/dist/agent/vendor-types/codex/app-server/v2/McpToolCallAppContext.d.ts +0 -7
  237. package/dist/agent/vendor-types/codex/app-server/v2/McpToolCallAppContext.js +0 -2
  238. package/dist/agent/vendor-types/codex/app-server/v2/McpToolCallError.d.ts +0 -3
  239. package/dist/agent/vendor-types/codex/app-server/v2/McpToolCallError.js +0 -2
  240. package/dist/agent/vendor-types/codex/app-server/v2/McpToolCallResult.d.ts +0 -6
  241. package/dist/agent/vendor-types/codex/app-server/v2/McpToolCallResult.js +0 -2
  242. package/dist/agent/vendor-types/codex/app-server/v2/McpToolCallStatus.d.ts +0 -1
  243. package/dist/agent/vendor-types/codex/app-server/v2/McpToolCallStatus.js +0 -2
  244. package/dist/agent/vendor-types/codex/app-server/v2/MemoryCitation.d.ts +0 -5
  245. package/dist/agent/vendor-types/codex/app-server/v2/MemoryCitation.js +0 -2
  246. package/dist/agent/vendor-types/codex/app-server/v2/MemoryCitationEntry.d.ts +0 -6
  247. package/dist/agent/vendor-types/codex/app-server/v2/MemoryCitationEntry.js +0 -2
  248. package/dist/agent/vendor-types/codex/app-server/v2/PatchApplyStatus.d.ts +0 -1
  249. package/dist/agent/vendor-types/codex/app-server/v2/PatchApplyStatus.js +0 -2
  250. package/dist/agent/vendor-types/codex/app-server/v2/PatchChangeKind.d.ts +0 -8
  251. package/dist/agent/vendor-types/codex/app-server/v2/PatchChangeKind.js +0 -2
  252. package/dist/agent/vendor-types/codex/app-server/v2/SubAgentActivityKind.d.ts +0 -1
  253. package/dist/agent/vendor-types/codex/app-server/v2/SubAgentActivityKind.js +0 -2
  254. package/dist/agent/vendor-types/codex/app-server/v2/TextElement.d.ts +0 -11
  255. package/dist/agent/vendor-types/codex/app-server/v2/TextElement.js +0 -2
  256. package/dist/agent/vendor-types/codex/app-server/v2/ThreadItem.d.ts +0 -215
  257. package/dist/agent/vendor-types/codex/app-server/v2/ThreadItem.js +0 -2
  258. package/dist/agent/vendor-types/codex/app-server/v2/UserInput.d.ts +0 -35
  259. package/dist/agent/vendor-types/codex/app-server/v2/UserInput.js +0 -2
  260. package/dist/agent/vendor-types/codex/app-server/v2/WebSearchAction.d.ts +0 -14
  261. package/dist/agent/vendor-types/codex/app-server/v2/WebSearchAction.js +0 -2
  262. package/dist/cli/services.d.ts +0 -19
  263. package/dist/cli/services.js +0 -34
  264. package/dist/dimension/http.d.ts +0 -7
  265. package/dist/dimension/http.js +0 -77
  266. package/dist/dimension/storage.d.ts +0 -39
  267. package/dist/dimension/storage.js +0 -79
  268. package/dist/portal-gateway/fakes.d.ts +0 -3
  269. package/dist/portal-gateway/fakes.js +0 -11
  270. package/dist/portal-gateway/gatewayStorage.d.ts +0 -66
  271. package/dist/portal-gateway/gatewayStorage.js +0 -125
  272. package/dist/portal-gateway/portalStorage.d.ts +0 -34
  273. package/dist/portal-gateway/portalStorage.js +0 -44
  274. package/dist/sandbox/boatService.d.ts +0 -52
  275. package/dist/sandbox/boatService.js +0 -343
  276. package/dist/sandbox/containerService.d.ts +0 -15
  277. package/dist/sandbox/containerService.js +0 -184
  278. package/dist/sandbox/endpointProxy.d.ts +0 -90
  279. package/dist/sandbox/endpointProxy.js +0 -716
  280. package/dist/sandbox/exeDevAuth.d.ts +0 -16
  281. package/dist/sandbox/exeDevAuth.js +0 -49
  282. package/dist/sandbox/localService.d.ts +0 -19
  283. package/dist/sandbox/localService.js +0 -200
  284. package/dist/sandbox/sseConnection.d.ts +0 -41
  285. package/dist/sandbox/sseConnection.js +0 -166
  286. package/dist/sandbox/sshService.d.ts +0 -30
  287. package/dist/sandbox/sshService.js +0 -680
@@ -1,2 +1,2 @@
1
1
  // Generated by scripts/bundle-worker.ts — do not edit; run `bun run bundle:worker`.
2
- export const WORKER_SOURCE = "// @bun\n// agent/session/main.ts\nimport { chown } from \"fs/promises\";\n\n// sandbox/localService.ts\nimport { spawn } from \"child_process\";\nimport { link, mkdir, open, readFile, readdir, rename, rm, stat, unlink, writeFile } from \"fs/promises\";\nimport { request as httpRequest } from \"http\";\nimport { createConnection } from \"net\";\nimport { homedir } from \"os\";\nimport { Readable } from \"stream\";\nimport { basename, dirname, isAbsolute, join, relative, resolve } from \"path\";\n\n// sandbox/api.ts\nclass SandboxPathError extends Error {\n name = \"SandboxPathError\";\n}\n\nclass SandboxNotFoundError extends Error {\n name = \"SandboxNotFoundError\";\n}\n\nclass SandboxEndpointError extends Error {\n name = \"SandboxEndpointError\";\n}\n\n// sandbox/endpointProxy.ts\nfunction parseAccessibleHost(value) {\n const match = /^\\[(.+)\\]:(\\d+)$/.exec(value) ?? /^([^:]+):(\\d+)$/.exec(value);\n if (!match)\n return { host: value.replace(/^\\[(.+)\\]$/, \"$1\"), port: null };\n const port = Number(match[2]);\n checkPort(port);\n return { host: match[1], port };\n}\nvar BASIC_USER = \"hyperbrane\";\nfunction proxyCredentialsAuth() {\n return {\n bind({ host, port: pinned }) {\n const name = host.includes(\":\") ? `[${host}]` : host;\n return {\n firewall: true,\n plan({ scheme, port }) {\n if (scheme !== \"bearer\" && scheme !== \"basic\") {\n throw new SandboxEndpointError(`the endpoint proxy checks bearer or basic credentials, not \"${scheme}\"`);\n }\n const listen = pinnedPort(pinned, port);\n const secret = Buffer.from(crypto.getRandomValues(new Uint8Array(32))).toString(\"base64url\");\n const credentials = scheme === \"bearer\" ? { scheme, token: secret } : { scheme, username: BASIC_USER, password: secret };\n return {\n check: { scheme, credentials: scheme === \"bearer\" ? secret : btoa(`${BASIC_USER}:${secret}`) },\n ports: [listen ?? 0, listen ?? 0],\n publish: async (listening) => ({ url: `https://${name}:${listening}`, credentials })\n };\n }\n };\n }\n };\n}\nfunction pinnedPort(pinned, requested) {\n if (requested !== undefined)\n checkPort(requested);\n if (pinned !== null && requested !== undefined && requested !== pinned) {\n throw new SandboxEndpointError(`endpoints here listen on port ${pinned} (the accessible host's), not ${requested}`);\n }\n return pinned ?? requested ?? null;\n}\nfunction checkPort(port) {\n if (!Number.isInteger(port) || port < 1 || port > 65535)\n throw new SandboxEndpointError(`not a port: ${port}`);\n}\nvar ID_PATTERN = /^hyb-endpoint-(\\d+)-([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})$/;\nvar ENDPOINT_NAME = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/;\nfunction parseEndpointId(endpointId) {\n const match = ID_PATTERN.exec(endpointId);\n if (!match)\n throw new SandboxEndpointError(`not an endpoint id: \"${endpointId}\"`);\n return { port: Number(match[1]), name: match[2] };\n}\nvar STATE = 'B=\"${B:-$HOME/.local/state/hyperbrane/endpoints}\"';\nvar RUNNING = `pid=$(cat \"$B/$P/.pid\" 2>/dev/null) && kill -0 \"$pid\" 2>/dev/null && ps -p \"$pid\" -o args= | grep -q hyb-endpoint-proxy`;\nvar START_SCRIPT = `${STATE}\nexec python3 -c \"$1\" hyb-endpoint-proxy \"$B\"`;\nvar READ_SCRIPT = `${STATE}\ncat \"$B/$P/$N.json\" 2>/dev/null || exit 1`;\nvar RUNNING_SCRIPT = `${STATE}\n${RUNNING}`;\nvar WRITE_SCRIPT = `${STATE}\numask 077\n[ -d \"$B/$P\" ] || exit 44\ncat > \"$B/$P/.$N.tmp\" && mv -f \"$B/$P/.$N.tmp\" \"$B/$P/$N.json\"`;\nvar STATUS_SCRIPT = `${STATE}\n[ -e \"$B/$P/$N.json\" ] || exit 1\n${RUNNING} || exit 3`;\nvar REMOVE_SCRIPT = `${STATE}\nrm -f \"$B/$P/$N.json\"\nfor other in \"$B/$P\"/*.json; do [ -e \"$other\" ] && exit 0; done\nif ${RUNNING}; then kill \"$pid\"; fi\nrm -rf \"$B/$P\"\nexit 10`;\nfunction createProxyEndpoints(commands, options, where) {\n const accessible = parseAccessibleHost(options.accessibleHost);\n const auth = (options.auth ?? proxyCredentialsAuth()).bind(accessible);\n const firewall = options.needsFirewall === true && auth.firewall;\n const env = (vars) => ({\n ...options.stateDirectory === undefined ? {} : { B: options.stateDirectory },\n ...Object.fromEntries(Object.entries(vars).map(([name, value]) => [name, String(value)]))\n });\n const sh = (script, vars, stdin) => commands.runCommand([\"sh\", \"-c\", script], { env: env(vars), stdin });\n async function ufw(...args) {\n const result = await commands.runCommand([\"sudo\", \"-n\", \"ufw\", ...args]);\n if (result.exitCode !== 0)\n throw new Error(`ufw ${args.join(\" \")} on ${where} failed (exit ${result.exitCode}): ${result.stderr.trim()}`);\n }\n async function running(port) {\n return (await sh(RUNNING_SCRIPT, { P: port })).exitCode === 0;\n }\n async function stop(port) {\n const result = await sh(REMOVE_SCRIPT, { P: port, N: \"-\" });\n if (result.exitCode === 10 && firewall)\n await ufw(\"delete\", \"allow\", `${port}/tcp`);\n }\n async function proxyFor(plan) {\n const [low, high] = plan.ports;\n if (low === high && low !== 0 && await running(low))\n return low;\n const port = await start(plan.ports, plan.except ?? []);\n if (port === null)\n throw new Error(`starting the endpoint proxy on ${where} failed: no free port in ${low}-${high}`);\n return port;\n }\n async function start(ports, except) {\n const [low, high] = ports;\n const result = await commands.runCommand([\"sh\", \"-c\", START_SCRIPT, \"sh\", PROXY], {\n env: env({}),\n stdin: `${JSON.stringify({ ports, except })}\n`\n });\n const port = Number(result.stdout.trim());\n if (result.exitCode !== 0 || !Number.isInteger(port) || port <= 0) {\n if (low === high && low !== 0 && await running(low))\n return low;\n if (/no free port/.test(result.stderr))\n return null;\n throw new Error(`starting the endpoint proxy on ${where} failed (exit ${result.exitCode}): ${result.stderr.trim() || result.stdout.trim()}`);\n }\n if (firewall) {\n try {\n await ufw(\"allow\", `${port}/tcp`);\n } catch (error) {\n await stop(port).catch(() => {});\n throw error;\n }\n }\n return port;\n }\n function exposeEndpoint(request) {\n return exposeEndpointAs(crypto.randomUUID(), request);\n }\n async function exposeEndpointAs(name, request) {\n if (!ENDPOINT_NAME.test(name))\n throw new SandboxEndpointError(`not an endpoint name: \"${name}\"`);\n const { target, transport = \"http\", allowedOrigins = [] } = request;\n if (transport !== \"http\" && transport !== \"sse\")\n throw new SandboxEndpointError(`unknown transport: ${transport}`);\n const plan = auth.plan(request);\n const port = await proxyFor(plan);\n const id = `hyb-endpoint-${port}-${name}`;\n const published = await plan.publish(port);\n const kept = await sh(READ_SCRIPT, { P: port, N: name });\n if (kept.exitCode === 0) {\n const record2 = JSON.parse(kept.stdout);\n const same = JSON.stringify(record2.target) === JSON.stringify(target) && record2.transport === transport && [...record2.origins].sort().join(`\n`) === [...allowedOrigins].sort().join(`\n`) && (record2.check?.scheme ?? null) === (plan.check?.scheme ?? null);\n if (same)\n return { id, url: `${published.url}/${name}`, credentials: credentialsOf(record2.check, published.credentials), allowedOrigins };\n }\n const record = JSON.stringify({ target, transport, check: plan.check, origins: allowedOrigins });\n const written = await sh(WRITE_SCRIPT, { P: port, N: name }, record);\n if (written.exitCode !== 0) {\n throw new Error(`recording the endpoint for ${describe(target)} on ${where} failed (exit ${written.exitCode}): ${written.stderr.trim()}`);\n }\n return { id, url: `${published.url}/${name}`, credentials: published.credentials, allowedOrigins };\n }\n async function closeEndpoint(endpointId) {\n const { port, name } = parseEndpointId(endpointId);\n const result = await sh(REMOVE_SCRIPT, { P: port, N: name });\n if (result.exitCode !== 0 && result.exitCode !== 10) {\n throw new Error(`closing endpoint ${endpointId} on ${where} failed (exit ${result.exitCode}): ${result.stderr.trim()}`);\n }\n if (result.exitCode === 10 && firewall)\n await ufw(\"delete\", \"allow\", `${port}/tcp`);\n }\n async function updateEndpoint(endpointId, { allowedOrigins }) {\n const { port, name } = parseEndpointId(endpointId);\n const read = await sh(READ_SCRIPT, { P: port, N: name });\n if (read.exitCode !== 0)\n return false;\n const record = { ...JSON.parse(read.stdout), origins: allowedOrigins };\n const written = await sh(WRITE_SCRIPT, { P: port, N: name }, JSON.stringify(record));\n if (written.exitCode === 44)\n return false;\n if (written.exitCode !== 0) {\n throw new Error(`updating endpoint ${endpointId} on ${where} failed (exit ${written.exitCode}): ${written.stderr.trim()}`);\n }\n return true;\n }\n async function ensureEndpoint(endpointId) {\n const { port, name } = parseEndpointId(endpointId);\n const status = await sh(STATUS_SCRIPT, { P: port, N: name });\n if (status.exitCode === 0)\n return true;\n if (status.exitCode === 1)\n return false;\n if (status.exitCode !== 3) {\n throw new Error(`checking endpoint ${endpointId} on ${where} failed (exit ${status.exitCode}): ${status.stderr.trim()}`);\n }\n if (await start([port, port], []) !== null)\n return true;\n await closeEndpoint(endpointId);\n return false;\n }\n return { accessibleHost: options.accessibleHost, exposeEndpoint, exposeEndpointAs, closeEndpoint, ensureEndpoint, updateEndpoint };\n}\nfunction credentialsOf(check, none) {\n if (!check)\n return none;\n if (check.scheme === \"bearer\")\n return { scheme: \"bearer\", token: check.credentials };\n const decoded = atob(check.credentials);\n const colon = decoded.indexOf(\":\");\n return { scheme: \"basic\", username: decoded.slice(0, colon), password: decoded.slice(colon + 1) };\n}\nfunction describe(target) {\n return \"port\" in target ? `port ${target.port}` : target.unix;\n}\nvar PROXY = String.raw`\nimport errno, hmac, json, os, random, re, secrets, socket, sys, threading, urllib.parse\n\nconfig = json.loads(sys.stdin.readline())\nMAX_LINE = 16 * 1024 * 1024\nHEARTBEAT = 15\nPREFLIGHT = b\"Access-Control-Allow-Methods: GET, POST, OPTIONS\\r\\nAccess-Control-Allow-Headers: authorization, content-type\\r\\nAccess-Control-Max-Age: 600\\r\\n\"\nMAX_HEAD = 65536\nHEAD_TIMEOUT = 30\nHOP_BY_HOP = {b\"authorization\", b\"connection\", b\"keep-alive\", b\"proxy-connection\", b\"proxy-authorization\"}\nENDPOINT_NAME = re.compile(r\"^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$\")\n\n\ndef listen(port):\n if socket.has_dualstack_ipv6():\n return socket.create_server((\"\", port), family=socket.AF_INET6, dualstack_ipv6=True, backlog=128)\n return socket.create_server((\"\", port), backlog=128)\n\n\nlow, high = config[\"ports\"]\ncandidates = [port for port in range(low, high + 1) if port not in config[\"except\"]]\nrandom.shuffle(candidates)\nserver = None\nfor port in candidates:\n try:\n server = listen(port)\n break\n except OSError as e:\n if e.errno != errno.EADDRINUSE:\n raise\nif server is None:\n sys.stderr.write(\"no free port in %d-%d\\n\" % (low, high))\n sys.exit(1)\nPORT = server.getsockname()[1]\n\n# Endpoints recorded by a proxy that's gone (a reboot) are served again, as they were given out;\n# only that proxy's own leftovers (its pid, half-written records) go.\nos.umask(0o077)\nDIR = os.path.join(sys.argv[2], str(PORT))\nos.makedirs(DIR, mode=0o700, exist_ok=True)\nfor stale in os.listdir(DIR):\n if stale.startswith(\".\"):\n os.remove(os.path.join(DIR, stale))\n\n# Detached; the port is printed once the proxy's pid is recorded, so whoever started it can find it.\nready_read, ready_write = os.pipe()\nif os.fork():\n os.close(ready_write)\n if os.read(ready_read, 2) != b\"ok\":\n sys.exit(1)\n sys.stdout.write(\"%d\\n\" % PORT)\n sys.stdout.flush()\n os._exit(0)\nos.setsid()\nif os.fork():\n os._exit(0)\nwith open(os.path.join(DIR, \".pid\"), \"w\") as pid_file:\n pid_file.write(str(os.getpid()))\nos.write(ready_write, b\"ok\")\nos.close(ready_write)\nnull = os.open(os.devnull, os.O_RDWR)\nfor fd in (0, 1, 2):\n os.dup2(null, fd)\n\n\ndef record_path(name):\n return os.path.join(DIR, name + \".json\")\n\n\ndef load(name):\n \"\"\"The endpoint recorded under that name, or None.\"\"\"\n if not ENDPOINT_NAME.match(name):\n return None\n try:\n with open(record_path(name)) as record:\n return json.load(record)\n except (OSError, ValueError):\n return None\n\n\nclass Reply(Exception):\n \"\"\"Answers the request with an empty body and ends the connection: a refusal, a 204, a redirect.\"\"\"\n\n def __init__(self, status, extra=b\"\"):\n self.status = status\n self.extra = extra\n\n\nclass Reader:\n def __init__(self, conn):\n self.conn = conn\n self.buffer = b\"\"\n\n def fill(self):\n data = self.conn.recv(65536)\n if not data:\n raise Reply(b\"400 Bad Request\")\n self.buffer += data\n\n def until(self, marker, limit):\n while marker not in self.buffer:\n if len(self.buffer) > limit:\n raise Reply(b\"431 Request Header Fields Too Large\")\n self.fill()\n found, self.buffer = self.buffer.split(marker, 1)\n return found\n\n def exactly(self, size):\n while len(self.buffer) < size:\n self.fill()\n found, self.buffer = self.buffer[:size], self.buffer[size:]\n return found\n\n\ndef parse(head):\n lines = head.split(b\"\\r\\n\")\n if any(c in line for line in lines for c in (b\"\\r\", b\"\\n\", b\"\\0\")):\n raise Reply(b\"400 Bad Request\")\n method, sep, rest = lines[0].partition(b\" \")\n path, sep2, version = rest.partition(b\" \")\n if not (sep and sep2 and method and path.startswith(b\"/\")) or version not in (b\"HTTP/1.1\", b\"HTTP/1.0\"):\n raise Reply(b\"400 Bad Request\")\n headers = []\n for line in lines[1:]:\n name, sep, value = line.partition(b\":\")\n if not sep or not name or any(c in name for c in b\" \\t\"):\n raise Reply(b\"400 Bad Request\")\n headers.append((name, value.strip()))\n return method, path, version, headers\n\n\ndef header(headers, name):\n for n, v in headers:\n if n.lower() == name:\n return v\n return None\n\n\ndef authorized(headers, check):\n values = [v for n, v in headers if n.lower() == b\"authorization\"]\n if len(values) != 1:\n return False\n scheme, _, credentials = values[0].partition(b\" \")\n return scheme.lower() == check[\"scheme\"].encode() and hmac.compare_digest(credentials.strip(), check[\"credentials\"].encode())\n\n\ndef challenge(check):\n if check[\"scheme\"] == \"basic\":\n return b'WWW-Authenticate: Basic realm=\"hyperbrane\", charset=\"UTF-8\"\\r\\n'\n return b\"WWW-Authenticate: Bearer\\r\\n\"\n\n\ndef cors_headers(origin, endpoint):\n if origin is None or origin.decode(\"latin-1\") not in endpoint[\"origins\"]:\n return b\"\"\n return b\"Access-Control-Allow-Origin: \" + origin + b\"\\r\\nAccess-Control-Allow-Credentials: true\\r\\nVary: Origin\\r\\n\"\n\n\ndef framing(headers):\n lengths = [v for n, v in headers if n.lower() == b\"content-length\"]\n encodings = [v for n, v in headers if n.lower() == b\"transfer-encoding\"]\n if encodings:\n if lengths or len(encodings) != 1 or encodings[0].lower() != b\"chunked\":\n raise Reply(b\"400 Bad Request\")\n return \"chunked\"\n if len(lengths) > 1 or (lengths and not lengths[0].isdigit()):\n raise Reply(b\"400 Bad Request\")\n return int(lengths[0]) if lengths else 0\n\n\ndef forward_body(reader, up, body):\n if body == \"chunked\":\n while True:\n line = reader.until(b\"\\r\\n\", 4096)\n size_text = line.split(b\";\", 1)[0].strip()\n if not size_text or any(c not in b\"0123456789abcdefABCDEF\" for c in size_text):\n raise Reply(b\"400 Bad Request\")\n size = int(size_text, 16)\n if size == 0:\n # Trailers are dropped: read up to the blank line that ends them.\n while reader.until(b\"\\r\\n\", MAX_HEAD):\n pass\n up.sendall(b\"0\\r\\n\\r\\n\")\n return\n data = reader.exactly(size)\n if reader.exactly(2) != b\"\\r\\n\":\n raise Reply(b\"400 Bad Request\")\n up.sendall(b\"%x\\r\\n\" % size + data + b\"\\r\\n\")\n remaining = body\n while remaining:\n data = reader.exactly(min(remaining, 65536))\n up.sendall(data)\n remaining -= len(data)\n\n\ndef tune(sock):\n # Streams (an agent's, as SSE) go out event by event, and a peer that vanished without closing\n # is noticed within a couple of minutes instead of holding its connection forever.\n sock.setsockopt(socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1)\n if sock.family == socket.AF_UNIX:\n return\n sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)\n for name, value in ((\"TCP_KEEPIDLE\", 60), (\"TCP_KEEPINTVL\", 15), (\"TCP_KEEPCNT\", 4)):\n if hasattr(socket, name):\n sock.setsockopt(socket.IPPROTO_TCP, getattr(socket, name), value)\n\n\ndef connect_target(target):\n if \"unix\" in target:\n up = socket.socket(socket.AF_UNIX)\n up.connect(target[\"unix\"])\n else:\n up = socket.create_connection((\"localhost\", target[\"port\"]))\n tune(up)\n return up\n\n\ndef hang_up(sock):\n # shutdown, not just close: it also wakes a thread blocked reading the socket.\n if sock is None:\n return\n try:\n sock.shutdown(socket.SHUT_RDWR)\n except OSError:\n pass\n try:\n sock.close()\n except OSError:\n pass\n\n\ndef pump_response(up, conn, decided, state):\n \"\"\"Copies the target's side to the client until either end goes away, then closes the client's.\"\"\"\n first = b\"\"\n try:\n while True:\n data = up.recv(65536)\n if not data:\n break\n if not decided.is_set():\n first += data\n if b\"\\r\\n\" in first or len(first) > 64:\n state[\"upgraded\"] = first.startswith((b\"HTTP/1.1 101\", b\"HTTP/1.0 101\"))\n decided.set()\n conn.sendall(data)\n except OSError:\n pass\n finally:\n decided.set()\n hang_up(conn)\n\n\nclass Collect:\n \"\"\"forward_body's destination for a body kept here (a POST to an \"sse\" connection).\"\"\"\n\n def __init__(self):\n self.data = b\"\"\n\n def sendall(self, data):\n self.data += data\n if len(self.data) > MAX_LINE:\n raise Reply(b\"413 Content Too Large\")\n\n\nclass Connection:\n \"\"\"An \"sse\" connection to an endpoint's target; POSTs write to it, one at a time.\"\"\"\n\n def __init__(self, endpoint_name, sock):\n self.endpoint_name = endpoint_name\n self.sock = sock\n self.lock = threading.Lock()\n\n def write(self, data):\n with self.lock:\n self.sock.sendall(data)\n\n\nCONNECTIONS = {}\nCONNECTIONS_LOCK = threading.Lock()\n\n\ndef serve_sse(conn, reader, method, rest, body, cors, name, endpoint):\n if rest in (b\"\", b\"/\"):\n if method != b\"GET\":\n raise Reply(b\"405 Method Not Allowed\", b\"Allow: GET\\r\\n\" + cors)\n return stream_target(conn, cors, name, endpoint)\n if method != b\"POST\" or rest.count(b\"/\") != 1:\n raise Reply(b\"404 Not Found\", cors)\n with CONNECTIONS_LOCK:\n target = CONNECTIONS.get(rest[1:].decode(\"ascii\", \"replace\"))\n if target is None or target.endpoint_name != name:\n raise Reply(b\"404 Not Found\", cors)\n collected = Collect()\n forward_body(reader, collected, body)\n try:\n target.write(collected.data)\n except OSError:\n raise Reply(b\"404 Not Found\", cors)\n raise Reply(b\"204 No Content\", cors)\n\n\ndef watch_client(conn, up):\n # Anything the client sends after its request is dropped; its leaving ends the connection.\n try:\n while conn.recv(65536):\n pass\n except OSError:\n pass\n hang_up(up)\n\n\ndef heartbeat(send, stop, name, up):\n while not stop.wait(HEARTBEAT):\n # A closed endpoint takes its streams with it.\n if not os.path.exists(record_path(name)):\n hang_up(up)\n return\n try:\n send(b\": ping\\n\\n\")\n except OSError:\n return\n\n\ndef stream_target(conn, cors, name, endpoint):\n try:\n up = connect_target(endpoint[\"target\"])\n except OSError:\n raise Reply(b\"502 Bad Gateway\", cors)\n connection_id = secrets.token_hex(16)\n lock = threading.Lock()\n\n def send(data):\n with lock:\n conn.sendall(data)\n\n stop = threading.Event()\n with CONNECTIONS_LOCK:\n CONNECTIONS[connection_id] = Connection(name, up)\n try:\n conn.settimeout(None)\n send(b\"HTTP/1.1 200 OK\\r\\nContent-Type: text/event-stream\\r\\nCache-Control: no-cache, no-transform\\r\\nX-Accel-Buffering: no\\r\\nConnection: close\\r\\n\" + cors + b\"\\r\\n\")\n send(b\"event: open\\ndata: \" + json.dumps({\"connection\": connection_id}).encode() + b\"\\n\\n\")\n threading.Thread(target=heartbeat, args=(send, stop, name, up), daemon=True).start()\n threading.Thread(target=watch_client, args=(conn, up), daemon=True).start()\n pending = b\"\"\n while True:\n data = up.recv(65536)\n if not data:\n break\n *lines, pending = (pending + data).split(b\"\\n\")\n for line in lines:\n if line.endswith(b\"\\r\"):\n line = line[:-1]\n # A bare CR would end the event early on the client: the line can't go as SSE.\n if b\"\\r\" in line:\n return\n send(b\"data: \" + line + b\"\\n\\n\")\n if len(pending) > MAX_LINE:\n return\n send(b\"event: close\\ndata: {}\\n\\n\")\n except OSError:\n pass\n finally:\n stop.set()\n with CONNECTIONS_LOCK:\n CONNECTIONS.pop(connection_id, None)\n hang_up(up)\n hang_up(conn)\n\n\ndef return_to(method, query):\n if method != b\"GET\":\n raise Reply(b\"405 Method Not Allowed\", b\"Allow: GET\\r\\n\")\n to = urllib.parse.parse_qs(query.decode(\"latin-1\")).get(\"to\", [\"\"])[0]\n parts = urllib.parse.urlsplit(to)\n if parts.scheme not in (\"http\", \"https\") or not parts.netloc or any(ord(c) < 0x21 or ord(c) > 0x7E for c in to):\n raise Reply(b\"400 Bad Request\")\n origin = parts.scheme + \"://\" + parts.netloc\n for entry in os.listdir(DIR):\n endpoint = load(entry[:-5]) if entry.endswith(\".json\") else None\n if endpoint is not None and endpoint[\"check\"] is None and origin in endpoint[\"origins\"]:\n raise Reply(b\"302 Found\", b\"Location: \" + to.encode() + b\"\\r\\nCache-Control: no-store\\r\\n\")\n raise Reply(b\"400 Bad Request\")\n\n\ndef handle(conn):\n up = None\n try:\n conn.settimeout(HEAD_TIMEOUT)\n reader = Reader(conn)\n method, path, version, headers = parse(reader.until(b\"\\r\\n\\r\\n\", MAX_HEAD))\n route, _, query = path.partition(b\"?\")\n if route == b\"/__hyb/return\":\n return_to(method, query)\n name_bytes, slash, rest = route[1:].partition(b\"/\")\n name = name_bytes.decode(\"ascii\", \"replace\")\n endpoint = load(name)\n if endpoint is None:\n raise Reply(b\"404 Not Found\")\n cors = cors_headers(header(headers, b\"origin\"), endpoint)\n # A browser's preflight carries no credentials; it is answered here and never reaches the target.\n if method == b\"OPTIONS\" and header(headers, b\"access-control-request-method\") is not None:\n raise Reply(b\"204 No Content\", cors + PREFLIGHT) if cors else Reply(b\"403 Forbidden\")\n check = endpoint[\"check\"]\n if check and not authorized(headers, check):\n raise Reply(b\"401 Unauthorized\", challenge(check) + cors)\n body = framing(headers)\n if endpoint[\"transport\"] == \"sse\":\n return serve_sse(conn, reader, method, slash + rest, body, cors, name, endpoint)\n upgrade = any(n.lower() == b\"upgrade\" for n, _ in headers)\n try:\n up = connect_target(endpoint[\"target\"])\n except OSError:\n raise Reply(b\"502 Bad Gateway\", cors)\n target_path = slash + rest if slash else b\"/\"\n if query:\n target_path += b\"?\" + query\n kept = [n + b\": \" + v for n, v in headers if n.lower() not in HOP_BY_HOP]\n kept.append(b\"Connection: Upgrade\" if upgrade else b\"Connection: close\")\n up.sendall(method + b\" \" + target_path + b\" \" + version + b\"\\r\\n\" + b\"\\r\\n\".join(kept) + b\"\\r\\n\\r\\n\")\n decided = threading.Event()\n state = {\"upgraded\": False}\n # The request is done once the response is: the client side closes with it.\n pump = threading.Thread(target=pump_response, args=(up, conn, decided, state), daemon=True)\n pump.start()\n forward_body(reader, up, body)\n conn.settimeout(None)\n if upgrade:\n decided.wait()\n if upgrade and state[\"upgraded\"]:\n if reader.buffer:\n up.sendall(reader.buffer)\n while True:\n data = conn.recv(65536)\n if not data:\n break\n up.sendall(data)\n else:\n # Anything more from the client is dropped: it would reach the target unchecked.\n while conn.recv(65536):\n pass\n # The client is gone (or the response ended and closed it): a stream it was reading stops too.\n hang_up(up)\n pump.join()\n except Reply as reply:\n try:\n conn.sendall(b\"HTTP/1.1 \" + reply.status + b\"\\r\\nContent-Length: 0\\r\\nConnection: close\\r\\n\" + reply.extra + b\"\\r\\n\")\n except OSError:\n pass\n except (OSError, ValueError):\n pass\n finally:\n hang_up(up)\n hang_up(conn)\n\n\nwhile True:\n conn, _ = server.accept()\n tune(conn)\n threading.Thread(target=handle, args=(conn,), daemon=True).start()\n`;\n\n// sandbox/localService.ts\nfunction createLocalSandbox(root, { endpoints } = {}) {\n const base = resolve(root);\n function hostPath(path) {\n const full = resolve(base, isAbsolute(path) ? `.${path}` : path);\n const rel = relative(base, full);\n if (rel.startsWith(\"..\") || isAbsolute(rel))\n throw new SandboxPathError(`Path escapes sandbox: \"${path}\"`);\n return full;\n }\n async function notFoundAs(path, operation) {\n try {\n return await operation;\n } catch (error) {\n if (error.code === \"ENOENT\")\n throw new SandboxNotFoundError(`Not found: \"${path}\"`);\n throw error;\n }\n }\n async function writeTemp(full, data) {\n await mkdir(dirname(full), { recursive: true });\n const tmp = join(dirname(full), `.${basename(full)}.${crypto.randomUUID()}.tmp`);\n await writeFile(tmp, data);\n return tmp;\n }\n async function readFileLocal(path) {\n return new Uint8Array(await notFoundAs(path, readFile(hostPath(path))));\n }\n async function readFileRangeLocal(path, start, end) {\n const file = await notFoundAs(path, open(hostPath(path), \"r\"));\n try {\n const buffer = new Uint8Array(Math.max(0, end - start));\n let filled = 0;\n while (filled < buffer.length) {\n const { bytesRead } = await file.read(buffer, filled, buffer.length - filled, start + filled);\n if (bytesRead === 0)\n break;\n filled += bytesRead;\n }\n return buffer.subarray(0, filled);\n } finally {\n await file.close();\n }\n }\n async function writeFileLocal(path, data) {\n const full = hostPath(path);\n await rename(await writeTemp(full, data), full);\n }\n async function writeFileExclusive(path, data) {\n const full = hostPath(path);\n const tmp = await writeTemp(full, data);\n try {\n await link(tmp, full);\n return true;\n } catch (error) {\n if (error.code === \"EEXIST\")\n return false;\n throw error;\n } finally {\n await unlink(tmp);\n }\n }\n async function removeFile(path) {\n await rm(hostPath(path), { force: true });\n }\n async function createDirectory(path) {\n await mkdir(hostPath(path), { recursive: true });\n }\n async function removeDirectory(path) {\n await rm(hostPath(path), { recursive: true, force: true });\n }\n async function listDirectory(path) {\n return notFoundAs(path, readdir(hostPath(path)));\n }\n async function statLocal(path) {\n const stats = await notFoundAs(path, stat(hostPath(path)));\n const type = stats.isFile() ? \"file\" : stats.isDirectory() ? \"directory\" : \"other\";\n return { type, uid: stats.uid, gid: stats.gid, size: stats.size };\n }\n async function homeDirectory() {\n const rel = relative(base, homedir());\n if (rel.startsWith(\"..\") || isAbsolute(rel))\n throw new SandboxPathError(`Home directory is outside the sandbox`);\n return `/${rel}`;\n }\n function runCommand(cmd, { cwd, env = {}, stdin } = {}) {\n return new Promise((resolve2, reject) => {\n const [command, ...args] = cmd;\n if (!command)\n return reject(new Error(\"no command to run\"));\n const child = spawn(command, args, {\n cwd: hostPath(cwd ?? \".\"),\n env: { ...process.env, ...env },\n stdio: [stdin === undefined ? \"ignore\" : \"pipe\", \"pipe\", \"pipe\"]\n });\n const stdout = [];\n const stderr = [];\n child.stdout.on(\"data\", (chunk) => stdout.push(chunk));\n child.stderr.on(\"data\", (chunk) => stderr.push(chunk));\n child.once(\"error\", reject);\n child.once(\"close\", (code) => resolve2({ exitCode: code ?? -1, stdout: Buffer.concat(stdout).toString(), stderr: Buffer.concat(stderr).toString() }));\n if (stdin !== undefined)\n child.stdin.end(stdin);\n });\n }\n async function connect(path) {\n return socketConnection(createConnection({ path: hostPath(path) }), path);\n }\n async function fetchLocal(url, { unix, ...init } = {}) {\n if (unix === undefined || \"Bun\" in globalThis)\n return fetch(url, { ...init, unix: unix === undefined ? undefined : hostPath(unix) });\n return fetchOverSocket(url, hostPath(unix), init);\n }\n const sandbox = {\n readFile: readFileLocal,\n readFileRange: readFileRangeLocal,\n writeFile: writeFileLocal,\n writeFileExclusive,\n removeFile,\n createDirectory,\n removeDirectory,\n listDirectory,\n stat: statLocal,\n homeDirectory,\n runCommand,\n fetch: fetchLocal,\n connect\n };\n if (!endpoints)\n return sandbox;\n return { ...sandbox, ...createProxyEndpoints({ runCommand }, endpoints, \"this machine\") };\n}\nfunction fetchOverSocket(url, socketPath, { method = \"GET\", headers = {}, body, signal, timeout }) {\n return new Promise((resolve2, reject) => {\n const target = new URL(url);\n const request = httpRequest({ socketPath, path: `${target.pathname}${target.search}`, method, headers: { host: target.host, ...headers }, signal }, (response) => {\n const responseHeaders = new Headers;\n for (let i = 0;i + 1 < response.rawHeaders.length; i += 2)\n responseHeaders.append(response.rawHeaders[i], response.rawHeaders[i + 1]);\n const status = response.statusCode ?? 502;\n const nullBody = status === 204 || status === 304 || method === \"HEAD\";\n if (nullBody)\n response.resume();\n resolve2(new Response(nullBody ? null : Readable.toWeb(response), { status, headers: responseHeaders }));\n });\n request.once(\"error\", reject);\n if (typeof timeout === \"number\")\n request.setTimeout(timeout, () => request.destroy(new Error(`fetch ${url}: no data for ${timeout}ms`)));\n request.end(body === undefined ? undefined : typeof body === \"string\" ? body : Buffer.from(body));\n });\n}\nfunction socketConnection(stream, path, { opened = false } = {}) {\n return new Promise((resolve2, reject) => {\n let markClosed;\n const closed = new Promise((done) => markClosed = done);\n const listeners = [];\n stream.on(\"data\", (chunk) => {\n for (const listener of listeners)\n listener(new Uint8Array(chunk));\n });\n stream.once(\"close\", () => markClosed());\n stream.once(\"end\", () => markClosed());\n const connection = {\n write: (data) => void stream.write(data),\n onData: (listener) => void listeners.push(listener),\n closed,\n close: () => stream.end()\n };\n stream.once(\"error\", (error) => {\n markClosed();\n reject(new Error(`connecting to ${path} failed: ${error.message}`));\n });\n if (opened)\n resolve2(connection);\n else\n stream.once(\"connect\", () => resolve2(connection));\n });\n}\n\n// agent/session/login.ts\nfunction plain(text) {\n return text.replace(/\\x1b\\][^\\x07\\x1b]*(\\x07|\\x1b\\\\)/g, \"\").replace(/\\x1b\\[[0-9;?]*[a-zA-Z]/g, \"\");\n}\nfunction spawnLogin(cmd, { env, cwd }, parse) {\n const proc = Bun.spawn(cmd, { env, cwd, stdin: \"pipe\", stdout: \"pipe\", stderr: \"pipe\" });\n let output = \"\";\n let showPrompt;\n let noPrompt;\n const prompt = new Promise((resolve2, reject) => {\n showPrompt = resolve2;\n noPrompt = reject;\n });\n async function read(stream) {\n const decoder = new TextDecoder;\n for await (const chunk of stream) {\n output += plain(decoder.decode(chunk, { stream: true }));\n const found = parse(output);\n if (found)\n showPrompt(found);\n }\n }\n const reading = Promise.all([read(proc.stdout), read(proc.stderr)]);\n const done = reading.then(() => proc.exited).then((code) => {\n const tail = output.trim().split(`\n`).slice(-3).join(\" \").trim();\n noPrompt(new Error(`the login ended before showing where to sign in: ${tail}`));\n if (code !== 0)\n throw new Error(`the login failed (exit ${code}): ${tail}`);\n });\n prompt.catch(() => {});\n done.catch(() => {});\n return {\n prompt,\n done,\n submitCode(code) {\n proc.stdin.write(`${code}\n`);\n proc.stdin.flush();\n },\n cancel() {\n proc.kill();\n }\n };\n}\n\n// agent/session/claude/provision.ts\nimport { existsSync as existsSync2 } from \"fs\";\n\n// agent/session/install.ts\nimport { existsSync } from \"fs\";\n// agent/vendor-types/manifest.json\nvar manifest_default = {\n claude: {\n docs: \"https://code.claude.com/docs/en/agent-sdk/typescript\",\n sources: [\n {\n source: \"npm:@anthropic-ai/claude-agent-sdk@0.3.283\",\n into: \"agent-sdk\",\n files: 7\n }\n ]\n },\n codex: {\n docs: \"https://developers.openai.com/codex/app-server\",\n sources: [\n {\n source: \"npm:@openai/codex-sdk@0.157.1\",\n into: \"sdk\",\n files: 1\n },\n {\n source: \"github:openai/codex@rust-v0.157.1/codex-rs/app-server-protocol/schema/typescript\",\n into: \"app-server\",\n files: 740\n },\n {\n source: \"github:openai/codex@rust-v0.157.1/codex-rs/app-server-protocol/schema/json\",\n into: \"app-server-json\",\n files: 2\n }\n ]\n },\n pi: {\n docs: \"https://github.com/badlogic/pi-mono/blob/main/packages/coding-agent/docs/rpc.md\",\n sources: [\n {\n source: \"npm:@mariozechner/pi-coding-agent@0.73.1\",\n into: \"coding-agent\",\n files: 137\n },\n {\n source: \"npm:@mariozechner/pi-agent-core@0.73.1\",\n into: \"agent-core\",\n files: 5\n },\n {\n source: \"npm:@mariozechner/pi-ai@0.73.1\",\n into: \"ai\",\n files: 44\n }\n ]\n },\n opencode: {\n docs: \"https://opencode.ai/docs/server\",\n sources: [\n {\n source: \"npm:@opencode-ai/sdk@1.18.32\",\n into: \"sdk\",\n files: 39\n },\n {\n source: \"github:anomalyco/opencode@v1.18.32/packages/sdk\",\n into: \"\",\n files: 1\n }\n ]\n },\n openclaw: {\n docs: \"https://docs.openclaw.ai/gateway/protocol\",\n sources: [\n {\n source: \"npm:@openclaw/gateway-protocol@2026.9.6\",\n into: \"gateway-protocol\",\n files: 17\n }\n ]\n },\n hermes: {\n docs: \"https://hermes-agent.nousresearch.com/docs\",\n sources: [\n {\n source: \"github:NousResearch/hermes-agent@v2026.9.24/apps/shared/src\",\n into: \"gateway\",\n files: 3\n }\n ]\n }\n};\n\n// agent/session/install.ts\nfunction pinnedVersion(vendor, pkg, sourcePackage = pkg) {\n const prefix = `npm:${sourcePackage}@`;\n const source = manifest_default[vendor].sources.find((entry) => entry.source.startsWith(prefix));\n if (!source)\n throw new Error(`agent/vendor-types/manifest.json has no ${sourcePackage} for ${vendor} (needed for ${pkg})`);\n return source.source.slice(prefix.length);\n}\nasync function installedPackage(installDir, pkg, version, executable) {\n const manifest = Bun.file(`${installDir}/node_modules/${pkg}/package.json`);\n const found = await manifest.exists() ? (await manifest.json()).version ?? null : null;\n return { version: found, ready: found === version && existsSync(executable()) };\n}\nasync function installPackage(installDir, pkg, version, executable) {\n const installed = await installedPackage(installDir, pkg, version, executable);\n if (installed.ready)\n return;\n const force = installed.version === version ? [\"--force\"] : [];\n const proc = Bun.spawn([process.execPath, \"add\", \"--exact\", ...force, `${pkg}@${version}`], {\n cwd: installDir,\n stdin: \"ignore\",\n stdout: \"pipe\",\n stderr: \"pipe\"\n });\n const [stdout, stderr, exitCode] = await Promise.all([\n new Response(proc.stdout).text(),\n new Response(proc.stderr).text(),\n proc.exited\n ]);\n if (exitCode !== 0)\n throw new Error(`bun add ${pkg}@${version} failed (exit ${exitCode}): ${(stderr || stdout).trim()}`);\n if (!existsSync(executable()))\n throw new Error(`bun add ${pkg}@${version} left no ${executable()}: its platform package didn't install`);\n}\n\n// agent/session/claude/provision.ts\nvar CLAUDE_SDK_PACKAGE = \"@anthropic-ai/claude-agent-sdk\";\nfunction installClaude(installDir) {\n return installPackage(installDir, CLAUDE_SDK_PACKAGE, pinnedVersion(\"claude\", CLAUDE_SDK_PACKAGE), () => claudeExecutable(installDir));\n}\nfunction installedClaude(installDir) {\n return installedPackage(installDir, CLAUDE_SDK_PACKAGE, pinnedVersion(\"claude\", CLAUDE_SDK_PACKAGE), () => claudeExecutable(installDir));\n}\nfunction claudeExecutable(installDir) {\n const base = `${installDir}/node_modules/${CLAUDE_SDK_PACKAGE}-linux-${process.arch}`;\n const glibc = `${base}/claude`;\n return existsSync2(glibc) ? glibc : `${base}-musl/claude`;\n}\n\n// agent/session/claude/auth.ts\nvar GATEWAY_CODE = \"x#x\";\nvar claudeAuth = {\n async signedIn({ installDir, env, cwd }) {\n const proc = Bun.spawn([claudeExecutable(installDir), \"auth\", \"status\", \"--json\"], { env, cwd, stdout: \"pipe\", stderr: \"ignore\" });\n const [output, code] = await Promise.all([new Response(proc.stdout).text(), proc.exited]);\n if (code !== 0)\n return false;\n try {\n return JSON.parse(output).loggedIn === true;\n } catch {\n return false;\n }\n },\n login({ installDir, env, cwd }, gatewaySignedIn) {\n const login = spawnLogin([claudeExecutable(installDir), \"auth\", \"login\"], { env, cwd }, (output) => {\n const url = /https:\\/\\/\\S*oauth\\/authorize\\S*/.exec(output)?.[0];\n return url ? { url, needsCode: true } : null;\n });\n if (gatewaySignedIn)\n login.prompt.then(() => login.submitCode(GATEWAY_CODE), () => {});\n return login;\n }\n};\n\n// agent/api.ts\nvar AGENT_BACKENDS = [\"claude\", \"codex\"];\n\nclass AgentInvalidError extends Error {\n name = \"AgentInvalidError\";\n}\n\nclass AgentNotFoundError extends Error {\n name = \"AgentNotFoundError\";\n}\n\nclass AgentConflictError extends Error {\n name = \"AgentConflictError\";\n}\n\nclass AgentBackendNotInstalledError extends AgentConflictError {\n name = \"AgentBackendNotInstalledError\";\n}\n\n// agent/session/claude/backgroundTasks.ts\nfunction claudeBackgroundTasks() {\n let tasks = [];\n return {\n observe(message) {\n if (message.type !== \"system\")\n return;\n if (message.subtype === \"background_tasks_changed\")\n tasks = message.tasks;\n if (message.subtype === \"task_notification\")\n tasks = tasks.filter((task) => task.task_id !== message.task_id);\n },\n list: async () => tasks\n };\n}\nfunction claudeStopTask(query, tasks) {\n return async (taskId) => {\n if (!(await tasks.list()).some((task) => task.task_id === taskId))\n throw new AgentNotFoundError(`no background task ${taskId}`);\n await query.stopTask(taskId);\n };\n}\n\n// agent/session/claude/home.ts\nfunction claudeHomeEnvironment(home) {\n return { CLAUDE_CONFIG_DIR: home };\n}\n\n// agent/session/claude/input.ts\nfunction createPromptQueue() {\n const queued = [];\n let wake;\n let closed = false;\n function push(message) {\n queued.push(message);\n wake?.();\n }\n function close() {\n closed = true;\n wake?.();\n }\n async function* iterate() {\n for (;; ) {\n while (queued.length > 0)\n yield queued.shift();\n if (closed)\n return;\n await new Promise((resolve2) => wake = resolve2);\n wake = undefined;\n }\n }\n return { push, close, [Symbol.asyncIterator]: iterate };\n}\nfunction claudeInput(prompts, queue) {\n return async (message) => {\n if (!message.uuid)\n throw new Error(\"a message sent to claude needs a uuid to be acknowledged by\");\n const received = queue.sent({ ...message, uuid: message.uuid });\n prompts.push(message);\n await received;\n };\n}\n\n// agent/session/claude/messageQueue.ts\nvar RECEIVE_TIMEOUT_MS = 60000;\nfunction claudeMessageQueue() {\n const commands = new Map;\n let taken = null;\n const receipts = new Map;\n function observe(message) {\n const event = message;\n if (event.type !== \"command_lifecycle\" || !event.command_uuid || !event.state)\n return;\n const command = commands.get(event.command_uuid);\n if (command) {\n command.state = event.state;\n if (event.state === \"started\")\n taken = command.message;\n if (event.state !== \"queued\")\n commands.delete(event.command_uuid);\n }\n const receipt = receipts.get(event.command_uuid);\n if (!receipt)\n return;\n receipts.delete(event.command_uuid);\n if (event.state === \"queued\" || event.state === \"started\")\n receipt.resolve();\n else\n receipt.reject(new Error(`claude ${event.state} the message`));\n }\n function sent(message) {\n commands.set(message.uuid, { message, state: null });\n return new Promise((resolve2, reject) => {\n const timer = setTimeout(() => {\n receipts.delete(message.uuid);\n commands.delete(message.uuid);\n reject(new Error(\"claude didn't confirm it received the message\"));\n }, RECEIVE_TIMEOUT_MS);\n receipts.set(message.uuid, {\n resolve: () => (clearTimeout(timer), resolve2()),\n reject: (error) => (clearTimeout(timer), commands.delete(message.uuid), reject(error))\n });\n });\n }\n async function lastUserMessages() {\n const queued = [...commands.values()].filter((command) => command.state === \"queued\");\n return [...taken ? [{ message: taken, queued: false }] : [], ...queued.map((command) => ({ message: command.message, queued: true }))];\n }\n return { observe, sent, lastUserMessages };\n}\n\n// agent/session/claude/status.ts\nvar SESSION_STATE_EVENTS = { CLAUDE_CODE_EMIT_SESSION_STATE_EVENTS: \"1\" };\nfunction claudeStatus() {\n let status = \"idle\";\n return {\n observe(message) {\n if (message.type !== \"system\" || message.subtype !== \"session_state_changed\")\n return;\n status = message.state === \"requires_action\" ? \"waiting\" : message.state;\n },\n status: async () => status\n };\n}\n\n// agent/session/claude/interrupt.ts\nfunction claudeInterrupt(query) {\n return async () => {\n await query.interrupt();\n };\n}\n\n// agent/session/claude/model.ts\nfunction claudeModel(query) {\n return {\n listModels: () => query.supportedModels(),\n setModel: (model) => query.setModel(model ?? undefined)\n };\n}\n\n// agent/session/sdkMessages.ts\nvar ASK_USER_QUESTION = \"AskUserQuestion\";\nfunction resultUsage({ input = 0, output = 0, cacheRead = 0, cacheWrite = 0 } = {}) {\n return {\n input_tokens: input,\n output_tokens: output,\n cache_read_input_tokens: cacheRead,\n cache_creation_input_tokens: cacheWrite,\n cache_creation: { ephemeral_1h_input_tokens: 0, ephemeral_5m_input_tokens: 0 },\n server_tool_use: { web_fetch_requests: 0, web_search_requests: 0 },\n service_tier: \"standard\"\n };\n}\nfunction userMessageText(message) {\n const content = message.message.content;\n if (typeof content === \"string\")\n return content;\n if (!Array.isArray(content))\n return \"\";\n return content.map((block) => block.type === \"text\" && typeof block.text === \"string\" ? block.text : \"\").filter(Boolean).join(`\n`);\n}\n\n// agent/session/claude/permissions.ts\nfunction claudePermissions(context, questions) {\n const canUseTool = (toolName, input, options) => {\n if (toolName === ASK_USER_QUESTION)\n return questions.answer(input, options);\n const { signal, toolUseID, decisionReason } = options;\n return context.requestPermission({ tool_name: toolName, input, tool_use_id: toolUseID, decision_reason: decisionReason }, signal);\n };\n const preToolUse = [\n {\n hooks: [async () => ({ hookSpecificOutput: { hookEventName: \"PreToolUse\", permissionDecision: \"ask\" } })]\n }\n ];\n return { canUseTool, preToolUse };\n}\n\n// agent/session/claude/questions.ts\nvar QUESTION_DIALOG_KINDS = [\"permission_ask_user_question\", \"ask_user_question\", \"user_question\"];\nfunction claudeQuestions(context) {\n async function ask(input, toolUseId, signal) {\n const questions = Array.isArray(input.questions) ? input.questions : [];\n const response = await context.askQuestions({ tool_use_id: toolUseId, questions }, signal);\n if (!response)\n return { behavior: \"deny\", message: \"The user dismissed the questions.\" };\n return { behavior: \"allow\", updatedInput: { ...input, answers: response.answers } };\n }\n const onUserDialog = async (request, { signal }) => {\n if (!QUESTION_DIALOG_KINDS.includes(request.dialogKind))\n return { behavior: \"cancelled\" };\n const result = await ask(request.payload, request.toolUseID ?? crypto.randomUUID(), signal);\n if (result.behavior !== \"allow\")\n return { behavior: \"cancelled\" };\n return { behavior: \"completed\", result };\n };\n return {\n answer: (input, { signal, toolUseID }) => ask(input, toolUseID, signal),\n onUserDialog,\n supportedDialogKinds: QUESTION_DIALOG_KINDS\n };\n}\n\n// agent/session/claude/sdk.ts\nasync function loadClaudeSdk(installDir) {\n return await import(Bun.resolveSync(CLAUDE_SDK_PACKAGE, installDir));\n}\n\n// agent/session/claude/stream.ts\nasync function startClaudeStream(context, prompts, permissions, questions, backgroundTasks, status, queue) {\n const sdk = await loadClaudeSdk(context.installDir);\n const query = sdk.query({\n prompt: prompts,\n options: {\n cwd: context.cwd,\n env: { ...context.env, ...SESSION_STATE_EVENTS },\n model: context.model ?? undefined,\n resume: context.nativeId ?? undefined,\n includePartialMessages: true,\n permissionMode: \"default\",\n settingSources: [],\n canUseTool: permissions.canUseTool,\n hooks: { PreToolUse: permissions.preToolUse },\n onUserDialog: questions.onUserDialog,\n supportedDialogKinds: questions.supportedDialogKinds,\n stderr: (data) => process.stderr.write(`[claude ${context.spec.name}] ${data}`)\n }\n });\n pump(context, query, [backgroundTasks, status, queue]).then(() => context.exited(), (error) => context.exited(error));\n return query;\n}\nasync function pump(context, query, observers) {\n for await (const message of query) {\n for (const observer of observers)\n observer.observe(message);\n if (\"session_id\" in message && typeof message.session_id === \"string\" && message.session_id) {\n context.setNativeId(message.session_id);\n }\n const streamed = toStreamingMessage(message);\n if (streamed)\n context.emit(streamed);\n }\n}\nfunction toStreamingMessage(message) {\n switch (message.type) {\n case \"assistant\":\n case \"stream_event\":\n case \"result\":\n return message;\n case \"user\":\n return { ...message, uuid: message.uuid ?? crypto.randomUUID(), session_id: message.session_id ?? \"\" };\n case \"system\":\n return message.subtype === \"init\" ? message : null;\n default:\n return null;\n }\n}\n\n// agent/session/fileTranscript.ts\nfunction sandboxFiles(sandbox) {\n return {\n size: async (path) => (await sandbox.stat(path)).size,\n readFileRange: (path, start, end) => sandbox.readFileRange(path, start, end),\n listDirectory: (path) => sandbox.listDirectory(path)\n };\n}\nfunction locateTranscript(files, home, layout, nativeId) {\n const escape = (text) => text.replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$&\");\n const [before = \"\", after = \"\"] = layout.name.split(\"{id}\").map((part) => part.split(\"*\").map(escape).join(\".*\"));\n const name = new RegExp(`^${before}${escape(nativeId)}${after}$`);\n return findFile(files, `${home}/${layout.dir}`, layout.depth, (entry) => name.test(entry));\n}\nvar CHUNK_BYTES = 64 * 1024;\nvar TIME_SLACK_MS = 60000;\nvar PROBE_LINES = 3;\nvar PROBE_BYTES = 4 * CHUNK_BYTES;\nvar NEWLINE = 10;\nfunction lineTime(entry, field) {\n const value = entry?.[field];\n const time = typeof value === \"string\" ? Date.parse(value) : NaN;\n return Number.isNaN(time) ? null : time;\n}\nvar SCAN_BYTES = 1024 * 1024;\nvar searchedCopies = new Map;\nvar SEARCHED_FILES = 16;\nfunction createFileTranscript(files, locate, lineMessages, layout) {\n function parse(bytes, start) {\n try {\n const entry = JSON.parse(new TextDecoder().decode(bytes));\n return { start, time: lineTime(entry, layout.time), messages: lineMessages(entry) };\n } catch {\n return { start, time: null, messages: [] };\n }\n }\n function kept(from, to, skip) {\n const parts = [];\n let start = from;\n for (const stretch of [...skip].sort((a, b) => a.start - b.start)) {\n if (stretch.end <= start || stretch.start >= to)\n continue;\n if (stretch.start > start)\n parts.push({ start, end: stretch.start });\n start = Math.max(start, stretch.end);\n }\n if (start < to)\n parts.push({ start, end: to });\n return parts;\n }\n async function* backward(path, end, skip = []) {\n for (const part of kept(0, end, skip).reverse())\n yield* backwardIn(path, part.start, part.end);\n }\n async function* backwardIn(path, floor, end) {\n let position = end;\n let carry = new Uint8Array(0);\n while (position > floor) {\n const from = Math.max(floor, position - CHUNK_BYTES);\n const chunk = await files.readFileRange(path, from, position);\n const bytes = joined(chunk, carry);\n let lineEnd = bytes.length;\n for (let index = bytes.length - 1;index >= 0; index--) {\n if (bytes[index] !== NEWLINE)\n continue;\n if (lineEnd > index + 1)\n yield parse(bytes.subarray(index + 1, lineEnd), from + index + 1);\n lineEnd = index;\n }\n carry = bytes.slice(0, lineEnd);\n position = from;\n }\n if (carry.length > 0)\n yield parse(carry, floor);\n }\n async function* forward(path, start, end, skip = []) {\n for (const part of kept(start, end, skip))\n yield* forwardIn(path, part.start, part.end);\n }\n async function* forwardIn(path, start, end) {\n let position = start;\n let carry = new Uint8Array(0);\n let carryStart = start;\n while (position < end) {\n const to = Math.min(end, position + CHUNK_BYTES);\n const bytes = joined(carry, await files.readFileRange(path, position, to));\n let lineStart2 = 0;\n for (let index = 0;index < bytes.length; index++) {\n if (bytes[index] !== NEWLINE)\n continue;\n if (index > lineStart2)\n yield parse(bytes.subarray(lineStart2, index), carryStart + lineStart2);\n lineStart2 = index + 1;\n }\n carry = bytes.slice(lineStart2);\n carryStart += lineStart2;\n position = to;\n }\n if (carry.length > 0)\n yield parse(carry, carryStart);\n }\n async function seek(path, low, high, target, skip) {\n return (await narrow(path, low, high, target, skip)).high;\n }\n async function narrow(path, low, high, target, skip) {\n while (high - low > CHUNK_BYTES) {\n let middle = Math.floor((low + high) / 2);\n const inside = skip.find((stretch) => stretch.start <= middle && middle < stretch.end);\n if (inside) {\n if (inside.end >= high) {\n high = Math.max(low, inside.start);\n continue;\n }\n middle = inside.end;\n }\n const probe = await probeTime(path, middle, high, skip);\n if (!probe)\n break;\n if (probe.time >= target)\n high = probe.start;\n else\n low = probe.start;\n }\n return { low, high };\n }\n async function probeTime(path, from, limit, skip) {\n let start = -1;\n let time = Infinity;\n let timed = 0;\n for await (const line of forward(path, from, Math.min(limit, from + PROBE_BYTES), skip)) {\n if (line.start === from && from > 0)\n continue;\n if (line.start >= limit)\n break;\n if (start < 0)\n start = line.start;\n if (line.time === null)\n continue;\n time = Math.min(time, line.time);\n if (++timed === PROBE_LINES)\n break;\n }\n return start < 0 || timed === 0 ? null : { start, time };\n }\n async function timeAt(path, from, size, skip) {\n for await (const line of forward(path, from, Math.min(size, from + PROBE_BYTES), skip))\n if (line.time !== null)\n return line.time;\n return null;\n }\n async function lineStart(path, at) {\n for await (const line of backward(path, at + 1))\n return line.start;\n return 0;\n }\n function copiesOf(path, size) {\n if (!layout.copies)\n return Promise.resolve([]);\n const key = `${path}\\x00${size}`;\n let copies = searchedCopies.get(key);\n if (!copies) {\n copies = findCopies(path, size, layout.copies);\n copies.catch(() => searchedCopies.delete(key));\n searchedCopies.set(key, copies);\n if (searchedCopies.size > SEARCHED_FILES)\n searchedCopies.delete(searchedCopies.keys().next().value);\n }\n return copies;\n }\n async function findCopies(path, size, marker) {\n const needle = Buffer.from(marker);\n const found = [];\n for (let position = 0;position < size; position += SCAN_BYTES) {\n const from = Math.max(0, position - needle.length + 1);\n const bytes = Buffer.from(await files.readFileRange(path, from, Math.min(size, position + SCAN_BYTES)));\n for (let index = bytes.indexOf(needle);index >= 0; index = bytes.indexOf(needle, index + 1)) {\n if (from + index >= position || position === 0)\n found.push(from + index);\n }\n }\n const copies = [];\n for (const [index, at] of found.entries()) {\n const start = await lineStart(path, at);\n let earlier = null;\n for await (const before of backward(path, start)) {\n if (before.time === null)\n continue;\n earlier = before.time;\n break;\n }\n if (earlier === null || copies.some((copy) => copy.start <= start && start < copy.end))\n continue;\n let time = null;\n for await (const line of forward(path, start, size)) {\n time = line.time;\n break;\n }\n if (time === null || time >= earlier)\n continue;\n const next = found[index + 1];\n const near = await narrow(path, start + 1, next === undefined ? size : await lineStart(path, next), earlier + 1, []);\n let end = near.high;\n for await (const line of forward(path, near.low, near.high)) {\n if (line.start <= start || line.time === null || line.time <= earlier)\n continue;\n end = line.start;\n break;\n }\n copies.push({ start, end });\n }\n return copies;\n }\n async function* pagedBackward(path, end, after, skip) {\n let next = after;\n let waiting = [];\n const settle = function* (before) {\n const [timed, ...untimed] = waiting;\n if (!timed)\n return;\n const own = timed.time;\n const late = before !== null && own < before - TIME_SLACK_MS && (next === null || own < next - TIME_SLACK_MS);\n const ahead = before !== null && own > before + TIME_SLACK_MS && (next === null || own > next + TIME_SLACK_MS);\n const time = late || ahead ? before : own;\n yield { ...timed, time };\n for (const line of untimed)\n yield { ...line, time };\n next = own;\n waiting = [];\n };\n for await (const line of backward(path, end, skip)) {\n if (line.time === null) {\n if (waiting.length === 0)\n yield { ...line, time: next ?? Infinity };\n else\n waiting.push(line);\n continue;\n }\n yield* settle(line.time);\n waiting = [line];\n }\n yield* settle(null);\n }\n async function page(before, limit, found) {\n const path = await locate();\n if (!path)\n return { messages: [], nextBefore: null };\n const size = await files.size(path);\n const copies = found?.copies ?? await copiesOf(path, size);\n const from = Math.min(found?.end ?? (before === null ? size : await seek(path, 0, size, before + TIME_SLACK_MS, copies)), size);\n const after = found ? found.after : from < size ? await timeAt(path, from, size, copies) : null;\n const taken = [];\n let count = 0;\n let oldest = Infinity;\n let older = false;\n for await (const line of pagedBackward(path, from, after, copies)) {\n if (count >= limit && line.time < oldest - TIME_SLACK_MS) {\n older = true;\n break;\n }\n if (line.messages.length === 0 || before !== null && !(line.time < before))\n continue;\n taken.push(line);\n count += line.messages.length;\n if (count >= limit)\n oldest = oldestOnPage(taken, limit);\n }\n const kept2 = count >= limit ? taken.filter((line) => line.time >= oldest) : taken;\n if (kept2.length < taken.length)\n older = true;\n return {\n messages: kept2.sort((a, b) => a.start - b.start).flatMap((line) => line.messages),\n nextBefore: older && Number.isFinite(oldest) ? new Date(oldest).toISOString() : null\n };\n }\n async function replay(afterId, emit) {\n const path = await locate();\n if (!path)\n return afterId === undefined;\n const end = await files.size(path);\n const copies = await copiesOf(path, end);\n let start = 0;\n if (afterId !== undefined) {\n let found = null;\n for await (const line of backward(path, end, copies)) {\n if (line.messages.some((message) => message.uuid === afterId)) {\n found = line;\n break;\n }\n }\n if (!found)\n return false;\n start = found.start;\n }\n let passed = afterId === undefined;\n for await (const line of forward(path, start, end, copies)) {\n for (const message of line.messages) {\n if (passed)\n emit(message);\n else if (message.uuid === afterId)\n passed = true;\n }\n }\n return true;\n }\n return { page, replay };\n}\nfunction oldestOnPage(lines, limit) {\n const newestFirst = [...lines].sort((a, b) => b.time - a.time);\n let count = 0;\n for (const line of newestFirst) {\n count += line.messages.length;\n if (count >= limit)\n return line.time;\n }\n return newestFirst[newestFirst.length - 1]?.time ?? Infinity;\n}\nfunction joined(first, second) {\n if (first.length === 0)\n return second;\n if (second.length === 0)\n return first;\n const bytes = new Uint8Array(first.length + second.length);\n bytes.set(first);\n bytes.set(second, first.length);\n return bytes;\n}\nvar DEFAULT_PAGE_SIZE = 50;\nvar MAX_PAGE_SIZE = 500;\nasync function transcriptPage(transcript, { limit, before, cursor } = {}, found) {\n const time = transcriptTime(before ?? cursor);\n if (!transcript)\n return { messages: [], nextBefore: null, nextCursor: null };\n const size = Math.min(Math.max(Math.floor(limit ?? DEFAULT_PAGE_SIZE), 1), MAX_PAGE_SIZE);\n const page = await transcript.page(time, size, found);\n return { ...page, nextCursor: page.nextBefore };\n}\nfunction transcriptTime(before) {\n if (before === undefined)\n return null;\n const time = Date.parse(before);\n if (Number.isNaN(time))\n throw new AgentInvalidError(`invalid time ${before}: give an ISO 8601 time`);\n return time;\n}\nasync function findFile(files, dir, depth, matches) {\n let names;\n try {\n names = await files.listDirectory(dir);\n } catch (error) {\n if (error instanceof SandboxNotFoundError)\n return null;\n throw error;\n }\n if (depth <= 1) {\n const name = names.find(matches);\n return name === undefined ? null : `${dir}/${name}`;\n }\n const found = await Promise.all(names.sort().reverse().map((name) => findFile(files, `${dir}/${name}`, depth - 1, matches).catch(() => null)));\n return found.find((path) => path !== null) ?? null;\n}\n\n// agent/session/claude/transcript.ts\nfunction claudeTranscript({ nativeId, env, files }) {\n const home = env.CLAUDE_CONFIG_DIR ?? `${env.HOME}/.claude`;\n return createFileTranscript(files, () => locateTranscript(files, home, CLAUDE_TRANSCRIPT_LAYOUT, nativeId), claudeLineMessages, CLAUDE_TRANSCRIPT_LAYOUT);\n}\nvar CLAUDE_TRANSCRIPT_LAYOUT = {\n dir: \"projects\",\n depth: 2,\n name: \"{id}.jsonl\",\n time: \"timestamp\",\n copies: '\"subtype\":\"compact_boundary\"'\n};\nfunction claudeLineMessages(line) {\n const entry = line;\n if (entry.type !== \"user\" && entry.type !== \"assistant\")\n return [];\n if (entry.isSidechain || entry.isMeta || !entry.uuid || !entry.message)\n return [];\n return [{ type: entry.type, message: entry.message, parent_tool_use_id: null, uuid: entry.uuid, session_id: entry.sessionId ?? \"\" }];\n}\n\n// agent/session/claude/index.ts\nvar claudeBackend = {\n install: installClaude,\n installed: installedClaude,\n auth: claudeAuth,\n transcript: claudeTranscript,\n homeEnvironment: claudeHomeEnvironment,\n async start(context) {\n const prompts = createPromptQueue();\n const questions = claudeQuestions(context);\n const backgroundTasks = claudeBackgroundTasks();\n const status = claudeStatus();\n const queue = claudeMessageQueue();\n const query = await startClaudeStream(context, prompts, claudePermissions(context, questions), questions, backgroundTasks, status, queue);\n return {\n sendMessage: claudeInput(prompts, queue),\n getSessionStatus: status.status,\n getLastUserMessages: queue.lastUserMessages,\n cancel: claudeInterrupt(query),\n ...claudeModel(query),\n listBackgroundTasks: backgroundTasks.list,\n stopTask: claudeStopTask(query, backgroundTasks),\n async close() {\n prompts.close();\n query.close();\n }\n };\n }\n};\n\n// agent/session/codex/provision.ts\nvar CODEX_PACKAGE = \"@openai/codex\";\nvar CODEX_VERSION = () => pinnedVersion(\"codex\", CODEX_PACKAGE, \"@openai/codex-sdk\");\nfunction installCodex(installDir) {\n return installPackage(installDir, CODEX_PACKAGE, CODEX_VERSION(), () => codexExecutable(installDir).path);\n}\nfunction installedCodex(installDir) {\n return installedPackage(installDir, CODEX_PACKAGE, CODEX_VERSION(), () => codexExecutable(installDir).path);\n}\nvar LINUX_TARGETS = {\n x64: { pkg: \"@openai/codex-linux-x64\", triple: \"x86_64-unknown-linux-musl\" },\n arm64: { pkg: \"@openai/codex-linux-arm64\", triple: \"aarch64-unknown-linux-musl\" }\n};\nfunction codexExecutable(installDir) {\n const target = LINUX_TARGETS[process.arch];\n if (process.platform !== \"linux\" || !target)\n throw new Error(`codex: unsupported platform ${process.platform}/${process.arch}`);\n return {\n path: `${installDir}/node_modules/${target.pkg}/vendor/${target.triple}/bin/codex`,\n env: { CODEX_MANAGED_PACKAGE_ROOT: `${installDir}/node_modules/${CODEX_PACKAGE}`, CODEX_MANAGED_BY_BUN: \"1\" }\n };\n}\n\n// agent/session/codex/auth.ts\nfunction run({ installDir, env, cwd }, args) {\n const executable = codexExecutable(installDir);\n return { cmd: [executable.path, ...args], env: { ...env, ...executable.env }, cwd };\n}\nvar codexAuth = {\n async signedIn(environment) {\n const { cmd, env, cwd } = run(environment, [\"login\", \"status\"]);\n const proc = Bun.spawn(cmd, { env, cwd, stdout: \"ignore\", stderr: \"ignore\" });\n return await proc.exited === 0;\n },\n login(environment) {\n const { cmd, env, cwd } = run(environment, [\"login\", \"--device-auth\"]);\n return spawnLogin(cmd, { env, cwd }, (output) => {\n const url = /https:\\/\\/\\S+\\/device\\S*/.exec(output)?.[0];\n const userCode = /^\\s*([A-Z0-9]{4}-[A-Z0-9]{4,})\\s*$/m.exec(output)?.[1];\n return url && userCode ? { url, userCode, needsCode: false } : null;\n });\n }\n};\n\n// agent/session/codex/backgroundTasks.ts\nimport { readdirSync, readFileSync } from \"fs\";\nvar STOP_GRACE_MS = 1000;\nfunction codexBackgroundTasks() {\n const running = new Map;\n const background = new Map;\n function observe(notification) {\n switch (notification.method) {\n case \"item/started\": {\n const { item } = notification.params;\n if (item.type === \"commandExecution\")\n running.set(item.id, { task_id: item.id, task_type: \"local_bash\", description: item.command });\n return;\n }\n case \"item/completed\": {\n const { item } = notification.params;\n if (item.type !== \"commandExecution\")\n return;\n running.delete(item.id);\n background.delete(item.id);\n return;\n }\n case \"turn/completed\":\n for (const [id, task] of running)\n background.set(id, task);\n running.clear();\n return;\n }\n }\n async function stop(taskId, appServerPid) {\n const task = background.get(taskId);\n if (!task)\n throw new AgentNotFoundError(`no background task ${taskId}`);\n const targets = commandProcesses(appServerPid, task.description);\n signal(targets, \"SIGTERM\");\n const deadline = Date.now() + STOP_GRACE_MS;\n while (targets.some(alive) && Date.now() < deadline)\n await Bun.sleep(50);\n signal(targets.filter(alive), \"SIGKILL\");\n background.delete(taskId);\n }\n return { observe, list: async () => [...background.values()], stop };\n}\nfunction processes() {\n const entries = [];\n for (const name of readdirSync(\"/proc\")) {\n if (!/^\\d+$/.test(name))\n continue;\n try {\n const stat2 = readFileSync(`/proc/${name}/stat`, \"utf8\");\n const ppid = Number(stat2.slice(stat2.lastIndexOf(\")\") + 2).split(\" \")[1]);\n const argv = readFileSync(`/proc/${name}/cmdline`, \"utf8\").split(\"\\x00\").filter(Boolean);\n entries.push({ pid: Number(name), ppid, argv });\n } catch {}\n }\n return entries;\n}\nfunction commandProcesses(root, command) {\n const all = processes();\n const children = new Map;\n for (const entry of all)\n children.set(entry.ppid, [...children.get(entry.ppid) ?? [], entry.pid]);\n const under = (pid) => (children.get(pid) ?? []).flatMap((child) => [child, ...under(child)]);\n const descendants = new Set(under(root));\n const shells = all.filter((entry) => descendants.has(entry.pid) && entry.argv.length >= 3 && [\"-c\", \"-lc\"].includes(entry.argv.at(-2)) && command.includes(entry.argv.at(-1)));\n return [...new Set(shells.flatMap((shell) => [shell.pid, ...under(shell.pid)]))];\n}\nfunction signal(pids, name) {\n for (const pid of pids) {\n try {\n process.kill(pid, name);\n } catch {}\n }\n}\nfunction alive(pid) {\n try {\n process.kill(pid, 0);\n return true;\n } catch {\n return false;\n }\n}\n\n// agent/session/codex/input.ts\nfunction createCodexInput(thread, queue, initialModel) {\n let model = initialModel;\n async function sendMessage(message) {\n if (!message.uuid)\n throw new Error(\"a message sent to codex needs a uuid to be known by\");\n const { rpc, threadId } = thread();\n await rpc.request(\"turn/start\", {\n threadId,\n input: [{ type: \"text\", text: userMessageText(message), text_elements: [] }],\n clientUserMessageId: message.uuid,\n model\n });\n queue.sent(message, message.uuid);\n }\n function setModel(next) {\n model = next;\n }\n return { sendMessage, setModel };\n}\n\n// agent/session/codex/messageQueue.ts\nfunction codexMessageQueue() {\n const queued = new Map;\n let taken = null;\n return {\n observe(notification) {\n if (notification.method !== \"item/started\")\n return;\n const { item } = notification.params;\n if (item.type !== \"userMessage\" || !item.clientId)\n return;\n const message = queued.get(item.clientId);\n if (!message)\n return;\n queued.delete(item.clientId);\n taken = message;\n },\n sent(message, clientId) {\n queued.set(clientId, message);\n },\n async lastUserMessages() {\n return [...taken ? [{ message: taken, queued: false }] : [], ...[...queued.values()].map((message) => ({ message, queued: true }))];\n }\n };\n}\n\n// agent/session/codex/status.ts\nfunction codexStatus() {\n let status = \"idle\";\n return {\n observe(notification) {\n if (notification.method !== \"thread/status/changed\")\n return;\n const reported = notification.params.status;\n if (reported.type === \"active\")\n status = reported.activeFlags.length > 0 ? \"waiting\" : \"running\";\n else if (reported.type === \"systemError\")\n status = \"error\";\n else\n status = \"idle\";\n },\n status: async () => status\n };\n}\n\n// agent/session/codex/interrupt.ts\nfunction codexInterrupt(thread) {\n return async () => {\n const { rpc, threadId, activeTurn } = thread();\n const turnId = activeTurn();\n if (!turnId)\n return;\n await rpc.request(\"turn/interrupt\", { threadId, turnId });\n };\n}\n\n// agent/session/codex/model.ts\nfunction codexModel(thread, input) {\n async function listModels() {\n const { data } = await thread().rpc.request(\"model/list\", {});\n return data.map((model) => ({ value: model.model, displayName: model.displayName, description: model.description }));\n }\n async function setModel(model) {\n input.setModel(model);\n }\n return { listModels, setModel };\n}\n\n// agent/session/codex/permissions.ts\nfunction codexPermissions(context) {\n function ask(request) {\n return context.requestPermission(request);\n }\n async function answer(request, rpc) {\n switch (request.method) {\n case \"item/commandExecution/requestApproval\": {\n const { params } = request;\n const decision = await ask({\n tool_name: \"Bash\",\n input: { command: params.command ?? \"\", cwd: params.cwd },\n tool_use_id: params.itemId,\n decision_reason: params.reason ?? undefined\n });\n const response = { decision: decision.behavior === \"allow\" ? \"accept\" : \"decline\" };\n return rpc.respond(request.id, response);\n }\n case \"item/fileChange/requestApproval\": {\n const { params } = request;\n const decision = await ask({\n tool_name: \"ApplyPatch\",\n input: { grantRoot: params.grantRoot ?? null },\n tool_use_id: params.itemId,\n decision_reason: params.reason ?? undefined\n });\n const response = { decision: decision.behavior === \"allow\" ? \"accept\" : \"decline\" };\n return rpc.respond(request.id, response);\n }\n case \"execCommandApproval\": {\n const { params } = request;\n const decision = await ask({\n tool_name: \"Bash\",\n input: { command: params.command.join(\" \"), cwd: params.cwd },\n tool_use_id: params.callId,\n decision_reason: params.reason ?? undefined\n });\n const response = {\n decision: decision.behavior === \"allow\" ? \"approved\" : { denied: { rejection: decision.message } }\n };\n return rpc.respond(request.id, response);\n }\n case \"applyPatchApproval\": {\n const { params } = request;\n const decision = await ask({\n tool_name: \"ApplyPatch\",\n input: { changes: params.fileChanges, grantRoot: params.grantRoot },\n tool_use_id: params.callId,\n decision_reason: params.reason ?? undefined\n });\n const response = {\n decision: decision.behavior === \"allow\" ? \"approved\" : { denied: { rejection: decision.message } }\n };\n return rpc.respond(request.id, response);\n }\n default:\n return rpc.respondError(request.id, `${request.method} is not supported by hyperbrane`);\n }\n }\n return (request, rpc) => {\n answer(request, rpc).catch((error) => {\n console.error(`answering codex's ${request.method} failed:`, error);\n rpc.respondError(request.id, error.message);\n });\n };\n}\n\n// agent/session/codex/questions.ts\nfunction codexQuestions(context, thread) {\n return async (params) => {\n const questions = params.questions.map((question) => ({\n question: question.question,\n header: question.header,\n options: question.options ?? [],\n multiSelect: false\n }));\n thread().emitToolUse(params.itemId, ASK_USER_QUESTION, { questions });\n const response = await context.askQuestions({ tool_use_id: params.itemId, questions });\n if (!response)\n thread().emitToolResult(params.itemId, \"The user dismissed the questions.\", true);\n else\n thread().emitToolResult(params.itemId, answersText(response.answers), false);\n const answers = {};\n for (const question of params.questions) {\n const answer = response?.answers[question.question];\n answers[question.id] = { answers: answer === undefined ? [] : [answer] };\n }\n return { answers };\n };\n}\nfunction answersText(answers) {\n const pairs = Object.entries(answers).map(([question, answer]) => `\"${question}\"=\"${answer}\"`);\n return `User has answered your questions: ${pairs.join(\", \")}.`;\n}\n\n// agent/session/codex/home.ts\nfunction codexHomeEnvironment(home) {\n return { CODEX_HOME: home };\n}\n\n// agent/session/codex/messages.ts\nfunction backendId(id) {\n return id;\n}\nfunction toolResultId(itemId) {\n return `${itemId}:result`;\n}\nfunction assistantMessage(uuid, content, threadId, model) {\n const usage = { ...resultUsage(), cache_creation: null, server_tool_use: null, service_tier: null };\n return {\n type: \"assistant\",\n message: {\n id: uuid,\n type: \"message\",\n role: \"assistant\",\n model,\n content,\n container: null,\n context_management: null,\n stop_reason: null,\n stop_sequence: null,\n usage\n },\n parent_tool_use_id: null,\n uuid: backendId(uuid),\n session_id: threadId\n };\n}\nfunction toolResultMessage(itemId, content, isError, threadId) {\n return {\n type: \"user\",\n message: { role: \"user\", content: [{ type: \"tool_result\", tool_use_id: itemId, content, is_error: isError }] },\n parent_tool_use_id: null,\n uuid: backendId(toolResultId(itemId)),\n session_id: threadId\n };\n}\nfunction itemMessages(item, threadId, model) {\n if (item.type === \"userMessage\") {\n const text = item.content.map((input) => input.type === \"text\" ? input.text : \"\").join(\"\");\n return [{ type: \"user\", message: { role: \"user\", content: text }, parent_tool_use_id: null, uuid: backendId(item.clientId ?? item.id), session_id: threadId }];\n }\n if (item.type === \"agentMessage\")\n return [assistantMessage(item.id, [{ type: \"text\", text: item.text, citations: null }], threadId, model)];\n const toolUse = toolUseOf(item);\n const toolResult = toolResultOf(item);\n if (!toolUse)\n return [];\n const messages = [assistantMessage(item.id, [toolUse], threadId, model)];\n if (toolResult)\n messages.push(toolResultMessage(item.id, toolResult.content, toolResult.is_error, threadId));\n return messages;\n}\nfunction shownCommand(argv) {\n return argv.map((arg) => /^[\\w@%+=:,./-]+$/.test(arg) ? arg : `'${arg.replaceAll(\"'\", \"'\\\\''\")}'`).join(\" \");\n}\nfunction rolloutItemMessages(stored, threadId) {\n const item = stored;\n const text = (content) => (content ?? []).map((part) => part.text ?? \"\").join(\"\");\n if (item.type === \"UserMessage\" && \"content\" in item) {\n const user = item;\n return [{ type: \"user\", message: { role: \"user\", content: text(user.content) }, parent_tool_use_id: null, uuid: backendId(user.client_id ?? user.id), session_id: threadId }];\n }\n if (item.type === \"AgentMessage\" && item.id) {\n const agent = item;\n return [assistantMessage(agent.id, [{ type: \"text\", text: text(agent.content), citations: null }], threadId, \"\")];\n }\n if (item.type === \"CommandExecution\" && item.id) {\n const command = item;\n const input = { command: shownCommand(command.command ?? []), cwd: (command.cwd ?? \"\").replace(/^file:\\/\\//, \"\") };\n return [\n assistantMessage(command.id, [{ type: \"tool_use\", id: command.id, name: \"Bash\", input }], threadId, \"\"),\n toolResultMessage(command.id, command.aggregated_output ?? \"\", command.status !== \"completed\" || (command.exit_code ?? 0) !== 0, threadId)\n ];\n }\n return [];\n}\nfunction toolUseOf(item) {\n switch (item.type) {\n case \"commandExecution\":\n return { type: \"tool_use\", id: item.id, name: \"Bash\", input: { command: item.command, cwd: item.cwd } };\n case \"fileChange\":\n return { type: \"tool_use\", id: item.id, name: \"ApplyPatch\", input: { changes: item.changes } };\n case \"mcpToolCall\":\n return { type: \"tool_use\", id: item.id, name: `mcp__${item.server}__${item.tool}`, input: item.arguments };\n case \"dynamicToolCall\":\n return { type: \"tool_use\", id: item.id, name: item.tool, input: item.arguments };\n default:\n return null;\n }\n}\nfunction toolResultOf(item) {\n switch (item.type) {\n case \"commandExecution\":\n return {\n type: \"tool_result\",\n tool_use_id: item.id,\n content: item.aggregatedOutput ?? \"\",\n is_error: item.status !== \"completed\" || (item.exitCode ?? 0) !== 0\n };\n case \"fileChange\":\n return { type: \"tool_result\", tool_use_id: item.id, content: item.status, is_error: item.status !== \"completed\" };\n case \"mcpToolCall\":\n return {\n type: \"tool_result\",\n tool_use_id: item.id,\n content: JSON.stringify(item.error ?? item.result?.content ?? null),\n is_error: item.status !== \"completed\"\n };\n case \"dynamicToolCall\":\n return {\n type: \"tool_result\",\n tool_use_id: item.id,\n content: JSON.stringify(item.contentItems ?? null),\n is_error: item.success === false\n };\n default:\n return null;\n }\n}\n\n// agent/session/codex/transcript.ts\nfunction codexTranscript({ nativeId, env, files }) {\n const home = env.CODEX_HOME ?? `${env.HOME}/.codex`;\n return createFileTranscript(files, () => locateTranscript(files, home, CODEX_TRANSCRIPT_LAYOUT, nativeId), codexLineMessages(nativeId), CODEX_TRANSCRIPT_LAYOUT);\n}\nvar CODEX_TRANSCRIPT_LAYOUT = { dir: \"sessions\", depth: 4, name: \"rollout-*-{id}.jsonl\", time: \"timestamp\" };\nfunction codexLineMessages(threadId) {\n return (line) => {\n const { type, payload } = line;\n if (type !== \"event_msg\" || payload?.type !== \"item_completed\" || !payload.item)\n return [];\n return rolloutItemMessages(payload.item, threadId);\n };\n}\n\n// lib/version.ts\nvar HYPERBRANE_VERSION = \"v1\";\n\n// agent/session/codex/rpc.ts\nvar METHOD_NOT_FOUND = -32601;\nfunction spawnCodexAppServer(executable, { cwd, env }, handlers) {\n const args = [\"app-server\", \"-c\", \"tools.experimental_request_user_input.enabled=true\", \"--enable\", \"default_mode_request_user_input\"];\n const proc = Bun.spawn([executable.path, ...args], {\n cwd,\n env: { ...env, ...executable.env },\n stdin: \"pipe\",\n stdout: \"pipe\",\n stderr: \"pipe\"\n });\n const pending = new Map;\n let nextId = 1;\n function send(message) {\n proc.stdin.write(JSON.stringify(message) + `\n`);\n proc.stdin.flush();\n }\n function dispatch(message) {\n if (message.id !== undefined && message.method === undefined) {\n const waiting = pending.get(message.id);\n pending.delete(message.id);\n if (message.error)\n waiting?.reject(new Error(`codex: ${message.error.message ?? JSON.stringify(message.error)}`));\n else\n waiting?.resolve(message.result);\n return;\n }\n if (message.id !== undefined)\n handlers.onRequest(message);\n else\n handlers.onNotification(message);\n }\n async function readLines() {\n const decoder = new TextDecoder;\n let buffered = \"\";\n for await (const chunk of proc.stdout) {\n buffered += decoder.decode(chunk, { stream: true });\n let newline;\n while ((newline = buffered.indexOf(`\n`)) >= 0) {\n const line = buffered.slice(0, newline).trim();\n buffered = buffered.slice(newline + 1);\n if (line)\n dispatch(JSON.parse(line));\n }\n }\n }\n async function forwardStderr() {\n for await (const chunk of proc.stderr)\n process.stderr.write(chunk);\n }\n forwardStderr().catch(() => {});\n readLines().then(() => proc.exited).then((code) => finish(code === 0 ? undefined : new Error(`codex app-server exited with code ${code}`)), (error) => finish(error));\n function finish(error) {\n for (const waiting of pending.values())\n waiting.reject(error ?? new Error(\"codex app-server exited\"));\n pending.clear();\n handlers.onExit(error);\n }\n function request(method, params) {\n const id = nextId++;\n return new Promise((resolve2, reject) => {\n pending.set(id, { resolve: (result) => resolve2(result), reject });\n send({ id, method, params });\n });\n }\n function notify(method) {\n send({ method });\n }\n function respond(id, result) {\n send({ id, result });\n }\n function respondError(id, message) {\n send({ id, error: { code: METHOD_NOT_FOUND, message } });\n }\n function close() {\n proc.stdin.end();\n proc.kill();\n }\n return { pid: proc.pid, request, notify, respond, respondError, close };\n}\n\n// agent/session/codex/stream.ts\nasync function startCodexStream(context, hooks) {\n let threadId = context.nativeId ?? \"\";\n let model = context.model ?? \"\";\n let turn = null;\n const rpc = spawnCodexAppServer(codexExecutable(context.installDir), { cwd: context.cwd, env: context.env }, {\n onNotification,\n onRequest: (request) => hooks.onServerRequest(request, rpc),\n onExit: (error) => context.exited(error)\n });\n function base() {\n return { parent_tool_use_id: null, uuid: crypto.randomUUID(), session_id: threadId };\n }\n function currentTurn(id) {\n turn ??= { id, startedAt: Date.now(), lastText: \"\", usage: null, errors: [] };\n turn.id ??= id;\n return turn;\n }\n function onNotification(notification) {\n for (const observer of hooks.observers)\n observer.observe(notification);\n switch (notification.method) {\n case \"turn/started\":\n currentTurn(notification.params.turn.id);\n return;\n case \"item/agentMessage/delta\":\n context.emit({\n type: \"stream_event\",\n event: { type: \"content_block_delta\", index: 0, delta: { type: \"text_delta\", text: notification.params.delta } },\n ...base()\n });\n return;\n case \"item/reasoning/summaryTextDelta\":\n case \"item/reasoning/textDelta\":\n context.emit({\n type: \"stream_event\",\n event: { type: \"content_block_delta\", index: 0, delta: { type: \"thinking_delta\", thinking: notification.params.delta } },\n ...base()\n });\n return;\n case \"item/started\": {\n const { item } = notification.params;\n const toolUse = toolUseOf(item);\n if (toolUse)\n context.emit(assistantMessage(item.id, [toolUse], threadId, model));\n return;\n }\n case \"item/completed\": {\n const { item } = notification.params;\n if (item.type === \"agentMessage\")\n currentTurn(notification.params.turnId).lastText = item.text;\n if (item.type === \"userMessage\")\n return;\n const messages = itemMessages(item, threadId, model);\n for (const message of toolUseOf(item) ? messages.slice(1) : messages)\n context.emit(message);\n return;\n }\n case \"thread/tokenUsage/updated\":\n currentTurn(notification.params.turnId).usage = notification.params.tokenUsage.last;\n return;\n case \"error\":\n if (!notification.params.willRetry)\n currentTurn(notification.params.turnId).errors.push(notification.params.error.message);\n return;\n case \"turn/completed\":\n context.emit(resultOf(currentTurn(notification.params.turn.id), notification.params.turn));\n turn = null;\n return;\n }\n }\n function resultOf(state, finished) {\n const duration = finished.durationMs ?? Date.now() - state.startedAt;\n const usage = resultUsage({\n input: state.usage?.inputTokens,\n output: state.usage?.outputTokens,\n cacheRead: state.usage?.cachedInputTokens,\n cacheWrite: state.usage?.cacheWriteInputTokens\n });\n const common = {\n duration_ms: duration,\n duration_api_ms: duration,\n num_turns: 1,\n total_cost_usd: 0,\n usage,\n modelUsage: {},\n permission_denials: [],\n uuid: crypto.randomUUID(),\n session_id: threadId\n };\n if (finished.status === \"completed\") {\n return { type: \"result\", subtype: \"success\", is_error: false, result: state.lastText, stop_reason: \"end_turn\", ...common };\n }\n const errors = [...state.errors];\n if (finished.error)\n errors.push(finished.error.message);\n if (errors.length === 0)\n errors.push(`turn ${finished.status}`);\n return { type: \"result\", subtype: \"error_during_execution\", is_error: true, stop_reason: null, errors, ...common };\n }\n await rpc.request(\"initialize\", {\n clientInfo: { name: \"hyperbrane\", title: \"hyperbrane\", version: HYPERBRANE_VERSION },\n capabilities: { experimentalApi: true, requestAttestation: false }\n });\n rpc.notify(\"initialized\");\n const settings = {\n cwd: context.spec.cwd ?? null,\n model: context.model,\n approvalPolicy: \"untrusted\",\n sandbox: \"danger-full-access\"\n };\n const started = threadId ? await rpc.request(\"thread/resume\", { threadId, ...settings }) : await rpc.request(\"thread/start\", settings);\n threadId = started.thread.id;\n model = started.model;\n context.setNativeId(threadId);\n return {\n rpc,\n threadId,\n model,\n activeTurn: () => turn?.id ?? null,\n emitToolUse: (id, name, input) => context.emit(assistantMessage(id, [{ type: \"tool_use\", id, name, input }], threadId, model)),\n emitToolResult: (id, content, isError) => context.emit(toolResultMessage(id, content, isError, threadId))\n };\n}\n\n// agent/session/codex/index.ts\nvar codexBackend = {\n install: installCodex,\n installed: installedCodex,\n auth: codexAuth,\n transcript: codexTranscript,\n homeEnvironment: codexHomeEnvironment,\n async start(context) {\n let thread;\n const current = () => thread;\n const queue = codexMessageQueue();\n const status = codexStatus();\n const input = createCodexInput(current, queue, context.model);\n const permissions = codexPermissions(context);\n const questions = codexQuestions(context, current);\n function onServerRequest(request, rpc) {\n if (request.method !== \"item/tool/requestUserInput\")\n return permissions(request, rpc);\n questions(request.params).then((response) => rpc.respond(request.id, response), (error) => rpc.respondError(request.id, error.message));\n }\n const backgroundTasks = codexBackgroundTasks();\n thread = await startCodexStream(context, { onServerRequest, observers: [backgroundTasks, status, queue] });\n return {\n sendMessage: input.sendMessage,\n getSessionStatus: status.status,\n getLastUserMessages: queue.lastUserMessages,\n cancel: codexInterrupt(current),\n ...codexModel(current, input),\n listBackgroundTasks: backgroundTasks.list,\n stopTask: (taskId) => backgroundTasks.stop(taskId, current().rpc.pid),\n async close() {\n current().rpc.close();\n }\n };\n }\n};\n\n// agent/session/backends.ts\nvar SESSION_BACKENDS = {\n claude: claudeBackend,\n codex: codexBackend\n};\n\n// dimension/paths.ts\nvar WORKSPACE_PATH = \"/workspace\";\nvar RUN_PATH = \"/run/hyperbrane\";\nvar STATE_PATH = \"/var/lib/hyperbrane\";\n\n// lib/jsonDirectory.ts\nvar EXTENSION = \".json\";\nvar NAME_PATTERN = /^[a-zA-Z0-9][a-zA-Z0-9_.-]{0,62}$/;\n\nclass InvalidNameError extends Error {\n name = \"InvalidNameError\";\n}\nfunction checkName(name) {\n if (!NAME_PATTERN.test(name)) {\n throw new InvalidNameError(`Invalid name \"${name}\": use letters, digits, \"_\", \".\" and \"-\", up to 63 characters`);\n }\n return name;\n}\nfunction createJsonDirectory(sandbox, dir) {\n async function pathFor(name) {\n return `${await dir()}/${checkName(name)}${EXTENSION}`;\n }\n function serialize(record) {\n return JSON.stringify(record, null, 2) + `\n`;\n }\n async function readPath(path) {\n try {\n return JSON.parse(new TextDecoder().decode(await sandbox.readFile(path)));\n } catch (error) {\n if (error instanceof SandboxNotFoundError)\n return null;\n throw error;\n }\n }\n async function read(name) {\n return readPath(await pathFor(name));\n }\n async function insert(name, record) {\n const path = await pathFor(name);\n if (await sandbox.writeFileExclusive(path, serialize(record)))\n return record;\n return await readPath(path) ?? insert(name, record);\n }\n async function save(name, record) {\n await sandbox.writeFile(await pathFor(name), serialize(record));\n }\n async function remove(name) {\n await sandbox.removeFile(await pathFor(name));\n }\n async function entries() {\n const path = await dir();\n const all = await sandbox.runCommand([\"sh\", \"-c\", LIST_SCRIPT, \"sh\", path]).catch(() => null);\n if (all?.exitCode === MISSING)\n return [];\n if (all?.exitCode === 0) {\n return all.stdout.split(RECORD_END).filter((text) => text.trim()).flatMap((text) => {\n const newline = text.indexOf(`\n`);\n try {\n return [[text.slice(0, newline).slice(0, -EXTENSION.length), JSON.parse(text.slice(newline + 1))]];\n } catch {\n return [];\n }\n });\n }\n let files;\n try {\n files = await sandbox.listDirectory(path);\n } catch (error) {\n if (error instanceof SandboxNotFoundError)\n return [];\n throw error;\n }\n const records = await Promise.all(files.filter((file) => file.endsWith(EXTENSION)).map(async (file) => [file.slice(0, -EXTENSION.length), await readPath(`${path}/${file}`)]));\n return records.filter((entry) => entry[1] !== null);\n }\n async function list() {\n return (await entries()).map(([, record]) => record);\n }\n return { read, insert, save, remove, list, entries };\n}\nvar MISSING = 44;\nvar RECORD_END = `\n\\x1E\n`;\nvar LIST_SCRIPT = `cd \"$1\" 2>/dev/null || exit ${MISSING}\nfor file in *${EXTENSION}; do\n [ -f \"$file\" ] || continue\n printf '%s\\\\n' \"$file\" && cat \"$file\" && printf '\\\\n\\\\036\\\\n'\ndone`;\n\n// agent/session/sessionStorage.ts\nfunction workerSocketPath(runDirectory, agentName) {\n return `${runDirectory}/${agentName}.sock`;\n}\nfunction sessionsDirectory(stateDirectory, agentName) {\n return `${stateDirectory}/agents/${agentName}/sessions`;\n}\nfunction backendHomePath(stateDirectory, backend) {\n return `${stateDirectory}/backends/${backend}`;\n}\nfunction createSessionStorage(sandbox, agentName, { stateDirectory = STATE_PATH, runDirectory = RUN_PATH } = {}) {\n const sessionsDir = sessionsDirectory(stateDirectory, agentName);\n const sessions = createJsonDirectory(sandbox, async () => sessionsDir);\n const sessionDir = (sessionName) => `${sessionsDir}/${checkName(sessionName)}`;\n const permissionRequests = (sessionName) => createJsonDirectory(sandbox, async () => `${sessionDir(sessionName)}/permission-requests`);\n const questionRequests = (sessionName) => createJsonDirectory(sandbox, async () => `${sessionDir(sessionName)}/question-requests`);\n const sessionFiles = (sessionName) => createJsonDirectory(sandbox, async () => sessionDir(sessionName));\n async function oldestFirst(stored) {\n return (await stored).sort((a, b) => a.at - b.at).map((entry) => entry.request);\n }\n async function getSessions() {\n return sessions.list();\n }\n async function insertSession(record) {\n return sessions.insert(record.spec.name, record);\n }\n async function saveSession(record) {\n await sessions.save(record.spec.name, record);\n }\n async function removeSession(sessionName) {\n await sandbox.removeDirectory(sessionDir(sessionName));\n await sessions.remove(sessionName);\n }\n async function getPermissionRequests(sessionName) {\n return oldestFirst(permissionRequests(sessionName).list());\n }\n async function savePermissionRequest(sessionName, request) {\n await permissionRequests(sessionName).save(request.id, { request, at: Date.now() });\n }\n async function removePermissionRequest(sessionName, requestId) {\n await permissionRequests(sessionName).remove(requestId);\n }\n async function getQuestionRequests(sessionName) {\n return oldestFirst(questionRequests(sessionName).list());\n }\n async function saveQuestionRequest(sessionName, request) {\n await questionRequests(sessionName).save(request.id, { request, at: Date.now() });\n }\n async function removeQuestionRequest(sessionName, requestId) {\n await questionRequests(sessionName).remove(requestId);\n }\n async function readAuth(sessionName) {\n return sessionFiles(sessionName).read(\"auth\");\n }\n async function saveAuth(sessionName, record) {\n await sessionFiles(sessionName).save(\"auth\", record);\n }\n async function socketPath() {\n return workerSocketPath(runDirectory, agentName);\n }\n async function backendHome(backend) {\n const path = backendHomePath(stateDirectory, backend);\n await sandbox.createDirectory(path);\n return path;\n }\n return {\n getSessions,\n insertSession,\n saveSession,\n removeSession,\n getPermissionRequests,\n savePermissionRequest,\n removePermissionRequest,\n getQuestionRequests,\n saveQuestionRequest,\n removeQuestionRequest,\n readAuth,\n saveAuth,\n socketPath,\n backendHome\n };\n}\n\n// agent/session/worker/workerServer.ts\nimport { rm as rm2 } from \"fs/promises\";\n\n// agent/session/worker/jsonRpc.ts\nvar PARSE_ERROR = -32700;\nfunction createJsonRpcPeer(write, options) {\n const pending = new Map;\n let nextId = 1;\n let buffered = \"\";\n let closedWith;\n function send(message) {\n if (closedWith)\n return;\n write(JSON.stringify({ jsonrpc: \"2.0\", ...message }) + `\n`);\n }\n function handle(message) {\n if (message.method === undefined) {\n if (message.id === undefined || message.id === null)\n return;\n const waiting = pending.get(message.id);\n pending.delete(message.id);\n if (message.error)\n waiting?.reject(options.decodeError(message.error));\n else\n waiting?.resolve(message.result);\n return;\n }\n if (message.id === undefined || message.id === null) {\n options.onNotification?.(message.method, message.params);\n return;\n }\n const id = message.id;\n options.onRequest(message.method, message.params).then((result) => send({ id, result: result ?? null }), (error) => send({ id, error: options.encodeError(error) }));\n }\n function receive(text) {\n buffered += text;\n let newline;\n while ((newline = buffered.indexOf(`\n`)) >= 0) {\n const line = buffered.slice(0, newline).trim();\n buffered = buffered.slice(newline + 1);\n if (!line)\n continue;\n let message;\n try {\n message = JSON.parse(line);\n } catch {\n send({ id: null, error: { code: PARSE_ERROR, message: \"not JSON\" } });\n continue;\n }\n handle(message);\n }\n }\n function request(method, params) {\n if (closedWith)\n return Promise.reject(closedWith);\n const id = nextId++;\n return new Promise((resolve2, reject) => {\n pending.set(id, { resolve: resolve2, reject });\n send({ id, method, params });\n });\n }\n function notify(method, params) {\n send({ method, params });\n }\n function close(error) {\n closedWith ??= error;\n for (const waiting of pending.values())\n waiting.reject(error);\n pending.clear();\n }\n return { receive, request, notify, close };\n}\nfunction createSocketWriter(socket) {\n const encoder = new TextEncoder;\n let backlog = null;\n function write(text) {\n const bytes = encoder.encode(text);\n if (backlog) {\n const joined2 = new Uint8Array(backlog.length + bytes.length);\n joined2.set(backlog);\n joined2.set(bytes, backlog.length);\n backlog = joined2;\n return;\n }\n const written = Math.max(socket.write(bytes), 0);\n if (written < bytes.length)\n backlog = bytes.subarray(written);\n }\n function drain() {\n if (!backlog)\n return;\n const written = Math.max(socket.write(backlog), 0);\n backlog = written < backlog.length ? backlog.subarray(written) : null;\n }\n return { write, drain };\n}\n\n// agent/session/worker/protocol.ts\nvar METHOD_NOT_FOUND2 = -32601;\nvar INVALID_PARAMS = -32602;\nvar INTERNAL_ERROR = -32603;\nvar NOT_FOUND = -32004;\nvar CONFLICT = -32009;\nvar BACKEND_NOT_INSTALLED = -32010;\n\nclass WorkerMethodNotFoundError extends Error {\n name = \"WorkerMethodNotFoundError\";\n}\nfunction encodeWorkerError(error) {\n const message = error instanceof Error ? error.message : String(error);\n if (error instanceof AgentInvalidError)\n return { code: INVALID_PARAMS, message };\n if (error instanceof AgentNotFoundError)\n return { code: NOT_FOUND, message };\n if (error instanceof AgentBackendNotInstalledError)\n return { code: BACKEND_NOT_INSTALLED, message };\n if (error instanceof AgentConflictError)\n return { code: CONFLICT, message };\n if (error instanceof WorkerMethodNotFoundError)\n return { code: METHOD_NOT_FOUND2, message };\n return { code: INTERNAL_ERROR, message };\n}\nfunction decodeWorkerError({ code, message }) {\n if (code === INVALID_PARAMS)\n return new AgentInvalidError(message);\n if (code === NOT_FOUND)\n return new AgentNotFoundError(message);\n if (code === CONFLICT)\n return new AgentConflictError(message);\n if (code === BACKEND_NOT_INSTALLED)\n return new AgentBackendNotInstalledError(message);\n return new Error(`worker: ${message}`);\n}\n\n// agent/session/worker/workerParams.ts\nvar WORKER_PARAMS = {\n \"worker/health\": () => ({}),\n \"worker/shutdown\": () => ({}),\n \"backend/install\": (params) => ({ backend: backend(params.backend) }),\n \"backend/list\": () => ({}),\n \"session/create\": (params) => ({ session: session(object(params.session, \"session\")) }),\n \"session/list\": () => ({}),\n \"session/update\": (params) => ({ session: name(params), limits: limits(object(params.limits, \"limits\")) }),\n \"session/stop\": (params) => ({ session: name(params) }),\n \"session/send\": (params) => ({ session: name(params), message: userMessage(params.message) }),\n \"session/interrupt\": (params) => ({ session: name(params) }),\n \"session/status\": (params) => ({ session: name(params) }),\n \"session/lastUserMessages\": (params) => ({ session: name(params) }),\n \"session/subscribe\": (params) => ({\n session: name(params),\n subscription: text(params.subscription, \"subscription\"),\n after_id: optional(params.after_id, (value) => text(value, \"after_id\"))\n }),\n \"session/unsubscribe\": (params) => ({ subscription: text(params.subscription, \"subscription\") }),\n \"session/transcript\": (params) => ({\n session: name(params),\n limit: optional(params.limit, (value) => number(value, \"limit\")),\n before: params.before === undefined ? optional(params.cursor, (value) => text(value, \"cursor\")) : text(params.before, \"before\")\n }),\n \"permission/list\": (params) => ({ session: name(params) }),\n \"permission/respond\": (params) => ({\n session: name(params),\n request: text(params.request, \"request\"),\n result: permissionResult(params.result)\n }),\n \"question/list\": (params) => ({ session: name(params) }),\n \"question/respond\": (params) => ({\n session: name(params),\n request: text(params.request, \"request\"),\n response: questionResponse(params.response)\n }),\n \"model/list\": (params) => ({ session: name(params) }),\n \"model/set\": (params) => ({\n session: name(params),\n model: params.model === null ? null : text(params.model, \"the model (a model name, or null for the backend's default)\")\n }),\n \"task/list\": (params) => ({ session: name(params) }),\n \"task/stop\": (params) => ({ session: name(params), task: text(params.task, \"task\") }),\n \"auth/status\": (params) => ({ session: name(params) }),\n \"auth/login\": (params) => ({\n session: name(params),\n gatewaySignedIn: optional(params.gatewaySignedIn, (value) => boolean(value, \"gatewaySignedIn\")) ?? false\n }),\n \"auth/code\": (params) => ({ session: name(params), code: text(params.code, \"the code (the one the sign-in page showed)\").trim() })\n};\nfunction invalid(message) {\n throw new AgentInvalidError(message);\n}\nfunction name(params) {\n return text(params.session, \"session\");\n}\nfunction object(value, what) {\n if (value === null || typeof value !== \"object\" || Array.isArray(value))\n invalid(`${what} must be an object`);\n return value;\n}\nfunction text(value, what) {\n if (typeof value !== \"string\" || value.trim() === \"\")\n invalid(`${what} must be a non-empty string`);\n return value;\n}\nfunction number(value, what) {\n if (typeof value !== \"number\" || !Number.isFinite(value))\n invalid(`${what} must be a number`);\n return value;\n}\nfunction boolean(value, what) {\n if (typeof value !== \"boolean\")\n invalid(`${what} must be true or false`);\n return value;\n}\nfunction optional(value, parse) {\n return value === undefined ? undefined : parse(value);\n}\nfunction backend(value) {\n const known = AGENT_BACKENDS.find((name2) => name2 === value);\n if (!known)\n invalid(`unknown backend \"${String(value)}\"; known: ${AGENT_BACKENDS.join(\", \")}`);\n return known;\n}\nfunction memoryLimit(value) {\n const bytes = number(value, \"memoryLimit\");\n if (!(bytes > 0))\n invalid(\"memoryLimit must be positive\");\n return bytes;\n}\nfunction cpuLimit(value) {\n const cores = number(value, \"cpuLimit\");\n if (!(cores > 0))\n invalid(\"cpuLimit must be positive\");\n return cores;\n}\nfunction environment(value) {\n const fields = object(value, \"env\");\n for (const [key, entry] of Object.entries(fields))\n if (typeof entry !== \"string\")\n invalid(`env.${key} must be a string`);\n return fields;\n}\nfunction session(fields) {\n return {\n name: text(fields.name, \"the session's name\"),\n backend: backend(fields.backend),\n memoryLimit: memoryLimit(fields.memoryLimit),\n cpuLimit: cpuLimit(fields.cpuLimit),\n cwd: optional(fields.cwd, (value) => text(value, \"cwd\")),\n env: optional(fields.env, environment)\n };\n}\nfunction limits(fields) {\n return { memoryLimit: optional(fields.memoryLimit, memoryLimit), cpuLimit: optional(fields.cpuLimit, cpuLimit) };\n}\nfunction userMessage(value) {\n const fields = object(value, 'a message (an SDK user message: {type: \"user\", message})');\n if (fields.type !== \"user\")\n invalid('a message is an SDK user message: {type: \"user\", message}');\n const message = object(fields.message, \"message.message\");\n if (message.role !== \"user\")\n invalid('message.message.role must be \"user\"');\n if (typeof message.content !== \"string\" && !Array.isArray(message.content))\n invalid(\"message.message.content must be a string or an array of content blocks\");\n return value;\n}\nfunction permissionResult(value) {\n const fields = object(value, \"result\");\n if (fields.behavior === \"allow\") {\n return { behavior: \"allow\", updatedInput: optional(fields.updatedInput, (input) => object(input, \"updatedInput\")) };\n }\n if (fields.behavior === \"deny\") {\n return {\n behavior: \"deny\",\n message: typeof fields.message === \"string\" ? fields.message : invalid(\"a denial needs a message\"),\n interrupt: optional(fields.interrupt, (interrupt) => boolean(interrupt, \"interrupt\"))\n };\n }\n return invalid('a permission result is {behavior: \"allow\"} or {behavior: \"deny\", message}');\n}\nfunction questionResponse(value) {\n const answers = object(object(value, \"response\").answers, \"a question response's answers ({<question>: <answer>})\");\n for (const [question, answer] of Object.entries(answers))\n if (typeof answer !== \"string\")\n invalid(`the answer to \"${question}\" must be a string`);\n return { answers };\n}\n\n// agent/session/worker/workerServer.ts\nvar INTERNAL_ERROR_LOGGED = -32603;\nfunction createWorkerServer(service, options) {\n let listener;\n function ref(session2) {\n return { agentName: options.health.agentName, sessionName: session2 };\n }\n const handlers = {\n \"worker/health\": async () => options.health,\n \"worker/shutdown\": async () => {\n setTimeout(options.onShutdown, 0);\n return null;\n },\n \"backend/install\": async ({ backend: backend2 }) => nothing(await service.install(options.health.agentName, backend2)),\n \"backend/list\": () => service.listBackends(options.health.agentName),\n \"session/create\": ({ session: session2 }) => service.createSession(options.health.agentName, session2),\n \"session/list\": () => service.listSessions(),\n \"session/update\": ({ session: session2, limits: limits2 }) => service.updateSession(ref(session2), limits2),\n \"session/stop\": async ({ session: session2 }) => nothing(await service.stopSession(ref(session2))),\n \"session/send\": async ({ session: session2, message }) => nothing(await service.sendMessage(ref(session2), message)),\n \"session/interrupt\": async ({ session: session2 }) => nothing(await service.cancel(ref(session2))),\n \"session/status\": ({ session: session2 }) => service.getSessionStatus(ref(session2)),\n \"session/lastUserMessages\": ({ session: session2 }) => service.getLastUserMessages(ref(session2)),\n \"session/subscribe\": async ({ session: session2, subscription, after_id }, connection) => {\n if (connection.subscriptions.has(subscription))\n throw new AgentConflictError(`subscription ${subscription} already exists`);\n let unsubscribe = null;\n let cancelled = false;\n connection.subscriptions.set(subscription, () => {\n cancelled = true;\n unsubscribe?.();\n });\n try {\n unsubscribe = await service.subscribe(ref(session2), after_id, (message) => {\n const notification = { subscription, message };\n connection.peer.notify(\"session/message\", notification);\n });\n } catch (error) {\n connection.subscriptions.delete(subscription);\n throw error;\n }\n if (cancelled)\n unsubscribe();\n return null;\n },\n \"session/unsubscribe\": async ({ subscription }, connection) => {\n connection.subscriptions.get(subscription)?.();\n connection.subscriptions.delete(subscription);\n return null;\n },\n \"session/transcript\": ({ session: session2, limit, before }) => service.getTranscript(ref(session2), { limit, before }),\n \"permission/list\": ({ session: session2 }) => service.listPermissionRequests(ref(session2)),\n \"permission/respond\": async ({ session: session2, request, result }) => nothing(await service.respondPermissionRequest(ref(session2), request, result)),\n \"question/list\": ({ session: session2 }) => service.listQuestionRequests(ref(session2)),\n \"question/respond\": async ({ session: session2, request, response }) => nothing(await service.respondQuestionRequest(ref(session2), request, response)),\n \"model/list\": ({ session: session2 }) => service.listModels(ref(session2)),\n \"model/set\": async ({ session: session2, model }) => nothing(await service.setModel(ref(session2), model)),\n \"task/list\": ({ session: session2 }) => service.listBackgroundTasks(ref(session2)),\n \"task/stop\": async ({ session: session2, task }) => nothing(await service.stopTask(ref(session2), task)),\n \"auth/status\": ({ session: session2 }) => service.getAuthStatus(ref(session2)),\n \"auth/login\": ({ session: session2, gatewaySignedIn }) => service.login(ref(session2), gatewaySignedIn),\n \"auth/code\": ({ session: session2, code }) => service.submitAuthCode(ref(session2), code)\n };\n function handle(method, params, connection) {\n return handlers[method](WORKER_PARAMS[method](params), connection);\n }\n async function dispatch(method, params, connection) {\n if (!isWorkerMethod(method))\n throw new WorkerMethodNotFoundError(`no method ${method}`);\n const fields = params ?? {};\n if (typeof fields !== \"object\" || Array.isArray(fields))\n throw new AgentInvalidError(`${method} takes an object of params`);\n return handle(method, fields, connection);\n }\n function openConnection(socket) {\n const writer = createSocketWriter(socket);\n const peer = createJsonRpcPeer(writer.write, {\n onRequest: (method, params) => dispatch(method, params, connection),\n encodeError: (error) => {\n const encoded = encodeWorkerError(error);\n if (encoded.code === INTERNAL_ERROR_LOGGED)\n console.error(error);\n return encoded;\n },\n decodeError: decodeWorkerError\n });\n const connection = { peer, writer, subscriptions: new Map, decoder: new TextDecoder };\n return connection;\n }\n async function start() {\n await rm2(options.socketPath, { force: true });\n listener = Bun.listen({\n unix: options.socketPath,\n socket: {\n open(socket) {\n socket.data = openConnection(socket);\n },\n data(socket, data) {\n socket.data.peer.receive(socket.data.decoder.decode(data, { stream: true }));\n },\n drain(socket) {\n socket.data.writer.drain();\n },\n close(socket) {\n for (const unsubscribe of socket.data.subscriptions.values())\n unsubscribe();\n socket.data.subscriptions.clear();\n socket.data.peer.close(new Error(\"the connection closed\"));\n },\n error(_socket, error) {\n console.error(\"worker connection failed:\", error);\n }\n }\n });\n }\n function stop() {\n listener?.stop(true);\n listener = undefined;\n }\n return { start, stop };\n}\nfunction isWorkerMethod(method) {\n return Object.hasOwn(WORKER_PARAMS, method);\n}\nfunction nothing(_done) {\n return null;\n}\n\n// agent/session/workerService.ts\nimport { statSync } from \"fs\";\n\n// agent/session/pending.ts\nfunction createPendingRequests(store, fallback) {\n const waiting = new Map;\n function add(request, signal2) {\n const id = crypto.randomUUID();\n return new Promise((resolve2) => {\n let settled = false;\n const settle = (response) => {\n if (settled)\n return;\n settled = true;\n waiting.delete(id);\n signal2?.removeEventListener(\"abort\", aborted);\n store.remove(id).catch((error) => console.error(`removing request ${id} failed:`, error));\n resolve2(response);\n };\n const aborted = () => settle(fallback(\"the request was cancelled\"));\n if (signal2?.aborted)\n return aborted();\n signal2?.addEventListener(\"abort\", aborted);\n waiting.set(id, settle);\n store.save({ ...request, id }).catch((error) => {\n console.error(`keeping request ${id} failed:`, error);\n settle(fallback(\"the request couldn't be kept\"));\n });\n });\n }\n async function list() {\n return (await store.list()).filter((request) => waiting.has(request.id));\n }\n async function answer(id, response) {\n const settle = waiting.get(id);\n if (!settle)\n return false;\n settle(response);\n return true;\n }\n async function dropAll(reason) {\n for (const settle of [...waiting.values()])\n settle(fallback(reason));\n for (const request of await store.list())\n if (!waiting.has(request.id))\n await store.remove(request.id);\n }\n return { add, list, answer, dropAll };\n}\n\n// agent/session/workerService.ts\nfunction createWorkerService(config) {\n const sessions = new Map;\n let installing = Promise.resolve();\n async function loadSessions() {\n for (const record of await config.storage.getSessions()) {\n const state = await newState(record);\n sessions.set(record.spec.name, state);\n await dropRequests(state, \"the worker restarted\");\n const auth = await config.storage.readAuth(record.spec.name);\n if (auth?.login)\n await config.storage.saveAuth(record.spec.name, { login: null, error: auth.error });\n }\n }\n async function newState(record) {\n return {\n ...record,\n listeners: new Set,\n running: null,\n startedAt: 0,\n generation: 0,\n session: null,\n login: null,\n permissionRequests: createPendingRequests({\n list: () => config.storage.getPermissionRequests(record.spec.name),\n save: (request) => config.storage.savePermissionRequest(record.spec.name, request),\n remove: (id) => config.storage.removePermissionRequest(record.spec.name, id)\n }, (message) => ({ behavior: \"deny\", message })),\n questionRequests: createPendingRequests({\n list: () => config.storage.getQuestionRequests(record.spec.name),\n save: (request) => config.storage.saveQuestionRequest(record.spec.name, request),\n remove: (id) => config.storage.removeQuestionRequest(record.spec.name, id)\n }, () => null)\n };\n }\n async function saveRecord(state) {\n await config.storage.saveSession({ spec: state.spec, nativeId: state.nativeId, model: state.model });\n }\n async function info(state) {\n return { ...state.spec, agentName: config.agentName, status: await statusOf(state), nativeId: state.nativeId, model: state.model };\n }\n async function statusOf(state) {\n if (!state.running)\n return \"stopped\";\n if (!state.session)\n return \"starting\";\n return state.session.getSessionStatus();\n }\n async function lastStoredPrompt(state) {\n const transcript = await transcriptOf(state);\n let before = null;\n while (transcript) {\n const page = await transcript.page(before, LAST_PROMPT_PAGE_SIZE);\n const prompt = page.messages.findLast((message) => message.type === \"user\" && isPrompt(message.message.content));\n if (prompt?.type === \"user\")\n return { message: prompt, queued: false };\n if (!page.nextBefore)\n return null;\n before = Date.parse(page.nextBefore);\n }\n return null;\n }\n function trustChangedSince(time) {\n if (!config.trustBundle)\n return false;\n try {\n return statSync(config.trustBundle).mtimeMs > time;\n } catch {\n return false;\n }\n }\n function requireAgent(agentName) {\n if (agentName !== config.agentName)\n throw new AgentNotFoundError(`this worker runs agent ${config.agentName}, not ${agentName}`);\n }\n function requireSession({ agentName, sessionName }) {\n requireAgent(agentName);\n const state = sessions.get(sessionName);\n if (!state)\n throw new AgentNotFoundError(`session ${sessionName} does not exist`);\n return state;\n }\n async function dropRequests(state, reason) {\n await Promise.all([state.permissionRequests.dropAll(reason), state.questionRequests.dropAll(reason)]);\n }\n function broadcast(state, message) {\n for (const listener of state.listeners)\n listener(message);\n }\n async function transcriptOf(state) {\n if (!state.nativeId)\n return null;\n return config.backends[state.spec.backend].transcript({ nativeId: state.nativeId, env: await environmentOf(state), files: config.files });\n }\n async function environmentOf(state) {\n const env = {};\n for (const [key, value] of Object.entries(process.env))\n if (value !== undefined)\n env[key] = value;\n const backend2 = config.backends[state.spec.backend];\n return { ...env, ...backend2.homeEnvironment(await config.storage.backendHome(state.spec.backend)), ...state.spec.env };\n }\n async function authEnvironment(state) {\n return { installDir: config.installDir, env: await environmentOf(state), cwd: state.spec.cwd ?? process.cwd() };\n }\n async function requireInstalled(backend2) {\n if ((await config.backends[backend2].installed(config.installDir)).ready)\n return;\n throw new AgentBackendNotInstalledError(`${backend2} isn't installed in agent ${config.agentName}'s dimension, or not completely: install it`);\n }\n async function authStatus(state) {\n const auth = await config.storage.readAuth(state.spec.name);\n if (state.login && auth?.login)\n return auth.login;\n await requireInstalled(state.spec.backend);\n if (await config.backends[state.spec.backend].auth.signedIn(await authEnvironment(state)))\n return { state: \"signedIn\" };\n return auth?.error ? { state: \"signedOut\", error: auth.error } : { state: \"signedOut\" };\n }\n function saveAuth(state, record) {\n return config.storage.saveAuth(state.spec.name, record);\n }\n function watchLogin(state, login2) {\n return login2.done.then(async () => {\n if (state.login?.process !== login2)\n return;\n state.login = null;\n await saveAuth(state, { login: null, error: null });\n if (await statusOf(state) === \"idle\")\n await closeSession(state);\n }, async (error) => {\n if (state.login?.process !== login2)\n return;\n state.login = null;\n await saveAuth(state, { login: null, error: error.message });\n });\n }\n async function settleLogin(state, settled, timeoutMs) {\n await Promise.race([settled, Bun.sleep(timeoutMs)]);\n return authStatus(state);\n }\n function contextFor(state, generation, env) {\n const current = () => state.generation === generation;\n return {\n spec: state.spec,\n nativeId: state.nativeId,\n cwd: state.spec.cwd ?? process.cwd(),\n model: state.model,\n installDir: config.installDir,\n env,\n emit(message) {\n if (!current())\n return;\n broadcast(state, message);\n },\n setNativeId(id) {\n if (!current() || state.nativeId === id)\n return;\n state.nativeId = id;\n saveRecord(state).catch((error) => console.error(`saving session ${state.spec.name} failed:`, error));\n },\n async requestPermission(request, signal2) {\n if (!current())\n return { behavior: \"deny\", message: \"the session stopped\" };\n return state.permissionRequests.add(request, signal2);\n },\n async askQuestions(request, signal2) {\n if (!current())\n return null;\n return state.questionRequests.add(request, signal2);\n },\n exited(error) {\n if (!current())\n return;\n const session2 = state.session;\n state.running = null;\n state.session = null;\n dropRequests(state, \"the agent exited\").catch((error2) => console.error(`dropping ${state.spec.name}'s requests failed:`, error2));\n if (error)\n console.error(`session ${state.spec.name} exited:`, error);\n session2?.getSessionStatus().then((last) => {\n if (last !== \"running\" && last !== \"waiting\")\n return;\n broadcast(state, {\n type: \"result\",\n subtype: \"error_during_execution\",\n duration_ms: 0,\n duration_api_ms: 0,\n is_error: true,\n num_turns: 0,\n stop_reason: null,\n total_cost_usd: 0,\n usage: resultUsage(),\n modelUsage: {},\n permission_denials: [],\n errors: [`the agent exited${error ? `: ${error.message}` : \"\"}`],\n uuid: crypto.randomUUID(),\n session_id: state.nativeId ?? \"\"\n });\n });\n }\n };\n }\n function ensureRunning(state) {\n if (state.running)\n return state.running;\n const generation = ++state.generation;\n state.startedAt = Date.now();\n const starting = requireInstalled(state.spec.backend).then(() => environmentOf(state)).then((env) => config.backends[state.spec.backend].start(contextFor(state, generation, env)));\n state.running = starting;\n starting.then((session2) => {\n if (state.generation === generation)\n state.session = session2;\n }, () => {\n if (state.generation === generation)\n state.running = null;\n });\n return starting;\n }\n async function closeSession(state) {\n const running = state.running;\n state.generation++;\n state.running = null;\n state.session = null;\n await dropRequests(state, \"the session stopped\");\n if (running)\n await (await running.catch(() => null))?.close();\n }\n async function cancelLogin(state) {\n if (!state.login)\n return;\n state.login.process.cancel();\n state.login = null;\n const auth = await config.storage.readAuth(state.spec.name);\n await saveAuth(state, { login: null, error: auth?.error ?? null });\n }\n async function listBackends(agentName) {\n requireAgent(agentName);\n return Promise.all(AGENT_BACKENDS.map(async (backend2) => ({ backend: backend2, ...await config.backends[backend2].installed(config.installDir) })));\n }\n async function install(agentName, backend2) {\n requireAgent(agentName);\n const run2 = installing.then(() => config.backends[backend2].install(config.installDir));\n installing = run2.catch(() => {});\n await run2;\n }\n async function createSession(agentName, session2) {\n requireAgent(agentName);\n const spec = validSession(session2);\n const existing = sessions.get(spec.name);\n if (existing) {\n if (!sameSpec(existing.spec, spec))\n throw new AgentConflictError(`session ${spec.name} already exists with a different spec`);\n return info(existing);\n }\n const record = await config.storage.insertSession({ spec, nativeId: null, model: null });\n const state = await newState(record);\n sessions.set(spec.name, state);\n return info(state);\n }\n async function listSessions() {\n return Promise.all([...sessions.values()].map(info));\n }\n async function updateSession(ref, limits2) {\n const state = requireSession(ref);\n const { memoryLimit: memoryLimit2, cpuLimit: cpuLimit2 } = limits2;\n state.spec = { ...state.spec, memoryLimit: memoryLimit2 ?? state.spec.memoryLimit, cpuLimit: cpuLimit2 ?? state.spec.cpuLimit };\n await saveRecord(state);\n return info(state);\n }\n async function stopSession(ref) {\n requireAgent(ref.agentName);\n const state = sessions.get(ref.sessionName);\n if (!state)\n return;\n sessions.delete(ref.sessionName);\n await closeSession(state);\n state.login?.process.cancel();\n state.login = null;\n state.listeners.clear();\n await config.storage.removeSession(state.spec.name);\n }\n async function sendMessage(ref, sent) {\n const state = requireSession(ref);\n if (await statusOf(state) === \"idle\" && trustChangedSince(state.startedAt))\n await closeSession(state);\n const uuid = sent.uuid ?? crypto.randomUUID();\n const message = { ...sent, uuid, session_id: state.nativeId ?? \"\" };\n await (await ensureRunning(state)).sendMessage(message);\n broadcast(state, { ...message, uuid, session_id: message.session_id });\n }\n async function cancel(ref) {\n const state = requireSession(ref);\n await dropRequests(state, \"the turn was interrupted\");\n if (state.running)\n await (await state.running).cancel();\n }\n async function getSessionStatus(ref) {\n return statusOf(requireSession(ref));\n }\n async function getLastUserMessages(ref) {\n const state = requireSession(ref);\n if (state.session)\n return state.session.getLastUserMessages();\n const stored = await lastStoredPrompt(state);\n return stored ? [stored] : [];\n }\n async function subscribe(ref, afterId, emit) {\n const state = requireSession(ref);\n let held = [];\n const listener = (message) => held ? held.push(message) : emit(message);\n state.listeners.add(listener);\n const unsubscribe = () => void state.listeners.delete(listener);\n try {\n const replayed = new Set;\n const transcript = await transcriptOf(state);\n const found = transcript ? await transcript.replay(afterId, (message) => {\n replayed.add(message.uuid);\n emit(message);\n }) : afterId === undefined;\n if (!found) {\n throw new AgentInvalidError(`no message ${afterId} in session ${ref.sessionName}: after_id is the uuid of a user or assistant message (partial output and results aren't stored)`);\n }\n for (const message of held)\n if (!replayed.has(message.uuid))\n emit(message);\n held = null;\n } catch (error) {\n unsubscribe();\n throw error;\n }\n return unsubscribe;\n }\n async function getTranscript(ref, request = {}) {\n return transcriptPage(await transcriptOf(requireSession(ref)), request);\n }\n async function listPermissionRequests(ref) {\n return requireSession(ref).permissionRequests.list();\n }\n async function respondPermissionRequest(ref, requestId, result) {\n const state = requireSession(ref);\n if (!await state.permissionRequests.answer(requestId, result))\n throw new AgentNotFoundError(`no pending permission request ${requestId}`);\n }\n async function listQuestionRequests(ref) {\n return requireSession(ref).questionRequests.list();\n }\n async function respondQuestionRequest(ref, requestId, response) {\n const state = requireSession(ref);\n if (!await state.questionRequests.answer(requestId, response)) {\n throw new AgentNotFoundError(`no pending question request ${requestId}`);\n }\n }\n async function listModels(ref) {\n return (await ensureRunning(requireSession(ref))).listModels();\n }\n async function setModel(ref, model) {\n const state = requireSession(ref);\n state.model = model;\n await saveRecord(state);\n if (state.running)\n await (await state.running).setModel(model);\n }\n async function listBackgroundTasks(ref) {\n const state = requireSession(ref);\n return state.running ? (await state.running).listBackgroundTasks() : [];\n }\n async function stopTask(ref, taskId) {\n const state = requireSession(ref);\n if (!state.running)\n throw new AgentNotFoundError(`no background task ${taskId}: session ${ref.sessionName}'s CLI isn't running`);\n await (await state.running).stopTask(taskId);\n }\n async function login(ref, gatewaySignedIn) {\n const state = requireSession(ref);\n if (state.login)\n return authStatus(state);\n await requireInstalled(state.spec.backend);\n if (await config.backends[state.spec.backend].auth.signedIn(await authEnvironment(state)))\n return { state: \"signedIn\" };\n const login2 = config.backends[state.spec.backend].auth.login(await authEnvironment(state), gatewaySignedIn);\n const entry = { process: login2, settled: Promise.resolve() };\n state.login = entry;\n await saveAuth(state, { login: null, error: null });\n entry.settled = watchLogin(state, login2);\n try {\n const prompt = await Promise.race([\n login2.prompt,\n Bun.sleep(LOGIN_PROMPT_TIMEOUT_MS).then(() => Promise.reject(new Error(\"the login didn't show where to sign in\")))\n ]);\n if (state.login === entry)\n await saveAuth(state, { login: { state: \"pending\", ...prompt }, error: null });\n } catch (error) {\n if (state.login === entry)\n await cancelLogin(state);\n await saveAuth(state, { login: null, error: error.message });\n return authStatus(state);\n }\n return settleLogin(state, entry.settled, gatewaySignedIn ? LOGIN_COMPLETION_TIMEOUT_MS : 0);\n }\n async function submitAuthCode(ref, code) {\n const state = requireSession(ref);\n const login2 = state.login;\n const prompt = (await config.storage.readAuth(ref.sessionName))?.login;\n if (!login2 || !prompt)\n throw new AgentInvalidError(`session ${ref.sessionName} has no sign-in waiting`);\n if (!prompt.needsCode)\n throw new AgentInvalidError(`session ${ref.sessionName}'s sign-in takes no code: finish it at ${prompt.url}`);\n login2.process.submitCode(code);\n return settleLogin(state, login2.settled, LOGIN_COMPLETION_TIMEOUT_MS);\n }\n async function close() {\n await Promise.all([...sessions.values()].map(closeSession));\n }\n return {\n load: loadSessions,\n close,\n install,\n listBackends,\n createSession,\n listSessions,\n updateSession,\n stopSession,\n sendMessage,\n cancel,\n getSessionStatus,\n getLastUserMessages,\n subscribe,\n getTranscript,\n listPermissionRequests,\n respondPermissionRequest,\n listQuestionRequests,\n respondQuestionRequest,\n listModels,\n setModel,\n listBackgroundTasks,\n stopTask,\n getAuthStatus: async (ref) => authStatus(requireSession(ref)),\n login,\n submitAuthCode\n };\n}\nvar LAST_PROMPT_PAGE_SIZE = 50;\nfunction isPrompt(content) {\n if (typeof content === \"string\")\n return true;\n return Array.isArray(content) && content.some((block) => block.type === \"text\");\n}\nvar LOGIN_PROMPT_TIMEOUT_MS = 30000;\nvar LOGIN_COMPLETION_TIMEOUT_MS = 60000;\nfunction validSession(spec) {\n try {\n checkName(spec.name);\n } catch (error) {\n if (error instanceof InvalidNameError)\n throw new AgentInvalidError(`invalid session name: ${error.message}`);\n throw error;\n }\n return { ...spec, cwd: spec.cwd ?? WORKSPACE_PATH };\n}\nfunction sameSpec(a, b) {\n return a.backend === b.backend && a.memoryLimit === b.memoryLimit && a.cpuLimit === b.cpuLimit && a.cwd === b.cwd && JSON.stringify(a.env ?? {}) === JSON.stringify(b.env ?? {});\n}\n\n// agent/session/main.ts\nfunction required(name2) {\n const value = process.env[name2];\n if (!value)\n throw new Error(`${name2} is not set`);\n return value;\n}\nvar agentName = required(\"HYB_AGENT\");\nvar build = required(\"HYB_WORKER_BUILD\");\nvar files = createLocalSandbox(\"/\");\nvar storage = createSessionStorage(files, agentName);\nvar service = createWorkerService({\n agentName,\n storage,\n installDir: required(\"HYB_INSTALL_DIR\"),\n files: sandboxFiles(files),\n trustBundle: process.env.NODE_EXTRA_CA_CERTS,\n backends: SESSION_BACKENDS\n});\nvar socketPath = await storage.socketPath();\nvar server = createWorkerServer(service, { socketPath, health: { agentName, build }, onShutdown: shutdown });\nfunction shutdown() {\n server.stop();\n service.close().catch((error) => console.error(\"stopping the sessions failed:\", error)).finally(() => process.exit(0));\n}\nfor (const signal2 of [\"SIGTERM\", \"SIGINT\"])\n process.once(signal2, shutdown);\nawait service.load();\nawait server.start();\nvar socketOwner = process.env.HYB_SOCKET_OWNER;\nif (socketOwner) {\n const [uid, gid] = socketOwner.split(\":\").map(Number);\n await chown(socketPath, uid, gid);\n}\nconsole.log(`session worker for agent ${agentName} (build ${build}) listening on ${socketPath}`);\n";
2
+ export const WORKER_SOURCE = "// @bun\n// agent/session/main.ts\nimport { chown, rm as rm3, writeFile as writeFile3 } from \"fs/promises\";\nimport { dirname as dirname2 } from \"path\";\n\n// sandbox/providers/local/localService.ts\nimport { spawn } from \"child_process\";\nimport { randomUUID } from \"crypto\";\nimport * as fs from \"fs/promises\";\nimport { connect as netConnect, Socket } from \"net\";\nimport { homedir, userInfo } from \"os\";\nimport { basename, dirname, join, resolve } from \"path\";\n\n// sandbox/api.ts\nclass SandboxNotFoundError extends Error {\n name = \"SandboxNotFoundError\";\n}\nclass SandboxConnectionRefusedError extends Error {\n name = \"SandboxConnectionRefusedError\";\n}\n\n// sandbox/storage/descriptors.ts\nfunction makeDescriptor(ctx, id, spec) {\n return {\n id,\n kind: ctx.kind,\n name: spec.name,\n ...ctx.sshHost === undefined ? {} : { sshHost: ctx.sshHost },\n ...ctx.sshUser === undefined ? {} : { sshUser: ctx.sshUser },\n ...ctx.sshPort === undefined ? {} : { sshPort: ctx.sshPort },\n ...spec.dataEndpointOptions === undefined ? {} : { dataEndpointOptions: spec.dataEndpointOptions }\n };\n}\nasync function createDescriptor(ctx, storage, id, spec) {\n const descriptor = makeDescriptor(ctx, id, spec);\n await storage.saveDescriptor(descriptor);\n return [{ ...ctx, id }, descriptor];\n}\nasync function openDescriptor(ctx, storage, id) {\n return await storage.readDescriptor() ?? storage.insertDescriptor(makeDescriptor(ctx, id, { name: id }));\n}\nasync function getDescriptor(storage, where) {\n const descriptor = await storage.readDescriptor();\n if (!descriptor)\n throw new Error(`${where} has no descriptor: opening it saves one`);\n return descriptor;\n}\n\n// sandbox/data-endpoints/dataEndpoints.ts\nimport { randomBytes } from \"crypto\";\n\n// ../node_modules/.bun/jose@6.2.13/node_modules/jose/dist/webapi/lib/buffer_utils.js\nvar encoder = new TextEncoder;\nvar decoder = new TextDecoder;\nvar strictDecoder = new TextDecoder(\"utf-8\", { fatal: true });\nvar UINT32_RANGE = 2 ** 32;\nfunction concat(...buffers) {\n const size = buffers.reduce((acc, { length }) => acc + length, 0), buf = new Uint8Array(size);\n let i = 0;\n for (const buffer of buffers)\n buf.set(buffer, i), i += buffer.length;\n return buf;\n}\nvar NON_ASCII = /[^\\x00-\\x7f]/;\nfunction encode(string) {\n if (typeof string == \"string\" && string.length >= 128) {\n if (NON_ASCII.test(string))\n throw new TypeError(\"non-ASCII string encountered in encode()\");\n return encoder.encode(string);\n }\n const bytes = new Uint8Array(string.length);\n for (let i = 0;i < string.length; i++) {\n const code = string.charCodeAt(i);\n if (code > 127)\n throw new TypeError(\"non-ASCII string encountered in encode()\");\n bytes[i] = code;\n }\n return bytes;\n}\nfunction encodeBase64(input, url = false) {\n if (Uint8Array.prototype.toBase64)\n return input.toBase64({ alphabet: url ? \"base64url\" : \"base64\", omitPadding: url });\n const CHUNK_SIZE = 32768, arr = [];\n for (let i = 0;i < input.length; i += CHUNK_SIZE)\n arr.push(String.fromCharCode.apply(null, input.subarray(i, i + CHUNK_SIZE)));\n const encoded = btoa(arr.join(\"\"));\n return url ? encoded.replace(/=/g, \"\").replace(/\\+/g, \"-\").replace(/\\//g, \"_\") : encoded;\n}\nfunction decodeBase64(encoded, url = false) {\n if (Uint8Array.fromBase64)\n return Uint8Array.fromBase64(encoded, { alphabet: url ? \"base64url\" : \"base64\" });\n if (url) {\n if (encoded.includes(\"+\") || encoded.includes(\"/\"))\n throw new TypeError(\"Invalid base64url\");\n encoded = encoded.replace(/-/g, \"+\").replace(/_/g, \"/\");\n }\n const binary = atob(encoded), bytes = new Uint8Array(binary.length);\n for (let i = 0;i < binary.length; i++)\n bytes[i] = binary.charCodeAt(i);\n return bytes;\n}\n\n// ../node_modules/.bun/jose@6.2.13/node_modules/jose/dist/webapi/util/errors.js\nclass JOSEError extends Error {\n static code = \"ERR_JOSE_GENERIC\";\n code = \"ERR_JOSE_GENERIC\";\n constructor(message, options) {\n super(message, options), this.name = this.constructor.name, Error.captureStackTrace?.(this, this.constructor);\n }\n}\nclass JOSENotSupported extends JOSEError {\n static code = \"ERR_JOSE_NOT_SUPPORTED\";\n code = \"ERR_JOSE_NOT_SUPPORTED\";\n}\nclass JWSInvalid extends JOSEError {\n static code = \"ERR_JWS_INVALID\";\n code = \"ERR_JWS_INVALID\";\n}\n\nclass JWTInvalid extends JOSEError {\n static code = \"ERR_JWT_INVALID\";\n code = \"ERR_JWT_INVALID\";\n}\n\n// ../node_modules/.bun/jose@6.2.13/node_modules/jose/dist/webapi/util/base64url.js\nvar invalid = \"The input to be decoded is not correctly encoded.\";\nfunction decode(input) {\n try {\n return decodeBase64(typeof input == \"string\" ? input : decoder.decode(input), true);\n } catch (cause) {\n throw new TypeError(invalid, { cause });\n }\n}\nfunction encode2(input) {\n return encodeBase64(typeof input == \"string\" ? encoder.encode(input) : input, true);\n}\n\n// ../node_modules/.bun/jose@6.2.13/node_modules/jose/dist/webapi/lib/validate.js\nfunction isObject(input) {\n if (typeof input != \"object\" || input === null || Object.prototype.toString.call(input) !== \"[object Object]\")\n return false;\n const prototype = Object.getPrototypeOf(input);\n return prototype === null || Object.getPrototypeOf(prototype) === null;\n}\nfunction isDisjoint(...headers) {\n const parameters = /* @__PURE__ */ new Set;\n for (const header of headers)\n if (header)\n for (const parameter of Object.keys(header)) {\n if (parameters.has(parameter))\n return false;\n parameters.add(parameter);\n }\n return true;\n}\nfunction assertNotSet(value, name) {\n if (value !== undefined)\n throw new TypeError(`${name} can only be called once`);\n}\nvar JWS_RECOGNIZED = { __proto__: null, b64: true };\nfunction validateCritDuplicates(Err, protectedHeader) {\n const { crit } = protectedHeader ?? {};\n if (Array.isArray(crit) && new Set(crit).size !== crit.length)\n throw new Err('\"crit\" (Critical) Header Parameter MUST NOT contain duplicate values');\n}\nfunction validateCrit(Err, recognizedDefault, recognizedOption, protectedHeader, joseHeader) {\n if (joseHeader.crit !== undefined && protectedHeader?.crit === undefined)\n throw new Err('\"crit\" (Critical) Header Parameter MUST be integrity protected');\n if (!protectedHeader || protectedHeader.crit === undefined)\n return [];\n if (!Array.isArray(protectedHeader.crit) || protectedHeader.crit.length === 0 || protectedHeader.crit.some((input) => typeof input != \"string\" || input.length === 0))\n throw new Err('\"crit\" (Critical) Header Parameter MUST be an array of non-empty strings when present');\n const recognized = recognizedOption === undefined ? recognizedDefault : { __proto__: null, ...recognizedOption, ...recognizedDefault };\n for (const parameter of protectedHeader.crit) {\n if (!(parameter in recognized))\n throw new JOSENotSupported(`Extension Header Parameter \"${parameter}\" is not recognized`);\n if (!Object.hasOwn(joseHeader, parameter) || joseHeader[parameter] === undefined)\n throw new Err(`Extension Header Parameter \"${parameter}\" is missing`);\n if (recognized[parameter] && (!Object.hasOwn(protectedHeader, parameter) || protectedHeader[parameter] === undefined))\n throw new Err(`Extension Header Parameter \"${parameter}\" MUST be integrity protected`);\n }\n return protectedHeader.crit;\n}\nfunction validateB64(protectedHeader, extensions) {\n if (extensions.includes(\"b64\")) {\n const b64 = protectedHeader.b64;\n if (typeof b64 != \"boolean\")\n throw new JWSInvalid('The \"b64\" (base64url-encode payload) Header Parameter must be a boolean');\n return b64;\n }\n return true;\n}\nfunction serializeJoseHeader(Err, header) {\n let serialized, parsed;\n try {\n serialized = JSON.stringify(header), parsed = JSON.parse(serialized);\n } catch (cause) {\n throw new Err(\"JOSE Header is not valid JSON\", { cause });\n }\n if (!isObject(parsed))\n throw new Err(\"JOSE Header is not a JSON object\");\n return [parsed, serialized];\n}\n\n// ../node_modules/.bun/jose@6.2.13/node_modules/jose/dist/webapi/lib/key.js\nvar tag = (key) => key[Symbol.toStringTag];\nvar jwkMatchesOp = (entry, key, usage) => {\n const { alg } = entry;\n if (key.use !== undefined) {\n const expected = usage === \"sign\" || usage === \"verify\" ? \"sig\" : \"enc\";\n if (key.use !== expected)\n throw new TypeError(`Invalid key for this operation, its \"use\" must be \"${expected}\" when present`);\n }\n if (key.alg !== undefined && key.alg !== alg)\n throw new TypeError(`Invalid key for this operation, its \"alg\" must be \"${alg}\" when present`);\n if (Array.isArray(key.key_ops)) {\n const expectedKeyOp = usage === \"encrypt\" || usage === \"decrypt\" ? entry.ops?.[usage === \"encrypt\" ? 0 : 1] : usage;\n if (expectedKeyOp && !key.key_ops.includes(expectedKeyOp))\n throw new TypeError(`Invalid key for this operation, its \"key_ops\" must include \"${expectedKeyOp}\" when present`);\n }\n};\nasync function prepareKey(entry, key, usage) {\n const { alg, secret } = entry, requiresPrivateKey = usage === \"decrypt\" || usage === \"sign\";\n if (secret && key instanceof Uint8Array)\n return key;\n let normalized, keyObject;\n if (isObject(key)) {\n if (normalized = normalizeJwk(key), typeof normalized.kty != \"string\")\n throw invalidKeyType(alg, key, secret);\n if (!(secret ? normalized.kty === \"oct\" && typeof normalized.k == \"string\" : normalized.kty !== \"oct\" && (requiresPrivateKey ? normalized.kty === \"AKP\" && typeof normalized.priv == \"string\" || typeof normalized.d == \"string\" : normalized.d === undefined && normalized.priv === undefined)))\n throw new TypeError(secret ? 'JSON Web Key for symmetric algorithms must have JWK \"kty\" (Key Type) equal to \"oct\" and the JWK \"k\" (Key Value) present' : `JSON Web Key for this operation must be a ${requiresPrivateKey ? \"private\" : \"public\"} JWK`);\n if (jwkMatchesOp(entry, normalized, usage), normalized.kty === \"oct\")\n return decode(normalized.k);\n if (!Object.isFrozen(key)) {\n const { key_ops } = key;\n Array.isArray(key_ops) && Object.freeze(key_ops), Object.freeze(key);\n }\n } else {\n if (!isKeyLike(key))\n throw invalidKeyType(alg, key, secret);\n const expectedType = secret ? \"secret\" : requiresPrivateKey ? \"private\" : \"public\";\n if (key.type !== expectedType && (secret || [\"secret\", \"public\", \"private\"].includes(key.type)))\n throw new TypeError(`${tag(key)} instances must be of type \"${expectedType}\" for the ${alg} algorithm`);\n if (isCryptoKey(key))\n return key;\n if (keyObject = key, keyObject.type === \"secret\")\n return keyObject.export();\n }\n cache ||= /* @__PURE__ */ new WeakMap;\n const cacheKey = key;\n let cached = cache.get(cacheKey);\n if (cached?.[alg])\n return cached[alg];\n if (cached || cache.set(cacheKey, cached = {}), keyObject && typeof keyObject.toCryptoKey == \"function\") {\n const isPublic = keyObject.type === \"public\", crv = nist[keyObject.asymmetricKeyDetails?.namedCurve], params = entry.resolve?.({ crv, asymmetricKeyType: keyObject.asymmetricKeyType }) ?? entry.subtle;\n return cached[alg] = keyObject.toCryptoKey(params, isPublic, entry.usages[isPublic ? 0 : 1]);\n }\n return normalized ??= keyObject.export({ format: \"jwk\" }), normalized.alg = alg, cached[alg] = await jwkToKey(entry, normalized);\n}\nvar cache;\nvar nist = {\n __proto__: null,\n prime256v1: \"P-256\",\n secp384r1: \"P-384\",\n secp521r1: \"P-521\"\n};\nvar isCryptoKey = (key) => {\n if (key?.[Symbol.toStringTag] === \"CryptoKey\")\n return true;\n try {\n return key instanceof CryptoKey;\n } catch {\n return false;\n }\n};\nvar isKeyObject = (key) => key?.[Symbol.toStringTag] === \"KeyObject\";\nvar isKeyLike = (key) => isCryptoKey(key) || isKeyObject(key);\nfunction message(msg, actual, ...types) {\n if (types.length > 2) {\n const last = types.pop();\n msg += `one of type ${types.join(\", \")}, or ${last}.`;\n } else\n types.length === 2 ? msg += `one of type ${types[0]} or ${types[1]}.` : msg += `of type ${types[0]}.`;\n return actual == null ? msg += ` Received ${actual}` : typeof actual == \"function\" && actual.name ? msg += ` Received function ${actual.name}` : typeof actual == \"object\" && actual != null && actual.constructor?.name && (msg += ` Received an instance of ${actual.constructor.name}`), msg;\n}\nfunction invalidKeyType(alg, actual, secret) {\n const types = [\"CryptoKey\", \"KeyObject\", \"JSON Web Key\"];\n return secret && types.push(\"Uint8Array\"), new TypeError(message(`Key for the ${alg} algorithm must be `, actual, ...types));\n}\nvar unusable = (name, prop = \"algorithm.name\") => new TypeError(`CryptoKey does not support this operation, its ${prop} must be ${name}`);\nfunction checkUsage(key, usage) {\n if (usage && !key.usages.includes(usage))\n throw new TypeError(`CryptoKey does not support this operation, its usages must include ${usage}.`);\n}\nfunction checkModulusLength(alg, key) {\n const { modulusLength } = key.algorithm;\n if (typeof modulusLength != \"number\" || modulusLength < 2048)\n throw new TypeError(`${alg} requires key modulusLength to be 2048 bits or larger`);\n}\nfunction checkCryptoKey(key, expected, usage) {\n const algorithm = key.algorithm;\n if (algorithm.name !== expected.name)\n throw unusable(expected.name);\n if (expected.hash && algorithm.hash?.name !== expected.hash)\n throw unusable(expected.hash, \"algorithm.hash\");\n if (expected.namedCurve && algorithm.namedCurve !== expected.namedCurve)\n throw unusable(expected.namedCurve, \"algorithm.namedCurve\");\n if (expected.length !== undefined && algorithm.length !== expected.length)\n throw unusable(expected.length, \"algorithm.length\");\n checkUsage(key, usage);\n}\nfunction snapshotJwk(jwk) {\n return { __proto__: null, ...jwk };\n}\nfunction normalizeJwk(jwk) {\n const normalized = snapshotJwk(jwk);\n if (normalized.ext !== undefined && typeof normalized.ext != \"boolean\")\n throw new TypeError('\"ext\" (Extractable) Parameter must be a boolean');\n if (normalized.key_ops !== undefined) {\n const value = normalized.key_ops, keyOps = Array.isArray(value) ? [...value] : undefined;\n if (!keyOps || keyOps.some((operation) => typeof operation != \"string\") || new Set(keyOps).size !== keyOps.length)\n throw new TypeError('\"key_ops\" (Key Operations) Parameter must be an array of unique strings');\n normalized.key_ops = keyOps;\n }\n return normalized;\n}\nasync function jwkToKey(entry, jwk, extractable) {\n if (!entry.kty.includes(jwk.kty))\n throw new JOSENotSupported('Invalid or unsupported JWK \"alg\" (Algorithm) Parameter value');\n const algorithm = entry.resolve?.({ kty: jwk.kty, crv: jwk.crv }) ?? entry.subtle, isPrivate = !!(jwk.d || jwk.priv), keyData = { ...jwk, ext: extractable ?? jwk.ext };\n return keyData.kty !== \"AKP\" && delete keyData.alg, delete keyData.use, crypto.subtle.importKey(\"jwk\", keyData, algorithm, keyData.ext ?? !isPrivate, jwk.key_ops ?? entry.usages[isPrivate ? 1 : 0]);\n}\nasync function rawKey(key, expected, usage, extractable = false) {\n return key instanceof Uint8Array && (key = await crypto.subtle.importKey(\"raw\", key, expected, extractable, [usage])), checkCryptoKey(key, expected, usage), key;\n}\n\n// ../node_modules/.bun/jose@6.2.13/node_modules/jose/dist/webapi/lib/key_descriptor.js\nfunction table(entries) {\n const out = { __proto__: null };\n for (const alg in entries)\n out[alg] = { ...entries[alg], alg };\n return out;\n}\n\n// ../node_modules/.bun/jose@6.2.13/node_modules/jose/dist/webapi/lib/jws_algorithms.js\nvar sig = [[\"verify\"], [\"sign\"]];\nfunction hmac(bits) {\n const subtle = { name: \"HMAC\", hash: `SHA-${bits}` };\n return { kty: [\"oct\"], secret: true, subtle, signing: subtle, usages: sig };\n}\nfunction rsa(bits, saltLength) {\n const subtle = { name: saltLength ? \"RSA-PSS\" : \"RSASSA-PKCS1-v1_5\", hash: `SHA-${bits}` };\n return {\n kty: [\"RSA\"],\n subtle,\n signing: saltLength ? { ...subtle, saltLength } : subtle,\n usages: sig,\n minRsaBits: 2048\n };\n}\nfunction ecdsa(crv, bits) {\n return {\n kty: [\"EC\"],\n crv,\n subtle: { name: \"ECDSA\", namedCurve: crv },\n signing: { name: \"ECDSA\", hash: `SHA-${bits}` },\n usages: sig\n };\n}\nfunction eddsa() {\n const subtle = { name: \"Ed25519\" };\n return {\n kty: [\"OKP\"],\n crv: \"Ed25519\",\n subtle,\n signing: subtle,\n usages: sig\n };\n}\nfunction mldsa(parameterSet) {\n const subtle = { name: `ML-DSA-${parameterSet}` };\n return {\n kty: [\"AKP\"],\n subtle,\n signing: subtle,\n usages: sig\n };\n}\nvar JWS = table({\n HS256: hmac(256),\n HS384: hmac(384),\n HS512: hmac(512),\n RS256: rsa(256),\n RS384: rsa(384),\n RS512: rsa(512),\n PS256: rsa(256, 32),\n PS384: rsa(384, 48),\n PS512: rsa(512, 64),\n ES256: ecdsa(\"P-256\", 256),\n ES384: ecdsa(\"P-384\", 384),\n ES512: ecdsa(\"P-521\", 512),\n EdDSA: eddsa(),\n Ed25519: eddsa(),\n \"ML-DSA-44\": mldsa(44),\n \"ML-DSA-65\": mldsa(65),\n \"ML-DSA-87\": mldsa(87)\n});\nfunction jwsAlgorithm(alg) {\n const entry = typeof alg == \"string\" ? JWS[alg] : undefined;\n if (!entry)\n throw new JOSENotSupported(`alg ${alg} is not supported either by JOSE or your javascript runtime`);\n return entry;\n}\n\n// ../node_modules/.bun/jose@6.2.13/node_modules/jose/dist/webapi/lib/jwt_claims_set.js\nvar epoch = (date) => Math.floor(date.getTime() / 1000);\nvar multipliers = {\n s: 1,\n m: 60,\n h: 3600,\n d: 86400,\n w: 604800,\n y: 31557600\n};\nvar REGEX = /^(\\+|\\-)? ?(\\d+|\\d+\\.\\d+) ?(seconds?|secs?|s|minutes?|mins?|m|hours?|hrs?|h|days?|d|weeks?|w|years?|yrs?|y)(?: (ago|from now))?$/i;\nfunction invalidDuration() {\n throw new TypeError(\"Invalid time period format\");\n}\nfunction secs(str) {\n typeof str != \"string\" && invalidDuration();\n const matched = REGEX.exec(str);\n (!matched || matched[4] && matched[1]) && invalidDuration();\n const value = parseFloat(matched[2]), durationSeconds = Math.round(value * multipliers[matched[3][0].toLowerCase()]);\n return Number.isFinite(durationSeconds) || invalidDuration(), matched[1] === \"-\" || matched[4] === \"ago\" ? -durationSeconds : durationSeconds;\n}\nfunction validateInput(label, input) {\n if (!Number.isFinite(input))\n throw new TypeError(`Invalid ${label} input`);\n return input;\n}\nfunction validateStringClaim(claim, value) {\n if (typeof value != \"string\")\n throw new TypeError(`\"${claim}\" claim must be a string`);\n}\nfunction validateAudienceClaim(value) {\n if (typeof value != \"string\" && (!Array.isArray(value) || Array.from(value).some((member) => typeof member != \"string\")))\n throw new TypeError('\"aud\" claim must be a string or an array of strings');\n}\nfunction numericDate(value, label) {\n return typeof value == \"number\" ? validateInput(label, value) : value instanceof Date ? validateInput(label, epoch(value)) : epoch(/* @__PURE__ */ new Date) + secs(value);\n}\nvar producerClaimsSets;\nfunction producerClaimsSet(producer) {\n return producerClaimsSets.get(producer);\n}\nfunction jwtClaimsSetBytes(producer) {\n const claimsSet = producerClaimsSet(producer);\n for (const claim of [\"iat\", \"nbf\", \"exp\"]) {\n const value = claimsSet[claim];\n if (typeof value == \"number\" && !Number.isFinite(value))\n throw new TypeError(`\"${claim}\" claim must be a finite number`);\n }\n return encoder.encode(JSON.stringify(claimsSet));\n}\nclass JWTClaimsBuilder {\n constructor(claimsSet = {}) {\n if (!isObject(claimsSet))\n throw new TypeError(\"JWT Claims Set MUST be an object\");\n (producerClaimsSets ||= /* @__PURE__ */ new WeakMap).set(this, structuredClone(claimsSet));\n }\n setIssuer(value) {\n return validateStringClaim(\"iss\", value), producerClaimsSet(this).iss = value, this;\n }\n setSubject(value) {\n return validateStringClaim(\"sub\", value), producerClaimsSet(this).sub = value, this;\n }\n setAudience(value) {\n return validateAudienceClaim(value), producerClaimsSet(this).aud = value, this;\n }\n setJti(value) {\n return validateStringClaim(\"jti\", value), producerClaimsSet(this).jti = value, this;\n }\n setNotBefore(value) {\n return producerClaimsSet(this).nbf = numericDate(value, \"setNotBefore\"), this;\n }\n setExpirationTime(value) {\n return producerClaimsSet(this).exp = numericDate(value, \"setExpirationTime\"), this;\n }\n setIssuedAt(value) {\n const claimsSet = producerClaimsSet(this);\n return value === undefined ? claimsSet.iat = epoch(/* @__PURE__ */ new Date) : typeof value == \"string\" ? claimsSet.iat = validateInput(\"setIssuedAt\", epoch(/* @__PURE__ */ new Date) + secs(value)) : claimsSet.iat = numericDate(value, \"setIssuedAt\"), this;\n }\n}\n\n// ../node_modules/.bun/jose@6.2.13/node_modules/jose/dist/webapi/lib/jws_sign.js\nasync function createSignature(input, key, rejectUnencoded) {\n let [payload, protectedHeader, unprotectedHeader, crit] = input, encodedProtectedHeader = \"\";\n if (protectedHeader !== undefined) {\n const normalized = serializeJoseHeader(JWSInvalid, protectedHeader);\n protectedHeader = normalized[0], encodedProtectedHeader = encode2(normalized[1]);\n }\n if (unprotectedHeader !== undefined && (unprotectedHeader = serializeJoseHeader(JWSInvalid, unprotectedHeader)[0]), !protectedHeader && !unprotectedHeader)\n throw new JWSInvalid(\"either setProtectedHeader or setUnprotectedHeader must be called before #sign()\");\n if (!isDisjoint(protectedHeader, unprotectedHeader))\n throw new JWSInvalid(\"JWS Protected and JWS Unprotected Header Parameter names must be disjoint\");\n const joseHeader = { ...protectedHeader, ...unprotectedHeader };\n validateCritDuplicates(JWSInvalid, protectedHeader);\n const b64 = validateB64(protectedHeader, validateCrit(JWSInvalid, JWS_RECOGNIZED, crit, protectedHeader, joseHeader));\n b64 || rejectUnencoded?.();\n const { alg } = joseHeader;\n if (typeof alg != \"string\" || !alg)\n throw new JWSInvalid('JWS \"alg\" (Algorithm) Header Parameter missing or invalid');\n const entry = jwsAlgorithm(alg);\n let encodedPayload = \"\", signingPayload = payload, signingInput;\n if (b64) {\n const encodedPayloadCache = input[4];\n encodedPayloadCache ? (encodedPayload = encodedPayloadCache[0] ??= encode2(payload), signingPayload = encodedPayloadCache[1] ??= encode(encodedPayload)) : (encodedPayload = encode2(payload), signingInput = encoder.encode(`${encodedProtectedHeader}.${encodedPayload}`));\n }\n signingInput ??= concat(encode(encodedProtectedHeader), encode(\".\"), signingPayload);\n const signingKey = await rawKey(await prepareKey(entry, key, \"sign\"), entry.subtle, \"sign\");\n entry.minRsaBits && checkModulusLength(entry.alg, signingKey);\n const jws = {\n signature: encode2(new Uint8Array(await crypto.subtle.sign(entry.signing, signingKey, signingInput))),\n payload: encodedPayload\n };\n return protectedHeader && (jws.protected = encodedProtectedHeader), unprotectedHeader && (jws.header = unprotectedHeader), [jws, b64];\n}\nasync function createCompactSignature(payload, protectedHeader, crit, key, rejectUnencoded) {\n const [jws] = await createSignature([payload, protectedHeader, undefined, crit], key, rejectUnencoded);\n return `${jws.protected}.${jws.payload}.${jws.signature}`;\n}\n\n// ../node_modules/.bun/jose@6.2.13/node_modules/jose/dist/webapi/jwt/sign.js\nvar SignJWT_base = JWTClaimsBuilder;\n\nclass SignJWT extends SignJWT_base {\n #protectedHeader;\n setProtectedHeader(protectedHeader) {\n return assertNotSet(this.#protectedHeader, \"setProtectedHeader\"), this.#protectedHeader = protectedHeader, this;\n }\n async sign(key, options) {\n return createCompactSignature(jwtClaimsSetBytes(this), this.#protectedHeader, options?.crit, key, () => {\n throw new JWTInvalid(\"JWTs MUST NOT use unencoded payload\");\n });\n }\n}\n\n// lib/sh.ts\nfunction sh(strings, ...values) {\n if (values.length > 0)\n throw new Error(\"sh`\\u2026` takes no interpolations: pass inputs as environment variables or arguments\");\n return scriptText(strings.raw[0]);\n}\nfunction scriptText(raw) {\n return raw.replace(/\\\\(\\$\\{|`)/g, \"$1\").replace(/^\\n/, \"\");\n}\n\n// sandbox/data-endpoints/dataEndpoints.ts\nvar DEFAULT_TTL_S = 12 * 3600;\nfunction signToken(secret, ttlSeconds) {\n return new SignJWT().setProtectedHeader({ alg: \"HS256\" }).setExpirationTime(`${ttlSeconds}s`).sign(new TextEncoder().encode(secret));\n}\nasync function listeningPorts(sandbox) {\n const listed = await sandbox.runCommand([\"sh\", \"-c\", LISTENING_PORTS]);\n if (listed.exitCode !== 0)\n throw new Error(`listing the ports in use failed: ${listed.stderr.trim()}`);\n return listed.stdout.split(`\n`).filter(Boolean).map(Number);\n}\nasync function withLock(sandbox, body) {\n const lock = `${await sandbox.homeDirectory()}/.local/state/hyperbrane/endpoints.lock`;\n const taken = await sandbox.runCommand([\"sh\", \"-c\", TAKE_LOCK, \"sh\", lock]);\n if (taken.exitCode !== 0)\n throw new Error(`${lock} stayed locked: ${taken.stderr.trim()}`);\n try {\n return await body();\n } finally {\n await sandbox.runCommand([\"rm\", \"-rf\", lock]);\n }\n}\nfunction under(base, endpoint) {\n if (base === undefined || new URL(base).pathname === \"/\")\n return endpoint;\n return { ...endpoint, url: `${base.replace(/\\/+$/, \"\")}/${endpoint.name}` };\n}\nfunction createEndpoints(sandbox, storage, ports) {\n const located = async (endpoints) => {\n const base = (await storage.readDescriptor())?.dataEndpointOptions?.url;\n return endpoints.map((endpoint) => under(base, endpoint));\n };\n async function openEndpoint(name) {\n const [endpoint] = await located([await openStored(name)]);\n return endpoint;\n }\n async function openStored(name) {\n return withLock(sandbox, async () => {\n const existing = await storage.readEndpoint(name);\n if (existing)\n return existing;\n const { from, to } = await ports.ports();\n const used = new Set([...(await storage.listEndpoints()).map((endpoint) => endpoint.port), ...await listeningPorts(sandbox)]);\n let port = from;\n while (port <= to && used.has(port))\n port++;\n if (port > to)\n throw new Error(`no data endpoint ports are left in ${from}-${to}`);\n const endpoint = { name, url: await ports.expose(port), port, secret: randomBytes(32).toString(\"base64url\") };\n await storage.saveEndpoint(endpoint);\n return endpoint;\n });\n }\n async function closeEndpoint(name) {\n await withLock(sandbox, async () => {\n const endpoint = await storage.readEndpoint(name);\n if (!endpoint)\n return;\n await ports.conceal(endpoint.port);\n await storage.removeEndpoint(name);\n });\n }\n async function credentials(name, {\n ttlSeconds = DEFAULT_TTL_S\n } = {}) {\n const endpoint = await storage.readEndpoint(name);\n if (!endpoint)\n throw new SandboxNotFoundError(`there is no data endpoint ${name}`);\n return { token: await signToken(endpoint.secret, ttlSeconds), ...await ports.credentials?.(endpoint, ttlSeconds) };\n }\n return {\n openEndpoint,\n closeEndpoint,\n listEndpoints: async () => located(await storage.listEndpoints()),\n credentials\n };\n}\nvar LISTENING_PORTS = sh`\nawk 'FNR > 1 && $4 == \"0A\" { n = split($2, local, \":\"); print local[n] }' /proc/net/tcp /proc/net/tcp6 2> /dev/null | while read -r hex; do\n printf '%d\\n' \"0x$hex\"\ndone\n`;\nvar TAKE_LOCK = sh`\nmkdir -p \"$(dirname \"$1\")\"\nwaited=0\nuntil mkdir \"$1\" 2> /dev/null; do\n if [ -n \"$(find \"$1\" -maxdepth 0 -mmin +2 2> /dev/null)\" ]; then\n rm -rf \"$1\"\n continue\n fi\n [ \"$waited\" -lt 1200 ] || exit 1\n sleep 0.1\n waited=$((waited + 1))\ndone\n`;\n\n// sandbox/data-endpoints/firewalledPorts.ts\nfunction firewalledPorts(sandbox, storage) {\n const options = async () => (await storage.readDescriptor())?.dataEndpointOptions;\n async function firewall(rule) {\n const result = await sandbox.runCommand([\"sudo\", \"-n\", \"ufw\", ...rule]);\n if (result.exitCode !== 0)\n throw new Error(`ufw ${rule.join(\" \")} failed: ${result.stderr.trim()}`);\n }\n return {\n async ports() {\n const ports = (await options())?.ports;\n if (!ports)\n throw new Error(\"this machine has no data endpoints: it's created with dataEndpointOptions.ports\");\n return ports;\n },\n async expose(port) {\n const found = await options();\n if (found?.needsFirewall)\n await firewall([\"allow\", `${port}/tcp`]);\n const url = new URL(found?.url ?? \"http://127.0.0.1\");\n url.port = String(port);\n return url.toString().replace(/\\/$/, \"\");\n },\n async conceal(port) {\n if ((await options())?.needsFirewall)\n await firewall([\"delete\", \"allow\", `${port}/tcp`]);\n }\n };\n}\n\n// sandbox/lib/httpOverStream.ts\nimport { request as httpRequest } from \"http\";\nimport { Readable } from \"stream\";\nfunction httpOver(url, connection, { method = \"GET\", headers = {}, body, signal, timeout }) {\n return new Promise((resolve, reject) => {\n const target = new URL(url);\n const request = httpRequest({ createConnection: connection, path: `${target.pathname}${target.search}`, method, headers: { host: target.host, ...headers }, signal }, (response) => {\n const responseHeaders = new Headers;\n for (let i = 0;i + 1 < response.rawHeaders.length; i += 2)\n responseHeaders.append(response.rawHeaders[i], response.rawHeaders[i + 1]);\n const status = response.statusCode ?? 502;\n const nullBody = status === 204 || status === 304 || method === \"HEAD\";\n if (nullBody)\n response.resume();\n resolve(new Response(nullBody ? null : Readable.toWeb(response), { status, headers: responseHeaders }));\n });\n request.once(\"error\", reject);\n if (typeof timeout === \"number\")\n request.setTimeout(timeout, () => request.destroy(new Error(`fetch ${url}: no data for ${timeout}ms`)));\n request.end(body === undefined ? undefined : typeof body === \"string\" ? body : Buffer.from(body));\n });\n}\n\n// lib/jsonDirectory.ts\nvar EXTENSION = \".json\";\nvar NAME_PATTERN = /^[a-zA-Z0-9][a-zA-Z0-9_.-]{0,62}$/;\n\nclass InvalidNameError extends Error {\n name = \"InvalidNameError\";\n}\nfunction checkName(name) {\n if (!NAME_PATTERN.test(name)) {\n throw new InvalidNameError(`Invalid name \"${name}\": use letters, digits, \"_\", \".\" and \"-\", up to 63 characters`);\n }\n return name;\n}\nfunction createJsonDirectory(sandbox, dir) {\n async function pathFor(name) {\n return `${await dir()}/${checkName(name)}${EXTENSION}`;\n }\n function serialize(record) {\n return JSON.stringify(record, null, 2) + `\n`;\n }\n async function readPath(path) {\n try {\n return JSON.parse(new TextDecoder().decode(await sandbox.readFile(path)));\n } catch (error) {\n if (error instanceof SandboxNotFoundError)\n return null;\n throw error;\n }\n }\n async function read(name) {\n return readPath(await pathFor(name));\n }\n async function insert(name, record) {\n const path = await pathFor(name);\n if (await sandbox.writeFileExclusive(path, serialize(record)))\n return record;\n return await readPath(path) ?? insert(name, record);\n }\n async function save(name, record) {\n await sandbox.writeFile(await pathFor(name), serialize(record));\n }\n async function remove(name) {\n await sandbox.removeFile(await pathFor(name));\n }\n async function entries() {\n const path = await dir();\n const all = await sandbox.runCommand([\"sh\", \"-c\", LIST_SCRIPT, \"sh\", path], { env: { MISSING: String(MISSING), EXTENSION } }).catch(() => null);\n if (all?.exitCode === MISSING)\n return [];\n if (all?.exitCode === 0) {\n return all.stdout.split(RECORD_END).filter((text) => text.trim()).flatMap((text) => {\n const newline = text.indexOf(`\n`);\n try {\n return [[text.slice(0, newline).slice(0, -EXTENSION.length), JSON.parse(text.slice(newline + 1))]];\n } catch {\n return [];\n }\n });\n }\n let files;\n try {\n files = await sandbox.listDirectory(path);\n } catch (error) {\n if (error instanceof SandboxNotFoundError)\n return [];\n throw error;\n }\n const records = await Promise.all(files.filter((file) => file.endsWith(EXTENSION)).map(async (file) => [file.slice(0, -EXTENSION.length), await readPath(`${path}/${file}`)]));\n return records.filter((entry) => entry[1] !== null);\n }\n async function list() {\n return (await entries()).map(([, record]) => record);\n }\n return { read, insert, save, remove, list, entries };\n}\nvar MISSING = 44;\nvar RECORD_END = `\n\\x1E\n`;\nvar LIST_SCRIPT = sh`\ncd \"$1\" 2>/dev/null || exit \"$MISSING\"\nfor file in *\"$EXTENSION\"; do\n [ -f \"$file\" ] || continue\n printf '%s\\n' \"$file\"\n cat \"$file\"\n printf '\\n\\036\\n'\ndone\n`;\n\n// sandbox/storage/sandboxStorage.ts\nvar DESCRIPTOR = \"sandbox\";\nfunction createSandboxStorage(sandbox) {\n const stateDirectory = async () => `${await sandbox.homeDirectory()}/.local/state/hyperbrane`;\n const endpointsDirectory = async () => `${await stateDirectory()}/endpoints`;\n const descriptors = createJsonDirectory(sandbox, stateDirectory);\n const endpoints = createJsonDirectory(sandbox, endpointsDirectory);\n async function readDescriptor() {\n return descriptors.read(DESCRIPTOR);\n }\n async function insertDescriptor(descriptor) {\n return descriptors.insert(DESCRIPTOR, descriptor);\n }\n async function saveDescriptor(descriptor) {\n await descriptors.save(DESCRIPTOR, descriptor);\n }\n async function readEndpoint(name) {\n return endpoints.read(name);\n }\n async function saveEndpoint(endpoint) {\n const directory = await endpointsDirectory();\n const made = await sandbox.runCommand([\"sh\", \"-c\", 'mkdir -p \"$1\" && chmod 700 \"$1\"', \"sh\", directory]);\n if (made.exitCode !== 0)\n throw new Error(`making ${directory} private failed: ${made.stderr.trim()}`);\n await endpoints.save(endpoint.name, endpoint);\n }\n async function removeEndpoint(name) {\n await endpoints.remove(name);\n }\n async function listEndpoints() {\n return endpoints.list();\n }\n return {\n readDescriptor,\n insertDescriptor,\n saveDescriptor,\n readEndpoint,\n saveEndpoint,\n removeEndpoint,\n listEndpoints\n };\n}\n\n// sandbox/providers/local/localService.ts\nfunction hostPath(path) {\n return resolve(\"/\", path);\n}\nasync function notFoundAs(path, operation) {\n try {\n return await operation;\n } catch (error) {\n if (error.code === \"ENOENT\")\n throw new SandboxNotFoundError(`Not found: \"${path}\"`);\n throw error;\n }\n}\nasync function writeTemp(full, data, mode = 438) {\n await fs.mkdir(dirname(full), { recursive: true });\n const tmp = join(dirname(full), `.${basename(full)}.${randomUUID()}.tmp`);\n await fs.writeFile(tmp, data, { mode });\n return tmp;\n}\nasync function readFile2(path) {\n return new Uint8Array(await notFoundAs(path, fs.readFile(hostPath(path))));\n}\nasync function readFileRange(path, start, end) {\n const file = await notFoundAs(path, fs.open(hostPath(path), \"r\"));\n try {\n const buffer = new Uint8Array(Math.max(0, end - start));\n let filled = 0;\n while (filled < buffer.length) {\n const { bytesRead } = await file.read(buffer, filled, buffer.length - filled, start + filled);\n if (bytesRead === 0)\n break;\n filled += bytesRead;\n }\n return buffer.subarray(0, filled);\n } finally {\n await file.close();\n }\n}\nasync function writeFile2(path, data) {\n const full = hostPath(path);\n await fs.rename(await writeTemp(full, data), full);\n}\nasync function writeFileExclusive(path, data) {\n const full = hostPath(path);\n const tmp = await writeTemp(full, data);\n try {\n await fs.link(tmp, full);\n return true;\n } catch (error) {\n if (error.code === \"EEXIST\")\n return false;\n throw error;\n } finally {\n await fs.unlink(tmp);\n }\n}\nasync function removeFile(path) {\n await fs.rm(hostPath(path), { force: true });\n}\nasync function createDirectory(path) {\n await fs.mkdir(hostPath(path), { recursive: true });\n}\nasync function removeDirectory(path) {\n await fs.rm(hostPath(path), { recursive: true, force: true });\n}\nasync function listDirectory(path) {\n return notFoundAs(path, fs.readdir(hostPath(path)));\n}\nasync function stat2(path) {\n const stats = await notFoundAs(path, fs.stat(hostPath(path)));\n const type = stats.isFile() ? \"file\" : stats.isDirectory() ? \"directory\" : \"other\";\n return { type, uid: stats.uid, gid: stats.gid, size: stats.size };\n}\nasync function homeDirectory() {\n return process.env.HOME || homedir();\n}\nfunction runCommand(cmd, { cwd, env = {}, stdin } = {}) {\n return new Promise((resolve, reject) => {\n const [command, ...args] = cmd;\n if (!command)\n return reject(new Error(\"no command to run\"));\n const child = spawn(command, args, {\n cwd: hostPath(cwd ?? \".\"),\n env: { ...process.env, ...env },\n stdio: [stdin === undefined ? \"ignore\" : \"pipe\", \"pipe\", \"pipe\"]\n });\n const stdout = [];\n const stderr = [];\n child.stdout.on(\"data\", (chunk) => stdout.push(chunk));\n child.stderr.on(\"data\", (chunk) => stderr.push(chunk));\n child.once(\"error\", reject);\n child.once(\"close\", (code) => resolve({ exitCode: code ?? -1, stdout: Buffer.concat(stdout).toString(), stderr: Buffer.concat(stderr).toString() }));\n if (stdin !== undefined)\n child.stdin.end(stdin);\n });\n}\nasync function state() {\n return \"running\";\n}\nasync function start() {}\nasync function destroy() {}\nfunction hasExpiration() {\n return false;\n}\nasync function getExpiration() {\n return null;\n}\nasync function setExpiration() {\n return null;\n}\nfunction hasShell(ctx) {\n return ctx.sshKey !== undefined;\n}\nasync function sshEndpoint(ctx) {\n if (ctx.sshKey === undefined)\n throw new Error(\"this machine has no shell: its context has no SSH key (sshKey)\");\n return {\n host: ctx.sshHost ?? \"127.0.0.1\",\n port: ctx.sshPort ?? 22,\n user: ctx.sshUser ?? userInfo().username,\n privateKey: ctx.sshKey\n };\n}\nasync function fetch(url, { unix, ...init } = {}) {\n if (unix === undefined || \"Bun\" in globalThis)\n return globalThis.fetch(url, { ...init, unix: unix === undefined ? undefined : hostPath(unix) });\n return httpOver(url, () => netConnect(hostPath(unix)), init);\n}\nfunction connect(path) {\n return new Promise((resolve, reject) => {\n const socket = new Socket;\n let markClosed;\n const closed = new Promise((done) => markClosed = done);\n const listeners = [];\n socket.on(\"data\", (chunk) => {\n for (const listener of listeners)\n listener(new Uint8Array(chunk));\n });\n socket.once(\"close\", () => markClosed());\n socket.once(\"end\", () => markClosed());\n socket.on(\"error\", (error) => {\n markClosed();\n const message = `connecting to ${path} failed: ${error.message}`;\n reject(error.code === \"ENOENT\" || error.code === \"ECONNREFUSED\" ? new SandboxConnectionRefusedError(message) : new Error(message));\n });\n socket.once(\"connect\", () => resolve({\n write: (data) => void socket.write(data),\n onData: (listener) => void listeners.push(listener),\n closed,\n close: () => socket.end()\n }));\n socket.connect({ path: hostPath(path) });\n });\n}\nfunction createLocalService(ctx) {\n const fileOps = {\n readFile: readFile2,\n readFileRange,\n writeFile: writeFile2,\n writeFileExclusive,\n removeFile,\n createDirectory,\n removeDirectory,\n listDirectory,\n stat: stat2,\n homeDirectory\n };\n const cmdOps = {\n runCommand\n };\n const netOps = {\n fetch,\n connect\n };\n const machine = { ...fileOps, ...cmdOps, ...netOps };\n const storage = createSandboxStorage(machine);\n const lifecycleOps = {\n create: (spec) => createDescriptor(ctx, storage, ctx.id ?? spec.name, spec),\n open: () => openDescriptor(ctx, storage, ctx.id ?? \"this machine\"),\n get: () => getDescriptor(storage, \"this machine\"),\n state,\n start,\n destroy\n };\n const dataOps = createEndpoints(machine, storage, firewalledPorts(machine, storage));\n const expirationOps = {\n hasExpiration,\n getExpiration,\n setExpiration\n };\n const shellOps = {\n hasShell: () => hasShell(ctx),\n sshEndpoint: () => sshEndpoint(ctx)\n };\n return {\n ...fileOps,\n ...lifecycleOps,\n ...cmdOps,\n ...dataOps,\n ...expirationOps,\n ...shellOps,\n ...netOps\n };\n}\n\n// agent/session/claude/auth.ts\nimport { readFile as readFile3 } from \"fs/promises\";\nimport { join as join2 } from \"path\";\n\n// agent/session/login.ts\nfunction plain(text) {\n return text.replace(/\\x1b\\][^\\x07\\x1b]*(\\x07|\\x1b\\\\)/g, \"\").replace(/\\x1b\\[[0-9;?]*[a-zA-Z]/g, \"\");\n}\nfunction spawnLogin(cmd, { env, cwd }, parse) {\n const proc = Bun.spawn(cmd, { env, cwd, stdin: \"pipe\", stdout: \"pipe\", stderr: \"pipe\" });\n let output = \"\";\n let showPrompt;\n let noPrompt;\n const prompt = new Promise((resolve, reject) => {\n showPrompt = resolve;\n noPrompt = reject;\n });\n async function read(stream) {\n const decoder = new TextDecoder;\n for await (const chunk of stream) {\n output += plain(decoder.decode(chunk, { stream: true }));\n const found = parse(output);\n if (found)\n showPrompt(found);\n }\n }\n const reading = Promise.all([read(proc.stdout), read(proc.stderr)]);\n const done = reading.then(() => proc.exited).then((code) => {\n const tail = output.trim().split(`\n`).slice(-3).join(\" \").trim();\n noPrompt(new Error(`the login ended before showing where to sign in: ${tail}`));\n if (code !== 0)\n throw new Error(`the login failed (exit ${code}): ${tail}`);\n });\n prompt.catch(() => {});\n done.catch(() => {});\n return {\n prompt,\n done,\n submitCode(code) {\n proc.stdin.write(`${code}\n`);\n proc.stdin.flush();\n },\n cancel() {\n proc.kill();\n }\n };\n}\n\n// agent/session/claude/provision.ts\nimport { existsSync as existsSync2 } from \"fs\";\n\n// agent/session/install.ts\nimport { existsSync } from \"fs\";\n// agent/vendor-types/manifest.json\nvar manifest_default = {\n claude: {\n docs: \"https://code.claude.com/docs/en/agent-sdk/typescript\",\n sources: [\n {\n source: \"npm:@anthropic-ai/claude-agent-sdk@0.3.283\",\n into: \"agent-sdk\",\n files: 7\n }\n ]\n },\n codex: {\n docs: \"https://developers.openai.com/codex/app-server\",\n sources: [\n {\n source: \"npm:@openai/codex-sdk@0.157.1\",\n into: \"sdk\",\n files: 1\n },\n {\n source: \"github:openai/codex@rust-v0.157.1/codex-rs/app-server-protocol/schema/typescript\",\n into: \"app-server\",\n files: 740\n },\n {\n source: \"github:openai/codex@rust-v0.157.1/codex-rs/app-server-protocol/schema/json\",\n into: \"app-server-json\",\n files: 2\n }\n ]\n },\n pi: {\n docs: \"https://github.com/badlogic/pi-mono/blob/main/packages/coding-agent/docs/rpc.md\",\n sources: [\n {\n source: \"npm:@mariozechner/pi-coding-agent@0.73.1\",\n into: \"coding-agent\",\n files: 137\n },\n {\n source: \"npm:@mariozechner/pi-agent-core@0.73.1\",\n into: \"agent-core\",\n files: 5\n },\n {\n source: \"npm:@mariozechner/pi-ai@0.73.1\",\n into: \"ai\",\n files: 44\n }\n ]\n },\n opencode: {\n docs: \"https://opencode.ai/docs/server\",\n sources: [\n {\n source: \"npm:@opencode-ai/sdk@1.18.32\",\n into: \"sdk\",\n files: 39\n },\n {\n source: \"github:anomalyco/opencode@v1.18.32/packages/sdk\",\n into: \"\",\n files: 1\n }\n ]\n },\n openclaw: {\n docs: \"https://docs.openclaw.ai/gateway/protocol\",\n sources: [\n {\n source: \"npm:@openclaw/gateway-protocol@2026.9.6\",\n into: \"gateway-protocol\",\n files: 17\n }\n ]\n },\n hermes: {\n docs: \"https://hermes-agent.nousresearch.com/docs\",\n sources: [\n {\n source: \"github:NousResearch/hermes-agent@v2026.9.24/apps/shared/src\",\n into: \"gateway\",\n files: 3\n }\n ]\n }\n};\n\n// agent/session/install.ts\nfunction pinnedVersion(vendor, pkg, sourcePackage = pkg) {\n const prefix = `npm:${sourcePackage}@`;\n const source = manifest_default[vendor].sources.find((entry) => entry.source.startsWith(prefix));\n if (!source)\n throw new Error(`agent/vendor-types/manifest.json has no ${sourcePackage} for ${vendor} (needed for ${pkg})`);\n return source.source.slice(prefix.length);\n}\nasync function installedPackage(installDir, pkg, version, executable) {\n const manifest = Bun.file(`${installDir}/node_modules/${pkg}/package.json`);\n const found = await manifest.exists() ? (await manifest.json()).version ?? null : null;\n return { version: found, ready: found !== null && existsSync(executable()), pinned: version };\n}\nasync function installPackage(installDir, pkg, version, executable) {\n const installed = await installedPackage(installDir, pkg, version, executable);\n if (installed.ready && installed.version === version)\n return;\n const force = installed.version === version ? [\"--force\"] : [];\n const proc = Bun.spawn([\"flock\", `${installDir}/.install.lock`, process.execPath, \"add\", \"--exact\", ...force, `${pkg}@${version}`], {\n cwd: installDir,\n stdin: \"ignore\",\n stdout: \"pipe\",\n stderr: \"pipe\"\n });\n const [stdout, stderr, exitCode] = await Promise.all([\n new Response(proc.stdout).text(),\n new Response(proc.stderr).text(),\n proc.exited\n ]);\n if (exitCode !== 0)\n throw new Error(`bun add ${pkg}@${version} failed (exit ${exitCode}): ${(stderr || stdout).trim()}`);\n if (!existsSync(executable()))\n throw new Error(`bun add ${pkg}@${version} left no ${executable()}: its platform package didn't install`);\n}\n\n// agent/session/claude/provision.ts\nvar CLAUDE_SDK_PACKAGE = \"@anthropic-ai/claude-agent-sdk\";\nfunction installClaude(installDir) {\n return installPackage(installDir, CLAUDE_SDK_PACKAGE, pinnedVersion(\"claude\", CLAUDE_SDK_PACKAGE), () => claudeExecutable(installDir));\n}\nfunction installedClaude(installDir) {\n return installedPackage(installDir, CLAUDE_SDK_PACKAGE, pinnedVersion(\"claude\", CLAUDE_SDK_PACKAGE), () => claudeExecutable(installDir));\n}\nfunction claudeExecutable(installDir) {\n const base = `${installDir}/node_modules/${CLAUDE_SDK_PACKAGE}-linux-${process.arch}`;\n const glibc = `${base}/claude`;\n return existsSync2(glibc) ? glibc : `${base}-musl/claude`;\n}\n\n// agent/session/claude/auth.ts\nvar GATEWAY_CODE = \"x#x\";\nvar CREDENTIAL_VARIABLES = [\"ANTHROPIC_API_KEY\", \"ANTHROPIC_AUTH_TOKEN\", \"CLAUDE_CODE_OAUTH_TOKEN\"];\nvar claudeAuth = {\n async signedIn({ env }) {\n if (CREDENTIAL_VARIABLES.some((name) => env[name]))\n return true;\n const config = env.CLAUDE_CONFIG_DIR ?? join2(env.HOME ?? \"\", \".claude\");\n const credentials = await readJson(join2(config, \".credentials.json\"));\n if (credentials?.claudeAiOauth?.accessToken)\n return true;\n const settings = await readJson(join2(config, \".claude.json\"));\n return Boolean(settings?.primaryApiKey);\n },\n login({ installDir, env, cwd }, gatewaySignedIn) {\n const login = spawnLogin([claudeExecutable(installDir), \"auth\", \"login\"], { env, cwd }, (output) => {\n const url = /https:\\/\\/\\S*oauth\\/authorize\\S*/.exec(output)?.[0];\n return url ? { url, needsCode: true } : null;\n });\n if (gatewaySignedIn)\n login.prompt.then(() => login.submitCode(GATEWAY_CODE), () => {});\n return login;\n }\n};\nasync function readJson(path) {\n try {\n return JSON.parse(await readFile3(path, \"utf8\"));\n } catch {\n return null;\n }\n}\n\n// agent/api.ts\nvar AGENT_BACKENDS = [\"claude\", \"codex\"];\nvar AGENT_PERMISSION_MODES = [\"ask\", \"auto\"];\n\nclass AgentInvalidError extends Error {\n name = \"AgentInvalidError\";\n}\n\nclass AgentNotFoundError extends Error {\n name = \"AgentNotFoundError\";\n}\n\nclass AgentConflictError extends Error {\n name = \"AgentConflictError\";\n}\n\nclass AgentBackendNotInstalledError extends AgentConflictError {\n name = \"AgentBackendNotInstalledError\";\n}\n\n// agent/session/claude/backgroundTasks.ts\nfunction claudeBackgroundTasks() {\n let tasks = [];\n return {\n observe(message) {\n if (message.type !== \"system\")\n return;\n if (message.subtype === \"background_tasks_changed\")\n tasks = message.tasks;\n if (message.subtype === \"task_notification\")\n tasks = tasks.filter((task) => task.task_id !== message.task_id);\n },\n list: async () => tasks\n };\n}\nfunction claudeStopTask(query, tasks) {\n return async (taskId) => {\n if (!(await tasks.list()).some((task) => task.task_id === taskId))\n throw new AgentNotFoundError(`no background task ${taskId}`);\n await query.stopTask(taskId);\n };\n}\n\n// agent/session/claude/home.ts\nfunction claudeHomeEnvironment(home) {\n return { CLAUDE_CONFIG_DIR: home };\n}\n\n// agent/session/claude/input.ts\nfunction createPromptQueue() {\n const queued = [];\n let wake;\n let closed = false;\n function push(message) {\n queued.push(message);\n wake?.();\n }\n function close() {\n closed = true;\n wake?.();\n }\n async function* iterate() {\n for (;; ) {\n while (queued.length > 0)\n yield queued.shift();\n if (closed)\n return;\n await new Promise((resolve) => wake = resolve);\n wake = undefined;\n }\n }\n return { push, close, [Symbol.asyncIterator]: iterate };\n}\nfunction claudeInput(prompts, queue) {\n return async (message) => {\n if (!message.uuid)\n throw new Error(\"a message sent to claude needs a uuid to be acknowledged by\");\n const received = queue.sent({ ...message, uuid: message.uuid });\n prompts.push(message);\n await received;\n };\n}\n\n// agent/session/claude/messageQueue.ts\nvar RECEIVE_TIMEOUT_MS = 60000;\nfunction claudeMessageQueue() {\n const commands = new Map;\n let taken = null;\n const receipts = new Map;\n function observe(message) {\n const event = message;\n if (event.type !== \"command_lifecycle\" || !event.command_uuid || !event.state)\n return;\n const command = commands.get(event.command_uuid);\n if (command) {\n command.state = event.state;\n if (event.state === \"started\")\n taken = command.message;\n if (event.state !== \"queued\")\n commands.delete(event.command_uuid);\n }\n const receipt = receipts.get(event.command_uuid);\n if (!receipt)\n return;\n receipts.delete(event.command_uuid);\n if (event.state === \"queued\" || event.state === \"started\")\n receipt.resolve();\n else\n receipt.reject(new Error(`claude ${event.state} the message`));\n }\n function sent(message) {\n commands.set(message.uuid, { message, state: null });\n return new Promise((resolve, reject) => {\n const timer = setTimeout(() => {\n receipts.delete(message.uuid);\n commands.delete(message.uuid);\n reject(new Error(\"claude didn't confirm it received the message\"));\n }, RECEIVE_TIMEOUT_MS);\n receipts.set(message.uuid, {\n resolve: () => (clearTimeout(timer), resolve()),\n reject: (error) => (clearTimeout(timer), commands.delete(message.uuid), reject(error))\n });\n });\n }\n async function lastUserMessages() {\n const queued = [...commands.values()].filter((command) => command.state === \"queued\");\n return [...taken ? [{ message: taken, queued: false }] : [], ...queued.map((command) => ({ message: command.message, queued: true }))];\n }\n return { observe, sent, lastUserMessages };\n}\n\n// agent/session/claude/status.ts\nvar SESSION_STATE_EVENTS = { CLAUDE_CODE_EMIT_SESSION_STATE_EVENTS: \"1\" };\nfunction claudeStatus(changed) {\n let active = false;\n return {\n observe(message) {\n if (message.type !== \"system\" || message.subtype !== \"session_state_changed\")\n return;\n const next = message.state !== \"idle\";\n if (next === active)\n return;\n active = next;\n changed();\n },\n active: () => active\n };\n}\n\n// agent/session/claude/interrupt.ts\nfunction claudeInterrupt(query) {\n return async () => {\n await query.interrupt();\n };\n}\n\n// agent/session/claude/model.ts\nfunction claudeModel(query) {\n return {\n listModels: () => query.supportedModels(),\n setModel: (model) => query.setModel(model ?? undefined)\n };\n}\n\n// agent/session/sdkMessages.ts\nvar ASK_USER_QUESTION = \"AskUserQuestion\";\nfunction resultUsage({ input = 0, output = 0, cacheRead = 0, cacheWrite = 0, thinking = 0 } = {}) {\n return {\n input_tokens: input,\n output_tokens: output,\n output_tokens_details: { thinking_tokens: thinking },\n cache_read_input_tokens: cacheRead,\n cache_creation_input_tokens: cacheWrite,\n cache_creation: { ephemeral_1h_input_tokens: 0, ephemeral_5m_input_tokens: 0 },\n server_tool_use: { web_fetch_requests: 0, web_search_requests: 0 },\n service_tier: \"standard\",\n fallback_credit: { status: { type: \"not_applied\", reason: \"not_enabled\" } },\n inference_geo: \"\",\n iterations: [],\n speed: \"standard\"\n };\n}\nfunction userMessageText(message) {\n const content = message.message.content;\n if (typeof content === \"string\")\n return content;\n if (!Array.isArray(content))\n return \"\";\n return content.map((block) => block.type === \"text\" && typeof block.text === \"string\" ? block.text : \"\").filter(Boolean).join(`\n`);\n}\n\n// agent/session/claude/permissions.ts\nfunction claudePermissionMode(mode) {\n return mode === \"auto\" ? \"bypassPermissions\" : \"default\";\n}\nfunction claudePermissions(context, questions) {\n let mode = context.permissionMode;\n const canUseTool = (toolName, input, options) => {\n if (toolName === ASK_USER_QUESTION)\n return questions.answer(input, options);\n const { signal, toolUseID, decisionReason } = options;\n return context.requestPermission({ tool_name: toolName, input, tool_use_id: toolUseID, decision_reason: decisionReason }, signal);\n };\n const preToolUse = [\n {\n hooks: [async () => mode === \"auto\" ? {} : { hookSpecificOutput: { hookEventName: \"PreToolUse\", permissionDecision: \"ask\" } }]\n }\n ];\n async function setMode(query, next) {\n mode = next;\n await query.setPermissionMode(claudePermissionMode(next));\n }\n return { canUseTool, preToolUse, mode: () => mode, setMode };\n}\n\n// agent/session/claude/questions.ts\nvar QUESTION_DIALOG_KINDS = [\"permission_ask_user_question\", \"ask_user_question\", \"user_question\"];\nfunction claudeQuestions(context) {\n async function ask(input, toolUseId, signal) {\n const questions = Array.isArray(input.questions) ? input.questions : [];\n const response = await context.askQuestions({ tool_use_id: toolUseId, questions }, signal);\n if (!response)\n return { behavior: \"deny\", message: \"The user dismissed the questions.\" };\n return { behavior: \"allow\", updatedInput: { ...input, answers: response.answers } };\n }\n const onUserDialog = async (request, { signal }) => {\n if (!QUESTION_DIALOG_KINDS.includes(request.dialogKind))\n return { behavior: \"cancelled\" };\n const result = await ask(request.payload, request.toolUseID ?? crypto.randomUUID(), signal);\n if (result.behavior !== \"allow\")\n return { behavior: \"cancelled\" };\n return { behavior: \"completed\", result };\n };\n return {\n answer: (input, { signal, toolUseID }) => ask(input, toolUseID, signal),\n onUserDialog,\n supportedDialogKinds: QUESTION_DIALOG_KINDS\n };\n}\n\n// agent/session/claude/stream.ts\nimport { spawn as spawn2 } from \"child_process\";\n\n// agent/session/claude/sdk.ts\nasync function loadClaudeSdk(installDir) {\n return await import(Bun.resolveSync(CLAUDE_SDK_PACKAGE, installDir));\n}\n\n// agent/session/claude/stream.ts\nasync function startClaudeStream(context, prompts, permissions, questions, backgroundTasks, status, queue) {\n const sdk = await loadClaudeSdk(context.installDir);\n let cli = null;\n const query = sdk.query({\n prompt: prompts,\n options: {\n cwd: context.cwd,\n env: { ...context.env, ...SESSION_STATE_EVENTS },\n model: context.model ?? undefined,\n resume: context.nativeId ?? undefined,\n includePartialMessages: true,\n permissionMode: claudePermissionMode(permissions.mode()),\n allowDangerouslySkipPermissions: true,\n settingSources: [],\n canUseTool: permissions.canUseTool,\n hooks: { PreToolUse: permissions.preToolUse },\n onUserDialog: questions.onUserDialog,\n supportedDialogKinds: questions.supportedDialogKinds,\n spawnClaudeCodeProcess: (options) => {\n cli = spawnCli(options, context.spec.name);\n return cli.process;\n }\n }\n });\n const exit = async () => {\n query.close();\n return cli ? cli.exit : null;\n };\n const subagents = {\n observe(message) {\n if (message.type === \"system\" && message.subtype === \"task_started\" && message.tool_use_id && message.subagent_type) {\n context.subagentStarted(message.tool_use_id, message.task_id);\n }\n }\n };\n pump(context, query, [backgroundTasks, status, queue, subagents]).then(async () => context.exited(await exit()), async (error) => context.exited(await exit(), error));\n return query;\n}\nfunction spawnCli({ command, args, cwd, env, signal }, sessionName) {\n const child = spawn2(command, args, { cwd, env, signal, stdio: [\"pipe\", \"pipe\", \"pipe\"] });\n child.stderr.on(\"data\", (data) => process.stderr.write(`[claude ${sessionName}] ${data}`));\n const exit = new Promise((resolve) => {\n child.once(\"exit\", (code, signal) => resolve({ code, signal }));\n child.once(\"error\", () => {\n if (child.pid === undefined)\n resolve(null);\n });\n });\n return { process: child, exit };\n}\nasync function pump(context, query, observers) {\n for await (const message of query) {\n for (const observer of observers)\n observer.observe(message);\n if (\"session_id\" in message && typeof message.session_id === \"string\" && message.session_id) {\n context.setNativeId(message.session_id);\n }\n const streamed = toStreamingMessage(message);\n if (streamed)\n context.emit(streamed);\n }\n}\nfunction toStreamingMessage(message) {\n switch (message.type) {\n case \"assistant\":\n case \"stream_event\":\n case \"result\":\n return message;\n case \"user\":\n return { ...message, uuid: message.uuid ?? crypto.randomUUID(), session_id: message.session_id ?? \"\" };\n case \"system\":\n if (message.subtype === \"compact_boundary\")\n return { ...message, timestamp: new Date().toISOString() };\n return message.subtype === \"init\" ? message : null;\n default:\n return null;\n }\n}\n\n// agent/session/fileTranscript.ts\nfunction sandboxFiles(sandbox) {\n return {\n size: async (path) => (await sandbox.stat(path)).size,\n readFileRange: (path, start, end) => sandbox.readFileRange(path, start, end),\n listDirectory: (path) => sandbox.listDirectory(path)\n };\n}\nfunction locateTranscript(files, home, layout, nativeId) {\n const escape = (text) => text.replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$&\");\n const [before = \"\", after = \"\"] = layout.name.split(\"{id}\").map((part) => part.split(\"*\").map(escape).join(\".*\"));\n const name = new RegExp(`^${before}${escape(nativeId)}${after}$`);\n return findFile(files, `${home}/${layout.dir}`, layout.depth, (entry) => name.test(entry));\n}\nvar CHUNK_BYTES = 64 * 1024;\nvar TIME_SLACK_MS = 60000;\nvar PROBE_LINES = 3;\nvar PROBE_BYTES = 4 * CHUNK_BYTES;\nvar NEWLINE = 10;\nfunction lineTime(entry, field) {\n const value = entry?.[field];\n const time = typeof value === \"string\" ? Date.parse(value) : NaN;\n return Number.isNaN(time) ? null : time;\n}\nvar SCAN_BYTES = 1024 * 1024;\nvar searchedCopies = new Map;\nvar SEARCHED_FILES = 16;\nfunction createFileTranscript(files, locate, lineMessages, layout) {\n function parse(bytes, start) {\n try {\n const entry = JSON.parse(new TextDecoder().decode(bytes));\n return { start, time: lineTime(entry, layout.time), messages: lineMessages(entry) };\n } catch {\n return { start, time: null, messages: [] };\n }\n }\n function kept(from, to, skip) {\n const parts = [];\n let start = from;\n for (const stretch of [...skip].sort((a, b) => a.start - b.start)) {\n if (stretch.end <= start || stretch.start >= to)\n continue;\n if (stretch.start > start)\n parts.push({ start, end: stretch.start });\n start = Math.max(start, stretch.end);\n }\n if (start < to)\n parts.push({ start, end: to });\n return parts;\n }\n async function* backward(path, end, skip = []) {\n for (const part of kept(0, end, skip).reverse())\n yield* backwardIn(path, part.start, part.end);\n }\n async function* backwardIn(path, floor, end) {\n let position = end;\n let carry = new Uint8Array(0);\n while (position > floor) {\n const from = Math.max(floor, position - CHUNK_BYTES);\n const chunk = await files.readFileRange(path, from, position);\n const bytes = joined(chunk, carry);\n let lineEnd = bytes.length;\n for (let index = bytes.length - 1;index >= 0; index--) {\n if (bytes[index] !== NEWLINE)\n continue;\n if (lineEnd > index + 1)\n yield parse(bytes.subarray(index + 1, lineEnd), from + index + 1);\n lineEnd = index;\n }\n carry = bytes.slice(0, lineEnd);\n position = from;\n }\n if (carry.length > 0)\n yield parse(carry, floor);\n }\n async function* forward(path, start, end, skip = []) {\n for (const part of kept(start, end, skip))\n yield* forwardIn(path, part.start, part.end);\n }\n async function* forwardIn(path, start, end) {\n let position = start;\n let carry = new Uint8Array(0);\n let carryStart = start;\n while (position < end) {\n const to = Math.min(end, position + CHUNK_BYTES);\n const bytes = joined(carry, await files.readFileRange(path, position, to));\n let lineStart = 0;\n for (let index = 0;index < bytes.length; index++) {\n if (bytes[index] !== NEWLINE)\n continue;\n if (index > lineStart)\n yield parse(bytes.subarray(lineStart, index), carryStart + lineStart);\n lineStart = index + 1;\n }\n carry = bytes.slice(lineStart);\n carryStart += lineStart;\n position = to;\n }\n if (carry.length > 0)\n yield parse(carry, carryStart);\n }\n async function seek(path, low, high, target, skip) {\n return (await narrow(path, low, high, target, skip)).high;\n }\n async function narrow(path, low, high, target, skip) {\n while (high - low > CHUNK_BYTES) {\n let middle = Math.floor((low + high) / 2);\n const inside = skip.find((stretch) => stretch.start <= middle && middle < stretch.end);\n if (inside) {\n if (inside.end >= high) {\n high = Math.max(low, inside.start);\n continue;\n }\n middle = inside.end;\n }\n const probe = await probeTime(path, middle, high, skip);\n if (!probe)\n break;\n if (probe.time >= target)\n high = probe.start;\n else\n low = probe.start;\n }\n return { low, high };\n }\n async function probeTime(path, from, limit, skip) {\n let start = -1;\n let time = Infinity;\n let timed = 0;\n for await (const line of forward(path, from, Math.min(limit, from + PROBE_BYTES), skip)) {\n if (line.start === from && from > 0)\n continue;\n if (line.start >= limit)\n break;\n if (start < 0)\n start = line.start;\n if (line.time === null)\n continue;\n time = Math.min(time, line.time);\n if (++timed === PROBE_LINES)\n break;\n }\n return start < 0 || timed === 0 ? null : { start, time };\n }\n async function timeAt(path, from, size, skip) {\n for await (const line of forward(path, from, Math.min(size, from + PROBE_BYTES), skip))\n if (line.time !== null)\n return line.time;\n return null;\n }\n async function lineStart(path, at) {\n for await (const line of backward(path, at + 1))\n return line.start;\n return 0;\n }\n function copiesOf(path, size) {\n if (!layout.copies)\n return Promise.resolve([]);\n const key = `${path}\\x00${size}`;\n let copies = searchedCopies.get(key);\n if (!copies) {\n copies = findCopies(path, size, layout.copies);\n copies.catch(() => searchedCopies.delete(key));\n searchedCopies.set(key, copies);\n if (searchedCopies.size > SEARCHED_FILES)\n searchedCopies.delete(searchedCopies.keys().next().value);\n }\n return copies;\n }\n async function findCopies(path, size, marker) {\n const needle = Buffer.from(marker);\n const found = [];\n for (let position = 0;position < size; position += SCAN_BYTES) {\n const from = Math.max(0, position - needle.length + 1);\n const bytes = Buffer.from(await files.readFileRange(path, from, Math.min(size, position + SCAN_BYTES)));\n for (let index = bytes.indexOf(needle);index >= 0; index = bytes.indexOf(needle, index + 1)) {\n if (from + index >= position || position === 0)\n found.push(from + index);\n }\n }\n const copies = [];\n for (const [index, at] of found.entries()) {\n const start = await lineStart(path, at);\n let earlier = null;\n for await (const before of backward(path, start)) {\n if (before.time === null)\n continue;\n earlier = before.time;\n break;\n }\n if (earlier === null || copies.some((copy) => copy.start <= start && start < copy.end))\n continue;\n let time = null;\n for await (const line of forward(path, start, size)) {\n time = line.time;\n break;\n }\n if (time === null || time >= earlier)\n continue;\n const next = found[index + 1];\n const near = await narrow(path, start + 1, next === undefined ? size : await lineStart(path, next), earlier + 1, []);\n let end = near.high;\n for await (const line of forward(path, near.low, near.high)) {\n if (line.start <= start || line.time === null || line.time <= earlier)\n continue;\n end = line.start;\n break;\n }\n copies.push({ start, end });\n }\n return copies;\n }\n async function* pagedBackward(path, end, after, skip) {\n let next = after;\n let waiting = [];\n const settle = function* (before) {\n const [timed, ...untimed] = waiting;\n if (!timed)\n return;\n const own = timed.time;\n const late = before !== null && own < before - TIME_SLACK_MS && (next === null || own < next - TIME_SLACK_MS);\n const ahead = before !== null && own > before + TIME_SLACK_MS && (next === null || own > next + TIME_SLACK_MS);\n const time = late || ahead ? before : own;\n yield { ...timed, time };\n for (const line of untimed)\n yield { ...line, time };\n next = own;\n waiting = [];\n };\n for await (const line of backward(path, end, skip)) {\n if (line.time === null) {\n if (waiting.length === 0)\n yield { ...line, time: next ?? Infinity };\n else\n waiting.push(line);\n continue;\n }\n yield* settle(line.time);\n waiting = [line];\n }\n yield* settle(null);\n }\n async function page(before, limit, found) {\n const path = await locate();\n if (!path)\n return { messages: [], nextBefore: null };\n const size = await files.size(path);\n const copies = found?.copies ?? await copiesOf(path, size);\n const from = Math.min(found?.end ?? (before === null ? size : await seek(path, 0, size, before + TIME_SLACK_MS, copies)), size);\n const after = found ? found.after : from < size ? await timeAt(path, from, size, copies) : null;\n const taken = [];\n let count = 0;\n let oldest = Infinity;\n let older = false;\n for await (const line of pagedBackward(path, from, after, copies)) {\n if (count >= limit && line.time < oldest - TIME_SLACK_MS) {\n older = true;\n break;\n }\n if (line.messages.length === 0 || before !== null && !(line.time < before))\n continue;\n taken.push(line);\n count += line.messages.length;\n if (count >= limit)\n oldest = oldestOnPage(taken, limit);\n }\n const kept = count >= limit ? taken.filter((line) => line.time >= oldest) : taken;\n if (kept.length < taken.length)\n older = true;\n return {\n messages: kept.sort((a, b) => a.start - b.start).flatMap((line) => line.messages),\n nextBefore: older && Number.isFinite(oldest) ? new Date(oldest).toISOString() : null\n };\n }\n async function replay(afterId, emit) {\n const path = await locate();\n if (!path)\n return afterId === undefined;\n const end = await files.size(path);\n const copies = await copiesOf(path, end);\n let start = 0;\n if (afterId !== undefined) {\n let found = null;\n for await (const line of backward(path, end, copies)) {\n if (line.messages.some((message) => message.uuid === afterId)) {\n found = line;\n break;\n }\n }\n if (!found)\n return false;\n start = found.start;\n }\n let passed = afterId === undefined;\n for await (const line of forward(path, start, end, copies)) {\n for (const message of line.messages) {\n if (passed)\n emit(message);\n else if (message.uuid === afterId)\n passed = true;\n }\n }\n return true;\n }\n async function find(match) {\n const path = await locate();\n if (!path)\n return null;\n const end = await files.size(path);\n for await (const line of backward(path, end, await copiesOf(path, end))) {\n const found = line.messages.find(match);\n if (found)\n return found;\n }\n return null;\n }\n return { page, replay, find };\n}\nfunction oldestOnPage(lines, limit) {\n const newestFirst = [...lines].sort((a, b) => b.time - a.time);\n let count = 0;\n for (const line of newestFirst) {\n count += line.messages.length;\n if (count >= limit)\n return line.time;\n }\n return newestFirst[newestFirst.length - 1]?.time ?? Infinity;\n}\nfunction joined(first, second) {\n if (first.length === 0)\n return second;\n if (second.length === 0)\n return first;\n const bytes = new Uint8Array(first.length + second.length);\n bytes.set(first);\n bytes.set(second, first.length);\n return bytes;\n}\nvar DEFAULT_PAGE_SIZE = 50;\nvar MAX_PAGE_SIZE = 500;\nasync function transcriptPage(transcript, { limit, before, cursor } = {}, found) {\n const time = transcriptTime(before ?? cursor);\n if (!transcript)\n return { messages: [], nextBefore: null, nextCursor: null };\n const size = Math.min(Math.max(Math.floor(limit ?? DEFAULT_PAGE_SIZE), 1), MAX_PAGE_SIZE);\n const page = await transcript.page(time, size, found);\n return { ...page, nextCursor: page.nextBefore };\n}\nfunction transcriptTime(before) {\n if (before === undefined)\n return null;\n const time = Date.parse(before);\n if (Number.isNaN(time))\n throw new AgentInvalidError(`invalid time ${before}: give an ISO 8601 time`);\n return time;\n}\nasync function directoryNames(files, dir) {\n try {\n return await files.listDirectory(dir);\n } catch (error) {\n if (error instanceof SandboxNotFoundError)\n return null;\n throw error;\n }\n}\nasync function findFile(files, dir, depth, matches) {\n const names = await directoryNames(files, dir);\n if (!names)\n return null;\n if (depth <= 1) {\n const name = names.find(matches);\n return name === undefined ? null : `${dir}/${name}`;\n }\n const found = await Promise.all(names.sort().reverse().map((name) => findFile(files, `${dir}/${name}`, depth - 1, matches).catch(() => null)));\n return found.find((path) => path !== null) ?? null;\n}\n\n// agent/session/claude/transcript.ts\nfunction claudeTranscript({ nativeId, env, files }) {\n return createFileTranscript(files, () => locateTranscript(files, claudeHome(env), CLAUDE_TRANSCRIPT_LAYOUT, nativeId), claudeLineMessages, CLAUDE_TRANSCRIPT_LAYOUT);\n}\nfunction claudeSubagentTranscript(source, agentId, toolUseId) {\n return subagentFile(source, `agent-${agentId}.jsonl`, toolUseId);\n}\nasync function claudeFindSubagent(source, toolUseId) {\n const isResult = (message) => message.type === \"user\" && Array.isArray(message.message.content) && message.message.content.some((block) => block.type === \"tool_result\" && block.tool_use_id === toolUseId);\n let found = await claudeTranscript(source).find(isResult);\n const dir = found ? null : await subagentsDirectory(source);\n const names = dir ? await directoryNames(source.files, dir) ?? [] : [];\n for (const name of names.filter((entry) => SUBAGENT_FILE.test(entry))) {\n found = await subagentFile(source, name, toolUseId).find(isResult);\n if (found)\n break;\n }\n const agentId = found?.tool_use_result?.agentId;\n return typeof agentId === \"string\" ? agentId : null;\n}\nfunction subagentFile(source, name, toolUseId) {\n async function locate() {\n const dir = await subagentsDirectory(source);\n if (!dir)\n return null;\n return (await directoryNames(source.files, dir))?.includes(name) ? `${dir}/${name}` : null;\n }\n return createFileTranscript(source.files, locate, (line) => lineMessages(line, toolUseId), CLAUDE_TRANSCRIPT_LAYOUT);\n}\nasync function subagentsDirectory({ nativeId, env, files }) {\n const main = await locateTranscript(files, claudeHome(env), CLAUDE_TRANSCRIPT_LAYOUT, nativeId);\n return main ? `${main.slice(0, -\".jsonl\".length)}/subagents` : null;\n}\nfunction claudeHome(env) {\n return env.CLAUDE_CONFIG_DIR ?? `${env.HOME}/.claude`;\n}\nvar SUBAGENT_FILE = /^agent-.+\\.jsonl$/;\nvar CLAUDE_TRANSCRIPT_LAYOUT = {\n dir: \"projects\",\n depth: 2,\n name: \"{id}.jsonl\",\n time: \"timestamp\",\n copies: '\"subtype\":\"compact_boundary\"'\n};\nfunction claudeLineMessages(line) {\n return lineMessages(line, null);\n}\nfunction lineMessages(line, parentToolUseId) {\n const entry = line;\n if (entry.type === \"system\" && entry.subtype === \"compact_boundary\")\n return compaction(entry);\n if (entry.type !== \"user\" && entry.type !== \"assistant\")\n return [];\n if (entry.isSidechain && parentToolUseId === null || entry.isMeta || !entry.uuid || !entry.message)\n return [];\n const common = { parent_tool_use_id: parentToolUseId, uuid: entry.uuid, session_id: entry.sessionId ?? \"\", ...entry.timestamp ? { timestamp: entry.timestamp } : {} };\n if (entry.type === \"assistant\")\n return [{ type: \"assistant\", message: entry.message, ...common }];\n return [{ type: \"user\", message: entry.message, ...common, ...entry.toolUseResult !== undefined ? { tool_use_result: entry.toolUseResult } : {} }];\n}\nfunction compaction(entry) {\n const meta = entry.compactMetadata;\n if (!entry.uuid || !meta?.trigger)\n return [];\n const { preservedSegment: segment, preservedMessages: preserved } = meta;\n return [\n {\n type: \"system\",\n subtype: \"compact_boundary\",\n compact_metadata: {\n trigger: meta.trigger,\n pre_tokens: meta.preTokens ?? 0,\n ...meta.postTokens !== undefined ? { post_tokens: meta.postTokens } : {},\n ...meta.durationMs !== undefined ? { duration_ms: meta.durationMs } : {},\n ...segment ? { preserved_segment: { head_uuid: segment.headUuid, anchor_uuid: segment.anchorUuid, tail_uuid: segment.tailUuid } } : {},\n ...preserved ? { preserved_messages: { anchor_uuid: preserved.anchorUuid, uuids: preserved.uuids } } : {}\n },\n uuid: entry.uuid,\n session_id: entry.sessionId ?? \"\",\n ...entry.timestamp ? { timestamp: entry.timestamp } : {}\n }\n ];\n}\n\n// agent/session/claude/index.ts\nvar claudeBackend = {\n install: installClaude,\n installed: installedClaude,\n auth: claudeAuth,\n transcript: claudeTranscript,\n findSubagent: claudeFindSubagent,\n subagentTranscript: claudeSubagentTranscript,\n homeEnvironment: claudeHomeEnvironment,\n async start(context) {\n const prompts = createPromptQueue();\n const questions = claudeQuestions(context);\n const backgroundTasks = claudeBackgroundTasks();\n const status = claudeStatus(() => context.activeChanged());\n const queue = claudeMessageQueue();\n const permissions = claudePermissions(context, questions);\n const query = await startClaudeStream(context, prompts, permissions, questions, backgroundTasks, status, queue);\n return {\n sendMessage: claudeInput(prompts, queue),\n active: status.active,\n getLastUserMessages: queue.lastUserMessages,\n cancel: claudeInterrupt(query),\n ...claudeModel(query),\n setPermissionMode: (mode) => permissions.setMode(query, mode),\n listBackgroundTasks: backgroundTasks.list,\n stopTask: claudeStopTask(query, backgroundTasks),\n async close() {\n prompts.close();\n query.close();\n }\n };\n }\n};\n\n// agent/session/codex/provision.ts\nvar CODEX_PACKAGE = \"@openai/codex\";\nvar CODEX_VERSION = () => pinnedVersion(\"codex\", CODEX_PACKAGE, \"@openai/codex-sdk\");\nfunction installCodex(installDir) {\n return installPackage(installDir, CODEX_PACKAGE, CODEX_VERSION(), () => codexExecutable(installDir).path);\n}\nfunction installedCodex(installDir) {\n return installedPackage(installDir, CODEX_PACKAGE, CODEX_VERSION(), () => codexExecutable(installDir).path);\n}\nvar LINUX_TARGETS = {\n x64: { pkg: \"@openai/codex-linux-x64\", triple: \"x86_64-unknown-linux-musl\" },\n arm64: { pkg: \"@openai/codex-linux-arm64\", triple: \"aarch64-unknown-linux-musl\" }\n};\nfunction codexExecutable(installDir) {\n const target = LINUX_TARGETS[process.arch];\n if (process.platform !== \"linux\" || !target)\n throw new Error(`codex: unsupported platform ${process.platform}/${process.arch}`);\n return {\n path: `${installDir}/node_modules/${target.pkg}/vendor/${target.triple}/bin/codex`,\n env: { CODEX_MANAGED_PACKAGE_ROOT: `${installDir}/node_modules/${CODEX_PACKAGE}`, CODEX_MANAGED_BY_BUN: \"1\" }\n };\n}\n\n// agent/session/codex/auth.ts\nfunction run({ installDir, env, cwd }, args) {\n const executable = codexExecutable(installDir);\n return { cmd: [executable.path, ...args], env: { ...env, ...executable.env }, cwd };\n}\nvar codexAuth = {\n async signedIn(environment) {\n const { cmd, env, cwd } = run(environment, [\"login\", \"status\"]);\n const proc = Bun.spawn(cmd, { env, cwd, stdout: \"ignore\", stderr: \"ignore\" });\n return await proc.exited === 0;\n },\n login(environment) {\n const { cmd, env, cwd } = run(environment, [\"login\", \"--device-auth\"]);\n return spawnLogin(cmd, { env, cwd }, (output) => {\n const url = /https:\\/\\/\\S+\\/device\\S*/.exec(output)?.[0];\n const userCode = /^\\s*([A-Z0-9]{4}-[A-Z0-9]{4,})\\s*$/m.exec(output)?.[1];\n return url && userCode ? { url, userCode, needsCode: false } : null;\n });\n }\n};\n\n// agent/session/codex/backgroundTasks.ts\nimport { readdirSync, readFileSync } from \"fs\";\nvar STOP_GRACE_MS = 1000;\nfunction codexBackgroundTasks() {\n const running = new Map;\n const background = new Map;\n function observe(notification) {\n switch (notification.method) {\n case \"item/started\": {\n const { item } = notification.params;\n if (item.type === \"commandExecution\")\n running.set(item.id, { task_id: item.id, task_type: \"local_bash\", description: item.command });\n return;\n }\n case \"item/completed\": {\n const { item } = notification.params;\n if (item.type !== \"commandExecution\")\n return;\n running.delete(item.id);\n background.delete(item.id);\n return;\n }\n case \"turn/completed\":\n for (const [id, task] of running)\n background.set(id, task);\n running.clear();\n return;\n }\n }\n async function stop(taskId, appServerPid) {\n const task = background.get(taskId);\n if (!task)\n throw new AgentNotFoundError(`no background task ${taskId}`);\n const targets = commandProcesses(appServerPid, task.description);\n signal(targets, \"SIGTERM\");\n const deadline = Date.now() + STOP_GRACE_MS;\n while (targets.some(alive) && Date.now() < deadline)\n await Bun.sleep(50);\n signal(targets.filter(alive), \"SIGKILL\");\n background.delete(taskId);\n }\n return { observe, list: async () => [...background.values()], stop };\n}\nfunction processes() {\n const entries = [];\n for (const name of readdirSync(\"/proc\")) {\n if (!/^\\d+$/.test(name))\n continue;\n try {\n const stat = readFileSync(`/proc/${name}/stat`, \"utf8\");\n const ppid = Number(stat.slice(stat.lastIndexOf(\")\") + 2).split(\" \")[1]);\n const argv = readFileSync(`/proc/${name}/cmdline`, \"utf8\").split(\"\\x00\").filter(Boolean);\n entries.push({ pid: Number(name), ppid, argv });\n } catch {}\n }\n return entries;\n}\nfunction commandProcesses(root, command) {\n const all = processes();\n const children = new Map;\n for (const entry of all)\n children.set(entry.ppid, [...children.get(entry.ppid) ?? [], entry.pid]);\n const under = (pid) => (children.get(pid) ?? []).flatMap((child) => [child, ...under(child)]);\n const descendants = new Set(under(root));\n const shells = all.filter((entry) => descendants.has(entry.pid) && entry.argv.length >= 3 && [\"-c\", \"-lc\"].includes(entry.argv.at(-2)) && command.includes(entry.argv.at(-1)));\n return [...new Set(shells.flatMap((shell) => [shell.pid, ...under(shell.pid)]))];\n}\nfunction signal(pids, name) {\n for (const pid of pids) {\n try {\n process.kill(pid, name);\n } catch {}\n }\n}\nfunction alive(pid) {\n try {\n process.kill(pid, 0);\n return true;\n } catch {\n return false;\n }\n}\n\n// agent/session/codex/input.ts\nfunction codexApprovalPolicy(mode) {\n return mode === \"auto\" ? \"never\" : \"untrusted\";\n}\nfunction createCodexInput(thread, queue, initialModel, initialMode) {\n let model = initialModel;\n let mode = initialMode;\n async function sendMessage(message) {\n if (!message.uuid)\n throw new Error(\"a message sent to codex needs a uuid to be known by\");\n const { rpc, threadId } = thread();\n await rpc.request(\"turn/start\", {\n threadId,\n input: [{ type: \"text\", text: userMessageText(message), text_elements: [] }],\n clientUserMessageId: message.uuid,\n model,\n approvalPolicy: codexApprovalPolicy(mode)\n });\n queue.sent(message, message.uuid);\n }\n function setModel(next) {\n model = next;\n }\n async function setPermissionMode(next) {\n mode = next;\n }\n return { sendMessage, setModel, setPermissionMode };\n}\n\n// agent/session/codex/messageQueue.ts\nfunction codexMessageQueue() {\n const queued = new Map;\n let taken = null;\n return {\n observe(notification) {\n if (notification.method !== \"item/started\")\n return;\n const { item } = notification.params;\n if (item.type !== \"userMessage\" || !item.clientId)\n return;\n const message = queued.get(item.clientId);\n if (!message)\n return;\n queued.delete(item.clientId);\n taken = message;\n },\n sent(message, clientId) {\n queued.set(clientId, message);\n },\n async lastUserMessages() {\n return [...taken ? [{ message: taken, queued: false }] : [], ...[...queued.values()].map((message) => ({ message, queued: true }))];\n }\n };\n}\n\n// agent/session/codex/status.ts\nfunction codexStatus(changed) {\n let active = false;\n return {\n observe(notification) {\n if (notification.method !== \"thread/status/changed\")\n return;\n const next = notification.params.status.type === \"active\";\n if (next === active)\n return;\n active = next;\n changed();\n },\n active: () => active\n };\n}\n\n// agent/session/codex/interrupt.ts\nfunction codexInterrupt(thread) {\n return async () => {\n const { rpc, threadId, activeTurn } = thread();\n const turnId = activeTurn();\n if (!turnId)\n return;\n await rpc.request(\"turn/interrupt\", { threadId, turnId });\n };\n}\n\n// agent/session/codex/model.ts\nfunction codexModel(thread, input) {\n async function listModels() {\n const { data } = await thread().rpc.request(\"model/list\", {});\n return data.map((model) => ({ value: model.model, displayName: model.displayName, description: model.description }));\n }\n async function setModel(model) {\n input.setModel(model);\n }\n return { listModels, setModel };\n}\n\n// agent/session/codex/permissions.ts\nfunction codexPermissions(context) {\n function ask(request) {\n return context.requestPermission(request);\n }\n async function answer(request, rpc) {\n switch (request.method) {\n case \"item/commandExecution/requestApproval\": {\n const { params } = request;\n const decision = await ask({\n tool_name: \"commandExecution\",\n input: { command: params.command ?? \"\", cwd: params.cwd },\n tool_use_id: params.itemId,\n decision_reason: params.reason ?? undefined\n });\n const response = { decision: decision.behavior === \"allow\" ? \"accept\" : \"decline\" };\n return rpc.respond(request.id, response);\n }\n case \"item/fileChange/requestApproval\": {\n const { params } = request;\n const decision = await ask({\n tool_name: \"fileChange\",\n input: { grantRoot: params.grantRoot ?? null },\n tool_use_id: params.itemId,\n decision_reason: params.reason ?? undefined\n });\n const response = { decision: decision.behavior === \"allow\" ? \"accept\" : \"decline\" };\n return rpc.respond(request.id, response);\n }\n case \"execCommandApproval\": {\n const { params } = request;\n const decision = await ask({\n tool_name: \"commandExecution\",\n input: { command: params.command.join(\" \"), cwd: params.cwd },\n tool_use_id: params.callId,\n decision_reason: params.reason ?? undefined\n });\n const response = {\n decision: decision.behavior === \"allow\" ? \"approved\" : { denied: { rejection: decision.message } }\n };\n return rpc.respond(request.id, response);\n }\n case \"applyPatchApproval\": {\n const { params } = request;\n const decision = await ask({\n tool_name: \"fileChange\",\n input: { changes: params.fileChanges, grantRoot: params.grantRoot },\n tool_use_id: params.callId,\n decision_reason: params.reason ?? undefined\n });\n const response = {\n decision: decision.behavior === \"allow\" ? \"approved\" : { denied: { rejection: decision.message } }\n };\n return rpc.respond(request.id, response);\n }\n default:\n return rpc.respondError(request.id, `${request.method} is not supported by hyperbrane`);\n }\n }\n return (request, rpc) => {\n answer(request, rpc).catch((error) => {\n console.error(`answering codex's ${request.method} failed:`, error);\n rpc.respondError(request.id, error.message);\n });\n };\n}\n\n// agent/session/codex/questions.ts\nfunction codexQuestions(context, thread) {\n return async (params) => {\n const questions = params.questions.map((question) => ({\n question: question.question,\n header: question.header,\n options: question.options ?? [],\n multiSelect: false\n }));\n thread().emitToolUse(params.itemId, ASK_USER_QUESTION, { questions });\n const response = await context.askQuestions({ tool_use_id: params.itemId, questions });\n if (!response)\n thread().emitToolResult(params.itemId, \"The user dismissed the questions.\", true);\n else\n thread().emitToolResult(params.itemId, answersText(response.answers), false);\n const answers = {};\n for (const question of params.questions) {\n const answer = response?.answers[question.question];\n answers[question.id] = { answers: answer === undefined ? [] : [answer] };\n }\n return { answers };\n };\n}\nfunction answersText(answers) {\n const pairs = Object.entries(answers).map(([question, answer]) => `\"${question}\"=\"${answer}\"`);\n return `User has answered your questions: ${pairs.join(\", \")}.`;\n}\n\n// agent/session/codex/home.ts\nfunction codexHomeEnvironment(home) {\n return { CODEX_HOME: home };\n}\n\n// lib/version.ts\nvar HYPERBRANE_VERSION = \"v1\";\n\n// agent/session/codex/messages.ts\nfunction backendId(id) {\n return id;\n}\nfunction toolResultId(itemId) {\n return `${itemId}:result`;\n}\nfunction assistantMessage(uuid, content, threadId, model, extras = {}) {\n const usage = {\n ...resultUsage(),\n cache_creation: null,\n server_tool_use: null,\n service_tier: null,\n fallback_credit: null,\n inference_geo: null,\n iterations: null,\n output_tokens_details: null,\n speed: null\n };\n return {\n type: \"assistant\",\n message: {\n id: uuid,\n type: \"message\",\n role: \"assistant\",\n model,\n content,\n container: null,\n context_management: null,\n stop_reason: null,\n stop_sequence: null,\n stop_details: null,\n diagnostics: null,\n usage\n },\n parent_tool_use_id: null,\n uuid: backendId(uuid),\n session_id: threadId,\n ...extras\n };\n}\nfunction toolResultMessage(itemId, content, isError, threadId, output) {\n return {\n type: \"user\",\n message: { role: \"user\", content: [{ type: \"tool_result\", tool_use_id: itemId, content, is_error: isError }] },\n parent_tool_use_id: null,\n uuid: backendId(toolResultId(itemId)),\n session_id: threadId,\n ...output === undefined ? {} : { tool_use_result: output }\n };\n}\nfunction eventMessage(id, event, threadId) {\n return { type: \"system\", subtype: \"session_event\", event, uuid: id, session_id: threadId };\n}\nfunction itemMessages(item, threadId, model, finished = true) {\n const call = toolCallOf(item);\n if (call) {\n const messages = [assistantMessage(item.id, [call], threadId, model)];\n const result = finished ? toolResultOf(item) : null;\n if (result)\n messages.push(toolResultMessage(item.id, result.content, result.isError, threadId, item));\n return messages;\n }\n switch (item.type) {\n case \"userMessage\":\n return [{ type: \"user\", message: { role: \"user\", content: userContent(item.content) }, parent_tool_use_id: null, uuid: backendId(item.clientId ?? item.id), session_id: threadId }];\n case \"hookPrompt\":\n return [\n {\n type: \"user\",\n message: { role: \"user\", content: item.fragments.map((fragment) => fragment.text).join(`\n`) },\n parent_tool_use_id: null,\n uuid: backendId(item.id),\n session_id: threadId\n }\n ];\n case \"agentMessage\": {\n const citations = item.memoryCitation?.entries.map((entry, index) => ({\n type: \"search_result_location\",\n source: entry.path,\n title: entry.note,\n cited_text: \"\",\n search_result_index: index,\n start_block_index: entry.lineStart,\n end_block_index: entry.lineEnd\n }));\n const content = [{ type: \"text\", text: item.text, citations: citations?.length ? citations : null }];\n if (item.questions?.length) {\n const questions = item.questions.map((question) => ({\n question: question.title,\n header: \"\",\n options: (question.options ?? []).map((label) => ({ label, description: \"\" })),\n multiSelect: false\n }));\n content.push({ type: \"tool_use\", id: `${item.id}:questions`, name: ASK_USER_QUESTION, input: { questions } });\n }\n const extras = {\n ...item.phase ? { phase: item.phase === \"final_answer\" ? \"final\" : \"commentary\" } : {},\n ...item.delivery === \"async\" ? { async: true } : {}\n };\n return [assistantMessage(item.id, content, threadId, model, extras)];\n }\n case \"reasoning\":\n return [assistantMessage(item.id, [{ type: \"thinking\", thinking: [...item.summary, ...item.content].join(`\n\n`), signature: \"\" }], threadId, model)];\n case \"contextCompaction\":\n return [{ type: \"system\", subtype: \"compact_boundary\", uuid: backendId(item.id), session_id: threadId }];\n case \"enteredReviewMode\":\n return [eventMessage(item.id, { kind: \"review\", state: \"entered\", review: item.review }, threadId)];\n case \"exitedReviewMode\":\n return [eventMessage(item.id, { kind: \"review\", state: \"exited\", review: item.review }, threadId)];\n case \"subAgentActivity\":\n return [eventMessage(item.id, { kind: \"subagent\", activity: item.kind, agent: item.agentThreadId, path: item.agentPath }, threadId)];\n default:\n return [];\n }\n}\nfunction entryMessages({ item, startedAtMs, completedAtMs }, threadId, model, parentToolUseId = null) {\n const started = startedAtMs ?? completedAtMs;\n const completed = completedAtMs ?? startedAtMs;\n const at = (time) => time === null ? {} : { timestamp: new Date(time).toISOString() };\n const messages = itemMessages(item, threadId, model, completedAtMs !== null).map((message) => underTool(message, parentToolUseId));\n return messages.map((message, index) => ({ ...message, ...at(index === 0 && toolCallOf(item) ? started : completed) }));\n}\nfunction underTool(message, parentToolUseId) {\n return message.type === \"system\" || parentToolUseId === null ? message : { ...message, parent_tool_use_id: parentToolUseId };\n}\nfunction toolCallOf(item) {\n const call = (input, name = item.type) => ({ type: \"tool_use\", id: item.id, name, input });\n switch (item.type) {\n case \"commandExecution\":\n return call({ command: item.command, cwd: item.cwd });\n case \"fileChange\":\n return call({ changes: item.changes });\n case \"mcpToolCall\":\n return { type: \"mcp_tool_use\", id: item.id, name: item.tool, server_name: item.server, input: item.arguments };\n case \"dynamicToolCall\":\n return call(item.arguments, item.tool);\n case \"functionCallOutput\":\n return call({}, item.name);\n case \"collabAgentToolCall\":\n return call({ prompt: item.prompt, model: item.model, reasoningEffort: item.reasoningEffort, receiverThreadIds: item.receiverThreadIds }, item.tool);\n case \"webSearch\":\n return call({ query: item.query, action: item.action });\n case \"imageView\":\n return call({ path: item.path });\n case \"imageGeneration\":\n return call({ revisedPrompt: item.revisedPrompt });\n case \"sleep\":\n return call({ durationMs: item.durationMs });\n case \"plan\":\n return call({ text: item.text });\n default:\n return null;\n }\n}\nfunction toolResultOf(item) {\n switch (item.type) {\n case \"commandExecution\":\n return { content: item.aggregatedOutput ?? \"\", isError: item.status !== \"completed\" || (item.exitCode ?? 0) !== 0 };\n case \"fileChange\":\n return { content: item.status, isError: item.status !== \"completed\" };\n case \"mcpToolCall\":\n return { content: item.error ? item.error.message : mcpContent(item.result?.content ?? []), isError: item.status !== \"completed\" };\n case \"dynamicToolCall\":\n return { content: inputContent(item.contentItems ?? []), isError: item.success === false };\n case \"functionCallOutput\":\n return { content: typeof item.output === \"string\" ? item.output : functionOutputContent(item.output), isError: false };\n case \"collabAgentToolCall\":\n return { content: JSON.stringify(item.agentsStates), isError: item.status === \"failed\" };\n case \"webSearch\":\n return { content: item.results ? JSON.stringify(item.results) : \"\", isError: false };\n case \"imageView\":\n case \"sleep\":\n return { content: \"\", isError: false };\n case \"imageGeneration\": {\n const image = base64Image(item.result);\n return { content: image ? [image] : \"\", isError: item.failure !== null };\n }\n case \"plan\":\n return { content: item.text, isError: false };\n default:\n return null;\n }\n}\nfunction userContent(inputs) {\n if (inputs.every((input) => input.type === \"text\"))\n return inputs.map((input) => input.text).join(\"\");\n return inputs.flatMap((input) => {\n if (input.type === \"text\")\n return [{ type: \"text\", text: input.text }];\n if (input.type === \"image\" && \"url\" in input)\n return [imageBlock(input.url)];\n return [];\n });\n}\nfunction mcpContent(content) {\n const texts = content.map((block) => block.type === \"text\" ? block.text : null);\n if (texts.every((text) => text !== null))\n return texts.join(`\n`);\n return JSON.stringify(content);\n}\nfunction inputContent(items) {\n return items.flatMap((item) => {\n if (item.type === \"inputText\")\n return [{ type: \"text\", text: item.text }];\n if (item.type === \"inputImage\")\n return [imageBlock(item.imageUrl)];\n return [];\n });\n}\nfunction functionOutputContent(items) {\n return items.flatMap((item) => {\n if (item.type === \"input_text\")\n return [{ type: \"text\", text: item.text }];\n if (item.type === \"input_image\" && \"image_url\" in item)\n return [imageBlock(item.image_url)];\n return [];\n });\n}\nfunction imageBlock(url) {\n const data = /^data:(image\\/(?:png|jpeg|gif|webp));base64,(.*)$/s.exec(url);\n if (data)\n return { type: \"image\", source: { type: \"base64\", media_type: data[1], data: data[2] } };\n return { type: \"image\", source: { type: \"url\", url } };\n}\nvar IMAGE_SIGNATURES = [\n [\"iVBORw0KGgo\", \"image/png\"],\n [\"/9j/\", \"image/jpeg\"],\n [\"R0lGOD\", \"image/gif\"],\n [\"UklGR\", \"image/webp\"]\n];\nfunction base64Image(data) {\n const media = IMAGE_SIGNATURES.find(([signature]) => data.startsWith(signature))?.[1];\n return media ? { type: \"image\", source: { type: \"base64\", media_type: media, data } } : null;\n}\n\n// agent/session/codex/rpc.ts\nvar METHOD_NOT_FOUND = -32601;\nfunction spawnCodexAppServer(executable, { cwd, env }, handlers) {\n const args = [\"app-server\", \"-c\", \"tools.experimental_request_user_input.enabled=true\", \"--enable\", \"default_mode_request_user_input\"];\n const proc = Bun.spawn([executable.path, ...args], {\n cwd,\n env: { ...env, ...executable.env },\n stdin: \"pipe\",\n stdout: \"pipe\",\n stderr: \"pipe\"\n });\n const pending = new Map;\n let nextId = 1;\n function send(message) {\n proc.stdin.write(JSON.stringify(message) + `\n`);\n proc.stdin.flush();\n }\n function dispatch(message) {\n if (message.id !== undefined && message.method === undefined) {\n const waiting = pending.get(message.id);\n pending.delete(message.id);\n if (message.error)\n waiting?.reject(new Error(`codex: ${message.error.message ?? JSON.stringify(message.error)}`));\n else\n waiting?.resolve(message.result);\n return;\n }\n if (message.id !== undefined)\n handlers.onRequest(message);\n else\n handlers.onNotification(message);\n }\n async function readLines() {\n const decoder = new TextDecoder;\n let buffered = \"\";\n for await (const chunk of proc.stdout) {\n buffered += decoder.decode(chunk, { stream: true });\n let newline;\n while ((newline = buffered.indexOf(`\n`)) >= 0) {\n const line = buffered.slice(0, newline).trim();\n buffered = buffered.slice(newline + 1);\n if (line)\n dispatch(JSON.parse(line));\n }\n }\n }\n async function forwardStderr() {\n for await (const chunk of proc.stderr)\n process.stderr.write(chunk);\n }\n forwardStderr().catch(() => {});\n readLines().then(() => proc.exited).then(() => {\n const exit = { code: proc.exitCode, signal: proc.signalCode === null ? null : String(proc.signalCode) };\n finish(exit, exit.code === 0 ? undefined : new Error(`codex app-server exited with ${exit.signal ?? `code ${exit.code}`}`));\n }, (error) => finish(null, error));\n function finish(exit, error) {\n for (const waiting of pending.values())\n waiting.reject(error ?? new Error(\"codex app-server exited\"));\n pending.clear();\n handlers.onExit(exit, error);\n }\n function request(method, params) {\n const id = nextId++;\n return new Promise((resolve, reject) => {\n pending.set(id, { resolve: (result) => resolve(result), reject });\n send({ id, method, params });\n });\n }\n function notify(method) {\n send({ method });\n }\n function respond(id, result) {\n send({ id, result });\n }\n function respondError(id, message) {\n send({ id, error: { code: METHOD_NOT_FOUND, message } });\n }\n function close() {\n proc.stdin.end();\n proc.kill();\n }\n return { pid: proc.pid, request, notify, respond, respondError, close };\n}\n\n// agent/session/codex/transcript.ts\nvar ITEMS_PAGE = 100;\nvar CURSORS_KEPT = 1000;\nvar THREADS_SEARCHED = 50;\nvar cursors = new Map;\nfunction codexSubagentTranscript(source, subagentThreadId, toolUseId) {\n return codexTranscript({ ...source, nativeId: subagentThreadId }, toolUseId);\n}\nasync function codexFindSubagent(source, toolUseId) {\n const threads = [source.nativeId];\n const seen = new Set(threads);\n for (let thread = threads.shift();thread !== undefined && seen.size <= THREADS_SEARCHED; thread = threads.shift()) {\n const found = await codexReading({ ...source, nativeId: thread }, async (list) => {\n for (let cursor = null;; ) {\n const response = await list(cursor);\n for (const { item } of response.data) {\n if (item.type !== \"collabAgentToolCall\")\n continue;\n if (item.id === toolUseId)\n return item.receiverThreadIds[0] ?? null;\n for (const receiver of item.receiverThreadIds) {\n if (seen.has(receiver))\n continue;\n seen.add(receiver);\n threads.push(receiver);\n }\n }\n if (!response.nextCursor)\n return;\n cursor = response.nextCursor;\n }\n });\n if (found !== undefined)\n return found;\n }\n return null;\n}\nasync function codexReading({ nativeId: threadId, env, installDir }, read) {\n let rpc = null;\n rpc = spawnCodexAppServer(codexExecutable(installDir), { env }, {\n onNotification: () => {},\n onRequest: (request) => rpc?.respondError(request.id, \"this app-server only reads thread history\"),\n onExit: () => {}\n });\n const reader = rpc;\n try {\n await reader.request(\"initialize\", {\n clientInfo: { name: \"hyperbrane\", title: \"hyperbrane\", version: HYPERBRANE_VERSION },\n capabilities: { experimentalApi: true, requestAttestation: false }\n });\n reader.notify(\"initialized\");\n return await read((cursor) => reader.request(\"thread/items/list\", { threadId, cursor, limit: ITEMS_PAGE, sortDirection: \"desc\" }));\n } finally {\n reader.close();\n }\n}\nfunction codexTranscript(source, parentToolUseId = null) {\n const threadId = source.nativeId;\n const reading = (read) => codexReading(source, read);\n const messagesOf = (entry) => entryMessages(entry, threadId, \"\", parentToolUseId);\n const timeOf = (entry) => entry.startedAtMs ?? entry.completedAtMs ?? 0;\n const cursorKey = (time) => `${threadId} ${time}`;\n function keepCursor(time, cursor) {\n cursors.delete(cursorKey(time));\n cursors.set(cursorKey(time), cursor);\n if (cursors.size > CURSORS_KEPT)\n cursors.delete(cursors.keys().next().value);\n }\n const page = (before, limit) => reading((list) => pageOf(list, before, limit));\n const replay = (afterId, emit) => reading((list) => replayOf(list, afterId, emit));\n async function pageOf(list, before, limit) {\n let cursor = before === null ? null : cursors.get(cursorKey(before)) ?? null;\n const taken = [];\n let count = 0;\n let boundary = Infinity;\n let boundaryCursor = null;\n let older = false;\n pages:\n for (;; ) {\n const response = await list(cursor);\n for (const entry of response.data) {\n const time = timeOf(entry);\n if (before !== null && time >= before)\n continue;\n if (count >= limit && time < boundary) {\n older = true;\n break pages;\n }\n const messages = messagesOf(entry);\n if (messages.length === 0)\n continue;\n taken.push(messages);\n count += messages.length;\n if (count >= limit && boundary === Infinity) {\n boundary = time;\n boundaryCursor = cursor;\n }\n }\n if (!response.nextCursor)\n break;\n cursor = response.nextCursor;\n }\n if (older)\n keepCursor(boundary, boundaryCursor);\n return { messages: taken.reverse().flat(), nextBefore: older ? new Date(boundary).toISOString() : null };\n }\n async function replayOf(list, afterId, emit) {\n const newestFirst = [];\n let found = afterId === undefined;\n let cursor = null;\n scan:\n for (;; ) {\n const response = await list(cursor);\n for (const entry of response.data) {\n const messages = messagesOf(entry);\n newestFirst.push(messages);\n if (messages.some((message) => message.uuid === afterId)) {\n found = true;\n break scan;\n }\n }\n if (!response.nextCursor)\n break;\n cursor = response.nextCursor;\n }\n if (!found)\n return false;\n let passed = afterId === undefined;\n for (const messages of newestFirst.reverse()) {\n for (const message of messages) {\n if (passed)\n emit(message);\n else if (message.uuid === afterId)\n passed = true;\n }\n }\n return true;\n }\n return { page, replay };\n}\n\n// agent/session/codex/stream.ts\nasync function startCodexStream(context, hooks) {\n let threadId = context.nativeId ?? \"\";\n let model = context.model ?? \"\";\n let turn = null;\n const rpc = spawnCodexAppServer(codexExecutable(context.installDir), { cwd: context.cwd, env: context.env }, {\n onNotification,\n onRequest: (request) => hooks.onServerRequest(request, rpc),\n onExit: (exit, error) => context.exited(exit, error)\n });\n function base(parent = null, session = threadId) {\n return { parent_tool_use_id: parent, uuid: crypto.randomUUID(), session_id: session };\n }\n const subagentThreads = new Map;\n function noteSubagents(item) {\n if (item.type !== \"collabAgentToolCall\")\n return;\n for (const thread of item.receiverThreadIds) {\n if (subagentThreads.has(thread))\n continue;\n subagentThreads.set(thread, item.id);\n context.subagentStarted(item.id, thread);\n }\n }\n function delta(notification, parent, session = threadId) {\n switch (notification.method) {\n case \"item/agentMessage/delta\":\n return { type: \"stream_event\", event: { type: \"content_block_delta\", index: 0, delta: { type: \"text_delta\", text: notification.params.delta } }, ...base(parent, session) };\n case \"item/reasoning/summaryTextDelta\":\n case \"item/reasoning/textDelta\":\n return {\n type: \"stream_event\",\n event: { type: \"content_block_delta\", index: 0, delta: { type: \"thinking_delta\", thinking: notification.params.delta, estimated_tokens: null } },\n ...base(parent, session)\n };\n default:\n return null;\n }\n }\n function onSubagentNotification(notification, thread) {\n const parent = subagentThreads.get(thread);\n if (!parent)\n return;\n const streamed = delta(notification, parent, thread);\n if (streamed)\n return context.emit(streamed);\n if (notification.method === \"item/started\") {\n const { item } = notification.params;\n noteSubagents(item);\n const call = toolCallOf(item);\n if (call)\n context.emit({ ...underTool(assistantMessage(item.id, [call], thread, model), parent), timestamp: new Date(notification.params.startedAtMs).toISOString() });\n }\n if (notification.method === \"item/completed\") {\n const { item } = notification.params;\n noteSubagents(item);\n const messages = itemMessages(item, thread, model).map((message) => underTool(message, parent));\n const timestamp = new Date(notification.params.completedAtMs).toISOString();\n for (const message of toolCallOf(item) ? messages.slice(1) : messages)\n context.emit({ ...message, timestamp });\n }\n }\n function currentTurn(id) {\n turn ??= { id, startedAt: Date.now(), lastText: \"\", usage: null, errors: [] };\n turn.id ??= id;\n return turn;\n }\n function onNotification(notification) {\n const thread = notification.params?.threadId;\n if (typeof thread === \"string\" && threadId !== \"\" && thread !== threadId)\n return onSubagentNotification(notification, thread);\n for (const observer of hooks.observers)\n observer.observe(notification);\n const streamed = delta(notification, null);\n if (streamed)\n return context.emit(streamed);\n switch (notification.method) {\n case \"turn/started\":\n currentTurn(notification.params.turn.id);\n context.setNativeId(threadId);\n return;\n case \"item/started\": {\n const { item } = notification.params;\n noteSubagents(item);\n const call = toolCallOf(item);\n if (call)\n context.emit({ ...assistantMessage(item.id, [call], threadId, model), timestamp: new Date(notification.params.startedAtMs).toISOString() });\n return;\n }\n case \"item/completed\": {\n const { item } = notification.params;\n noteSubagents(item);\n if (item.type === \"agentMessage\")\n currentTurn(notification.params.turnId).lastText = item.text;\n if (item.type === \"userMessage\")\n return;\n const messages = itemMessages(item, threadId, model);\n const timestamp = new Date(notification.params.completedAtMs).toISOString();\n for (const message of toolCallOf(item) ? messages.slice(1) : messages)\n context.emit({ ...message, timestamp });\n return;\n }\n case \"thread/tokenUsage/updated\":\n currentTurn(notification.params.turnId).usage = notification.params.tokenUsage.last;\n return;\n case \"error\":\n if (!notification.params.willRetry)\n currentTurn(notification.params.turnId).errors.push(notification.params.error.message);\n return;\n case \"turn/completed\":\n context.emit(resultOf(currentTurn(notification.params.turn.id), notification.params.turn));\n turn = null;\n return;\n }\n }\n function resultOf(state, finished) {\n const duration = finished.durationMs ?? Date.now() - state.startedAt;\n const usage = resultUsage({\n input: state.usage?.inputTokens,\n output: state.usage?.outputTokens,\n cacheRead: state.usage?.cachedInputTokens,\n cacheWrite: state.usage?.cacheWriteInputTokens,\n thinking: state.usage?.reasoningOutputTokens\n });\n const common = {\n duration_ms: duration,\n duration_api_ms: duration,\n num_turns: 1,\n total_cost_usd: 0,\n usage,\n modelUsage: {},\n permission_denials: [],\n uuid: crypto.randomUUID(),\n session_id: threadId\n };\n if (finished.status === \"completed\") {\n return { type: \"result\", subtype: \"success\", is_error: false, result: state.lastText, stop_reason: \"end_turn\", ...common };\n }\n const errors = [...state.errors];\n if (finished.error)\n errors.push(finished.error.message);\n if (errors.length === 0)\n errors.push(`turn ${finished.status}`);\n return { type: \"result\", subtype: \"error_during_execution\", is_error: true, stop_reason: null, errors, ...common };\n }\n await rpc.request(\"initialize\", {\n clientInfo: { name: \"hyperbrane\", title: \"hyperbrane\", version: HYPERBRANE_VERSION },\n capabilities: { experimentalApi: true, requestAttestation: false }\n });\n rpc.notify(\"initialized\");\n const settings = {\n cwd: context.spec.cwd ?? null,\n model: context.model,\n approvalPolicy: codexApprovalPolicy(context.permissionMode),\n sandbox: \"danger-full-access\"\n };\n const started = threadId ? await rpc.request(\"thread/resume\", { threadId, ...settings }) : await rpc.request(\"thread/start\", settings);\n threadId = started.thread.id;\n model = started.model;\n return {\n rpc,\n threadId,\n model,\n activeTurn: () => turn?.id ?? null,\n emitToolUse: (id, name, input) => context.emit(assistantMessage(id, [{ type: \"tool_use\", id, name, input }], threadId, model)),\n emitToolResult: (id, content, isError) => context.emit(toolResultMessage(id, content, isError, threadId))\n };\n}\n\n// agent/session/codex/index.ts\nvar codexBackend = {\n install: installCodex,\n installed: installedCodex,\n auth: codexAuth,\n transcript: (source) => codexTranscript(source),\n findSubagent: codexFindSubagent,\n subagentTranscript: codexSubagentTranscript,\n homeEnvironment: codexHomeEnvironment,\n async start(context) {\n let thread;\n const current = () => thread;\n const queue = codexMessageQueue();\n const status = codexStatus(() => context.activeChanged());\n const input = createCodexInput(current, queue, context.model, context.permissionMode);\n const permissions = codexPermissions(context);\n const questions = codexQuestions(context, current);\n function onServerRequest(request, rpc) {\n if (request.method !== \"item/tool/requestUserInput\")\n return permissions(request, rpc);\n questions(request.params).then((response) => rpc.respond(request.id, response), (error) => rpc.respondError(request.id, error.message));\n }\n const backgroundTasks = codexBackgroundTasks();\n thread = await startCodexStream(context, { onServerRequest, observers: [backgroundTasks, status, queue] });\n return {\n sendMessage: input.sendMessage,\n active: status.active,\n getLastUserMessages: queue.lastUserMessages,\n cancel: codexInterrupt(current),\n ...codexModel(current, input),\n setPermissionMode: input.setPermissionMode,\n listBackgroundTasks: backgroundTasks.list,\n stopTask: (taskId) => backgroundTasks.stop(taskId, current().rpc.pid),\n async close() {\n current().rpc.close();\n }\n };\n }\n};\n\n// agent/session/backends.ts\nvar SESSION_BACKENDS = {\n claude: claudeBackend,\n codex: codexBackend\n};\n\n// dimension/paths.ts\nfunction containerName(dimensionName) {\n return `hyb-${dimensionName}`;\n}\nvar WORKSPACE_PATH = \"/workspace\";\nvar RUN_PATH = \"/run/hyperbrane\";\nvar STATE_PATH = \"/var/lib/hyperbrane\";\nvar CA_BUNDLE_PATH = \"/etc/ssl/certs/ca-certificates.crt\";\nvar TRANSPORT_SOCKET = \".transport.sock\";\nfunction dimensionRunDirectory(dataDirectory, dimensionName) {\n return `${dataDirectory}/dimension-run/${dimensionName}`;\n}\nfunction dimensionStateDirectory(dataDirectory, dimensionName) {\n return `${dataDirectory}/dimension-state/${dimensionName}`;\n}\nvar dimensionLayout = {\n containerName,\n workspacePath: () => WORKSPACE_PATH,\n runPath: () => RUN_PATH,\n statePath: () => STATE_PATH,\n caBundlePath: () => CA_BUNDLE_PATH,\n runDirectory: dimensionRunDirectory,\n stateDirectory: dimensionStateDirectory,\n transportSocketPath: (dataDirectory, dimensionName) => `${dimensionRunDirectory(dataDirectory, dimensionName)}/${TRANSPORT_SOCKET}`\n};\n\n// dimension/api.ts\nvar MEMORY_UNITS = {\n \"\": 1,\n K: 1024,\n M: 1024 ** 2,\n G: 1024 ** 3,\n T: 1024 ** 4\n};\n\n// agent/session/sessionStorage.ts\nfunction workerSocketPath(runDirectory, agentName) {\n return `${runDirectory}/${agentName}.sock`;\n}\nfunction workerReadyPath(runDirectory, agentName) {\n return `${runDirectory}/${agentName}.ready`;\n}\nfunction sessionsDirectory(stateDirectory, agentName) {\n return `${stateDirectory}/agents/${agentName}/sessions`;\n}\nfunction backendHomePath(stateDirectory, backend) {\n return `${stateDirectory}/backends/${backend}`;\n}\nfunction createSessionStorage(sandbox, agentName, { stateDirectory = dimensionLayout.statePath(), runDirectory = dimensionLayout.runPath() } = {}) {\n const sessionsDir = sessionsDirectory(stateDirectory, agentName);\n const sessions = createJsonDirectory(sandbox, async () => sessionsDir);\n const sessionDir = (sessionName) => `${sessionsDir}/${checkName(sessionName)}`;\n const permissionRequests = (sessionName) => createJsonDirectory(sandbox, async () => `${sessionDir(sessionName)}/permission-requests`);\n const questionRequests = (sessionName) => createJsonDirectory(sandbox, async () => `${sessionDir(sessionName)}/question-requests`);\n const sessionFiles = (sessionName) => createJsonDirectory(sandbox, async () => sessionDir(sessionName));\n const statusFiles = (sessionName) => createJsonDirectory(sandbox, async () => sessionDir(sessionName));\n async function oldestFirst(stored) {\n return (await stored).sort((a, b) => a.at - b.at).map((entry) => entry.request);\n }\n async function getSessions() {\n return sessions.list();\n }\n async function insertSession(record) {\n return sessions.insert(record.spec.name, record);\n }\n async function saveSession(record) {\n await sessions.save(record.spec.name, record);\n }\n async function removeSession(sessionName) {\n await sandbox.removeDirectory(sessionDir(sessionName));\n await sessions.remove(sessionName);\n }\n async function getPermissionRequests(sessionName) {\n return oldestFirst(permissionRequests(sessionName).list());\n }\n async function savePermissionRequest(sessionName, request) {\n await permissionRequests(sessionName).save(request.id, { request, at: Date.now() });\n }\n async function removePermissionRequest(sessionName, requestId) {\n await permissionRequests(sessionName).remove(requestId);\n }\n async function getQuestionRequests(sessionName) {\n return oldestFirst(questionRequests(sessionName).list());\n }\n async function saveQuestionRequest(sessionName, request) {\n await questionRequests(sessionName).save(request.id, { request, at: Date.now() });\n }\n async function removeQuestionRequest(sessionName, requestId) {\n await questionRequests(sessionName).remove(requestId);\n }\n async function readAuth(sessionName) {\n return sessionFiles(sessionName).read(\"auth\");\n }\n async function saveAuth(sessionName, record) {\n await sessionFiles(sessionName).save(\"auth\", record);\n }\n async function saveStatus(sessionName, status) {\n await statusFiles(sessionName).save(\"status\", { status });\n }\n async function socketPath() {\n return workerSocketPath(runDirectory, agentName);\n }\n async function backendHome(backend) {\n const path = backendHomePath(stateDirectory, backend);\n await sandbox.createDirectory(path);\n return path;\n }\n return {\n getSessions,\n insertSession,\n saveSession,\n removeSession,\n getPermissionRequests,\n savePermissionRequest,\n removePermissionRequest,\n getQuestionRequests,\n saveQuestionRequest,\n removeQuestionRequest,\n readAuth,\n saveAuth,\n saveStatus,\n socketPath,\n backendHome\n };\n}\n\n// agent/session/worker/protocol.ts\nvar WORKER_PROTOCOL = 3;\nvar WorkerErrorCode = {\n methodNotFound: -32601,\n invalidParams: -32602,\n internalError: -32603,\n notFound: -32004,\n conflict: -32009,\n backendNotInstalled: -32010,\n protocolMismatch: -32011\n};\n\nclass WorkerMethodNotFoundError extends Error {\n name = \"WorkerMethodNotFoundError\";\n}\n\nclass WorkerProtocolMismatchError extends Error {\n name = \"WorkerProtocolMismatchError\";\n}\nfunction encodeWorkerError(error) {\n const message = error instanceof Error ? error.message : String(error);\n if (error instanceof AgentInvalidError)\n return { code: WorkerErrorCode.invalidParams, message };\n if (error instanceof AgentNotFoundError)\n return { code: WorkerErrorCode.notFound, message };\n if (error instanceof AgentBackendNotInstalledError)\n return { code: WorkerErrorCode.backendNotInstalled, message };\n if (error instanceof AgentConflictError)\n return { code: WorkerErrorCode.conflict, message };\n if (error instanceof WorkerMethodNotFoundError)\n return { code: WorkerErrorCode.methodNotFound, message };\n if (error instanceof WorkerProtocolMismatchError)\n return { code: WorkerErrorCode.protocolMismatch, message };\n return { code: WorkerErrorCode.internalError, message };\n}\nfunction decodeWorkerError({ code, message }) {\n if (code === WorkerErrorCode.invalidParams)\n return new AgentInvalidError(message);\n if (code === WorkerErrorCode.notFound)\n return new AgentNotFoundError(message);\n if (code === WorkerErrorCode.conflict)\n return new AgentConflictError(message);\n if (code === WorkerErrorCode.backendNotInstalled)\n return new AgentBackendNotInstalledError(message);\n if (code === WorkerErrorCode.methodNotFound)\n return new WorkerMethodNotFoundError(`worker: ${message}`);\n if (code === WorkerErrorCode.protocolMismatch)\n return new WorkerProtocolMismatchError(`worker: ${message}`);\n return new Error(`worker: ${message}`);\n}\n\n// agent/session/worker/workerServer.ts\nimport { rm as rm2 } from \"fs/promises\";\n\n// agent/session/worker/jsonRpc.ts\nvar PARSE_ERROR = -32700;\nfunction createJsonRpcPeer(write, options) {\n const pending = new Map;\n let nextId = 1;\n let buffered = \"\";\n let closedWith;\n function send(message) {\n if (closedWith)\n return;\n write(JSON.stringify({ jsonrpc: \"2.0\", ...message }) + `\n`);\n }\n function handle(message) {\n if (message.method === undefined) {\n if (message.id === undefined || message.id === null)\n return;\n const waiting = pending.get(message.id);\n pending.delete(message.id);\n if (message.error)\n waiting?.reject(options.decodeError(message.error));\n else\n waiting?.resolve(message.result);\n return;\n }\n if (message.id === undefined || message.id === null) {\n options.onNotification?.(message.method, message.params);\n return;\n }\n const id = message.id;\n options.onRequest(message.method, message.params, message.protocol).then((result) => send({ id, result: result ?? null }), (error) => send({ id, error: options.encodeError(error) }));\n }\n function receive(text) {\n buffered += text;\n let newline;\n while ((newline = buffered.indexOf(`\n`)) >= 0) {\n const line = buffered.slice(0, newline).trim();\n buffered = buffered.slice(newline + 1);\n if (!line)\n continue;\n let message;\n try {\n message = JSON.parse(line);\n } catch {\n send({ id: null, error: { code: PARSE_ERROR, message: \"not JSON\" } });\n continue;\n }\n handle(message);\n }\n }\n function request(method, params) {\n if (closedWith)\n return Promise.reject(closedWith);\n const id = nextId++;\n return new Promise((resolve, reject) => {\n pending.set(id, { resolve, reject });\n send({ id, method, params, ...options.protocol === undefined ? {} : { protocol: options.protocol } });\n });\n }\n function notify(method, params) {\n send({ method, params });\n }\n function close(error) {\n closedWith ??= error;\n for (const waiting of pending.values())\n waiting.reject(error);\n pending.clear();\n }\n return { receive, request, notify, close };\n}\nfunction createSocketWriter(socket) {\n const encoder = new TextEncoder;\n let backlog = null;\n function write(text) {\n const bytes = encoder.encode(text);\n if (backlog) {\n const joined = new Uint8Array(backlog.length + bytes.length);\n joined.set(backlog);\n joined.set(bytes, backlog.length);\n backlog = joined;\n return;\n }\n const written = Math.max(socket.write(bytes), 0);\n if (written < bytes.length)\n backlog = bytes.subarray(written);\n }\n function drain() {\n if (!backlog)\n return;\n const written = Math.max(socket.write(backlog), 0);\n backlog = written < backlog.length ? backlog.subarray(written) : null;\n }\n return { write, drain };\n}\n\n// agent/session/worker/workerParams.ts\nvar WORKER_PARAMS = {\n \"worker/health\": () => ({}),\n \"worker/shutdown\": () => ({}),\n \"backend/install\": (params) => ({ backend: backend(params.backend) }),\n \"backend/list\": () => ({}),\n \"session/create\": (params) => ({ session: session(object(params.session, \"session\")) }),\n \"session/list\": () => ({}),\n \"session/update\": (params) => ({ session: name(params), limits: limits(object(params.limits, \"limits\")) }),\n \"session/stop\": (params) => ({ session: name(params) }),\n \"session/send\": (params) => ({ session: name(params), message: userMessage(params.message) }),\n \"session/interrupt\": (params) => ({ session: name(params) }),\n \"session/status\": (params) => ({ session: name(params) }),\n \"session/lastUserMessages\": (params) => ({ session: name(params) }),\n \"session/subscribe\": (params) => ({\n session: name(params),\n subscription: text(params.subscription, \"subscription\"),\n after_id: optional(params.after_id, (value) => text(value, \"after_id\"))\n }),\n \"session/unsubscribe\": (params) => ({ subscription: text(params.subscription, \"subscription\") }),\n \"session/transcript\": (params) => ({\n session: name(params),\n limit: optional(params.limit, (value) => number(value, \"limit\")),\n before: params.before === undefined ? optional(params.cursor, (value) => text(value, \"cursor\")) : text(params.before, \"before\")\n }),\n \"session/subagentTranscript\": (params) => ({\n session: name(params),\n toolUseId: text(params.toolUseId, \"toolUseId\"),\n limit: optional(params.limit, (value) => number(value, \"limit\")),\n before: optional(params.before, (value) => text(value, \"before\"))\n }),\n \"permission/list\": (params) => ({ session: name(params) }),\n \"permission/respond\": (params) => ({\n session: name(params),\n request: text(params.request, \"request\"),\n result: permissionResult(params.result)\n }),\n \"question/list\": (params) => ({ session: name(params) }),\n \"question/respond\": (params) => ({\n session: name(params),\n request: text(params.request, \"request\"),\n response: questionResponse(params.response)\n }),\n \"model/list\": (params) => ({ session: name(params) }),\n \"model/set\": (params) => ({\n session: name(params),\n model: params.model === null ? null : text(params.model, \"the model (a model name, or null for the backend's default)\")\n }),\n \"permission/mode\": (params) => ({ session: name(params), mode: permissionMode(params.mode) }),\n \"task/list\": (params) => ({ session: name(params) }),\n \"task/stop\": (params) => ({ session: name(params), task: text(params.task, \"task\") }),\n \"auth/status\": (params) => ({ session: name(params) }),\n \"auth/login\": (params) => ({\n session: name(params),\n gatewaySignedIn: optional(params.gatewaySignedIn, (value) => boolean(value, \"gatewaySignedIn\")) ?? false\n }),\n \"auth/code\": (params) => ({ session: name(params), code: text(params.code, \"the code (the one the sign-in page showed)\").trim() })\n};\nfunction invalid2(message) {\n throw new AgentInvalidError(message);\n}\nfunction name(params) {\n return text(params.session, \"session\");\n}\nfunction object(value, what) {\n if (value === null || typeof value !== \"object\" || Array.isArray(value))\n invalid2(`${what} must be an object`);\n return value;\n}\nfunction text(value, what) {\n if (typeof value !== \"string\" || value.trim() === \"\")\n invalid2(`${what} must be a non-empty string`);\n return value;\n}\nfunction number(value, what) {\n if (typeof value !== \"number\" || !Number.isFinite(value))\n invalid2(`${what} must be a number`);\n return value;\n}\nfunction boolean(value, what) {\n if (typeof value !== \"boolean\")\n invalid2(`${what} must be true or false`);\n return value;\n}\nfunction optional(value, parse) {\n return value === undefined ? undefined : parse(value);\n}\nfunction permissionMode(value) {\n const known = AGENT_PERMISSION_MODES.find((mode) => mode === value);\n if (!known)\n invalid2(`unknown permission mode \"${String(value)}\"; known: ${AGENT_PERMISSION_MODES.join(\", \")}`);\n return known;\n}\nfunction backend(value) {\n const known = AGENT_BACKENDS.find((name) => name === value);\n if (!known)\n invalid2(`unknown backend \"${String(value)}\"; known: ${AGENT_BACKENDS.join(\", \")}`);\n return known;\n}\nfunction memoryLimit(value) {\n const bytes = number(value, \"memoryLimit\");\n if (!(bytes > 0))\n invalid2(\"memoryLimit must be positive\");\n return bytes;\n}\nfunction cpuLimit(value) {\n const cores = number(value, \"cpuLimit\");\n if (!(cores > 0))\n invalid2(\"cpuLimit must be positive\");\n return cores;\n}\nfunction environment(value) {\n const fields = object(value, \"env\");\n for (const [key, entry] of Object.entries(fields))\n if (typeof entry !== \"string\")\n invalid2(`env.${key} must be a string`);\n return fields;\n}\nfunction session(fields) {\n return {\n name: text(fields.name, \"the session's name\"),\n backend: backend(fields.backend),\n memoryLimit: memoryLimit(fields.memoryLimit),\n cpuLimit: cpuLimit(fields.cpuLimit),\n cwd: optional(fields.cwd, (value) => text(value, \"cwd\")),\n env: optional(fields.env, environment)\n };\n}\nfunction limits(fields) {\n return { memoryLimit: optional(fields.memoryLimit, memoryLimit), cpuLimit: optional(fields.cpuLimit, cpuLimit) };\n}\nfunction userMessage(value) {\n const fields = object(value, 'a message (an SDK user message: {type: \"user\", message})');\n if (fields.type !== \"user\")\n invalid2('a message is an SDK user message: {type: \"user\", message}');\n const message = object(fields.message, \"message.message\");\n if (message.role !== \"user\")\n invalid2('message.message.role must be \"user\"');\n if (typeof message.content !== \"string\" && !Array.isArray(message.content))\n invalid2(\"message.message.content must be a string or an array of content blocks\");\n return value;\n}\nfunction permissionResult(value) {\n const fields = object(value, \"result\");\n if (fields.behavior === \"allow\") {\n return { behavior: \"allow\", updatedInput: optional(fields.updatedInput, (input) => object(input, \"updatedInput\")) };\n }\n if (fields.behavior === \"deny\") {\n return {\n behavior: \"deny\",\n message: typeof fields.message === \"string\" ? fields.message : invalid2(\"a denial needs a message\"),\n interrupt: optional(fields.interrupt, (interrupt) => boolean(interrupt, \"interrupt\"))\n };\n }\n return invalid2('a permission result is {behavior: \"allow\"} or {behavior: \"deny\", message}');\n}\nfunction questionResponse(value) {\n const answers = object(object(value, \"response\").answers, \"a question response's answers ({<question>: <answer>})\");\n for (const [question, answer] of Object.entries(answers))\n if (typeof answer !== \"string\")\n invalid2(`the answer to \"${question}\" must be a string`);\n return { answers };\n}\n\n// agent/session/worker/workerServer.ts\nvar ANY_PROTOCOL = new Set([\"worker/health\", \"worker/shutdown\"]);\nfunction createWorkerServer(service, options) {\n let listener;\n function ref(session) {\n return { agentName: options.health.agentName, sessionName: session };\n }\n const handlers = {\n \"worker/health\": async () => options.health,\n \"worker/shutdown\": async () => {\n setTimeout(options.onShutdown, 0);\n return null;\n },\n \"backend/install\": async ({ backend }) => nothing(await service.install(options.health.agentName, backend)),\n \"backend/list\": () => service.listBackends(options.health.agentName),\n \"session/create\": ({ session }) => service.createSession(options.health.agentName, session),\n \"session/list\": () => service.listSessions(),\n \"session/update\": ({ session, limits }) => service.updateSession(ref(session), limits),\n \"session/stop\": async ({ session }) => nothing(await service.stopSession(ref(session))),\n \"session/send\": async ({ session, message }) => nothing(await service.sendMessage(ref(session), message)),\n \"session/interrupt\": async ({ session }) => nothing(await service.cancel(ref(session))),\n \"session/status\": ({ session }) => service.getSessionStatus(ref(session)),\n \"session/lastUserMessages\": ({ session }) => service.getLastUserMessages(ref(session)),\n \"session/subscribe\": async ({ session, subscription, after_id }, connection) => {\n if (connection.subscriptions.has(subscription))\n throw new AgentConflictError(`subscription ${subscription} already exists`);\n let unsubscribe = null;\n let cancelled = false;\n connection.subscriptions.set(subscription, () => {\n cancelled = true;\n unsubscribe?.();\n });\n try {\n unsubscribe = await service.subscribe(ref(session), after_id, (message) => {\n const notification = { subscription, message };\n connection.peer.notify(\"session/message\", notification);\n });\n } catch (error) {\n connection.subscriptions.delete(subscription);\n throw error;\n }\n if (cancelled)\n unsubscribe();\n return null;\n },\n \"session/unsubscribe\": async ({ subscription }, connection) => {\n connection.subscriptions.get(subscription)?.();\n connection.subscriptions.delete(subscription);\n return null;\n },\n \"session/transcript\": ({ session, limit, before }) => service.getTranscript(ref(session), { limit, before }),\n \"session/subagentTranscript\": ({ session, toolUseId, limit, before }) => service.getTranscript(ref(session), { limit, before, toolUseId }),\n \"permission/list\": ({ session }) => service.listPermissionRequests(ref(session)),\n \"permission/respond\": async ({ session, request, result }) => nothing(await service.respondPermissionRequest(ref(session), request, result)),\n \"question/list\": ({ session }) => service.listQuestionRequests(ref(session)),\n \"question/respond\": async ({ session, request, response }) => nothing(await service.respondQuestionRequest(ref(session), request, response)),\n \"model/list\": ({ session }) => service.listModels(ref(session)),\n \"model/set\": async ({ session, model }) => nothing(await service.setModel(ref(session), model)),\n \"permission/mode\": async ({ session, mode }) => nothing(await service.setPermissionMode(ref(session), mode)),\n \"task/list\": ({ session }) => service.listBackgroundTasks(ref(session)),\n \"task/stop\": async ({ session, task }) => nothing(await service.stopTask(ref(session), task)),\n \"auth/status\": ({ session }) => service.getAuthStatus(ref(session)),\n \"auth/login\": ({ session, gatewaySignedIn }) => service.login(ref(session), gatewaySignedIn),\n \"auth/code\": ({ session, code }) => service.submitAuthCode(ref(session), code)\n };\n function handle(method, params, connection) {\n return handlers[method](WORKER_PARAMS[method](params), connection);\n }\n async function dispatch(method, params, connection) {\n if (!isWorkerMethod(method))\n throw new WorkerMethodNotFoundError(`no method ${method}`);\n const fields = params ?? {};\n if (typeof fields !== \"object\" || Array.isArray(fields))\n throw new AgentInvalidError(`${method} takes an object of params`);\n return handle(method, fields, connection);\n }\n function openConnection(socket) {\n const writer = createSocketWriter(socket);\n const peer = createJsonRpcPeer(writer.write, {\n onRequest: (method, params, protocol) => {\n if (protocol !== undefined && protocol !== options.health.protocol && !ANY_PROTOCOL.has(method)) {\n return Promise.reject(new WorkerProtocolMismatchError(`this worker speaks protocol ${options.health.protocol}, not ${protocol}`));\n }\n return dispatch(method, params, connection);\n },\n encodeError: (error) => {\n const encoded = encodeWorkerError(error);\n if (encoded.code === WorkerErrorCode.internalError)\n console.error(error);\n return encoded;\n },\n decodeError: decodeWorkerError\n });\n const connection = { peer, writer, subscriptions: new Map, decoder: new TextDecoder };\n return connection;\n }\n async function start() {\n await rm2(options.socketPath, { force: true });\n listener = Bun.listen({\n unix: options.socketPath,\n socket: {\n open(socket) {\n socket.data = openConnection(socket);\n },\n data(socket, data) {\n socket.data.peer.receive(socket.data.decoder.decode(data, { stream: true }));\n },\n drain(socket) {\n socket.data.writer.drain();\n },\n close(socket) {\n for (const unsubscribe of socket.data.subscriptions.values())\n unsubscribe();\n socket.data.subscriptions.clear();\n socket.data.peer.close(new Error(\"the connection closed\"));\n },\n error(_socket, error) {\n console.error(\"worker connection failed:\", error);\n }\n }\n });\n }\n function stop() {\n listener?.stop(true);\n listener = undefined;\n }\n return { start, stop };\n}\nfunction isWorkerMethod(method) {\n return Object.hasOwn(WORKER_PARAMS, method);\n}\nfunction nothing(_done) {\n return null;\n}\n\n// agent/session/workerService.ts\nimport { statSync } from \"fs\";\n\n// agent/session/pending.ts\nfunction createPendingRequests(store, fallback) {\n const waiting = new Map;\n function add(request, signal) {\n const id = crypto.randomUUID();\n return new Promise((resolve) => {\n let settled = false;\n const settle = (response) => {\n if (settled)\n return;\n settled = true;\n waiting.delete(id);\n signal?.removeEventListener(\"abort\", aborted);\n store.remove(id).catch((error) => console.error(`removing request ${id} failed:`, error));\n resolve(response);\n };\n const aborted = () => settle(fallback(\"the request was cancelled\"));\n if (signal?.aborted)\n return aborted();\n signal?.addEventListener(\"abort\", aborted);\n waiting.set(id, settle);\n store.save({ ...request, id }).catch((error) => {\n console.error(`keeping request ${id} failed:`, error);\n settle(fallback(\"the request couldn't be kept\"));\n });\n });\n }\n async function list() {\n return (await store.list()).filter((request) => waiting.has(request.id));\n }\n async function answer(id, response) {\n const settle = waiting.get(id);\n if (!settle)\n return false;\n settle(response);\n return true;\n }\n async function dropAll(reason) {\n for (const settle of [...waiting.values()])\n settle(fallback(reason));\n for (const request of await store.list())\n if (!waiting.has(request.id))\n await store.remove(request.id);\n }\n return { add, list, count: () => waiting.size, answer, dropAll };\n}\n\n// agent/session/workerService.ts\nfunction createWorkerService(config) {\n const sessions = new Map;\n let installing = Promise.resolve();\n const installs = new Map;\n async function loadSessions() {\n for (const record of await config.storage.getSessions()) {\n const state = await newState(record);\n sessions.set(record.spec.name, state);\n noteStatus(state);\n await dropRequests(state, \"the worker restarted\");\n const auth = await config.storage.readAuth(record.spec.name);\n if (auth?.login)\n await config.storage.saveAuth(record.spec.name, { login: null, error: auth.error });\n }\n }\n async function newState(record) {\n return {\n ...record,\n listeners: new Set,\n running: null,\n startedAt: 0,\n generation: 0,\n session: null,\n login: null,\n accepted: null,\n sending: new Map,\n pending: [],\n draining: null,\n handing: null,\n exit: null,\n failure: null,\n tools: new Map,\n subagents: new Map,\n permissionMode: record.permissionMode ?? \"ask\",\n turnOpen: false,\n status: null,\n statusSaving: Promise.resolve(),\n permissionRequests: createPendingRequests({\n list: () => config.storage.getPermissionRequests(record.spec.name),\n save: (request) => config.storage.savePermissionRequest(record.spec.name, request),\n remove: (id) => config.storage.removePermissionRequest(record.spec.name, id)\n }, (message) => ({ behavior: \"deny\", message })),\n questionRequests: createPendingRequests({\n list: () => config.storage.getQuestionRequests(record.spec.name),\n save: (request) => config.storage.saveQuestionRequest(record.spec.name, request),\n remove: (id) => config.storage.removeQuestionRequest(record.spec.name, id)\n }, () => null)\n };\n }\n async function saveRecord(state) {\n await config.storage.saveSession({ spec: state.spec, nativeId: state.nativeId, model: state.model, permissionMode: state.permissionMode });\n }\n async function info(state) {\n return { ...state.spec, agentName: config.agentName, status: currentStatus(state), nativeId: state.nativeId, model: state.model, permissionMode: state.permissionMode };\n }\n function statusOf(state) {\n if (!state.running) {\n const exited = { state: \"exited\", code: state.exit?.code ?? null, signal: state.exit?.signal ?? null };\n return state.failure ? { ...exited, error: state.failure } : exited;\n }\n if (!state.session) {\n const install = installs.get(state.spec.backend);\n return install ? { state: \"installing\", backend: state.spec.backend, version: install.version } : { state: \"starting\" };\n }\n if (state.permissionRequests.count() + state.questionRequests.count() > 0)\n return { state: \"waiting\" };\n if (!state.session.active())\n return { state: \"idle\" };\n if (state.tools.size > 0)\n return { state: \"tool\", tools: [...state.tools.values()] };\n return { state: \"thinking\" };\n }\n async function lastStoredPrompt(state) {\n const transcript = await transcriptOf(state);\n let before = null;\n while (transcript) {\n const page = await transcript.page(before, LAST_PROMPT_PAGE_SIZE);\n const prompt = page.messages.findLast((message) => message.type === \"user\" && isPrompt(message.message.content));\n if (prompt?.type === \"user\")\n return { message: prompt, queued: false };\n if (!page.nextBefore)\n return null;\n before = Date.parse(page.nextBefore);\n }\n return null;\n }\n function trustChangedSince(time) {\n if (!config.trustBundle)\n return false;\n try {\n return statSync(config.trustBundle).mtimeMs > time;\n } catch {\n return false;\n }\n }\n function requireAgent(agentName) {\n if (agentName !== config.agentName)\n throw new AgentNotFoundError(`this worker runs agent ${config.agentName}, not ${agentName}`);\n }\n function requireSession({ agentName, sessionName }) {\n requireAgent(agentName);\n const state = sessions.get(sessionName);\n if (!state)\n throw new AgentNotFoundError(`session ${sessionName} does not exist`);\n return state;\n }\n async function dropRequests(state, reason) {\n await Promise.all([state.permissionRequests.dropAll(reason), state.questionRequests.dropAll(reason)]);\n }\n function broadcast(state, message) {\n if (message.type === \"result\")\n state.turnOpen = false;\n else if (message.type === \"user\" || message.type === \"assistant\")\n state.turnOpen = true;\n noteToolCalls(state, message);\n for (const listener of state.listeners)\n listener(message);\n if (message.type !== \"stream_event\")\n noteStatus(state);\n }\n function noteToolCalls(state, message) {\n if (message.type === \"assistant\" && message.parent_tool_use_id === null) {\n for (const block of message.message.content)\n if (block.type === \"tool_use\" || block.type === \"mcp_tool_use\")\n state.tools.set(block.id, block.name);\n }\n if (message.type === \"user\" && Array.isArray(message.message.content)) {\n for (const block of message.message.content)\n if (block.type === \"tool_result\")\n state.tools.delete(block.tool_use_id);\n }\n }\n function noteStatus(state) {\n const computed = statusOf(state);\n if (state.status && sameStatus(computed, state.status))\n return;\n const status = { ...computed, since: Date.now() };\n state.status = status;\n for (const listener of state.listeners)\n listener({ type: \"session_status\", status });\n state.statusSaving = state.statusSaving.then(async () => {\n if (sessions.get(state.spec.name) !== state)\n return;\n await config.storage.saveStatus(state.spec.name, status);\n }).catch((error) => console.error(`saving session ${state.spec.name}'s status failed:`, error));\n }\n function currentStatus(state) {\n noteStatus(state);\n return state.status;\n }\n async function transcriptSource(state) {\n if (!state.nativeId)\n return null;\n return { nativeId: state.nativeId, env: await environmentOf(state), files: config.files, installDir: config.installDir };\n }\n async function transcriptOf(state) {\n const source = await transcriptSource(state);\n return source && config.backends[state.spec.backend].transcript(source);\n }\n async function subagentTranscriptOf(state, toolUseId) {\n const source = await transcriptSource(state);\n if (!source)\n return null;\n const backend = config.backends[state.spec.backend];\n const subagent = state.subagents.get(toolUseId) ?? await backend.findSubagent(source, toolUseId);\n return subagent ? backend.subagentTranscript(source, subagent, toolUseId) : null;\n }\n async function environmentOf(state) {\n const env = {};\n for (const [key, value] of Object.entries(process.env))\n if (value !== undefined)\n env[key] = value;\n const backend = config.backends[state.spec.backend];\n return { ...env, ...backend.homeEnvironment(await config.storage.backendHome(state.spec.backend)), ...state.spec.env };\n }\n async function authEnvironment(state) {\n return { installDir: config.installDir, env: await environmentOf(state), cwd: state.spec.cwd ?? process.cwd() };\n }\n function runInstall(backend, version) {\n const underway = installs.get(backend);\n if (underway)\n return underway.done;\n const run = installing.then(() => config.backends[backend].install(config.installDir));\n installing = run.catch(() => {});\n const done = run.finally(() => {\n installs.delete(backend);\n noteBackendStatus(backend);\n });\n installs.set(backend, { version, done });\n noteBackendStatus(backend);\n return done;\n }\n function noteBackendStatus(backend) {\n for (const state of sessions.values())\n if (state.spec.backend === backend)\n noteStatus(state);\n }\n async function ensureBackend(state) {\n const backend = state.spec.backend;\n const installed = await config.backends[backend].installed(config.installDir);\n if (installed.ready && installed.version === installed.pinned)\n return;\n try {\n await runInstall(backend, installed.pinned);\n } catch (error) {\n const reason = error.message;\n if (!installed.ready)\n throw new AgentBackendNotInstalledError(`installing ${backend} ${installed.pinned} failed: ${reason}`);\n console.error(`updating ${backend} to ${installed.pinned} failed:`, error);\n broadcast(state, { type: \"session_notice\", text: `updating ${backend} from ${installed.version} to ${installed.pinned} failed, so ${installed.version} runs: ${reason}` });\n }\n }\n async function authStatus(state) {\n const auth = await config.storage.readAuth(state.spec.name);\n if (state.login && auth?.login)\n return auth.login;\n const backend = state.spec.backend;\n if (!(await config.backends[backend].installed(config.installDir)).ready) {\n return { state: \"signedOut\", error: `${backend} isn't installed yet: it installs when the session's CLI first starts` };\n }\n if (await config.backends[state.spec.backend].auth.signedIn(await authEnvironment(state)))\n return { state: \"signedIn\" };\n return auth?.error ? { state: \"signedOut\", error: auth.error } : { state: \"signedOut\" };\n }\n function saveAuth(state, record) {\n return config.storage.saveAuth(state.spec.name, record);\n }\n function watchLogin(state, login) {\n return login.done.then(async () => {\n if (state.login?.process !== login)\n return;\n state.login = null;\n await saveAuth(state, { login: null, error: null });\n if (statusOf(state).state === \"idle\")\n await closeSession(state);\n }, async (error) => {\n if (state.login?.process !== login)\n return;\n state.login = null;\n await saveAuth(state, { login: null, error: error.message });\n });\n }\n async function settleLogin(state, settled, timeoutMs) {\n await Promise.race([settled, Bun.sleep(timeoutMs)]);\n return authStatus(state);\n }\n function contextFor(state, generation, env) {\n const current = () => state.generation === generation;\n return {\n spec: state.spec,\n nativeId: state.nativeId,\n cwd: state.spec.cwd ?? process.cwd(),\n model: state.model,\n permissionMode: state.permissionMode,\n installDir: config.installDir,\n env,\n emit(message) {\n if (!current())\n return;\n broadcast(state, message);\n },\n setNativeId(id) {\n if (!current() || state.nativeId === id)\n return;\n state.nativeId = id;\n saveRecord(state).catch((error) => console.error(`saving session ${state.spec.name} failed:`, error));\n },\n async requestPermission(request, signal) {\n if (!current())\n return { behavior: \"deny\", message: \"the session stopped\" };\n if (state.permissionMode === \"auto\")\n return { behavior: \"allow\", updatedInput: request.input };\n const answer = state.permissionRequests.add(request, signal);\n noteStatus(state);\n return answer.finally(() => noteStatus(state));\n },\n async askQuestions(request, signal) {\n if (!current())\n return null;\n const answer = state.questionRequests.add(request, signal);\n noteStatus(state);\n return answer.finally(() => noteStatus(state));\n },\n subagentStarted(toolUseId, subagentId) {\n if (!current())\n return;\n state.subagents.set(toolUseId, subagentId);\n if (state.subagents.size > SUBAGENTS_KEPT)\n state.subagents.delete(state.subagents.keys().next().value);\n },\n activeChanged() {\n if (!current())\n return;\n if (!state.session?.active())\n state.tools.clear();\n noteStatus(state);\n },\n exited(exit, error) {\n if (!current())\n return;\n state.running = null;\n state.session = null;\n state.exit = exit;\n state.failure = error ? `${state.spec.backend} exited: ${error.message}` : null;\n state.tools.clear();\n if (error)\n console.error(`session ${state.spec.name} exited:`, error);\n if (state.turnOpen) {\n broadcast(state, {\n type: \"result\",\n subtype: \"error_during_execution\",\n duration_ms: 0,\n duration_api_ms: 0,\n is_error: true,\n num_turns: 0,\n stop_reason: null,\n total_cost_usd: 0,\n usage: resultUsage(),\n modelUsage: {},\n permission_denials: [],\n errors: [`the agent exited${error ? `: ${error.message}` : \"\"}`],\n uuid: crypto.randomUUID(),\n session_id: state.nativeId ?? \"\"\n });\n }\n noteStatus(state);\n dropRequests(state, \"the agent exited\").catch((error) => console.error(`dropping ${state.spec.name}'s requests failed:`, error));\n }\n };\n }\n function ensureRunning(state) {\n if (state.running)\n return state.running;\n const generation = ++state.generation;\n state.startedAt = Date.now();\n state.failure = null;\n const backend = state.spec.backend;\n const starting = ensureBackend(state).then(() => environmentOf(state)).then((env) => config.backends[backend].start(contextFor(state, generation, env)).catch((error) => {\n throw new Error(`${backend} didn't start: ${error.message}`);\n }));\n state.running = starting;\n noteStatus(state);\n starting.then((session) => {\n if (state.generation === generation)\n state.session = session;\n noteStatus(state);\n }, (error) => {\n if (state.generation === generation) {\n state.running = null;\n state.failure = error.message;\n }\n noteStatus(state);\n });\n return starting;\n }\n async function closeSession(state) {\n const running = state.running;\n state.generation++;\n state.running = null;\n state.session = null;\n state.exit = null;\n state.failure = null;\n state.tools.clear();\n state.turnOpen = false;\n noteStatus(state);\n await dropRequests(state, \"the session stopped\");\n if (running)\n await (await running.catch(() => null))?.close();\n }\n async function cancelLogin(state) {\n if (!state.login)\n return;\n state.login.process.cancel();\n state.login = null;\n const auth = await config.storage.readAuth(state.spec.name);\n await saveAuth(state, { login: null, error: auth?.error ?? null });\n }\n async function listBackends(agentName) {\n requireAgent(agentName);\n return Promise.all(AGENT_BACKENDS.map(async (backend) => ({ backend, ...await config.backends[backend].installed(config.installDir) })));\n }\n async function install(agentName, backend) {\n requireAgent(agentName);\n await runInstall(backend, (await config.backends[backend].installed(config.installDir)).pinned);\n }\n async function createSession(agentName, session) {\n requireAgent(agentName);\n const spec = validSession(session);\n const existing = sessions.get(spec.name);\n if (existing) {\n if (!sameSpec(existing.spec, spec))\n throw new AgentConflictError(`session ${spec.name} already exists with a different spec`);\n return info(existing);\n }\n const record = await config.storage.insertSession({ spec, nativeId: null, model: null });\n const state = await newState(record);\n sessions.set(spec.name, state);\n noteStatus(state);\n return info(state);\n }\n async function listSessions() {\n return Promise.all([...sessions.values()].map(info));\n }\n async function updateSession(ref, limits) {\n const state = requireSession(ref);\n const { memoryLimit, cpuLimit } = limits;\n state.spec = { ...state.spec, memoryLimit: memoryLimit ?? state.spec.memoryLimit, cpuLimit: cpuLimit ?? state.spec.cpuLimit };\n await saveRecord(state);\n return info(state);\n }\n async function stopSession(ref) {\n requireAgent(ref.agentName);\n const state = sessions.get(ref.sessionName);\n if (!state)\n return;\n failPending(state, \"the session stopped\");\n sessions.delete(ref.sessionName);\n await closeSession(state);\n await state.statusSaving;\n state.login?.process.cancel();\n state.login = null;\n state.listeners.clear();\n await config.storage.removeSession(state.spec.name);\n }\n async function sendMessage(ref, sent) {\n const state = requireSession(ref);\n if (!sent.uuid)\n return deliver(state, sent);\n const uuid = sent.uuid;\n const underway = state.sending.get(uuid);\n if (underway)\n return underway;\n const sending = (async () => {\n const accepted = await acceptedOf(state);\n if (accepted.has(uuid))\n return;\n await deliver(state, sent);\n accepted.add(uuid);\n if (accepted.size > ACCEPTED_KEPT)\n accepted.delete(accepted.values().next().value);\n })();\n state.sending.set(uuid, sending);\n try {\n await sending;\n } finally {\n state.sending.delete(uuid);\n }\n }\n async function acceptedOf(state) {\n if (state.accepted)\n return state.accepted;\n const seeded = new Set;\n const transcript = await transcriptOf(state);\n const page = transcript ? await transcript.page(null, ACCEPTED_SEED_PAGE_SIZE) : null;\n for (const message of page?.messages ?? [])\n if (message.type === \"user\" && isPrompt(message.message.content))\n seeded.add(message.uuid);\n state.accepted ??= seeded;\n return state.accepted;\n }\n async function deliver(state, sent) {\n if (statusOf(state).state === \"idle\" && trustChangedSince(state.startedAt))\n await closeSession(state);\n state.pending.push({ ...sent, uuid: sent.uuid ?? crypto.randomUUID(), session_id: state.nativeId ?? \"\" });\n drain(state);\n }\n function drain(state) {\n if (state.draining)\n return;\n const current = () => sessions.get(state.spec.name) === state;\n state.draining = (async () => {\n while (state.pending.length > 0 && current()) {\n let running;\n try {\n running = await ensureRunning(state);\n } catch (error) {\n failPending(state, error.message);\n return;\n }\n if (state.session !== running)\n continue;\n const message = state.pending.shift();\n if (!message)\n return;\n state.handing = message;\n try {\n await running.sendMessage(message);\n } catch (error) {\n failPrompt(state, message, error.message);\n continue;\n } finally {\n state.handing = null;\n }\n broadcast(state, { ...message, timestamp: message.timestamp ?? new Date().toISOString() });\n }\n })().finally(() => {\n state.draining = null;\n if (state.pending.length > 0 && current())\n drain(state);\n });\n }\n function failPrompt(state, message, error) {\n state.accepted?.delete(message.uuid);\n broadcast(state, { type: \"prompt_failed\", uuid: message.uuid, error });\n }\n function failPending(state, error) {\n for (const message of state.pending.splice(0))\n failPrompt(state, message, error);\n }\n async function cancel(ref) {\n const state = requireSession(ref);\n failPending(state, \"the turn was interrupted\");\n await dropRequests(state, \"the turn was interrupted\");\n if (state.session)\n await state.session.cancel();\n }\n async function getSessionStatus(ref) {\n return currentStatus(requireSession(ref));\n }\n async function getLastUserMessages(ref) {\n const state = requireSession(ref);\n const waiting = [...state.handing ? [state.handing] : [], ...state.pending];\n const listed = state.session ? await state.session.getLastUserMessages() : await lastStoredPrompt(state).then((stored) => stored ? [stored] : []);\n const known = new Set(listed.map(({ message }) => message.uuid));\n return [...listed, ...waiting.filter((message) => !known.has(message.uuid)).map((message) => ({ message, queued: true }))];\n }\n async function subscribe(ref, afterId, emit) {\n const state = requireSession(ref);\n let held = [];\n const listener = (message) => held ? held.push(message) : emit(message);\n const status = currentStatus(state);\n state.listeners.add(listener);\n emit({ type: \"session_status\", status });\n const unsubscribe = () => void state.listeners.delete(listener);\n try {\n const replayed = new Set;\n const transcript = await transcriptOf(state);\n const found = transcript ? await transcript.replay(afterId, (message) => {\n replayed.add(message.uuid);\n emit(message);\n }) : afterId === undefined;\n if (!found) {\n throw new AgentInvalidError(`no message ${afterId} in session ${ref.sessionName}: after_id is the uuid of a user or assistant message (partial output and results aren't stored)`);\n }\n for (const message of held)\n if (!(\"uuid\" in message) || !replayed.has(message.uuid))\n emit(message);\n held = null;\n } catch (error) {\n unsubscribe();\n throw error;\n }\n return unsubscribe;\n }\n async function getTranscript(ref, request = {}) {\n const state = requireSession(ref);\n if (request.toolUseId !== undefined)\n return transcriptPage(await subagentTranscriptOf(state, request.toolUseId), request);\n return transcriptPage(await transcriptOf(state), request);\n }\n async function listPermissionRequests(ref) {\n return requireSession(ref).permissionRequests.list();\n }\n async function respondPermissionRequest(ref, requestId, result) {\n const state = requireSession(ref);\n if (!await state.permissionRequests.answer(requestId, result))\n throw new AgentNotFoundError(`no pending permission request ${requestId}`);\n }\n async function listQuestionRequests(ref) {\n return requireSession(ref).questionRequests.list();\n }\n async function respondQuestionRequest(ref, requestId, response) {\n const state = requireSession(ref);\n if (!await state.questionRequests.answer(requestId, response)) {\n throw new AgentNotFoundError(`no pending question request ${requestId}`);\n }\n }\n async function listModels(ref) {\n return (await ensureRunning(requireSession(ref))).listModels();\n }\n async function setModel(ref, model) {\n const state = requireSession(ref);\n state.model = model;\n await saveRecord(state);\n if (state.running)\n await (await state.running).setModel(model);\n }\n async function setPermissionMode(ref, mode) {\n const state = requireSession(ref);\n state.permissionMode = mode;\n await saveRecord(state);\n if (state.running)\n await (await state.running).setPermissionMode(mode);\n if (mode !== \"auto\")\n return;\n for (const request of await state.permissionRequests.list())\n await state.permissionRequests.answer(request.id, { behavior: \"allow\", updatedInput: request.input });\n }\n async function listBackgroundTasks(ref) {\n const state = requireSession(ref);\n return state.running ? (await state.running).listBackgroundTasks() : [];\n }\n async function stopTask(ref, taskId) {\n const state = requireSession(ref);\n if (!state.running)\n throw new AgentNotFoundError(`no background task ${taskId}: session ${ref.sessionName}'s CLI isn't running`);\n await (await state.running).stopTask(taskId);\n }\n async function login(ref, gatewaySignedIn) {\n const state = requireSession(ref);\n if (state.login)\n return authStatus(state);\n await ensureBackend(state);\n if (await config.backends[state.spec.backend].auth.signedIn(await authEnvironment(state)))\n return { state: \"signedIn\" };\n const login = config.backends[state.spec.backend].auth.login(await authEnvironment(state), gatewaySignedIn);\n const entry = { process: login, settled: Promise.resolve() };\n state.login = entry;\n await saveAuth(state, { login: null, error: null });\n entry.settled = watchLogin(state, login);\n try {\n const prompt = await Promise.race([\n login.prompt,\n Bun.sleep(LOGIN_PROMPT_TIMEOUT_MS).then(() => Promise.reject(new Error(\"the login didn't show where to sign in\")))\n ]);\n if (state.login === entry)\n await saveAuth(state, { login: { state: \"pending\", ...prompt }, error: null });\n } catch (error) {\n if (state.login === entry)\n await cancelLogin(state);\n await saveAuth(state, { login: null, error: error.message });\n return authStatus(state);\n }\n return settleLogin(state, entry.settled, gatewaySignedIn ? LOGIN_COMPLETION_TIMEOUT_MS : 0);\n }\n async function submitAuthCode(ref, code) {\n const state = requireSession(ref);\n const login = state.login;\n const prompt = (await config.storage.readAuth(ref.sessionName))?.login;\n if (!login || !prompt)\n throw new AgentInvalidError(`session ${ref.sessionName} has no sign-in waiting`);\n if (!prompt.needsCode)\n throw new AgentInvalidError(`session ${ref.sessionName}'s sign-in takes no code: finish it at ${prompt.url}`);\n login.process.submitCode(code);\n return settleLogin(state, login.settled, LOGIN_COMPLETION_TIMEOUT_MS);\n }\n async function close() {\n for (const state of sessions.values())\n failPending(state, \"the agent's worker stopped\");\n await Promise.all([...sessions.values()].map(closeSession));\n }\n return {\n load: loadSessions,\n close,\n install,\n listBackends,\n createSession,\n listSessions,\n updateSession,\n stopSession,\n sendMessage,\n cancel,\n getSessionStatus,\n getLastUserMessages,\n subscribe,\n getTranscript,\n listPermissionRequests,\n respondPermissionRequest,\n listQuestionRequests,\n respondQuestionRequest,\n listModels,\n setModel,\n setPermissionMode,\n listBackgroundTasks,\n stopTask,\n getAuthStatus: async (ref) => authStatus(requireSession(ref)),\n login,\n submitAuthCode\n };\n}\nvar LAST_PROMPT_PAGE_SIZE = 50;\nvar SUBAGENTS_KEPT = 1000;\nvar ACCEPTED_KEPT = 500;\nvar ACCEPTED_SEED_PAGE_SIZE = 100;\nfunction isPrompt(content) {\n if (typeof content === \"string\")\n return true;\n return Array.isArray(content) && content.some((block) => block.type === \"text\");\n}\nvar LOGIN_PROMPT_TIMEOUT_MS = 30000;\nvar LOGIN_COMPLETION_TIMEOUT_MS = 60000;\nfunction sameStatus(a, b) {\n const { since: _a, ...first } = a;\n const { since: _b, ...second } = b;\n return JSON.stringify(first) === JSON.stringify(second);\n}\nfunction validSession(spec) {\n try {\n checkName(spec.name);\n } catch (error) {\n if (error instanceof InvalidNameError)\n throw new AgentInvalidError(`invalid session name: ${error.message}`);\n throw error;\n }\n return { ...spec, cwd: spec.cwd ?? dimensionLayout.workspacePath() };\n}\nfunction sameSpec(a, b) {\n return a.backend === b.backend && a.memoryLimit === b.memoryLimit && a.cpuLimit === b.cpuLimit && a.cwd === b.cwd && JSON.stringify(a.env ?? {}) === JSON.stringify(b.env ?? {});\n}\n\n// agent/session/main.ts\nfunction required(name) {\n const value = process.env[name];\n if (!value)\n throw new Error(`${name} is not set`);\n return value;\n}\nvar agentName = required(\"HYB_AGENT\");\nvar build = required(\"HYB_WORKER_BUILD\");\nvar protocol = Number(process.env.HYB_WORKER_PROTOCOL ?? WORKER_PROTOCOL);\nvar files = createLocalService({ kind: \"local\" });\nvar storage = createSessionStorage(files, agentName);\nvar service = createWorkerService({\n agentName,\n storage,\n installDir: required(\"HYB_INSTALL_DIR\"),\n files: sandboxFiles(files),\n trustBundle: process.env.NODE_EXTRA_CA_CERTS,\n backends: SESSION_BACKENDS\n});\nvar socketPath = await storage.socketPath();\nvar readyPath = workerReadyPath(dirname2(socketPath), agentName);\nvar server = createWorkerServer(service, { socketPath, health: { agentName, build, protocol }, onShutdown: shutdown });\nfunction shutdown() {\n server.stop();\n rm3(readyPath, { force: true }).catch(() => {});\n service.close().catch((error) => console.error(\"stopping the sessions failed:\", error)).finally(() => process.exit(0));\n}\nfor (const signal of [\"SIGTERM\", \"SIGINT\"])\n process.once(signal, shutdown);\nawait service.load();\nawait server.start();\nvar socketOwner = process.env.HYB_SOCKET_OWNER;\nif (socketOwner) {\n const [uid, gid] = socketOwner.split(\":\").map(Number);\n await chown(socketPath, uid, gid);\n}\nawait writeFile3(readyPath, `${process.pid} ${build} ${protocol}\n`);\nconsole.log(`session worker for agent ${agentName} (build ${build}) listening on ${socketPath}`);\n";