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
@@ -0,0 +1,479 @@
1
+ import { dimensionLayout } from "../dimension/api.js";
2
+ import { sh } from "../lib/sh.js";
3
+ import { AGENT_BACKENDS, AgentConflictError, AgentNotFoundError, } from "./api.js";
4
+ import { codexPackage } from "./session/codex/provision.js";
5
+ import { WORKER_PROTOCOL } from "./session/worker/protocol.js";
6
+ import { claudePackage } from "./session/claude/provision.js";
7
+ import { workerBundle } from "./workerBundle.js";
8
+ export const WORKER_DIR = `${dimensionLayout.statePath()}/worker`;
9
+ const OLD_WORKER_DIR = "/opt/hyperbrane/worker";
10
+ const SCRIPTS_DIR = "/opt/hyperbrane";
11
+ const START_TIMEOUT_S = 30;
12
+ const STOP_TIMEOUT_S = 10;
13
+ const EXIT = { noDimension: 40, notRunning: 41, oldDimension: 42, conflict: 43, noAgent: 44, thirdUser: 45, needBundle: 46, noSession: 47 };
14
+ const AUTH_UPSTREAMS = { claude: "anthropic", codex: "openai" };
15
+ function backendPackage(backend) {
16
+ return backend === "claude" ? claudePackage() : codexPackage();
17
+ }
18
+ export async function createAgentScript(host, agent, options = {}) {
19
+ const bundle = await workerBundle();
20
+ const env = {
21
+ ...dimensionEnv(agent.dimensionName, options),
22
+ ...(options.replaceBuild ? { REPLACE_BUILD: "1" } : {}),
23
+ AGENT: agent.name,
24
+ BUILD: bundle.build,
25
+ PROTOCOL: String(WORKER_PROTOCOL),
26
+ CA_BUNDLE: dimensionLayout.caBundlePath(),
27
+ START_TIMEOUT: String(START_TIMEOUT_S),
28
+ STOP_TIMEOUT: String(STOP_TIMEOUT_S),
29
+ };
30
+ let result = await run(host, CREATE_AGENT, env);
31
+ if (result.exitCode === EXIT.needBundle)
32
+ result = await run(host, CREATE_AGENT, { ...env, HAS_BUNDLE: "1" }, bundle.source);
33
+ check(result, `starting agent ${agent.name}`, agent);
34
+ }
35
+ export async function stopAgentScript(host, agentName, options = {}) {
36
+ const result = await run(host, STOP_AGENT, { ...dataEnv(options), AGENT: agentName, STOP_TIMEOUT: String(STOP_TIMEOUT_S) });
37
+ check(result, `stopping agent ${agentName}`);
38
+ }
39
+ export async function listAgentsScript(host, options = {}) {
40
+ const result = check(await run(host, LIST_AGENTS, dataEnv(options)), "listing agents");
41
+ return records(result.stdout).map(([, agent]) => agent);
42
+ }
43
+ export async function listSessionsScript(host, options = {}) {
44
+ const result = check(await run(host, LIST_SESSIONS, dataEnv(options)), "listing sessions");
45
+ const running = new Set(result.stdout
46
+ .split("\n")
47
+ .filter((line) => line.startsWith("running "))
48
+ .map((line) => line.slice("running ".length)));
49
+ return records(result.stdout).map(([header, record]) => {
50
+ const [agentName = "", saved = ""] = header.split("\t");
51
+ const status = !running.has(agentName) ? { state: "exited", code: null, signal: null } : (savedStatus(saved) ?? { state: "idle" });
52
+ return { ...record.spec, agentName, status, nativeId: record.nativeId, model: record.model, permissionMode: record.permissionMode ?? "ask" };
53
+ });
54
+ }
55
+ export async function installScript(host, agentName, backend, options = {}) {
56
+ const { pkg, version, executables } = backendPackage(backend);
57
+ const env = { ...dataEnv(options), AGENT: agentName, PKG: pkg, VERSION: version, EXECUTABLES: executables, CA_BUNDLE: dimensionLayout.caBundlePath() };
58
+ check(await run(host, INSTALL_BACKEND, env), `installing ${backend} for agent ${agentName}`);
59
+ }
60
+ export async function loginStateScript(host, ref, options = {}) {
61
+ const upstreams = Object.entries(AUTH_UPSTREAMS)
62
+ .map(([backend, upstream]) => `${backend}\t${upstream}`)
63
+ .join("\n");
64
+ const result = check(await run(host, LOGIN_STATE, { ...dataEnv(options), AGENT: ref.agentName, SESSION: ref.sessionName, UPSTREAMS: upstreams }), `signing in ${ref.agentName}/${ref.sessionName}`);
65
+ const [backend = "", signedIn] = result.stdout.trim().split("\t");
66
+ if (!AGENT_BACKENDS.includes(backend))
67
+ throw new Error(`session ${ref.sessionName} has no known backend (${backend})`);
68
+ return { backend: backend, gatewaySignedIn: signedIn === "1" };
69
+ }
70
+ export async function agentsDownScript(host, options = {}) {
71
+ const result = check(await run(host, AGENTS_DOWN, dataEnv(options)), "finding agents to restore");
72
+ return result.stdout
73
+ .split("\n")
74
+ .filter(Boolean)
75
+ .map((line) => {
76
+ const [name = "", dimensionName = ""] = line.split("\t");
77
+ return { name, dimensionName };
78
+ });
79
+ }
80
+ export async function workerSocketScript(host, agentName, options = {}) {
81
+ const result = check(await run(host, WORKER_SOCKET, { ...dataEnv(options), AGENT: agentName }), `finding agent ${agentName}'s worker`);
82
+ const [dimensionName = "", socket = ""] = result.stdout.split("\n");
83
+ return { dimensionName, socket };
84
+ }
85
+ export async function listBackendsScript(host, agentName, options = {}) {
86
+ const lines = AGENT_BACKENDS.map((backend) => {
87
+ const { pkg, version, executables } = backendPackage(backend);
88
+ return [backend, pkg, version, executables].join("\t");
89
+ });
90
+ const result = check(await run(host, LIST_BACKENDS, { ...dataEnv(options), AGENT: agentName, BACKENDS: lines.join("\n") }), "listing backends");
91
+ return result.stdout
92
+ .split("\n")
93
+ .filter(Boolean)
94
+ .map((line) => {
95
+ const [backend, installed = "", ready] = line.split("\t");
96
+ return { backend: backend, version: installed || null, ready: ready === "1", pinned: backendPackage(backend).version };
97
+ });
98
+ }
99
+ function dataEnv({ dataDirectory }) {
100
+ return {
101
+ ...(dataDirectory === undefined ? {} : { DATA: dataDirectory }),
102
+ CONTAINER_PREFIX: dimensionLayout.containerName(""),
103
+ RUN_PATH: dimensionLayout.runPath(),
104
+ STATE_PATH: dimensionLayout.statePath(),
105
+ WORKER_DIR,
106
+ SCRIPTS_DIR,
107
+ OLD_WORKER_DIR,
108
+ ...Object.fromEntries(Object.entries(EXIT).map(([name, code]) => [`E_${name.replace(/[A-Z]/g, (c) => `_${c}`).toUpperCase()}`, String(code)])),
109
+ };
110
+ }
111
+ function dimensionEnv(dimensionName, options) {
112
+ return { ...dataEnv(options), DIMENSION: dimensionName };
113
+ }
114
+ function run(host, script, env, stdin) {
115
+ const inDimension = { KILL_AGENT, PREPARE_WORKER, PUT_SCRIPT, START_WORKER, REMOVE_OLD_SCRIPTS, INSTALL_IN_DIMENSION };
116
+ return host.runCommand(["sh", "-c", `${PRELUDE}\n${script}`], { env: { ...inDimension, ...env }, stdin });
117
+ }
118
+ function check(result, what, agent) {
119
+ const said = result.stderr.trim();
120
+ switch (result.exitCode) {
121
+ case 0:
122
+ return result;
123
+ case EXIT.noDimension:
124
+ throw new AgentNotFoundError(`dimension ${agent?.dimensionName ?? said} does not exist`);
125
+ case EXIT.notRunning:
126
+ throw new AgentConflictError(`dimension ${agent?.dimensionName ?? said} is not running`);
127
+ case EXIT.oldDimension:
128
+ throw new AgentConflictError(`dimension ${agent?.dimensionName ?? said} lacks the ${dimensionLayout.runPath()} and ${dimensionLayout.statePath()} mounts agents need (it predates them); recreate it`);
129
+ case EXIT.conflict:
130
+ throw new AgentConflictError(`agent ${agent?.name ?? ""} already exists in another dimension: ${said}`);
131
+ case EXIT.noAgent:
132
+ throw new AgentNotFoundError(`agent ${said} does not exist`);
133
+ case EXIT.noSession:
134
+ throw new AgentNotFoundError(`session ${said} does not exist`);
135
+ case EXIT.thirdUser:
136
+ throw new AgentConflictError(`${what}: ${said}`);
137
+ default:
138
+ throw new Error(`${what} failed (exit ${result.exitCode}): ${said || result.stdout.trim()}`);
139
+ }
140
+ }
141
+ function records(stdout) {
142
+ return stdout
143
+ .split(RECORD_END)
144
+ .map((block) => block.replace(/^(running [^\n]*\n)+/, ""))
145
+ .filter((block) => block.trim())
146
+ .flatMap((block) => {
147
+ const newline = block.indexOf("\n");
148
+ try {
149
+ return [[block.slice(0, newline), JSON.parse(block.slice(newline + 1))]];
150
+ }
151
+ catch {
152
+ return [];
153
+ }
154
+ });
155
+ }
156
+ function savedStatus(file) {
157
+ try {
158
+ const { status } = JSON.parse(file);
159
+ if (!status)
160
+ return null;
161
+ if (status.state === "tool")
162
+ return Array.isArray(status.tools) ? status : null;
163
+ return SESSION_STATES.has(status.state) ? status : null;
164
+ }
165
+ catch {
166
+ return null;
167
+ }
168
+ }
169
+ const SESSION_STATES = new Set(["exited", "starting", "waiting", "idle", "thinking"]);
170
+ const RECORD_END = "\n\x1e\n";
171
+ const PRELUDE = sh `
172
+ DATA="\${DATA:-$HOME/.local/share/hyperbrane}"
173
+
174
+ agent_dimension() {
175
+ record="$DATA/agents/$1.json"
176
+ if [ ! -f "$record" ]; then
177
+ echo "$1" >&2
178
+ exit "$E_NO_AGENT"
179
+ fi
180
+ DIMENSION="$(sed -n 's/^ *"dimensionName": *"\([^"]*\)".*/\1/p' "$record")"
181
+ }
182
+
183
+ # Exits unless dimension $DIMENSION exists and runs, with the mounts agents need. Sets CONTAINER,
184
+ # DIMENSION_USER (whom it runs as, uid[:gid]) and RUN (its run directory on the machine).
185
+ require_dimension() {
186
+ CONTAINER="$CONTAINER_PREFIX$DIMENSION"
187
+ RUN="$DATA/dimension-run/$DIMENSION"
188
+ format='{{index .Config.Labels "hyperbrane.dimension"}}|{{.State.Running}}|{{range .Mounts}}{{.Destination}},{{end}}|{{.Config.User}}'
189
+ if ! info="$(docker inspect -f "$format" "$CONTAINER" 2>/dev/null)"; then
190
+ echo "$DIMENSION" >&2
191
+ exit "$E_NO_DIMENSION"
192
+ fi
193
+ IFS='|' read -r label running mounts DIMENSION_USER <<INFO
194
+ $info
195
+ INFO
196
+ if [ "$label" != "$DIMENSION" ]; then
197
+ echo "$DIMENSION" >&2
198
+ exit "$E_NO_DIMENSION"
199
+ fi
200
+ if [ "$running" != true ]; then
201
+ echo "$DIMENSION" >&2
202
+ exit "$E_NOT_RUNNING"
203
+ fi
204
+ case "$mounts" in
205
+ *"$RUN_PATH,"*"$STATE_PATH,"* | *"$STATE_PATH,"*"$RUN_PATH,"*) ;;
206
+ *)
207
+ echo "$DIMENSION" >&2
208
+ exit "$E_OLD_DIMENSION"
209
+ ;;
210
+ esac
211
+ DIMENSION_USER="\${DIMENSION_USER:-0:0}"
212
+ }
213
+
214
+ # Whether agent $1's worker runs, of any build, and can be reached: its ready file names a live
215
+ # shellcheck disable=SC2034
216
+ worker_running() {
217
+ WORKER_PID=""
218
+ WORKER_BUILD=""
219
+ WORKER_PROTOCOL=""
220
+ [ -f "$RUN/$1.ready" ] && [ -S "$RUN/$1.sock" ] || return 1
221
+ read -r WORKER_PID WORKER_BUILD WORKER_PROTOCOL < "$RUN/$1.ready" || return 1
222
+ docker exec -u 0 "$CONTAINER" grep -qs "hyperbrane/worker" "/proc/$WORKER_PID/cmdline"
223
+ }
224
+
225
+ stop_worker() {
226
+ if worker_running "$1"; then
227
+ docker exec -u 0 "$CONTAINER" kill "$WORKER_PID" 2>/dev/null || true
228
+ waited=0
229
+ while [ "$waited" -lt "$STOP_TIMEOUT" ] && docker exec -u 0 "$CONTAINER" kill -0 "$WORKER_PID" 2>/dev/null; do
230
+ sleep 1
231
+ waited=$((waited + 1))
232
+ done
233
+ fi
234
+ docker exec -u "$DIMENSION_USER" -e AGENT="$1" "$CONTAINER" sh -c "$KILL_AGENT"
235
+ rm -f "$RUN/$1.ready" 2>/dev/null || true
236
+ }
237
+ `;
238
+ const KILL_AGENT = sh `
239
+ for process in /proc/[0-9]*; do
240
+ if tr '\0' '\n' < "$process/environ" 2>/dev/null | grep -qx "HYB_AGENT=$AGENT"; then
241
+ kill -9 "\${process#/proc/}" 2>/dev/null || true
242
+ fi
243
+ done
244
+ `;
245
+ const PREPARE_WORKER = sh `
246
+ set -eu
247
+ mkdir -p "$WORKER_DIR" "$SCRIPTS_DIR"
248
+ chown "$OWNER" "$WORKER_DIR" "$SCRIPTS_DIR" "$RUN_PATH" "$STATE_PATH"
249
+ if [ ! -e "$WORKER_DIR/node_modules" ] && [ -d "$OLD_WORKER_DIR/node_modules" ]; then
250
+ cp -a "$OLD_WORKER_DIR/." "$WORKER_DIR/"
251
+ rm -rf "$OLD_WORKER_DIR"
252
+ fi
253
+ if [ ! -f "$WORKER_DIR/package.json" ]; then
254
+ printf '{\n "name": "hyperbrane-worker",\n "private": true\n}\n' > "$WORKER_DIR/package.json"
255
+ chown "$OWNER" "$WORKER_DIR/package.json"
256
+ fi
257
+ printf '[install]\ncafile = "%s"\n' "$CA_BUNDLE" > "$WORKER_DIR/bunfig.toml"
258
+ chown "$OWNER" "$WORKER_DIR/bunfig.toml"
259
+ `;
260
+ const PUT_SCRIPT = sh `
261
+ set -eu
262
+ cat > "$SCRIPT.part"
263
+ mv -f "$SCRIPT.part" "$SCRIPT"
264
+ `;
265
+ const START_WORKER = sh `
266
+ HOME="$(getent passwd "$(id -u)" | cut -d: -f6)"
267
+ export HOME
268
+ cd "$HOME" 2>/dev/null || cd /
269
+ exec bun "$HYB_WORKER_SCRIPT" >> "$HYB_LOG" 2>&1 < /dev/null
270
+ `;
271
+ const REMOVE_OLD_SCRIPTS = sh `
272
+ for old in "$SCRIPTS_DIR"/worker-*.js; do
273
+ [ "$old" = "$SCRIPTS_DIR/worker-$BUILD.js" ] || rm -f "$old"
274
+ done
275
+ `;
276
+ const CREATE_AGENT = sh `
277
+ set -eu
278
+ DIMENSION_WANTED="$DIMENSION"
279
+ require_dimension
280
+
281
+ mkdir -p "$DATA/agents"
282
+ record="$DATA/agents/$AGENT.json"
283
+ if [ ! -f "$record" ]; then
284
+ printf '{\n "name": "%s",\n "dimensionName": "%s"\n}\n' "$AGENT" "$DIMENSION" > "$record.$$"
285
+ ln "$record.$$" "$record" 2>/dev/null || true
286
+ rm -f "$record.$$"
287
+ fi
288
+ agent_dimension "$AGENT"
289
+ if [ "$DIMENSION" != "$DIMENSION_WANTED" ]; then
290
+ echo "$DIMENSION" >&2
291
+ exit "$E_CONFLICT"
292
+ fi
293
+
294
+ mkdir -p "$RUN"
295
+ exec 8> "$RUN/$AGENT.start.lock"
296
+ flock -w "$((START_TIMEOUT + STOP_TIMEOUT + 30))" 8
297
+
298
+ if worker_running "$AGENT" && [ "$WORKER_PROTOCOL" = "$PROTOCOL" ] && { [ -z "\${REPLACE_BUILD:-}" ] || [ "$WORKER_BUILD" = "$BUILD" ]; }; then exit 0; fi
299
+
300
+ runs_as="\${DIMENSION_USER%%:*}"
301
+ SOCKET_OWNER=""
302
+ if [ "$runs_as" = 0 ]; then
303
+ SOCKET_OWNER="$(id -u):$(id -g)"
304
+ elif [ "$runs_as" != "$(id -u)" ]; then
305
+ echo "agent $AGENT's worker would run as uid $runs_as, whose socket uid $(id -u) can't connect to" >&2
306
+ exit "$E_THIRD_USER"
307
+ fi
308
+
309
+ docker exec -u 0 -e OWNER="$DIMENSION_USER" -e WORKER_DIR -e SCRIPTS_DIR -e OLD_WORKER_DIR -e RUN_PATH -e STATE_PATH -e CA_BUNDLE \
310
+ "$CONTAINER" sh -c "$PREPARE_WORKER"
311
+
312
+ script="$SCRIPTS_DIR/worker-$BUILD.js"
313
+ if ! docker exec "$CONTAINER" test -f "$script"; then
314
+ [ "\${HAS_BUNDLE:-}" = 1 ] || exit "$E_NEED_BUNDLE"
315
+ docker exec -i -u "$DIMENSION_USER" -e SCRIPT="$script" "$CONTAINER" sh -c "$PUT_SCRIPT"
316
+ fi
317
+
318
+ stop_worker "$AGENT"
319
+ docker exec -d -u "$DIMENSION_USER" \
320
+ -e HYB_AGENT="$AGENT" -e HYB_LOG="$RUN_PATH/$AGENT.log" -e HYB_INSTALL_DIR="$WORKER_DIR" \
321
+ -e HYB_WORKER_SCRIPT="$script" -e HYB_WORKER_BUILD="$BUILD" -e HYB_SOCKET_OWNER="$SOCKET_OWNER" \
322
+ -e NODE_EXTRA_CA_CERTS="$CA_BUNDLE" -e SSL_CERT_FILE="$CA_BUNDLE" \
323
+ "$CONTAINER" sh -c "$START_WORKER"
324
+
325
+ waited=0
326
+ until worker_running "$AGENT" && [ "$WORKER_BUILD" = "$BUILD" ]; do
327
+ if [ "$waited" -ge "$((START_TIMEOUT * 10))" ]; then
328
+ echo "agent $AGENT's worker did not come up:" >&2
329
+ tail -c 2000 "$RUN/$AGENT.log" >&2 2>/dev/null || true
330
+ exit 1
331
+ fi
332
+ sleep 0.1
333
+ waited=$((waited + 1))
334
+ done
335
+ docker exec -u 0 -e SCRIPTS_DIR -e BUILD "$CONTAINER" sh -c "$REMOVE_OLD_SCRIPTS"
336
+ `;
337
+ const STOP_AGENT = sh `
338
+ set -eu
339
+ [ -f "$DATA/agents/$AGENT.json" ] || exit 0
340
+ agent_dimension "$AGENT"
341
+ require_dimension
342
+ stop_worker "$AGENT"
343
+ rm -f "$DATA/agents/$AGENT.json"
344
+ `;
345
+ const WORKER_SOCKET = sh `
346
+ set -eu
347
+ agent_dimension "$AGENT"
348
+ printf '%s\n%s\n' "$DIMENSION" "$DATA/dimension-run/$DIMENSION/$AGENT.sock"
349
+ `;
350
+ const LIST_AGENTS = sh `
351
+ for record in "$DATA"/agents/*.json; do
352
+ [ -f "$record" ] || continue
353
+ name="\${record##*/}"
354
+ printf '%s\n' "\${name%.json}"
355
+ cat "$record"
356
+ printf '\n\036\n'
357
+ done
358
+ `;
359
+ const LIST_SESSIONS = sh `
360
+ checks="$(mktemp -d)"
361
+ for record in "$DATA"/agents/*.json; do
362
+ [ -f "$record" ] || continue
363
+ agent="\${record##*/}"
364
+ agent="\${agent%.json}"
365
+ agent_dimension "$agent"
366
+ for session in "$DATA/dimension-state/$DIMENSION/agents/$agent/sessions"/*.json; do
367
+ [ -f "$session" ] || continue
368
+ status="$(tr -d '\n' < "\${session%.json}/status.json" 2>/dev/null || true)"
369
+ printf '%s\t%s\n' "$agent" "$status"
370
+ cat "$session"
371
+ printf '\n\036\n'
372
+ done
373
+ (
374
+ # shellcheck disable=SC2034
375
+ CONTAINER="$CONTAINER_PREFIX$DIMENSION"
376
+ # shellcheck disable=SC2034
377
+ RUN="$DATA/dimension-run/$DIMENSION"
378
+ if worker_running "$agent"; then echo "running $agent" > "$checks/$agent"; fi
379
+ ) &
380
+ done
381
+ wait
382
+ cat "$checks"/* 2>/dev/null || true
383
+ rm -rf "$checks"
384
+ `;
385
+ const INSTALL_IN_DIMENSION = sh `
386
+ set -eu
387
+ cd "$WORKER_DIR"
388
+ HOME="$(getent passwd "$(id -u)" | cut -d: -f6)"
389
+ export HOME
390
+ exec 9> .install.lock
391
+ flock 9
392
+ installed() {
393
+ manifest="node_modules/$PKG/package.json"
394
+ [ -f "$manifest" ] || return 1
395
+ grep -q "\"version\": *\"$VERSION\"" "$manifest" || return 1
396
+ # shellcheck disable=SC2086
397
+ for executable in $EXECUTABLES; do
398
+ for found in node_modules/$executable; do
399
+ [ -x "$found" ] && return 0
400
+ done
401
+ done
402
+ return 1
403
+ }
404
+ installed && exit 0
405
+ force=""
406
+ if [ -f "node_modules/$PKG/package.json" ] && grep -q "\"version\": *\"$VERSION\"" "node_modules/$PKG/package.json"; then force=--force; fi
407
+ # shellcheck disable=SC2086
408
+ bun add --exact $force "$PKG@$VERSION"
409
+ installed || { echo "bun add $PKG@$VERSION left no executable ($EXECUTABLES)" >&2; exit 1; }
410
+ `;
411
+ const INSTALL_BACKEND = sh `
412
+ set -eu
413
+ agent_dimension "$AGENT"
414
+ require_dimension
415
+ docker exec -u "$DIMENSION_USER" -e WORKER_DIR -e PKG -e VERSION -e EXECUTABLES \
416
+ -e NODE_EXTRA_CA_CERTS="$CA_BUNDLE" -e SSL_CERT_FILE="$CA_BUNDLE" "$CONTAINER" sh -c "$INSTALL_IN_DIMENSION"
417
+ `;
418
+ const LIST_BACKENDS = sh `
419
+ set -eu
420
+ agent_dimension "$AGENT"
421
+ modules="$DATA/dimension-state/$DIMENSION/worker/node_modules"
422
+ tab="$(printf '\t')"
423
+ printf '%s\n' "$BACKENDS" | while IFS="$tab" read -r backend pkg _pinned executables; do
424
+ installed="$(sed -n 's/^ *"version": *"\([^"]*\)".*/\1/p' "$modules/$pkg/package.json" 2>/dev/null | head -n 1)"
425
+ ready=0
426
+ if [ -n "$installed" ]; then
427
+ # shellcheck disable=SC2086
428
+ for executable in $executables; do
429
+ for found in "$modules"/$executable; do
430
+ [ -x "$found" ] && ready=1
431
+ done
432
+ done
433
+ fi
434
+ printf '%s\t%s\t%s\n' "$backend" "$installed" "$ready"
435
+ done
436
+ `;
437
+ const LOGIN_STATE = sh `
438
+ set -eu
439
+ agent_dimension "$AGENT"
440
+ record="$DATA/dimension-state/$DIMENSION/agents/$AGENT/sessions/$SESSION.json"
441
+ if [ ! -f "$record" ]; then
442
+ echo "$SESSION" >&2
443
+ exit "$E_NO_SESSION"
444
+ fi
445
+ backend="$(sed -n 's/^ *"backend": *"\([^"]*\)".*/\1/p' "$record" | head -n 1)"
446
+ tab="$(printf '\t')"
447
+ upstream="$(printf '%s\n' "$UPSTREAMS" | while IFS="$tab" read -r name value; do
448
+ if [ "$name" = "$backend" ]; then echo "$value"; fi
449
+ done)"
450
+ signed=0
451
+ for portal in "$DATA"/portals/*.json; do
452
+ [ -f "$portal" ] || continue
453
+ grep -q "\"dimensionName\": *\"$DIMENSION\"" "$portal" || continue
454
+ gateway="$(sed -n 's/^ *"gatewayName": *"\([^"]*\)".*/\1/p' "$portal")"
455
+ state="$DATA/gateway-state/$gateway"
456
+ if [ -n "$upstream" ] && [ -f "$state/upstreams/$upstream.json" ] && [ -f "$state/credentials/$upstream.oauth.json" ]; then signed=1; fi
457
+ done
458
+ printf '%s\t%s\n' "$backend" "$signed"
459
+ `;
460
+ const AGENTS_DOWN = sh `
461
+ checks="$(mktemp -d)"
462
+ for record in "$DATA"/agents/*.json; do
463
+ [ -f "$record" ] || continue
464
+ agent="\${record##*/}"
465
+ agent="\${agent%.json}"
466
+ agent_dimension "$agent"
467
+ (
468
+ CONTAINER="$CONTAINER_PREFIX$DIMENSION"
469
+ # shellcheck disable=SC2034
470
+ RUN="$DATA/dimension-run/$DIMENSION"
471
+ [ "$(docker inspect -f '{{.State.Running}}' "$CONTAINER" 2>/dev/null)" = true ] || exit 0
472
+ worker_running "$agent" && exit 0
473
+ printf '%s\t%s\n' "$agent" "$DIMENSION" > "$checks/$agent"
474
+ ) &
475
+ done
476
+ wait
477
+ cat "$checks"/* 2>/dev/null || true
478
+ rm -rf "$checks"
479
+ `;
@@ -1,11 +1,5 @@
1
1
  import type { Sandbox } from "../sandbox/api.ts";
2
2
  import { type AgentTranscriptPage, type AgentTranscriptRequest } from "./api.ts";
3
- /**
4
- * A page of the session's transcript, read on `host` from the dimension's state directory (its host
5
- * side) by the backend's own layout and parsing, so nothing has to run: one command, plus a read
6
- * for each further chunk the rare page that needs more takes. Null for a session whose env moves the backend's home
7
- * elsewhere (into the container, where only its worker reaches it).
8
- */
9
3
  export declare function readHostTranscript(host: Sandbox, { stateDirectory, agentName, sessionName }: {
10
4
  stateDirectory: string;
11
5
  agentName: string;
@@ -2,12 +2,6 @@ import { AgentNotFoundError } from "./api.js";
2
2
  import { CHUNK_BYTES, PROBE_BYTES, PROBE_LINES, TIME_SLACK_MS, createFileTranscript, prefetchedFiles, sandboxFiles, transcriptPage, transcriptTime, } from "./session/fileTranscript.js";
3
3
  import { backendHomePath, sessionRecordPath } from "./session/sessionStorage.js";
4
4
  import { STORED_TRANSCRIPTS } from "./session/storedTranscripts.js";
5
- /**
6
- * In one round trip: the session's record, its backend's file (found as the backend lays them out),
7
- * the stretches written again in it, where the page starts (for a time, by bisecting the rest of the
8
- * file as FileTranscript.page does) and what comes before that (PREFETCH_BYTES of it). The same
9
- * searches as fileTranscript.ts, here where the file is. Args: a JSON object, see readHostTranscript.
10
- */
11
5
  const READ_SCRIPT = String.raw `
12
6
  import base64, datetime, fnmatch, glob, json, mmap, os, sys
13
7
  args = json.loads(sys.argv[1])
@@ -146,16 +140,9 @@ if native_id and layout:
146
140
  out.update(path=path, size=size, end=end, after=after, copies=[[a, b] for a, b in copies], pieces=pieces)
147
141
  print(json.dumps(out))
148
142
  `;
149
- /** What's sent of the file with the record: a page and the slack around it, mostly, so it takes no more reads. */
150
143
  const PREFETCH_BYTES = 8 * CHUNK_BYTES;
151
- /**
152
- * A page of the session's transcript, read on `host` from the dimension's state directory (its host
153
- * side) by the backend's own layout and parsing, so nothing has to run: one command, plus a read
154
- * for each further chunk the rare page that needs more takes. Null for a session whose env moves the backend's home
155
- * elsewhere (into the container, where only its worker reaches it).
156
- */
157
144
  export async function readHostTranscript(host, { stateDirectory, agentName, sessionName }, { limit, before, cursor }) {
158
- before ??= cursor; // its old name
145
+ before ??= cursor;
159
146
  const args = {
160
147
  record: sessionRecordPath(stateDirectory, agentName, sessionName),
161
148
  homes: Object.fromEntries(Object.keys(STORED_TRANSCRIPTS).map((backend) => [backend, backendHomePath(stateDirectory, backend)])),
@@ -174,6 +161,8 @@ export async function readHostTranscript(host, { stateDirectory, agentName, sess
174
161
  if (!record)
175
162
  throw new AgentNotFoundError(`session ${sessionName} does not exist`);
176
163
  const stored = STORED_TRANSCRIPTS[record.spec.backend];
164
+ if (!stored)
165
+ return null;
177
166
  if (Object.keys(stored.homeEnvironment("")).some((name) => record.spec.env?.[name] !== undefined))
178
167
  return null;
179
168
  if (!record.nativeId)
@@ -1,82 +1,67 @@
1
- import type { AgentBackendInfo, AgentBackgroundTasks, AgentInput, AgentInterrupt, AgentMessageQueue, AgentModels, AgentPermissionRequest, AgentPermissionResult, AgentQuestionRequest, AgentQuestionResponse, AgentSession, AgentSessionStatus, AgentStreamingMessage, SessionRef } from "../api.ts";
2
- import type { FileTranscript, TranscriptFiles } from "./fileTranscript.ts";
3
- /** A capability's calls for one session: those of api.ts, with the session already chosen. */
1
+ import type { AgentBackendInfo, AgentBackgroundTasks, AgentInput, AgentInterrupt, AgentMessageQueue, AgentModels, AgentPermissionMode, AgentPermissionModes, AgentPermissionRequest, AgentPermissionResult, AgentQuestionRequest, AgentQuestionResponse, AgentSession, AgentStreamingMessage, SessionRef } from "../api.ts";
2
+ import type { Transcript, TranscriptFiles } from "./fileTranscript.ts";
4
3
  export type ForSession<Capability> = {
5
4
  [K in keyof Capability]: Capability[K] extends (ref: SessionRef, ...args: infer Args) => infer Result ? (...args: Args) => Result : never;
6
5
  };
7
- /** What one session's CLI runs with. */
8
6
  export type SessionLaunch = {
9
7
  spec: AgentSession;
10
- /** The backend's id for the conversation, from an earlier run, to resume it; null for a new one. */
11
8
  nativeId: string | null;
12
9
  cwd: string;
13
- /** The model chosen through AgentModels; null for the backend's default. */
14
10
  model: string | null;
15
- /** Where backends are installed (see SessionBackend.install). */
11
+ permissionMode: AgentPermissionMode;
16
12
  installDir: string;
17
- /** The worker's own environment, the CLI pointed at its home, and the session's. */
18
13
  env: Record<string, string>;
19
14
  };
20
- /** What the CLI reports to, and asks of, the worker. */
21
15
  export type SessionCallbacks = {
22
- /** Appends to the session's stream. */
23
16
  emit(message: AgentStreamingMessage): void;
24
- /** Records the backend's conversation id, so a later run can resume it. */
25
17
  setNativeId(id: string): void;
26
- /** The decision on a tool call: someone's answer, or a denial once the turn is interrupted, the session stops, or `signal` aborts. */
27
18
  requestPermission(request: Omit<AgentPermissionRequest, "id">, signal?: AbortSignal): Promise<AgentPermissionResult>;
28
- /** The user's answers, or null once the turn is interrupted, the session stops, or `signal` aborts. */
29
19
  askQuestions(request: Omit<AgentQuestionRequest, "id">, signal?: AbortSignal): Promise<AgentQuestionResponse | null>;
30
- /** The CLI is gone (crashed, or closed); the next message starts it again. */
31
- exited(error?: Error): void;
20
+ exited(exit: CliExit | null, error?: Error): void;
21
+ activeChanged(): void;
22
+ subagentStarted(toolUseId: string, subagentId: string): void;
23
+ };
24
+ export type CliExit = {
25
+ code: number | null;
26
+ signal: string | null;
32
27
  };
33
28
  export type SessionContext = SessionLaunch & SessionCallbacks;
34
- /** One session's running CLI: the capabilities it serves itself. */
35
- export type RunningSession = ForSession<AgentInput & AgentInterrupt & AgentSessionStatus & AgentMessageQueue & AgentModels & AgentBackgroundTasks> & {
29
+ export type RunningSession = ForSession<AgentInput & AgentInterrupt & AgentMessageQueue & AgentModels & AgentPermissionModes & AgentBackgroundTasks> & {
30
+ active(): boolean;
36
31
  close(): Promise<void>;
37
32
  };
38
- /** What a CLI's sign-in commands run with. */
39
33
  export type AuthEnvironment = {
40
34
  installDir: string;
41
35
  env: Record<string, string>;
42
36
  cwd: string;
43
37
  };
44
- /** A sign-in in progress: the CLI's own login command. */
45
38
  export interface LoginProcess {
46
- /** Resolves once the CLI has shown where to sign in. */
47
39
  prompt: Promise<{
48
40
  url: string;
49
41
  userCode?: string;
50
42
  needsCode: boolean;
51
43
  }>;
52
- /** Resolves when the CLI signed in; rejects with why it didn't. */
53
44
  done: Promise<void>;
54
- /** Gives the CLI the code the sign-in page showed. */
55
45
  submitCode(code: string): void;
56
46
  cancel(): void;
57
47
  }
58
- /** A CLI's sign-in, through its own commands. The credentials it saves are fakes when a gateway holds the real ones. */
59
48
  export type BackendAuth = {
60
49
  signedIn(environment: AuthEnvironment): Promise<boolean>;
61
- /** With `gatewaySignedIn` (the dimension's gateway holds the upstream's credential) it completes by itself: the gateway answers. */
62
50
  login(environment: AuthEnvironment, gatewaySignedIn: boolean): LoginProcess;
63
51
  };
64
- /** What finds a session's conversation in its backend's storage, read through `files`. */
65
52
  export type TranscriptSource = {
66
53
  nativeId: string;
67
54
  env: Record<string, string>;
68
55
  files: TranscriptFiles;
56
+ installDir: string;
69
57
  };
70
- /** An agent CLI, wired in agent/session/<backend>/: one file per capability. */
71
58
  export type SessionBackend = {
72
- /** Installs the backend under `installDir`, or updates it to the pinned version. Runs in the dimension. */
73
59
  install(installDir: string): Promise<void>;
74
- /** What's installed under `installDir`, and whether it's what install leaves: this release's version, complete. */
75
- installed(installDir: string): Promise<Pick<AgentBackendInfo, "version" | "ready">>;
60
+ installed(installDir: string): Promise<Omit<AgentBackendInfo, "backend">>;
76
61
  start(context: SessionContext): Promise<RunningSession>;
77
62
  auth: BackendAuth;
78
- /** The conversation `nativeId` in the backend's own storage, which needs no CLI running. */
79
- transcript(source: TranscriptSource): FileTranscript;
80
- /** The environment that points the CLI at `home` for everything it keeps (see SessionStorage.backendHome). */
63
+ transcript(source: TranscriptSource): Transcript;
64
+ findSubagent(source: TranscriptSource, toolUseId: string): Promise<string | null>;
65
+ subagentTranscript(source: TranscriptSource, subagentId: string, toolUseId: string): Transcript;
81
66
  homeEnvironment(home: string): Record<string, string>;
82
67
  };
@@ -1,2 +1 @@
1
- /** Points claude at `home` for everything it keeps: its .claude.json too, which otherwise sits in the home directory. */
2
1
  export declare function claudeHomeEnvironment(home: string): Record<string, string>;
@@ -1,4 +1,3 @@
1
- /** Points claude at `home` for everything it keeps: its .claude.json too, which otherwise sits in the home directory. */
2
1
  export function claudeHomeEnvironment(home) {
3
2
  return { CLAUDE_CONFIG_DIR: home };
4
3
  }
@@ -0,0 +1,10 @@
1
+ import type { AgentBackendInfo } from "../../api.ts";
2
+ export declare const CLAUDE_SDK_PACKAGE = "../../../vendor-types/claude/agent-sdk/sdk.js";
3
+ export declare function claudePackage(): {
4
+ pkg: string;
5
+ version: string;
6
+ executables: string;
7
+ };
8
+ export declare function installClaude(installDir: string): Promise<void>;
9
+ export declare function installedClaude(installDir: string): Promise<Omit<AgentBackendInfo, "backend">>;
10
+ export declare function claudeExecutable(installDir: string): string;