hyperbrane 0.1.2 → 0.2.1

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 (300) hide show
  1. package/README.md +105 -23
  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 +64 -323
  6. package/dist/agent/agentStorage.d.ts +1 -20
  7. package/dist/agent/agentStorage.js +0 -30
  8. package/dist/agent/api.d.ts +105 -152
  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/dimensionAgentClient.d.ts +8 -0
  15. package/dist/agent/dimensionAgentClient.js +99 -0
  16. package/dist/agent/hostTranscript.d.ts +0 -6
  17. package/dist/agent/hostTranscript.js +3 -14
  18. package/dist/agent/session/backend.d.ts +18 -32
  19. package/dist/agent/session/claude/home.d.ts +0 -1
  20. package/dist/agent/session/claude/home.js +0 -1
  21. package/dist/agent/session/claude/provision.d.ts +10 -0
  22. package/dist/agent/session/claude/provision.js +17 -0
  23. package/dist/agent/session/claude/transcript.d.ts +3 -7
  24. package/dist/agent/session/claude/transcript.js +68 -14
  25. package/dist/agent/session/client.d.ts +1 -10
  26. package/dist/agent/session/client.js +0 -3
  27. package/dist/agent/session/codex/provision.d.ts +14 -0
  28. package/dist/agent/session/codex/provision.js +25 -0
  29. package/dist/agent/session/fileTranscript.d.ts +6 -49
  30. package/dist/agent/session/fileTranscript.js +26 -82
  31. package/dist/agent/session/install.d.ts +5 -0
  32. package/dist/agent/session/install.js +35 -0
  33. package/dist/agent/session/sessionStorage.d.ts +4 -35
  34. package/dist/agent/session/sessionStorage.js +10 -16
  35. package/dist/agent/session/sharedConnection.d.ts +0 -8
  36. package/dist/agent/session/sharedConnection.js +0 -7
  37. package/dist/agent/session/storedTranscripts.d.ts +1 -6
  38. package/dist/agent/session/storedTranscripts.js +0 -3
  39. package/dist/agent/session/worker/jsonRpc.d.ts +2 -13
  40. package/dist/agent/session/worker/jsonRpc.js +2 -11
  41. package/dist/agent/session/worker/protocol.d.ts +30 -21
  42. package/dist/agent/session/worker/protocol.js +29 -18
  43. package/dist/agent/session/worker/workerParams.d.ts +0 -5
  44. package/dist/agent/session/worker/workerParams.js +24 -17
  45. package/dist/agent/session/workerConnection.d.ts +2 -13
  46. package/dist/agent/session/workerConnection.js +7 -12
  47. package/dist/agent/session/workerGatewayConnection.d.ts +18 -0
  48. package/dist/agent/session/workerGatewayConnection.js +86 -0
  49. package/dist/agent/vendor-types/manifest.json +32 -0
  50. package/dist/agent/workerBundle.d.ts +4 -19
  51. package/dist/agent/workerBundle.generated.js +1 -1
  52. package/dist/agent/workerBundle.js +3 -30
  53. package/dist/agent/workerReplacement.d.ts +3 -0
  54. package/dist/agent/workerReplacement.js +49 -0
  55. package/dist/cli/agent.js +31 -16
  56. package/dist/cli/command.d.ts +10 -11
  57. package/dist/cli/command.js +0 -4
  58. package/dist/cli/dimension.js +6 -6
  59. package/dist/cli/gateway.js +3 -6
  60. package/dist/cli/main.js +14 -31
  61. package/dist/cli/streamPrinter.d.ts +2 -10
  62. package/dist/cli/streamPrinter.js +16 -46
  63. package/dist/cli/table.d.ts +0 -3
  64. package/dist/cli/table.js +0 -4
  65. package/dist/dimension/api.d.ts +42 -27
  66. package/dist/dimension/api.js +28 -47
  67. package/dist/dimension/client.d.ts +5 -0
  68. package/dist/dimension/client.js +4 -0
  69. package/dist/dimension/control.d.ts +22 -0
  70. package/dist/dimension/control.js +346 -0
  71. package/dist/dimension/image.d.ts +0 -5
  72. package/dist/dimension/image.js +0 -8
  73. package/dist/dimension/imageFiles.generated.js +1 -1
  74. package/dist/dimension/paths.d.ts +5 -4
  75. package/dist/dimension/paths.js +15 -6
  76. package/dist/dimension/service.d.ts +8 -24
  77. package/dist/dimension/service.js +85 -227
  78. package/dist/dimension/transport-worker.d.ts +1 -0
  79. package/dist/dimension/transport-worker.js +151 -0
  80. package/dist/dimension/transportBundle.d.ts +2 -0
  81. package/dist/dimension/transportBundle.generated.d.ts +1 -0
  82. package/dist/dimension/transportBundle.generated.js +2 -0
  83. package/dist/dimension/transportBundle.js +4 -0
  84. package/dist/dimension/transportClient.d.ts +10 -0
  85. package/dist/dimension/transportClient.js +115 -0
  86. package/dist/dimension/transportProtocol.d.ts +53 -0
  87. package/dist/dimension/transportProtocol.js +8 -0
  88. package/dist/index.d.ts +7 -9
  89. package/dist/index.js +7 -19
  90. package/dist/lib/control.d.ts +11 -0
  91. package/dist/lib/control.js +62 -0
  92. package/dist/lib/docker.d.ts +0 -22
  93. package/dist/lib/docker.js +0 -10
  94. package/dist/lib/image.d.ts +0 -3
  95. package/dist/lib/image.js +0 -2
  96. package/dist/lib/jsonDirectory.d.ts +0 -13
  97. package/dist/lib/jsonDirectory.js +34 -18
  98. package/dist/lib/scriptBundle.d.ts +6 -0
  99. package/dist/lib/scriptBundle.js +28 -0
  100. package/dist/lib/sh.d.ts +2 -0
  101. package/dist/lib/sh.js +8 -0
  102. package/dist/lib/sleep.d.ts +0 -1
  103. package/dist/lib/sleep.js +0 -1
  104. package/dist/lib/streamFetch.d.ts +15 -0
  105. package/dist/lib/streamFetch.js +150 -0
  106. package/dist/lib/tar.d.ts +0 -1
  107. package/dist/lib/tar.js +5 -11
  108. package/dist/lib/unixSocket.d.ts +2 -0
  109. package/dist/lib/unixSocket.js +28 -0
  110. package/dist/portal-gateway/api.d.ts +14 -44
  111. package/dist/portal-gateway/api.js +1 -3
  112. package/dist/portal-gateway/control.d.ts +42 -0
  113. package/dist/portal-gateway/control.js +657 -0
  114. package/dist/portal-gateway/gatewayClient.d.ts +5 -0
  115. package/dist/portal-gateway/gatewayClient.js +4 -0
  116. package/dist/portal-gateway/gatewayService.d.ts +8 -38
  117. package/dist/portal-gateway/gatewayService.js +82 -254
  118. package/dist/portal-gateway/image.d.ts +0 -1
  119. package/dist/portal-gateway/image.js +0 -2
  120. package/dist/portal-gateway/imageFiles.generated.js +2 -2
  121. package/dist/portal-gateway/portalClient.d.ts +5 -0
  122. package/dist/portal-gateway/portalClient.js +4 -0
  123. package/dist/portal-gateway/portalService.d.ts +5 -47
  124. package/dist/portal-gateway/portalService.js +19 -349
  125. package/dist/portal-gateway/transport-worker.d.ts +1 -0
  126. package/dist/portal-gateway/transport-worker.js +205 -0
  127. package/dist/portal-gateway/transportBundle.d.ts +2 -0
  128. package/dist/portal-gateway/transportBundle.generated.d.ts +1 -0
  129. package/dist/portal-gateway/transportBundle.generated.js +2 -0
  130. package/dist/portal-gateway/transportBundle.js +4 -0
  131. package/dist/portal-gateway/upstream.d.ts +0 -81
  132. package/dist/portal-gateway/upstream.js +0 -1
  133. package/dist/restore.d.ts +9 -0
  134. package/dist/restore.js +10 -0
  135. package/dist/sandbox/api.d.ts +126 -187
  136. package/dist/sandbox/api.js +5 -7
  137. package/dist/sandbox/client.d.ts +3 -0
  138. package/dist/sandbox/client.js +7 -0
  139. package/dist/sandbox/data-endpoints/dataEndpoints.d.ts +13 -0
  140. package/dist/sandbox/data-endpoints/dataEndpoints.js +100 -0
  141. package/dist/sandbox/data-endpoints/firewalledPorts.d.ts +4 -0
  142. package/dist/sandbox/data-endpoints/firewalledPorts.js +28 -0
  143. package/dist/sandbox/lib/httpOverStream.d.ts +3 -0
  144. package/dist/sandbox/lib/httpOverStream.js +21 -0
  145. package/dist/sandbox/lib/remoteFileOperations.d.ts +10 -0
  146. package/dist/sandbox/lib/remoteFileOperations.js +70 -0
  147. package/dist/sandbox/lib/shellCommand.d.ts +3 -0
  148. package/dist/sandbox/lib/shellCommand.js +7 -0
  149. package/dist/sandbox/lib/sshKey.d.ts +6 -0
  150. package/dist/sandbox/lib/sshKey.js +75 -0
  151. package/dist/sandbox/providers/boat/boatService.d.ts +3 -0
  152. package/dist/sandbox/providers/boat/boatService.js +373 -0
  153. package/dist/sandbox/providers/exedev/exeDevService.d.ts +2 -0
  154. package/dist/sandbox/providers/exedev/exeDevService.js +129 -0
  155. package/dist/sandbox/providers/exedev/exeDevToken.d.ts +1 -0
  156. package/dist/sandbox/providers/exedev/exeDevToken.js +50 -0
  157. package/dist/sandbox/providers/local/localService.d.ts +2 -0
  158. package/dist/sandbox/providers/local/localService.js +197 -0
  159. package/dist/sandbox/providers/ssh/sshService.d.ts +2 -0
  160. package/dist/sandbox/providers/ssh/sshService.js +83 -0
  161. package/dist/sandbox/providers/ssh/sshTransport.d.ts +12 -0
  162. package/dist/sandbox/providers/ssh/sshTransport.js +216 -0
  163. package/dist/sandbox/service.d.ts +3 -0
  164. package/dist/sandbox/service.js +26 -0
  165. package/dist/sandbox/storage/descriptors.d.ts +6 -0
  166. package/dist/sandbox/storage/descriptors.js +25 -0
  167. package/dist/sandbox/storage/sandboxStorage.d.ts +11 -0
  168. package/dist/sandbox/storage/sandboxStorage.js +42 -0
  169. package/dist/upstreams/anthropic.d.ts +0 -5
  170. package/dist/upstreams/anthropic.js +1 -8
  171. package/dist/upstreams/index.d.ts +2 -6
  172. package/dist/upstreams/index.js +0 -4
  173. package/dist/upstreams/openai.d.ts +0 -5
  174. package/dist/upstreams/openai.js +1 -13
  175. package/dist/vendor-types/claude/agent-sdk/bridge.d.ts +20 -4
  176. package/dist/vendor-types/claude/agent-sdk/browser-sdk.d.ts +24 -0
  177. package/dist/vendor-types/claude/agent-sdk/core.d.ts +2 -0
  178. package/dist/vendor-types/claude/agent-sdk/sdk-tools.d.ts +75 -6
  179. package/dist/vendor-types/claude/agent-sdk/sdk.d.ts +569 -100
  180. package/package.json +13 -4
  181. package/dist/agent/gatewaySignIns.d.ts +0 -5
  182. package/dist/agent/gatewaySignIns.js +0 -11
  183. package/dist/agent/session/codex/home.d.ts +0 -2
  184. package/dist/agent/session/codex/home.js +0 -4
  185. package/dist/agent/session/codex/messages.d.ts +0 -30
  186. package/dist/agent/session/codex/messages.js +0 -135
  187. package/dist/agent/session/codex/transcript.d.ts +0 -12
  188. package/dist/agent/session/codex/transcript.js +0 -22
  189. package/dist/agent/session/sdkMessages.d.ts +0 -15
  190. package/dist/agent/session/sdkMessages.js +0 -28
  191. package/dist/agent/session/workerSseConnection.d.ts +0 -31
  192. package/dist/agent/session/workerSseConnection.js +0 -76
  193. package/dist/agent/vendor-types/codex/app-server/AbsolutePathBuf.d.ts +0 -10
  194. package/dist/agent/vendor-types/codex/app-server/AbsolutePathBuf.js +0 -2
  195. package/dist/agent/vendor-types/codex/app-server/FunctionCallOutputBody.d.ts +0 -2
  196. package/dist/agent/vendor-types/codex/app-server/FunctionCallOutputBody.js +0 -2
  197. package/dist/agent/vendor-types/codex/app-server/FunctionCallOutputContentItem.d.ts +0 -22
  198. package/dist/agent/vendor-types/codex/app-server/FunctionCallOutputContentItem.js +0 -2
  199. package/dist/agent/vendor-types/codex/app-server/ImageDetail.d.ts +0 -1
  200. package/dist/agent/vendor-types/codex/app-server/ImageDetail.js +0 -2
  201. package/dist/agent/vendor-types/codex/app-server/ImageGenerationFailure.d.ts +0 -5
  202. package/dist/agent/vendor-types/codex/app-server/ImageGenerationFailure.js +0 -2
  203. package/dist/agent/vendor-types/codex/app-server/ImageGenerationItem.d.ts +0 -11
  204. package/dist/agent/vendor-types/codex/app-server/ImageGenerationItem.js +0 -2
  205. package/dist/agent/vendor-types/codex/app-server/LegacyAppPathString.d.ts +0 -23
  206. package/dist/agent/vendor-types/codex/app-server/LegacyAppPathString.js +0 -2
  207. package/dist/agent/vendor-types/codex/app-server/MessagePhase.d.ts +0 -7
  208. package/dist/agent/vendor-types/codex/app-server/MessagePhase.js +0 -2
  209. package/dist/agent/vendor-types/codex/app-server/ReasoningEffort.d.ts +0 -4
  210. package/dist/agent/vendor-types/codex/app-server/ReasoningEffort.js +0 -2
  211. package/dist/agent/vendor-types/codex/app-server/SleepItem.d.ts +0 -7
  212. package/dist/agent/vendor-types/codex/app-server/SleepItem.js +0 -2
  213. package/dist/agent/vendor-types/codex/app-server/WebSearchItem.d.ts +0 -14
  214. package/dist/agent/vendor-types/codex/app-server/WebSearchItem.js +0 -2
  215. package/dist/agent/vendor-types/codex/app-server/serde_json/JsonValue.d.ts +0 -3
  216. package/dist/agent/vendor-types/codex/app-server/serde_json/JsonValue.js +0 -2
  217. package/dist/agent/vendor-types/codex/app-server/v2/AgentMessageDelivery.d.ts +0 -1
  218. package/dist/agent/vendor-types/codex/app-server/v2/AgentMessageDelivery.js +0 -2
  219. package/dist/agent/vendor-types/codex/app-server/v2/AsyncUserInputQuestion.d.ts +0 -4
  220. package/dist/agent/vendor-types/codex/app-server/v2/AsyncUserInputQuestion.js +0 -2
  221. package/dist/agent/vendor-types/codex/app-server/v2/ByteRange.d.ts +0 -4
  222. package/dist/agent/vendor-types/codex/app-server/v2/ByteRange.js +0 -2
  223. package/dist/agent/vendor-types/codex/app-server/v2/CollabAgentState.d.ts +0 -5
  224. package/dist/agent/vendor-types/codex/app-server/v2/CollabAgentState.js +0 -2
  225. package/dist/agent/vendor-types/codex/app-server/v2/CollabAgentStatus.d.ts +0 -1
  226. package/dist/agent/vendor-types/codex/app-server/v2/CollabAgentStatus.js +0 -2
  227. package/dist/agent/vendor-types/codex/app-server/v2/CollabAgentTool.d.ts +0 -1
  228. package/dist/agent/vendor-types/codex/app-server/v2/CollabAgentTool.js +0 -2
  229. package/dist/agent/vendor-types/codex/app-server/v2/CollabAgentToolCallStatus.d.ts +0 -1
  230. package/dist/agent/vendor-types/codex/app-server/v2/CollabAgentToolCallStatus.js +0 -2
  231. package/dist/agent/vendor-types/codex/app-server/v2/CommandAction.d.ts +0 -19
  232. package/dist/agent/vendor-types/codex/app-server/v2/CommandAction.js +0 -2
  233. package/dist/agent/vendor-types/codex/app-server/v2/CommandExecutionSource.d.ts +0 -1
  234. package/dist/agent/vendor-types/codex/app-server/v2/CommandExecutionSource.js +0 -2
  235. package/dist/agent/vendor-types/codex/app-server/v2/CommandExecutionStatus.d.ts +0 -1
  236. package/dist/agent/vendor-types/codex/app-server/v2/CommandExecutionStatus.js +0 -2
  237. package/dist/agent/vendor-types/codex/app-server/v2/DynamicToolCallOutputContentItem.d.ts +0 -10
  238. package/dist/agent/vendor-types/codex/app-server/v2/DynamicToolCallOutputContentItem.js +0 -2
  239. package/dist/agent/vendor-types/codex/app-server/v2/DynamicToolCallStatus.d.ts +0 -1
  240. package/dist/agent/vendor-types/codex/app-server/v2/DynamicToolCallStatus.js +0 -2
  241. package/dist/agent/vendor-types/codex/app-server/v2/FileUpdateChange.d.ts +0 -6
  242. package/dist/agent/vendor-types/codex/app-server/v2/FileUpdateChange.js +0 -2
  243. package/dist/agent/vendor-types/codex/app-server/v2/HookPromptFragment.d.ts +0 -4
  244. package/dist/agent/vendor-types/codex/app-server/v2/HookPromptFragment.js +0 -2
  245. package/dist/agent/vendor-types/codex/app-server/v2/McpAppDisplayMode.d.ts +0 -1
  246. package/dist/agent/vendor-types/codex/app-server/v2/McpAppDisplayMode.js +0 -2
  247. package/dist/agent/vendor-types/codex/app-server/v2/McpAppUi.d.ts +0 -8
  248. package/dist/agent/vendor-types/codex/app-server/v2/McpAppUi.js +0 -2
  249. package/dist/agent/vendor-types/codex/app-server/v2/McpToolCallAppContext.d.ts +0 -7
  250. package/dist/agent/vendor-types/codex/app-server/v2/McpToolCallAppContext.js +0 -2
  251. package/dist/agent/vendor-types/codex/app-server/v2/McpToolCallError.d.ts +0 -3
  252. package/dist/agent/vendor-types/codex/app-server/v2/McpToolCallError.js +0 -2
  253. package/dist/agent/vendor-types/codex/app-server/v2/McpToolCallResult.d.ts +0 -6
  254. package/dist/agent/vendor-types/codex/app-server/v2/McpToolCallResult.js +0 -2
  255. package/dist/agent/vendor-types/codex/app-server/v2/McpToolCallStatus.d.ts +0 -1
  256. package/dist/agent/vendor-types/codex/app-server/v2/McpToolCallStatus.js +0 -2
  257. package/dist/agent/vendor-types/codex/app-server/v2/MemoryCitation.d.ts +0 -5
  258. package/dist/agent/vendor-types/codex/app-server/v2/MemoryCitation.js +0 -2
  259. package/dist/agent/vendor-types/codex/app-server/v2/MemoryCitationEntry.d.ts +0 -6
  260. package/dist/agent/vendor-types/codex/app-server/v2/MemoryCitationEntry.js +0 -2
  261. package/dist/agent/vendor-types/codex/app-server/v2/PatchApplyStatus.d.ts +0 -1
  262. package/dist/agent/vendor-types/codex/app-server/v2/PatchApplyStatus.js +0 -2
  263. package/dist/agent/vendor-types/codex/app-server/v2/PatchChangeKind.d.ts +0 -8
  264. package/dist/agent/vendor-types/codex/app-server/v2/PatchChangeKind.js +0 -2
  265. package/dist/agent/vendor-types/codex/app-server/v2/SubAgentActivityKind.d.ts +0 -1
  266. package/dist/agent/vendor-types/codex/app-server/v2/SubAgentActivityKind.js +0 -2
  267. package/dist/agent/vendor-types/codex/app-server/v2/TextElement.d.ts +0 -11
  268. package/dist/agent/vendor-types/codex/app-server/v2/TextElement.js +0 -2
  269. package/dist/agent/vendor-types/codex/app-server/v2/ThreadItem.d.ts +0 -215
  270. package/dist/agent/vendor-types/codex/app-server/v2/ThreadItem.js +0 -2
  271. package/dist/agent/vendor-types/codex/app-server/v2/UserInput.d.ts +0 -35
  272. package/dist/agent/vendor-types/codex/app-server/v2/UserInput.js +0 -2
  273. package/dist/agent/vendor-types/codex/app-server/v2/WebSearchAction.d.ts +0 -14
  274. package/dist/agent/vendor-types/codex/app-server/v2/WebSearchAction.js +0 -2
  275. package/dist/cli/services.d.ts +0 -19
  276. package/dist/cli/services.js +0 -34
  277. package/dist/dimension/http.d.ts +0 -7
  278. package/dist/dimension/http.js +0 -77
  279. package/dist/dimension/storage.d.ts +0 -39
  280. package/dist/dimension/storage.js +0 -79
  281. package/dist/portal-gateway/fakes.d.ts +0 -3
  282. package/dist/portal-gateway/fakes.js +0 -11
  283. package/dist/portal-gateway/gatewayStorage.d.ts +0 -66
  284. package/dist/portal-gateway/gatewayStorage.js +0 -125
  285. package/dist/portal-gateway/portalStorage.d.ts +0 -34
  286. package/dist/portal-gateway/portalStorage.js +0 -44
  287. package/dist/sandbox/boatService.d.ts +0 -52
  288. package/dist/sandbox/boatService.js +0 -343
  289. package/dist/sandbox/containerService.d.ts +0 -15
  290. package/dist/sandbox/containerService.js +0 -184
  291. package/dist/sandbox/endpointProxy.d.ts +0 -90
  292. package/dist/sandbox/endpointProxy.js +0 -716
  293. package/dist/sandbox/exeDevAuth.d.ts +0 -16
  294. package/dist/sandbox/exeDevAuth.js +0 -49
  295. package/dist/sandbox/localService.d.ts +0 -19
  296. package/dist/sandbox/localService.js +0 -200
  297. package/dist/sandbox/sseConnection.d.ts +0 -41
  298. package/dist/sandbox/sseConnection.js +0 -166
  299. package/dist/sandbox/sshService.d.ts +0 -30
  300. package/dist/sandbox/sshService.js +0 -680
@@ -7,40 +7,25 @@ export function sandboxFiles(sandbox) {
7
7
  listDirectory: (path) => sandbox.listDirectory(path),
8
8
  };
9
9
  }
10
- /** The file of conversation `nativeId` laid out as `layout` under `home`; null when there's none yet. */
11
10
  export function locateTranscript(files, home, layout, nativeId) {
12
11
  const escape = (text) => text.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
13
12
  const [before = "", after = ""] = layout.name.split("{id}").map((part) => part.split("*").map(escape).join(".*"));
14
13
  const name = new RegExp(`^${before}${escape(nativeId)}${after}$`);
15
14
  return findFile(files, `${home}/${layout.dir}`, layout.depth, (entry) => name.test(entry));
16
15
  }
17
- /** How much of the file is read at a time. */
18
16
  export const CHUNK_BYTES = 64 * 1024;
19
- /**
20
- * How far out of time order lines get, nearly always (parallel branches completing; in long claude
21
- * sessions half are within 2s, 99% within a minute): searches allow for this much.
22
- */
23
17
  export const TIME_SLACK_MS = 60_000;
24
- /** How many timed lines a probe of the bisection looks at: the earliest wins, so one odd line can't mislead it. */
25
18
  export const PROBE_LINES = 3;
26
- /** How much a probe reads, at most, before it gives up on finding a timed line (huge tool outputs). */
27
19
  export const PROBE_BYTES = 4 * CHUNK_BYTES;
28
20
  const NEWLINE = 0x0a;
29
- /** A line's time (epoch ms) from its `field`, null without a valid one. */
30
21
  function lineTime(entry, field) {
31
22
  const value = entry?.[field];
32
23
  const time = typeof value === "string" ? Date.parse(value) : NaN;
33
24
  return Number.isNaN(time) ? null : time;
34
25
  }
35
- /** How much is read at a time when searching the whole file for where stretches were written again. */
36
26
  const SCAN_BYTES = 1024 * 1024;
37
- /**
38
- * The stretches written again in the files searched last, by path and size: a search reads the whole
39
- * file, and a file the backend only appends to that hasn't grown has the same ones.
40
- */
41
27
  const searchedCopies = new Map();
42
28
  const SEARCHED_FILES = 16;
43
- /** `locate` finds the file; null when there's none yet (nothing stored). */
44
29
  export function createFileTranscript(files, locate, lineMessages, layout) {
45
30
  function parse(bytes, start) {
46
31
  try {
@@ -48,11 +33,9 @@ export function createFileTranscript(files, locate, lineMessages, layout) {
48
33
  return { start, time: lineTime(entry, layout.time), messages: lineMessages(entry) };
49
34
  }
50
35
  catch {
51
- // A line still being written (the last one), or one this reader doesn't know: nothing in it.
52
36
  return { start, time: null, messages: [] };
53
37
  }
54
38
  }
55
- /** The stretches between `from` and `to` that aren't skipped, in order. */
56
39
  function kept(from, to, skip) {
57
40
  const parts = [];
58
41
  let start = from;
@@ -67,14 +50,12 @@ export function createFileTranscript(files, locate, lineMessages, layout) {
67
50
  parts.push({ start, end: to });
68
51
  return parts;
69
52
  }
70
- /** The file's lines before byte `end`, last first, read a chunk at a time, passing over `skip`. */
71
53
  async function* backward(path, end, skip = []) {
72
54
  for (const part of kept(0, end, skip).reverse())
73
55
  yield* backwardIn(path, part.start, part.end);
74
56
  }
75
57
  async function* backwardIn(path, floor, end) {
76
58
  let position = end;
77
- // Bytes of a line that runs on into what was read before (later in the file).
78
59
  let carry = new Uint8Array(0);
79
60
  while (position > floor) {
80
61
  const from = Math.max(floor, position - CHUNK_BYTES);
@@ -94,7 +75,6 @@ export function createFileTranscript(files, locate, lineMessages, layout) {
94
75
  if (carry.length > 0)
95
76
  yield parse(carry, floor);
96
77
  }
97
- /** The file's lines from byte `start` to byte `end`, in order, read a chunk at a time, passing over `skip`. */
98
78
  async function* forward(path, start, end, skip = []) {
99
79
  for (const part of kept(start, end, skip))
100
80
  yield* forwardIn(path, part.start, part.end);
@@ -121,15 +101,9 @@ export function createFileTranscript(files, locate, lineMessages, layout) {
121
101
  if (carry.length > 0)
122
102
  yield parse(carry, carryStart);
123
103
  }
124
- /**
125
- * Where the lines from time `target` on start, about, between `low` and `high`: the start of a line
126
- * (or `high`) with only lines from before it, allowing for the slack, ahead of it. Bisects, each
127
- * probe reading the times of the first few lines after its middle, passing over `skip`.
128
- */
129
104
  async function seek(path, low, high, target, skip) {
130
105
  return (await narrow(path, low, high, target, skip)).high;
131
106
  }
132
- /** seek's bisection: where it got, from both sides. */
133
107
  async function narrow(path, low, high, target, skip) {
134
108
  while (high - low > CHUNK_BYTES) {
135
109
  let middle = Math.floor((low + high) / 2);
@@ -143,7 +117,7 @@ export function createFileTranscript(files, locate, lineMessages, layout) {
143
117
  }
144
118
  const probe = await probeTime(path, middle, high, skip);
145
119
  if (!probe)
146
- break; // one line spans it all: start from where the search got
120
+ break;
147
121
  if (probe.time >= target)
148
122
  high = probe.start;
149
123
  else
@@ -151,14 +125,13 @@ export function createFileTranscript(files, locate, lineMessages, layout) {
151
125
  }
152
126
  return { low, high };
153
127
  }
154
- /** The first line starting after `from` (before `limit`), with the earliest time of the next few timed lines. */
155
128
  async function probeTime(path, from, limit, skip) {
156
129
  let start = -1;
157
130
  let time = Infinity;
158
131
  let timed = 0;
159
132
  for await (const line of forward(path, from, Math.min(limit, from + PROBE_BYTES), skip)) {
160
133
  if (line.start === from && from > 0)
161
- continue; // the middle of a line: only its end was read
134
+ continue;
162
135
  if (line.start >= limit)
163
136
  break;
164
137
  if (start < 0)
@@ -171,25 +144,17 @@ export function createFileTranscript(files, locate, lineMessages, layout) {
171
144
  }
172
145
  return start < 0 || timed === 0 ? null : { start, time };
173
146
  }
174
- /** The time of the first timed line from `from` on (a line start), if there's one in reach. */
175
147
  async function timeAt(path, from, size, skip) {
176
148
  for await (const line of forward(path, from, Math.min(size, from + PROBE_BYTES), skip))
177
149
  if (line.time !== null)
178
150
  return line.time;
179
151
  return null;
180
152
  }
181
- /** Where the line holding byte `at` starts. */
182
153
  async function lineStart(path, at) {
183
154
  for await (const line of backward(path, at + 1))
184
155
  return line.start;
185
156
  return 0;
186
157
  }
187
- /**
188
- * The stretches the backend wrote again (TranscriptLayout.copies): each starts at a line with the
189
- * marker whose time goes back from the timed line before it, and runs until a line is newer than
190
- * that one. Found by searching the whole file for the marker; the rest only
191
- * reads around what's found.
192
- */
193
158
  function copiesOf(path, size) {
194
159
  if (!layout.copies)
195
160
  return Promise.resolve([]);
@@ -199,7 +164,6 @@ export function createFileTranscript(files, locate, lineMessages, layout) {
199
164
  copies = findCopies(path, size, layout.copies);
200
165
  copies.catch(() => searchedCopies.delete(key));
201
166
  searchedCopies.set(key, copies);
202
- // A few files' worth: a worker serves an agent's sessions.
203
167
  if (searchedCopies.size > SEARCHED_FILES)
204
168
  searchedCopies.delete(searchedCopies.keys().next().value);
205
169
  }
@@ -209,7 +173,6 @@ export function createFileTranscript(files, locate, lineMessages, layout) {
209
173
  const needle = Buffer.from(marker);
210
174
  const found = [];
211
175
  for (let position = 0; position < size; position += SCAN_BYTES) {
212
- // Overlapping by the marker's length, so one across two reads is found.
213
176
  const from = Math.max(0, position - needle.length + 1);
214
177
  const bytes = Buffer.from(await files.readFileRange(path, from, Math.min(size, position + SCAN_BYTES)));
215
178
  for (let index = bytes.indexOf(needle); index >= 0; index = bytes.indexOf(needle, index + 1)) {
@@ -219,7 +182,6 @@ export function createFileTranscript(files, locate, lineMessages, layout) {
219
182
  }
220
183
  const copies = [];
221
184
  for (const [index, at] of found.entries()) {
222
- // The marker's line, and the timed line before it.
223
185
  const start = await lineStart(path, at);
224
186
  let earlier = null;
225
187
  for await (const before of backward(path, start)) {
@@ -235,13 +197,8 @@ export function createFileTranscript(files, locate, lineMessages, layout) {
235
197
  time = line.time;
236
198
  break;
237
199
  }
238
- // A compaction as it happened comes after what's before it (compacting takes a while: 25s and
239
- // more); a copy starts back at its time.
240
200
  if (time === null || time >= earlier)
241
201
  continue;
242
- // It runs up to what was written before it, and ends with the first line newer than that. It
243
- // holds what was said since a compaction, so it ends by the next marker: the rest of the file
244
- // (other copies) can't mislead the search.
245
202
  const next = found[index + 1];
246
203
  const near = await narrow(path, start + 1, next === undefined ? size : await lineStart(path, next), earlier + 1, []);
247
204
  let end = near.high;
@@ -255,17 +212,9 @@ export function createFileTranscript(files, locate, lineMessages, layout) {
255
212
  }
256
213
  return copies;
257
214
  }
258
- /**
259
- * The file's lines before `end`, last first, each with the time it's paged by: its own, unless it's
260
- * odd, more than the slack away from both the timed lines around it in the same direction (a
261
- * background task's result written minutes after it began, a note dated ahead), when it's the one
262
- * before it's; a line without a time goes with the timed line after it. These times follow the file
263
- * order to within the slack, so the late result is paged where it is in the conversation.
264
- * `after`: the time of the first timed line from `end` on.
265
- */
266
215
  async function* pagedBackward(path, end, after, skip) {
267
- let next = after; // the time of the timed line after the one waiting
268
- let waiting = []; // a timed line and the untimed ones before it, until the one before it is read
216
+ let next = after;
217
+ let waiting = [];
269
218
  const settle = function* (before) {
270
219
  const [timed, ...untimed] = waiting;
271
220
  if (!timed)
@@ -282,7 +231,6 @@ export function createFileTranscript(files, locate, lineMessages, layout) {
282
231
  };
283
232
  for await (const line of backward(path, end, skip)) {
284
233
  if (line.time === null) {
285
- // Before any timed line: it goes with the line after the end, or is the newest.
286
234
  if (waiting.length === 0)
287
235
  yield { ...line, time: next ?? Infinity };
288
236
  else
@@ -302,11 +250,9 @@ export function createFileTranscript(files, locate, lineMessages, layout) {
302
250
  const copies = found?.copies ?? (await copiesOf(path, size));
303
251
  const from = Math.min(found?.end ?? (before === null ? size : await seek(path, 0, size, before + TIME_SLACK_MS, copies)), size);
304
252
  const after = found ? found.after : from < size ? await timeAt(path, from, size, copies) : null;
305
- // Read back until the page is full and a line is older than its oldest by more than the slack:
306
- // nothing before it can belong on the page.
307
253
  const taken = [];
308
254
  let count = 0;
309
- let oldest = Infinity; // the time of the page's limit-th newest message, once it's full
255
+ let oldest = Infinity;
310
256
  let older = false;
311
257
  for await (const line of pagedBackward(path, from, after, copies)) {
312
258
  if (count >= limit && line.time < oldest - TIME_SLACK_MS) {
@@ -320,8 +266,6 @@ export function createFileTranscript(files, locate, lineMessages, layout) {
320
266
  if (count >= limit)
321
267
  oldest = oldestOnPage(taken, limit);
322
268
  }
323
- // The page: its newest messages by time, ties with the oldest of them included. A line's messages
324
- // stay together, so a page can hold a message or so more than the limit.
325
269
  const kept = count >= limit ? taken.filter((line) => line.time >= oldest) : taken;
326
270
  if (kept.length < taken.length)
327
271
  older = true;
@@ -330,7 +274,6 @@ export function createFileTranscript(files, locate, lineMessages, layout) {
330
274
  nextBefore: older && Number.isFinite(oldest) ? new Date(oldest).toISOString() : null,
331
275
  };
332
276
  }
333
- // Passing over the copies too: a resumed session's stretch written again isn't replayed twice.
334
277
  async function replay(afterId, emit) {
335
278
  const path = await locate();
336
279
  if (!path)
@@ -361,9 +304,20 @@ export function createFileTranscript(files, locate, lineMessages, layout) {
361
304
  }
362
305
  return true;
363
306
  }
364
- return { page, replay };
307
+ async function find(match) {
308
+ const path = await locate();
309
+ if (!path)
310
+ return null;
311
+ const end = await files.size(path);
312
+ for await (const line of backward(path, end, await copiesOf(path, end))) {
313
+ const found = line.messages.find(match);
314
+ if (found)
315
+ return found;
316
+ }
317
+ return null;
318
+ }
319
+ return { page, replay, find };
365
320
  }
366
- /** The time of the `limit`-th newest message of `lines`. */
367
321
  function oldestOnPage(lines, limit) {
368
322
  const newestFirst = [...lines].sort((a, b) => b.time - a.time);
369
323
  let count = 0;
@@ -386,7 +340,6 @@ function joined(first, second) {
386
340
  }
387
341
  const DEFAULT_PAGE_SIZE = 50;
388
342
  const MAX_PAGE_SIZE = 500;
389
- /** A page of the API's transcript (AgentTranscript.getTranscript); none stored for a session that never ran. */
390
343
  export async function transcriptPage(transcript, { limit, before, cursor } = {}, found) {
391
344
  const time = transcriptTime(before ?? cursor);
392
345
  if (!transcript)
@@ -395,7 +348,6 @@ export async function transcriptPage(transcript, { limit, before, cursor } = {},
395
348
  const page = await transcript.page(time, size, found);
396
349
  return { ...page, nextCursor: page.nextBefore };
397
350
  }
398
- /** AgentTranscriptRequest.before as epoch ms; null for none. */
399
351
  export function transcriptTime(before) {
400
352
  if (before === undefined)
401
353
  return null;
@@ -404,35 +356,27 @@ export function transcriptTime(before) {
404
356
  throw new AgentInvalidError(`invalid time ${before}: give an ISO 8601 time`);
405
357
  return time;
406
358
  }
407
- /**
408
- * The first file `depth` levels under `dir` whose name `matches` (the backends' own layouts, like
409
- * projects/<project>/<id>.jsonl), each level listed at once; null when there's none, or no `dir`.
410
- */
411
- async function findFile(files, dir, depth, matches) {
412
- let names;
359
+ export async function directoryNames(files, dir) {
413
360
  try {
414
- names = await files.listDirectory(dir);
361
+ return await files.listDirectory(dir);
415
362
  }
416
363
  catch (error) {
417
364
  if (error instanceof SandboxNotFoundError)
418
365
  return null;
419
366
  throw error;
420
367
  }
368
+ }
369
+ async function findFile(files, dir, depth, matches) {
370
+ const names = await directoryNames(files, dir);
371
+ if (!names)
372
+ return null;
421
373
  if (depth <= 1) {
422
374
  const name = names.find(matches);
423
375
  return name === undefined ? null : `${dir}/${name}`;
424
376
  }
425
- // Newest first, where names sort by date (codex's YYYY/MM/DD): a recent conversation is the likely one.
426
- const found = await Promise.all(names.sort().reverse().map((name) =>
427
- // One that isn't a directory has nothing below it.
428
- findFile(files, `${dir}/${name}`, depth - 1, matches).catch(() => null)));
377
+ const found = await Promise.all(names.sort().reverse().map((name) => findFile(files, `${dir}/${name}`, depth - 1, matches).catch(() => null)));
429
378
  return found.find((path) => path !== null) ?? null;
430
379
  }
431
- /**
432
- * `files` with what was already fetched of the file at `path` in the same round trip: its size, and
433
- * pieces of it (what a page reads, mostly). Reading back beyond them (a page across huge tool
434
- * outputs) fetches twice as much as the time before, so it takes a few more reads, not one per chunk.
435
- */
436
380
  export function prefetchedFiles(files, path, size, pieces) {
437
381
  let more = Math.max(CHUNK_BYTES, ...pieces.map(({ bytes }) => bytes.length));
438
382
  return {
@@ -0,0 +1,5 @@
1
+ import manifest from "../vendor-types/manifest.json";
2
+ import type { AgentBackendInfo } from "../api.ts";
3
+ export declare function pinnedVersion(vendor: keyof typeof manifest, pkg: string, sourcePackage?: string): string;
4
+ export declare function installedPackage(installDir: string, pkg: string, version: string, executable: () => string): Promise<Omit<AgentBackendInfo, "backend">>;
5
+ export declare function installPackage(installDir: string, pkg: string, version: string, executable: () => string): Promise<void>;
@@ -0,0 +1,35 @@
1
+ import { existsSync } from "node:fs";
2
+ import manifest from "../vendor-types/manifest.json" with { type: "json" };
3
+ export function pinnedVersion(vendor, pkg, sourcePackage = pkg) {
4
+ const prefix = `npm:${sourcePackage}@`;
5
+ const source = manifest[vendor].sources.find((entry) => entry.source.startsWith(prefix));
6
+ if (!source)
7
+ throw new Error(`agent/vendor-types/manifest.json has no ${sourcePackage} for ${vendor} (needed for ${pkg})`);
8
+ return source.source.slice(prefix.length);
9
+ }
10
+ export async function installedPackage(installDir, pkg, version, executable) {
11
+ const manifest = Bun.file(`${installDir}/node_modules/${pkg}/package.json`);
12
+ const found = (await manifest.exists()) ? ((await manifest.json()).version ?? null) : null;
13
+ return { version: found, ready: found !== null && existsSync(executable()), pinned: version };
14
+ }
15
+ export async function installPackage(installDir, pkg, version, executable) {
16
+ const installed = await installedPackage(installDir, pkg, version, executable);
17
+ if (installed.ready && installed.version === version)
18
+ return;
19
+ const force = installed.version === version ? ["--force"] : [];
20
+ const proc = Bun.spawn(["flock", `${installDir}/.install.lock`, process.execPath, "add", "--exact", ...force, `${pkg}@${version}`], {
21
+ cwd: installDir,
22
+ stdin: "ignore",
23
+ stdout: "pipe",
24
+ stderr: "pipe",
25
+ });
26
+ const [stdout, stderr, exitCode] = await Promise.all([
27
+ new Response(proc.stdout).text(),
28
+ new Response(proc.stderr).text(),
29
+ proc.exited,
30
+ ]);
31
+ if (exitCode !== 0)
32
+ throw new Error(`bun add ${pkg}@${version} failed (exit ${exitCode}): ${(stderr || stdout).trim()}`);
33
+ if (!existsSync(executable()))
34
+ throw new Error(`bun add ${pkg}@${version} left no ${executable()}: its platform package didn't install`);
35
+ }
@@ -1,69 +1,38 @@
1
1
  import type { Sandbox } from "../../sandbox/api.ts";
2
- import type { AgentAuthStatus, AgentBackend, AgentPermissionRequest, AgentQuestionRequest, AgentSession } from "../api.ts";
3
- /** What the worker keeps of a session: never its messages, which are the backend's to store. */
2
+ import type { AgentAuthStatus, AgentBackend, AgentPermissionMode, AgentPermissionRequest, AgentQuestionRequest, AgentSession, AgentSessionState } from "../api.ts";
4
3
  export type SessionRecord = {
5
4
  spec: AgentSession;
6
- /** The backend's id for the conversation, once known: what a new worker resumes. */
7
5
  nativeId: string | null;
8
- /** Chosen through AgentModels; null for the backend's default. */
9
6
  model: string | null;
7
+ permissionMode?: AgentPermissionMode;
10
8
  };
11
- /** Where a session's CLI stands with its sign-in, as far as it outlives a request. */
12
9
  export type SessionAuthRecord = {
13
- /** Where the CLI's login in progress asked the user to sign in; null when none is. */
14
10
  login: Extract<AgentAuthStatus, {
15
11
  state: "pending";
16
12
  }> | null;
17
- /** Why the last login failed, if it did. */
18
13
  error: string | null;
19
14
  };
20
- /** Every name must pass checkName; operations throw InvalidNameError otherwise. */
21
15
  export interface SessionStorage {
22
16
  getSessions(): Promise<SessionRecord[]>;
23
- /** Stores the record unless one with that name exists; returns whichever record is stored afterwards. */
24
17
  insertSession(record: SessionRecord): Promise<SessionRecord>;
25
- /** Replaces the record. */
26
18
  saveSession(record: SessionRecord): Promise<void>;
27
- /** Removes the record and everything kept for the session. No-op if missing. */
28
19
  removeSession(sessionName: string): Promise<void>;
29
- /** The permission requests the session's CLI is waiting on, oldest first. */
30
20
  getPermissionRequests(sessionName: string): Promise<AgentPermissionRequest[]>;
31
21
  savePermissionRequest(sessionName: string, request: AgentPermissionRequest): Promise<void>;
32
- /** No-op if missing. */
33
22
  removePermissionRequest(sessionName: string, requestId: string): Promise<void>;
34
- /** The questions the session's CLI is waiting on, oldest first. */
35
23
  getQuestionRequests(sessionName: string): Promise<AgentQuestionRequest[]>;
36
24
  saveQuestionRequest(sessionName: string, request: AgentQuestionRequest): Promise<void>;
37
- /** No-op if missing. */
38
25
  removeQuestionRequest(sessionName: string, requestId: string): Promise<void>;
39
- /** Null until the session's CLI has been asked to sign in. */
40
26
  readAuth(sessionName: string): Promise<SessionAuthRecord | null>;
41
27
  saveAuth(sessionName: string, record: SessionAuthRecord): Promise<void>;
42
- /** Sandbox path of the unix socket the agent's worker listens on (see workerSocketPath). */
28
+ saveStatus(sessionName: string, status: AgentSessionState): Promise<void>;
43
29
  socketPath(): Promise<string>;
44
- /**
45
- * Sandbox path of the backend CLI's home (claude's config directory, codex's CODEX_HOME): its
46
- * sign-in, config and conversations, kept with the rest of the dimension's state. Shared by the
47
- * dimension's agents, like a home would be. Creates it.
48
- */
49
30
  backendHome(backend: AgentBackend): Promise<string>;
50
31
  }
51
- /**
52
- * The agent's worker socket in a dimension's run directory: RUN_PATH inside the dimension, or the
53
- * host side of that mount, so the host reaches the worker through it.
54
- */
55
32
  export declare function workerSocketPath(runDirectory: string, agentName: string): string;
56
- /** Where the session's record is in a dimension's state directory (see createSessionStorage). */
33
+ export declare function workerReadyPath(runDirectory: string, agentName: string): string;
57
34
  export declare function sessionRecordPath(stateDirectory: string, agentName: string, sessionName: string): string;
58
- /** Where the backend CLI's home is (SessionStorage.backendHome) in a dimension's state directory. */
59
35
  export declare function backendHomePath(stateDirectory: string, backend: AgentBackend): string;
60
- /**
61
- * `stateDirectory` is a sandbox path: the dimension's state directory (STATE_PATH, mounted from the
62
- * host's hyperbrane storage, so everything here lives there with the rest). Layout:
63
- * agents/<agent>/sessions/<session>.json, and agents/<agent>/sessions/<session>/ holding
64
- * permission-requests/<id>.json, question-requests/<id>.json and auth.json; backends/<backend>/
65
- * (the CLIs' homes). The socket goes in `runDirectory`, the dimension's run directory.
66
- */
67
36
  export declare function createSessionStorage(sandbox: Sandbox, agentName: string, { stateDirectory, runDirectory }?: {
68
37
  stateDirectory?: string;
69
38
  runDirectory?: string;
@@ -1,37 +1,28 @@
1
- import { RUN_PATH, STATE_PATH } from "../../dimension/paths.js";
1
+ import { dimensionLayout } from "../../dimension/api.js";
2
2
  import { checkName, createJsonDirectory } from "../../lib/jsonDirectory.js";
3
- /**
4
- * The agent's worker socket in a dimension's run directory: RUN_PATH inside the dimension, or the
5
- * host side of that mount, so the host reaches the worker through it.
6
- */
7
3
  export function workerSocketPath(runDirectory, agentName) {
8
4
  return `${runDirectory}/${agentName}.sock`;
9
5
  }
6
+ export function workerReadyPath(runDirectory, agentName) {
7
+ return `${runDirectory}/${agentName}.ready`;
8
+ }
10
9
  function sessionsDirectory(stateDirectory, agentName) {
11
10
  return `${stateDirectory}/agents/${agentName}/sessions`;
12
11
  }
13
- /** Where the session's record is in a dimension's state directory (see createSessionStorage). */
14
12
  export function sessionRecordPath(stateDirectory, agentName, sessionName) {
15
13
  return `${sessionsDirectory(stateDirectory, agentName)}/${checkName(sessionName)}.json`;
16
14
  }
17
- /** Where the backend CLI's home is (SessionStorage.backendHome) in a dimension's state directory. */
18
15
  export function backendHomePath(stateDirectory, backend) {
19
16
  return `${stateDirectory}/backends/${backend}`;
20
17
  }
21
- /**
22
- * `stateDirectory` is a sandbox path: the dimension's state directory (STATE_PATH, mounted from the
23
- * host's hyperbrane storage, so everything here lives there with the rest). Layout:
24
- * agents/<agent>/sessions/<session>.json, and agents/<agent>/sessions/<session>/ holding
25
- * permission-requests/<id>.json, question-requests/<id>.json and auth.json; backends/<backend>/
26
- * (the CLIs' homes). The socket goes in `runDirectory`, the dimension's run directory.
27
- */
28
- export function createSessionStorage(sandbox, agentName, { stateDirectory = STATE_PATH, runDirectory = RUN_PATH } = {}) {
18
+ export function createSessionStorage(sandbox, agentName, { stateDirectory = dimensionLayout.statePath(), runDirectory = dimensionLayout.runPath() } = {}) {
29
19
  const sessionsDir = sessionsDirectory(stateDirectory, agentName);
30
20
  const sessions = createJsonDirectory(sandbox, async () => sessionsDir);
31
21
  const sessionDir = (sessionName) => `${sessionsDir}/${checkName(sessionName)}`;
32
22
  const permissionRequests = (sessionName) => createJsonDirectory(sandbox, async () => `${sessionDir(sessionName)}/permission-requests`);
33
23
  const questionRequests = (sessionName) => createJsonDirectory(sandbox, async () => `${sessionDir(sessionName)}/question-requests`);
34
24
  const sessionFiles = (sessionName) => createJsonDirectory(sandbox, async () => sessionDir(sessionName));
25
+ const statusFiles = (sessionName) => createJsonDirectory(sandbox, async () => sessionDir(sessionName));
35
26
  async function oldestFirst(stored) {
36
27
  return (await stored).sort((a, b) => a.at - b.at).map((entry) => entry.request);
37
28
  }
@@ -44,7 +35,6 @@ export function createSessionStorage(sandbox, agentName, { stateDirectory = STAT
44
35
  async function saveSession(record) {
45
36
  await sessions.save(record.spec.name, record);
46
37
  }
47
- // Everything kept for it first: while the record is there, the removal can be retried.
48
38
  async function removeSession(sessionName) {
49
39
  await sandbox.removeDirectory(sessionDir(sessionName));
50
40
  await sessions.remove(sessionName);
@@ -73,6 +63,9 @@ export function createSessionStorage(sandbox, agentName, { stateDirectory = STAT
73
63
  async function saveAuth(sessionName, record) {
74
64
  await sessionFiles(sessionName).save("auth", record);
75
65
  }
66
+ async function saveStatus(sessionName, status) {
67
+ await statusFiles(sessionName).save("status", { status });
68
+ }
76
69
  async function socketPath() {
77
70
  return workerSocketPath(runDirectory, agentName);
78
71
  }
@@ -94,6 +87,7 @@ export function createSessionStorage(sandbox, agentName, { stateDirectory = STAT
94
87
  removeQuestionRequest,
95
88
  readAuth,
96
89
  saveAuth,
90
+ saveStatus,
97
91
  socketPath,
98
92
  backendHome,
99
93
  };
@@ -1,14 +1,6 @@
1
1
  import type { ConnectWorker } from "./workerConnection.ts";
2
2
  /** @sealed */
3
3
  export type SharedConnector = ConnectWorker & {
4
- /** Closes the connection they share (a later connect opens another). */
5
4
  close(): void;
6
5
  };
7
- /**
8
- * One connection to the worker, shared by everyone `connect`s through it: each gets a view of it
9
- * (its requests go over it, the worker's notifications reach every view, closing a view only
10
- * detaches it), so calls cost a round trip each rather than a connection each. Over an endpoint
11
- * that's what matters (workerSseConnector opens an event stream per connection). The connection is
12
- * opened on first use, and again after it closes.
13
- */
14
6
  export declare function sharedConnector(connect: ConnectWorker): SharedConnector;
@@ -1,10 +1,3 @@
1
- /**
2
- * One connection to the worker, shared by everyone `connect`s through it: each gets a view of it
3
- * (its requests go over it, the worker's notifications reach every view, closing a view only
4
- * detaches it), so calls cost a round trip each rather than a connection each. Over an endpoint
5
- * that's what matters (workerSseConnector opens an event stream per connection). The connection is
6
- * opened on first use, and again after it closes.
7
- */
8
1
  export function sharedConnector(connect) {
9
2
  let current = null;
10
3
  function open() {
@@ -1,13 +1,8 @@
1
1
  import type { AgentBackend } from "../api.ts";
2
2
  import type { SessionBackend } from "./backend.ts";
3
3
  import type { LineMessages, TranscriptLayout } from "./fileTranscript.ts";
4
- /**
5
- * Each backend's conversations as it stores them: where (under the home homeEnvironment points it
6
- * at) and how a line reads, for reading a transcript with nothing running, from the host. None of
7
- * the backends' other code, which runs only in the dimension.
8
- */
9
4
  export type StoredTranscripts = Pick<SessionBackend, "homeEnvironment"> & {
10
5
  layout: TranscriptLayout;
11
6
  lineMessages(nativeId: string): LineMessages;
12
7
  };
13
- export declare const STORED_TRANSCRIPTS: Record<AgentBackend, StoredTranscripts>;
8
+ export declare const STORED_TRANSCRIPTS: Partial<Record<AgentBackend, StoredTranscripts>>;
@@ -1,8 +1,5 @@
1
1
  import { claudeHomeEnvironment } from "./claude/home.js";
2
2
  import { CLAUDE_TRANSCRIPT_LAYOUT, claudeLineMessages } from "./claude/transcript.js";
3
- import { codexHomeEnvironment } from "./codex/home.js";
4
- import { CODEX_TRANSCRIPT_LAYOUT, codexLineMessages } from "./codex/transcript.js";
5
3
  export const STORED_TRANSCRIPTS = {
6
4
  claude: { homeEnvironment: claudeHomeEnvironment, layout: CLAUDE_TRANSCRIPT_LAYOUT, lineMessages: () => claudeLineMessages },
7
- codex: { homeEnvironment: codexHomeEnvironment, layout: CODEX_TRANSCRIPT_LAYOUT, lineMessages: codexLineMessages },
8
5
  };
@@ -1,7 +1,3 @@
1
- /**
2
- * JSON-RPC 2.0 over a byte stream, one JSON object per line (the framing codex's app-server uses).
3
- * Either end can send requests and notifications; the worker protocol (protocol.ts) is built on it.
4
- */
5
1
  export type JsonRpcId = string | number;
6
2
  export type JsonRpcErrorObject = {
7
3
  code: number;
@@ -9,29 +5,22 @@ export type JsonRpcErrorObject = {
9
5
  data?: unknown;
10
6
  };
11
7
  export type JsonRpcPeerOptions = {
12
- /** Answers a request; what it throws goes back as an error response, through `encodeError`. */
13
- onRequest(method: string, params: unknown): Promise<unknown>;
8
+ onRequest(method: string, params: unknown, protocol: number | undefined): Promise<unknown>;
9
+ protocol?: number;
14
10
  onNotification?(method: string, params: unknown): void;
15
11
  encodeError(error: unknown): JsonRpcErrorObject;
16
12
  decodeError(error: JsonRpcErrorObject): Error;
17
13
  };
18
14
  export interface JsonRpcPeer {
19
- /** Feeds text read from the connection; complete lines are handled as they arrive. */
20
15
  receive(text: string): void;
21
16
  request(method: string, params: unknown): Promise<unknown>;
22
17
  notify(method: string, params: unknown): void;
23
- /** Fails every request still waiting for its response. */
24
18
  close(error: Error): void;
25
19
  }
26
20
  export declare function createJsonRpcPeer(write: (line: string) => void, options: JsonRpcPeerOptions): JsonRpcPeer;
27
- /** The part of a Bun socket a writer needs. */
28
21
  type WritableSocket = {
29
22
  write(data: Uint8Array): number;
30
23
  };
31
- /**
32
- * Writes to a Bun socket without losing what it can't take yet: the rest is kept and written on
33
- * `drain`, which the socket's drain handler must call.
34
- */
35
24
  export declare function createSocketWriter(socket: WritableSocket): {
36
25
  write(text: string): void;
37
26
  drain(): void;
@@ -1,8 +1,3 @@
1
- /**
2
- * JSON-RPC 2.0 over a byte stream, one JSON object per line (the framing codex's app-server uses).
3
- * Either end can send requests and notifications; the worker protocol (protocol.ts) is built on it.
4
- */
5
- /** Answer for a line that isn't JSON-RPC at all. */
6
1
  const PARSE_ERROR = -32700;
7
2
  export function createJsonRpcPeer(write, options) {
8
3
  const pending = new Map();
@@ -31,7 +26,7 @@ export function createJsonRpcPeer(write, options) {
31
26
  return;
32
27
  }
33
28
  const id = message.id;
34
- options.onRequest(message.method, message.params).then((result) => send({ id, result: result ?? null }), (error) => send({ id, error: options.encodeError(error) }));
29
+ options.onRequest(message.method, message.params, message.protocol).then((result) => send({ id, result: result ?? null }), (error) => send({ id, error: options.encodeError(error) }));
35
30
  }
36
31
  function receive(text) {
37
32
  buffered += text;
@@ -58,7 +53,7 @@ export function createJsonRpcPeer(write, options) {
58
53
  const id = nextId++;
59
54
  return new Promise((resolve, reject) => {
60
55
  pending.set(id, { resolve, reject });
61
- send({ id, method, params });
56
+ send({ id, method, params, ...(options.protocol === undefined ? {} : { protocol: options.protocol }) });
62
57
  });
63
58
  }
64
59
  function notify(method, params) {
@@ -72,10 +67,6 @@ export function createJsonRpcPeer(write, options) {
72
67
  }
73
68
  return { receive, request, notify, close };
74
69
  }
75
- /**
76
- * Writes to a Bun socket without losing what it can't take yet: the rest is kept and written on
77
- * `drain`, which the socket's drain handler must call.
78
- */
79
70
  export function createSocketWriter(socket) {
80
71
  const encoder = new TextEncoder();
81
72
  let backlog = null;