@cydm/happy-elves 0.1.0-beta.31 → 0.1.0-beta.310

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 (342) hide show
  1. package/apps/cli/dist/commands/app.js +10 -0
  2. package/apps/cli/dist/commands/daemon.js +92 -4
  3. package/apps/cli/dist/commands/gateway.d.ts +2 -0
  4. package/apps/cli/dist/commands/gateway.js +429 -0
  5. package/apps/cli/dist/commands/lib/args.js +49 -0
  6. package/apps/cli/dist/commands/lib/bootstrap-daemon.d.ts +2 -2
  7. package/apps/cli/dist/commands/lib/bootstrap-daemon.js +2 -2
  8. package/apps/cli/dist/commands/lib/doctor.d.ts +11 -0
  9. package/apps/cli/dist/commands/lib/doctor.js +276 -11
  10. package/apps/cli/dist/commands/lib/gateway-store.d.ts +38 -0
  11. package/apps/cli/dist/commands/lib/gateway-store.js +33 -0
  12. package/apps/cli/dist/commands/lib/index.d.ts +4 -2
  13. package/apps/cli/dist/commands/lib/index.js +2 -0
  14. package/apps/cli/dist/commands/lib/json.d.ts +2 -2
  15. package/apps/cli/dist/commands/lib/json.js +5 -2
  16. package/apps/cli/dist/commands/lib/local-daemon.d.ts +1 -0
  17. package/apps/cli/dist/commands/lib/local-daemon.js +14 -0
  18. package/apps/cli/dist/commands/lib/paths.d.ts +2 -0
  19. package/apps/cli/dist/commands/lib/paths.js +2 -0
  20. package/apps/cli/dist/commands/lib/relay-db-audit.d.ts +37 -0
  21. package/apps/cli/dist/commands/lib/relay-db-audit.js +300 -0
  22. package/apps/cli/dist/commands/lib/relay-http.d.ts +1 -1
  23. package/apps/cli/dist/commands/lib/scope.d.ts +1 -1
  24. package/apps/cli/dist/commands/lib/session-output.d.ts +15 -1
  25. package/apps/cli/dist/commands/lib/session-output.js +214 -6
  26. package/apps/cli/dist/commands/lib/session-view.d.ts +2 -2
  27. package/apps/cli/dist/commands/lib/status.js +5 -1
  28. package/apps/cli/dist/commands/lib/types.d.ts +4 -2
  29. package/apps/cli/dist/commands/lib/usage.js +123 -10
  30. package/apps/cli/dist/commands/lib/workspace.d.ts +2 -2
  31. package/apps/cli/dist/commands/lib/workspace.js +63 -10
  32. package/apps/cli/dist/commands/machine.js +50 -9
  33. package/apps/cli/dist/commands/memory.d.ts +2 -0
  34. package/apps/cli/dist/commands/memory.js +179 -0
  35. package/apps/cli/dist/commands/relay.js +29 -2
  36. package/apps/cli/dist/commands/release.d.ts +2 -0
  37. package/apps/cli/dist/commands/release.js +197 -0
  38. package/apps/cli/dist/commands/remote.js +10 -2
  39. package/apps/cli/dist/commands/schedule.d.ts +2 -0
  40. package/apps/cli/dist/commands/schedule.js +273 -0
  41. package/apps/cli/dist/commands/session.js +517 -5
  42. package/apps/cli/dist/commands/turn.js +225 -9
  43. package/apps/cli/dist/commands/workspace.d.ts +2 -0
  44. package/apps/cli/dist/commands/workspace.js +68 -0
  45. package/apps/cli/package.json +6 -0
  46. package/apps/daemon/dist/gateway/adapters.d.ts +38 -0
  47. package/apps/daemon/dist/gateway/adapters.js +2 -0
  48. package/apps/daemon/dist/gateway/feishu.d.ts +65 -0
  49. package/apps/daemon/dist/gateway/feishu.js +493 -0
  50. package/apps/daemon/dist/gateway/format.d.ts +2 -0
  51. package/apps/daemon/dist/gateway/format.js +19 -0
  52. package/apps/daemon/dist/gateway/handler.d.ts +7 -0
  53. package/apps/daemon/dist/gateway/handler.js +151 -0
  54. package/apps/daemon/dist/gateway/runtime.d.ts +33 -0
  55. package/apps/daemon/dist/gateway/runtime.js +850 -0
  56. package/apps/daemon/dist/gateway/store.d.ts +92 -0
  57. package/apps/daemon/dist/gateway/store.js +268 -0
  58. package/apps/daemon/dist/memory/handler.d.ts +7 -0
  59. package/apps/daemon/dist/memory/handler.js +105 -0
  60. package/apps/daemon/dist/memory/manager.d.ts +44 -0
  61. package/apps/daemon/dist/memory/manager.js +359 -0
  62. package/apps/daemon/dist/paths.d.ts +3 -0
  63. package/apps/daemon/dist/paths.js +3 -0
  64. package/apps/daemon/dist/relay/admission.d.ts +30 -0
  65. package/apps/daemon/dist/relay/admission.js +31 -0
  66. package/apps/daemon/dist/relay/connection.js +37 -1
  67. package/apps/daemon/dist/relay/devtools.d.ts +1 -1
  68. package/apps/daemon/dist/relay/register.js +2 -0
  69. package/apps/daemon/dist/relay/send.d.ts +2 -2
  70. package/apps/daemon/dist/relay/send.js +2 -0
  71. package/apps/daemon/dist/relay-http.d.ts +1 -1
  72. package/apps/daemon/dist/runtime/external-provider.d.ts +1 -1
  73. package/apps/daemon/dist/runtime/external-provider.js +187 -17
  74. package/apps/daemon/dist/runtime.d.ts +1 -2
  75. package/apps/daemon/dist/runtime.js +0 -3
  76. package/apps/daemon/dist/schedule/handler.d.ts +9 -0
  77. package/apps/daemon/dist/schedule/handler.js +148 -0
  78. package/apps/daemon/dist/schedule/runner.d.ts +21 -0
  79. package/apps/daemon/dist/schedule/runner.js +547 -0
  80. package/apps/daemon/dist/schedule/store.d.ts +9 -0
  81. package/apps/daemon/dist/schedule/store.js +143 -0
  82. package/apps/daemon/dist/session/create-session.d.ts +1 -1
  83. package/apps/daemon/dist/session/directory.d.ts +1 -1
  84. package/apps/daemon/dist/session/events.d.ts +15 -2
  85. package/apps/daemon/dist/session/events.js +76 -24
  86. package/apps/daemon/dist/session/file-preview.d.ts +1 -1
  87. package/apps/daemon/dist/session/lifecycle.d.ts +26 -3
  88. package/apps/daemon/dist/session/lifecycle.js +161 -22
  89. package/apps/daemon/dist/session/metadata.d.ts +2 -2
  90. package/apps/daemon/dist/session/metadata.js +42 -1
  91. package/apps/daemon/dist/session/primitives.d.ts +1 -1
  92. package/apps/daemon/dist/session/primitives.js +37 -6
  93. package/apps/daemon/dist/session/prompt.d.ts +28 -1
  94. package/apps/daemon/dist/session/prompt.js +340 -5
  95. package/apps/daemon/dist/session/reconcile.d.ts +3 -0
  96. package/apps/daemon/dist/session/reconcile.js +235 -0
  97. package/apps/daemon/dist/session/runtime-handle.d.ts +1 -1
  98. package/apps/daemon/dist/start.js +5 -1
  99. package/apps/daemon/dist/state.d.ts +2 -2
  100. package/apps/daemon/dist/turn-coordinator.d.ts +1 -0
  101. package/apps/daemon/dist/turn-coordinator.js +4 -0
  102. package/apps/daemon/dist/types.d.ts +16 -1
  103. package/apps/daemon/package.json +3 -25
  104. package/apps/relay/dist/connections.d.ts +2 -0
  105. package/apps/relay/dist/controller-handlers.d.ts +42 -2
  106. package/apps/relay/dist/controller-handlers.js +349 -37
  107. package/apps/relay/dist/db.js +296 -2
  108. package/apps/relay/dist/errors.d.ts +2 -1
  109. package/apps/relay/dist/errors.js +3 -1
  110. package/apps/relay/dist/http-routes.js +659 -33
  111. package/apps/relay/dist/http-schemas.d.ts +156 -0
  112. package/apps/relay/dist/http-schemas.js +85 -0
  113. package/apps/relay/dist/index.js +31 -1
  114. package/apps/relay/dist/machine-handlers.d.ts +15 -7
  115. package/apps/relay/dist/machine-handlers.js +567 -27
  116. package/apps/relay/dist/projections.d.ts +1 -1
  117. package/apps/relay/dist/projections.js +13 -0
  118. package/apps/relay/dist/relay-context.d.ts +41 -3
  119. package/apps/relay/dist/relay-context.js +244 -19
  120. package/apps/relay/dist/repositories.d.ts +2 -2
  121. package/apps/relay/dist/repositories.js +28 -1
  122. package/apps/relay/dist/runtime-bindings.d.ts +25 -0
  123. package/apps/relay/dist/runtime-bindings.js +49 -0
  124. package/apps/relay/dist/scope.d.ts +1 -1
  125. package/apps/relay/dist/types.d.ts +71 -1
  126. package/apps/relay/dist/websocket.js +2 -0
  127. package/package.json +5 -11
  128. package/packages/agent-sdk/dist/index.d.ts +80 -0
  129. package/packages/agent-sdk/dist/index.js +16 -0
  130. package/packages/client/dist/account.d.ts +35 -2
  131. package/packages/client/dist/account.js +98 -1
  132. package/packages/client/dist/client.d.ts +59 -6
  133. package/packages/client/dist/client.js +312 -58
  134. package/packages/client/dist/index.d.ts +1 -1
  135. package/packages/client/dist/parsers.d.ts +28 -2
  136. package/packages/client/dist/parsers.js +167 -0
  137. package/packages/client/dist/transport.d.ts +21 -1
  138. package/packages/client/dist/transport.js +69 -6
  139. package/packages/client/dist/types.d.ts +177 -1
  140. package/packages/client/dist/validation.d.ts +1 -1
  141. package/packages/runtime/dist/index.d.ts +66 -0
  142. package/packages/runtime-acpx/dist/index.d.ts +1 -1
  143. package/packages/runtime-acpx/dist/index.js +8 -0
  144. package/packages/runtime-cli/dist/claude-history.d.ts +1 -2
  145. package/packages/runtime-cli/dist/claude-history.js +0 -3
  146. package/packages/runtime-cli/dist/claude-session-store.d.ts +0 -1
  147. package/packages/runtime-cli/dist/claude-session-store.js +1 -1
  148. package/packages/runtime-cli/dist/claude-turn.d.ts +2 -1
  149. package/packages/runtime-cli/dist/claude-turn.js +29 -9
  150. package/packages/runtime-cli/dist/codex-app-server.d.ts +8 -3
  151. package/packages/runtime-cli/dist/codex-app-server.js +122 -25
  152. package/packages/runtime-cli/dist/codex-history.d.ts +1 -2
  153. package/packages/runtime-cli/dist/codex-history.js +11 -5
  154. package/packages/runtime-cli/dist/codex-protocol.d.ts +2 -2
  155. package/packages/runtime-cli/dist/codex-protocol.js +4 -4
  156. package/packages/runtime-cli/dist/history-merge.d.ts +1 -1
  157. package/packages/runtime-cli/dist/index.d.ts +1 -1
  158. package/packages/runtime-cli/dist/index.js +108 -2
  159. package/packages/runtime-cli/dist/permissions.d.ts +1 -1
  160. package/packages/runtime-cli/dist/session-store.d.ts +2 -1
  161. package/packages/runtime-cli/dist/session-store.js +9 -8
  162. package/packages/shared/dist/index.d.ts +2 -0
  163. package/packages/shared/dist/index.js +2 -0
  164. package/packages/shared/dist/protocol-schemas.d.ts +1077 -0
  165. package/packages/shared/dist/protocol-schemas.js +273 -0
  166. package/packages/shared/dist/protocol-types.d.ts +371 -3
  167. package/packages/shared/dist/protocol.d.ts +181 -2
  168. package/packages/shared/dist/protocol.js +197 -1
  169. package/packages/shared/dist/session-tags.d.ts +12 -0
  170. package/packages/shared/dist/session-tags.js +50 -0
  171. package/apps/cli/dist/commands/account.js.map +0 -1
  172. package/apps/cli/dist/commands/app.js.map +0 -1
  173. package/apps/cli/dist/commands/collect.js.map +0 -1
  174. package/apps/cli/dist/commands/command.js.map +0 -1
  175. package/apps/cli/dist/commands/config.js.map +0 -1
  176. package/apps/cli/dist/commands/daemon.js.map +0 -1
  177. package/apps/cli/dist/commands/lib/args.js.map +0 -1
  178. package/apps/cli/dist/commands/lib/audit.js.map +0 -1
  179. package/apps/cli/dist/commands/lib/bootstrap-config.js.map +0 -1
  180. package/apps/cli/dist/commands/lib/bootstrap-daemon.js.map +0 -1
  181. package/apps/cli/dist/commands/lib/bootstrap-output.js.map +0 -1
  182. package/apps/cli/dist/commands/lib/bootstrap.js.map +0 -1
  183. package/apps/cli/dist/commands/lib/config.js.map +0 -1
  184. package/apps/cli/dist/commands/lib/doctor.js.map +0 -1
  185. package/apps/cli/dist/commands/lib/exit.js.map +0 -1
  186. package/apps/cli/dist/commands/lib/index.js.map +0 -1
  187. package/apps/cli/dist/commands/lib/json.js.map +0 -1
  188. package/apps/cli/dist/commands/lib/local-daemon.js.map +0 -1
  189. package/apps/cli/dist/commands/lib/loop-store.js.map +0 -1
  190. package/apps/cli/dist/commands/lib/paths.js.map +0 -1
  191. package/apps/cli/dist/commands/lib/relay-http.js.map +0 -1
  192. package/apps/cli/dist/commands/lib/scope.js.map +0 -1
  193. package/apps/cli/dist/commands/lib/session-output.js.map +0 -1
  194. package/apps/cli/dist/commands/lib/session-view.js.map +0 -1
  195. package/apps/cli/dist/commands/lib/status.js.map +0 -1
  196. package/apps/cli/dist/commands/lib/types.js.map +0 -1
  197. package/apps/cli/dist/commands/lib/usage.js.map +0 -1
  198. package/apps/cli/dist/commands/lib/workspace.js.map +0 -1
  199. package/apps/cli/dist/commands/loop.js.map +0 -1
  200. package/apps/cli/dist/commands/machine.js.map +0 -1
  201. package/apps/cli/dist/commands/relay.js.map +0 -1
  202. package/apps/cli/dist/commands/remote.js.map +0 -1
  203. package/apps/cli/dist/commands/session.js.map +0 -1
  204. package/apps/cli/dist/commands/token.js.map +0 -1
  205. package/apps/cli/dist/commands/turn.js.map +0 -1
  206. package/apps/cli/dist/errors.js.map +0 -1
  207. package/apps/cli/dist/index.js.map +0 -1
  208. package/apps/daemon/dist/app.js.map +0 -1
  209. package/apps/daemon/dist/args.js.map +0 -1
  210. package/apps/daemon/dist/audit.js.map +0 -1
  211. package/apps/daemon/dist/cli.js.map +0 -1
  212. package/apps/daemon/dist/config.js.map +0 -1
  213. package/apps/daemon/dist/errors.js.map +0 -1
  214. package/apps/daemon/dist/loop/runner.js.map +0 -1
  215. package/apps/daemon/dist/loop/store.js.map +0 -1
  216. package/apps/daemon/dist/pair.js.map +0 -1
  217. package/apps/daemon/dist/paths.js.map +0 -1
  218. package/apps/daemon/dist/process.js.map +0 -1
  219. package/apps/daemon/dist/relay/connection.js.map +0 -1
  220. package/apps/daemon/dist/relay/devtools.js.map +0 -1
  221. package/apps/daemon/dist/relay/register.js.map +0 -1
  222. package/apps/daemon/dist/relay/send.js.map +0 -1
  223. package/apps/daemon/dist/relay-http.js.map +0 -1
  224. package/apps/daemon/dist/runtime/external-provider.js.map +0 -1
  225. package/apps/daemon/dist/runtime.js.map +0 -1
  226. package/apps/daemon/dist/session/create-session.js.map +0 -1
  227. package/apps/daemon/dist/session/directory.js.map +0 -1
  228. package/apps/daemon/dist/session/events.js.map +0 -1
  229. package/apps/daemon/dist/session/file-preview.js.map +0 -1
  230. package/apps/daemon/dist/session/lifecycle.js.map +0 -1
  231. package/apps/daemon/dist/session/metadata.js.map +0 -1
  232. package/apps/daemon/dist/session/primitives.js.map +0 -1
  233. package/apps/daemon/dist/session/prompt.js.map +0 -1
  234. package/apps/daemon/dist/session/runtime-handle.js.map +0 -1
  235. package/apps/daemon/dist/start.js.map +0 -1
  236. package/apps/daemon/dist/state.js.map +0 -1
  237. package/apps/daemon/dist/turn-coordinator.js.map +0 -1
  238. package/apps/daemon/dist/types.js.map +0 -1
  239. package/apps/daemon/dist/utils.js.map +0 -1
  240. package/apps/relay/dist/auth.js.map +0 -1
  241. package/apps/relay/dist/connections.js.map +0 -1
  242. package/apps/relay/dist/controller-handlers.js.map +0 -1
  243. package/apps/relay/dist/db.js.map +0 -1
  244. package/apps/relay/dist/errors.js.map +0 -1
  245. package/apps/relay/dist/http-routes.js.map +0 -1
  246. package/apps/relay/dist/http-schemas.js.map +0 -1
  247. package/apps/relay/dist/index.js.map +0 -1
  248. package/apps/relay/dist/machine-handlers.js.map +0 -1
  249. package/apps/relay/dist/projections.js.map +0 -1
  250. package/apps/relay/dist/relay-context.js.map +0 -1
  251. package/apps/relay/dist/repositories.js.map +0 -1
  252. package/apps/relay/dist/retention.js.map +0 -1
  253. package/apps/relay/dist/scope.js.map +0 -1
  254. package/apps/relay/dist/security.js.map +0 -1
  255. package/apps/relay/dist/types.js.map +0 -1
  256. package/apps/relay/dist/websocket.js.map +0 -1
  257. package/apps/relay/package.json +0 -29
  258. package/packages/agent-sdk/dist/index.d.ts.map +0 -1
  259. package/packages/agent-sdk/dist/index.js.map +0 -1
  260. package/packages/agent-sdk/package.json +0 -20
  261. package/packages/client/dist/account.d.ts.map +0 -1
  262. package/packages/client/dist/account.js.map +0 -1
  263. package/packages/client/dist/client.d.ts.map +0 -1
  264. package/packages/client/dist/client.js.map +0 -1
  265. package/packages/client/dist/errors.d.ts.map +0 -1
  266. package/packages/client/dist/errors.js.map +0 -1
  267. package/packages/client/dist/http.d.ts.map +0 -1
  268. package/packages/client/dist/http.js.map +0 -1
  269. package/packages/client/dist/index.d.ts.map +0 -1
  270. package/packages/client/dist/index.js.map +0 -1
  271. package/packages/client/dist/parsers.d.ts.map +0 -1
  272. package/packages/client/dist/parsers.js.map +0 -1
  273. package/packages/client/dist/transport.d.ts.map +0 -1
  274. package/packages/client/dist/transport.js.map +0 -1
  275. package/packages/client/dist/types.d.ts.map +0 -1
  276. package/packages/client/dist/types.js.map +0 -1
  277. package/packages/client/dist/validation.d.ts.map +0 -1
  278. package/packages/client/dist/validation.js.map +0 -1
  279. package/packages/client/package.json +0 -22
  280. package/packages/pie-provider/dist/index.d.ts.map +0 -1
  281. package/packages/pie-provider/dist/index.js.map +0 -1
  282. package/packages/pie-provider/package.json +0 -26
  283. package/packages/runtime/dist/index.d.ts.map +0 -1
  284. package/packages/runtime/dist/index.js.map +0 -1
  285. package/packages/runtime/package.json +0 -19
  286. package/packages/runtime-acpx/dist/index.d.ts.map +0 -1
  287. package/packages/runtime-acpx/dist/index.js.map +0 -1
  288. package/packages/runtime-acpx/package.json +0 -23
  289. package/packages/runtime-cli/dist/async-queue.d.ts.map +0 -1
  290. package/packages/runtime-cli/dist/async-queue.js.map +0 -1
  291. package/packages/runtime-cli/dist/claude-history.d.ts.map +0 -1
  292. package/packages/runtime-cli/dist/claude-history.js.map +0 -1
  293. package/packages/runtime-cli/dist/claude-json.d.ts.map +0 -1
  294. package/packages/runtime-cli/dist/claude-json.js.map +0 -1
  295. package/packages/runtime-cli/dist/claude-rename.d.ts.map +0 -1
  296. package/packages/runtime-cli/dist/claude-rename.js.map +0 -1
  297. package/packages/runtime-cli/dist/claude-session-store.d.ts.map +0 -1
  298. package/packages/runtime-cli/dist/claude-session-store.js.map +0 -1
  299. package/packages/runtime-cli/dist/claude-turn.d.ts.map +0 -1
  300. package/packages/runtime-cli/dist/claude-turn.js.map +0 -1
  301. package/packages/runtime-cli/dist/codex-app-server.d.ts.map +0 -1
  302. package/packages/runtime-cli/dist/codex-app-server.js.map +0 -1
  303. package/packages/runtime-cli/dist/codex-approvals.d.ts.map +0 -1
  304. package/packages/runtime-cli/dist/codex-approvals.js.map +0 -1
  305. package/packages/runtime-cli/dist/codex-history.d.ts.map +0 -1
  306. package/packages/runtime-cli/dist/codex-history.js.map +0 -1
  307. package/packages/runtime-cli/dist/codex-json-rpc.d.ts.map +0 -1
  308. package/packages/runtime-cli/dist/codex-json-rpc.js.map +0 -1
  309. package/packages/runtime-cli/dist/codex-lifecycle.d.ts.map +0 -1
  310. package/packages/runtime-cli/dist/codex-lifecycle.js.map +0 -1
  311. package/packages/runtime-cli/dist/codex-protocol.d.ts.map +0 -1
  312. package/packages/runtime-cli/dist/codex-protocol.js.map +0 -1
  313. package/packages/runtime-cli/dist/command-resolver.d.ts.map +0 -1
  314. package/packages/runtime-cli/dist/command-resolver.js.map +0 -1
  315. package/packages/runtime-cli/dist/history-merge.d.ts.map +0 -1
  316. package/packages/runtime-cli/dist/history-merge.js.map +0 -1
  317. package/packages/runtime-cli/dist/index.d.ts.map +0 -1
  318. package/packages/runtime-cli/dist/index.js.map +0 -1
  319. package/packages/runtime-cli/dist/permissions.d.ts.map +0 -1
  320. package/packages/runtime-cli/dist/permissions.js.map +0 -1
  321. package/packages/runtime-cli/dist/session-store.d.ts.map +0 -1
  322. package/packages/runtime-cli/dist/session-store.js.map +0 -1
  323. package/packages/runtime-cli/package.json +0 -22
  324. package/packages/shared/dist/args.d.ts.map +0 -1
  325. package/packages/shared/dist/args.js.map +0 -1
  326. package/packages/shared/dist/crypto.d.ts.map +0 -1
  327. package/packages/shared/dist/crypto.js.map +0 -1
  328. package/packages/shared/dist/ids.d.ts.map +0 -1
  329. package/packages/shared/dist/ids.js.map +0 -1
  330. package/packages/shared/dist/index.d.ts.map +0 -1
  331. package/packages/shared/dist/index.js.map +0 -1
  332. package/packages/shared/dist/protocol-schemas.d.ts.map +0 -1
  333. package/packages/shared/dist/protocol-schemas.js.map +0 -1
  334. package/packages/shared/dist/protocol-types.d.ts.map +0 -1
  335. package/packages/shared/dist/protocol-types.js.map +0 -1
  336. package/packages/shared/dist/protocol.d.ts.map +0 -1
  337. package/packages/shared/dist/protocol.js.map +0 -1
  338. package/packages/shared/dist/session-name.d.ts.map +0 -1
  339. package/packages/shared/dist/session-name.js.map +0 -1
  340. package/packages/shared/dist/session-state.d.ts.map +0 -1
  341. package/packages/shared/dist/session-state.js.map +0 -1
  342. package/packages/shared/package.json +0 -24
@@ -1,4 +1,4 @@
1
- import type { EncryptedSessionEvent, MachineSnapshot, SessionSnapshot } from "@happy-elves/shared";
1
+ import type { EncryptedSessionEvent, MachineSnapshot, SessionSnapshot } from "../../../packages/shared/dist/index.js";
2
2
  import type { EventRow, MachineRow, SessionRow } from "./types.js";
3
3
  export declare function parseJson<T>(value: string | null | undefined, fallback: T): T;
4
4
  export declare function normalizeMachineCapabilities(value: unknown): MachineSnapshot["capabilities"];
@@ -89,12 +89,25 @@ export function sessionSnapshot(row, capabilitiesForMachine, historyModelForMach
89
89
  encryptedMetadata: parseJson(row.encrypted_metadata, undefined),
90
90
  currentHead: row.current_head ?? undefined,
91
91
  lastTurnId: row.last_turn_id ?? undefined,
92
+ headBasis: sessionHeadBasis(row),
92
93
  sourceSessionId: row.source_session_id ?? undefined,
93
94
  sourceCheckpointId: row.source_checkpoint_id ?? undefined,
94
95
  historyModel: historyModelForMachine?.(row.account_id, row.machine_id, row.agent),
95
96
  capabilities: capabilitiesForMachine(row.account_id, row.machine_id, row.agent),
96
97
  };
97
98
  }
99
+ function sessionHeadBasis(row) {
100
+ const basis = {};
101
+ if (row.head_basis_event_id !== null)
102
+ basis.eventId = row.head_basis_event_id;
103
+ if (row.head_basis_message_id !== null)
104
+ basis.messageId = row.head_basis_message_id;
105
+ if (row.head_basis_logical_time !== null)
106
+ basis.logicalTime = row.head_basis_logical_time;
107
+ if (row.head_basis_turn_seq !== null)
108
+ basis.turnSeq = row.head_basis_turn_seq;
109
+ return Object.keys(basis).length > 0 ? basis : undefined;
110
+ }
98
111
  export function eventSnapshot(row) {
99
112
  return {
100
113
  id: row.id,
@@ -1,8 +1,8 @@
1
1
  import type { DatabaseSync } from "node:sqlite";
2
- import { type EncryptedEnvelope, type EncryptedSessionEvent, type MachineSnapshot, type ServerMessage, type SessionSnapshot } from "@happy-elves/shared";
2
+ import { type EncryptedEnvelope, type EncryptedSessionEvent, type MachineSnapshot, type ServerMessage, type SessionSnapshot } from "../../../packages/shared/dist/index.js";
3
3
  import { parseJson } from "./projections.js";
4
4
  import { filterSnapshotForScope, isFullControllerToken, scopedTokenPublic, tokenScope } from "./scope.js";
5
- import type { ControllerConnection, ControllerInviteRow, EventRow, MachineConnection, SessionRow, TokenKind, TokenRecord, WebSocketLike } from "./types.js";
5
+ import type { ControllerConnection, ControllerInviteRow, EventRow, MachineConnection, RelaySessionClaimRow, SessionRow, TokenKind, TokenRecord, WebSocketLike } from "./types.js";
6
6
  type CreateRelayContextOptions = {
7
7
  db: DatabaseSync;
8
8
  eventReplayLimit: number;
@@ -29,6 +29,7 @@ export declare function createRelayContext(options: CreateRelayContextOptions):
29
29
  closeRevokedControllerConnections: (accountId: string, deviceId: string) => void;
30
30
  closeRevokedMachineConnection: (accountId: string, machineId: string) => void;
31
31
  connectedMachine: (accountId: string, machineId: string) => MachineConnection | undefined;
32
+ controllerDeviceOnline: (accountId: string, deviceId: string) => boolean;
32
33
  controllersByAccount: Map<string, Set<ControllerConnection>>;
33
34
  createPairingForAccount: (accountId: string) => {
34
35
  pairingCode: string;
@@ -43,11 +44,13 @@ export declare function createRelayContext(options: CreateRelayContextOptions):
43
44
  accountId: string;
44
45
  sessionId: string;
45
46
  machineId: string;
47
+ source: "controller" | "machine";
46
48
  messageId?: string;
47
49
  turnId: string;
48
50
  turnSeq?: number;
49
51
  occurredAt?: number;
50
52
  payload: EncryptedEnvelope;
53
+ updateSession?: boolean;
51
54
  }) => EncryptedSessionEvent;
52
55
  aliasedRuntimeEventHasRequestEvents: (params: {
53
56
  accountId: string;
@@ -55,16 +58,39 @@ export declare function createRelayContext(options: CreateRelayContextOptions):
55
58
  machineId: string;
56
59
  runtimeTurnId: string;
57
60
  }) => boolean;
61
+ activeSessionClaim: (accountId: string, sessionId: string) => RelaySessionClaimRow | undefined;
62
+ claimSessionTurn: (params: {
63
+ accountId: string;
64
+ sessionId: string;
65
+ machineId: string;
66
+ requestId: string;
67
+ turnId: string;
68
+ commandType: "prompt";
69
+ createdAt?: number;
70
+ }) => {
71
+ ok: true;
72
+ } | {
73
+ ok: false;
74
+ claim: RelaySessionClaimRow;
75
+ };
58
76
  isCommandPending: (accountId: string, requestId: string) => boolean;
77
+ isSessionCommandPending: (accountId: string, sessionId: string) => boolean;
59
78
  isFullControllerToken: typeof isFullControllerToken;
60
79
  machineCapabilities: (accountId: string, machineId: string) => MachineSnapshot["capabilities"] | undefined;
61
80
  machineMessageProcessed: (accountId: string, machineId: string, messageId: string) => boolean;
62
81
  machinesByKey: Map<string, MachineConnection>;
63
- markCommandPending: (accountId: string, machineId: string, requestId: string) => void;
82
+ markCommandPending: (accountId: string, machineId: string, requestId: string, options?: {
83
+ command?: string;
84
+ sessionId?: string;
85
+ }) => void;
64
86
  markMachineMessageProcessed: (accountId: string, machineId: string, messageId: string) => void;
87
+ markTokenSeen: (token: string) => void;
65
88
  now: () => number;
66
89
  parseJson: typeof parseJson;
67
90
  previousCommandResponse: (accountId: string, requestId: string) => ServerMessage | undefined;
91
+ previousAdmissionAck: (accountId: string, requestId: string) => Extract<ServerMessage, {
92
+ type: "server:ack";
93
+ }> | undefined;
68
94
  recordTurnAlias: (params: {
69
95
  accountId: string;
70
96
  sessionId: string;
@@ -77,6 +103,18 @@ export declare function createRelayContext(options: CreateRelayContextOptions):
77
103
  requireFullControllerToken: (authHeader: string | undefined) => TokenRecord;
78
104
  requireHttpToken: (authHeader: string | undefined, kind: TokenKind) => TokenRecord;
79
105
  resumeOfflineSessionsForMachine: (connection: MachineConnection) => void;
106
+ deliverOutboxCommand: (accountId: string, requestId: string) => "queued" | "delivered";
107
+ deliverQueuedCommandsForMachine: (connection: MachineConnection) => void;
108
+ finishSessionClaim: (params: {
109
+ accountId: string;
110
+ sessionId: string;
111
+ requestId?: string;
112
+ turnId?: string;
113
+ terminalStatus: "completed" | "cancelled" | "failed" | "error" | "unknown";
114
+ errorCode?: string;
115
+ finishedAt?: number;
116
+ }) => RelaySessionClaimRow | undefined;
117
+ markAdmissionStarted: (accountId: string, requestId: string, startedAt?: number) => void;
80
118
  scopedTokenPublic: typeof scopedTokenPublic;
81
119
  send: (socket: WebSocketLike, message: ServerMessage) => void;
82
120
  sendAck: (connection: ControllerConnection, message: Extract<ServerMessage, {
@@ -3,8 +3,10 @@ import { createConnectionState, machineKey } from "./connections.js";
3
3
  import { HttpError } from "./errors.js";
4
4
  import { parseJson } from "./projections.js";
5
5
  import { createRelayRepositories } from "./repositories.js";
6
+ import { markSessionRuntimeBindingsClosed } from "./runtime-bindings.js";
6
7
  import { filterSnapshotForScope, isFullControllerToken, messageForScopedController, scopedListAllows, scopedTokenPublic, tokenScope, } from "./scope.js";
7
8
  import { bearerToken, encodePairingCode, isPairingCodeMatch, tokenDigest } from "./security.js";
9
+ const REWRITE_HEAD_BASIS_PREFIX = "rewrite:";
8
10
  export function createRelayContext(options) {
9
11
  const { controllersByAccount, machinesByKey, pendingCommandRequests } = createConnectionState();
10
12
  const now = options.now ?? Date.now;
@@ -34,6 +36,7 @@ export function createRelayContext(options) {
34
36
  throw new HttpError(403, "AUTH_TOKEN_REVOKED", "Token has been revoked");
35
37
  if (record.expires_at && record.expires_at <= now())
36
38
  throw new HttpError(403, "AUTH_TOKEN_EXPIRED", "Token has expired");
39
+ markTokenSeen(record.token);
37
40
  return record;
38
41
  }
39
42
  function requireFullControllerToken(authHeader) {
@@ -86,6 +89,19 @@ export function createRelayContext(options) {
86
89
  }
87
90
  }
88
91
  }
92
+ function markTokenSeen(token) {
93
+ options.db.prepare("UPDATE tokens SET last_seen = ? WHERE token = ?").run(now(), token);
94
+ }
95
+ function controllerDeviceOnline(accountId, deviceId) {
96
+ const controllers = controllersByAccount.get(accountId);
97
+ if (!controllers)
98
+ return false;
99
+ for (const connection of controllers) {
100
+ if (connection.deviceId === deviceId)
101
+ return true;
102
+ }
103
+ return false;
104
+ }
89
105
  function closeRevokedMachineConnection(accountId, machineId) {
90
106
  const ts = now();
91
107
  const rows = options.db
@@ -163,15 +179,117 @@ export function createRelayContext(options) {
163
179
  .get(accountId, requestId);
164
180
  return row ? JSON.parse(row.response) : undefined;
165
181
  }
182
+ function previousAdmissionAck(accountId, requestId) {
183
+ const row = options.db
184
+ .prepare("SELECT * FROM relay_admissions WHERE account_id = ? AND request_id = ?")
185
+ .get(accountId, requestId);
186
+ if (!row)
187
+ return undefined;
188
+ return {
189
+ type: "server:ack",
190
+ requestId,
191
+ ok: true,
192
+ sessionId: row.session_id,
193
+ ...(row.turn_id ? { turnId: row.turn_id } : {}),
194
+ admission: "replayed",
195
+ dispatch: row.dispatch,
196
+ };
197
+ }
198
+ function activeSessionClaim(accountId, sessionId) {
199
+ const claim = rawActiveSessionClaim(accountId, sessionId);
200
+ if (!claim)
201
+ return undefined;
202
+ const unknownErrorCode = claimUnknownExecutionErrorCode(claim);
203
+ if (unknownErrorCode) {
204
+ finishClaimRecord(claim, { terminalStatus: "unknown", errorCode: unknownErrorCode });
205
+ return undefined;
206
+ }
207
+ return claim;
208
+ }
209
+ function rawActiveSessionClaim(accountId, sessionId) {
210
+ return options.db
211
+ .prepare(`SELECT * FROM relay_session_claims
212
+ WHERE account_id = ? AND session_id = ? AND state = 'active'`)
213
+ .get(accountId, sessionId);
214
+ }
215
+ function claimUnknownExecutionErrorCode(claim) {
216
+ const admission = options.db
217
+ .prepare(`SELECT last_error_code
218
+ FROM relay_admissions
219
+ WHERE account_id = ? AND request_id = ?`)
220
+ .get(claim.account_id, claim.request_id);
221
+ const code = admission?.last_error_code;
222
+ return code === "EXECUTION_UNKNOWN" || code === "EXECUTION_NOT_FOUND" ? code : undefined;
223
+ }
224
+ function finishClaimRecord(claim, params) {
225
+ const ts = params.finishedAt ?? now();
226
+ options.db
227
+ .prepare(`UPDATE relay_admissions
228
+ SET finished_at = COALESCE(finished_at, ?),
229
+ terminal_status = COALESCE(terminal_status, ?),
230
+ last_error_code = COALESCE(?, last_error_code),
231
+ updated_at = ?
232
+ WHERE account_id = ? AND request_id = ?`)
233
+ .run(ts, params.terminalStatus, params.errorCode ?? null, ts, claim.account_id, claim.request_id);
234
+ options.db
235
+ .prepare("DELETE FROM relay_session_claims WHERE account_id = ? AND session_id = ? AND request_id = ?")
236
+ .run(claim.account_id, claim.session_id, claim.request_id);
237
+ if (params.terminalStatus === "unknown") {
238
+ options.db
239
+ .prepare(`UPDATE sessions
240
+ SET status = 'ready', updated_at = ?
241
+ WHERE account_id = ? AND id = ? AND machine_id = ? AND status = 'running'`)
242
+ .run(ts, claim.account_id, claim.session_id, claim.machine_id);
243
+ }
244
+ return claim;
245
+ }
246
+ function claimSessionTurn(params) {
247
+ const existing = activeSessionClaim(params.accountId, params.sessionId);
248
+ if (existing && existing.request_id !== params.requestId)
249
+ return { ok: false, claim: existing };
250
+ if (existing)
251
+ return { ok: true };
252
+ const ts = params.createdAt ?? now();
253
+ options.db
254
+ .prepare(`INSERT INTO relay_session_claims
255
+ (account_id, session_id, request_id, machine_id, turn_id, command_type, state, created_at, updated_at)
256
+ VALUES (?, ?, ?, ?, ?, ?, 'active', ?, ?)`)
257
+ .run(params.accountId, params.sessionId, params.requestId, params.machineId, params.turnId, params.commandType, ts, ts);
258
+ return { ok: true };
259
+ }
260
+ function markAdmissionStarted(accountId, requestId, startedAt = now()) {
261
+ options.db
262
+ .prepare(`UPDATE relay_admissions
263
+ SET started_at = COALESCE(started_at, ?), updated_at = ?
264
+ WHERE account_id = ? AND request_id = ?`)
265
+ .run(startedAt, startedAt, accountId, requestId);
266
+ }
267
+ function finishSessionClaim(params) {
268
+ const claim = rawActiveSessionClaim(params.accountId, params.sessionId);
269
+ if (!claim)
270
+ return undefined;
271
+ if (params.requestId && claim.request_id !== params.requestId)
272
+ return claim;
273
+ if (params.turnId && claim.turn_id !== params.turnId)
274
+ return claim;
275
+ return finishClaimRecord(claim, params);
276
+ }
166
277
  function commandKey(accountId, requestId) {
167
278
  return `${accountId}:${requestId}`;
168
279
  }
169
- function markCommandPending(accountId, machineId, requestId) {
170
- pendingCommandRequests.set(commandKey(accountId, requestId), { accountId, machineId, requestId });
280
+ function markCommandPending(accountId, machineId, requestId, options = {}) {
281
+ pendingCommandRequests.set(commandKey(accountId, requestId), { accountId, machineId, requestId, ...options });
171
282
  }
172
283
  function isCommandPending(accountId, requestId) {
173
284
  return pendingCommandRequests.has(commandKey(accountId, requestId));
174
285
  }
286
+ function isSessionCommandPending(accountId, sessionId) {
287
+ for (const pending of pendingCommandRequests.values()) {
288
+ if (pending.accountId === accountId && pending.sessionId === sessionId)
289
+ return true;
290
+ }
291
+ return false;
292
+ }
175
293
  function clearCommandPending(accountId, requestId) {
176
294
  pendingCommandRequests.delete(commandKey(accountId, requestId));
177
295
  }
@@ -223,6 +341,48 @@ export function createRelayContext(options) {
223
341
  message: "Machine is offline",
224
342
  });
225
343
  }
344
+ function deliverOutboxCommand(accountId, requestId) {
345
+ const row = options.db
346
+ .prepare("SELECT * FROM relay_dispatch_outbox WHERE account_id = ? AND request_id = ?")
347
+ .get(accountId, requestId);
348
+ if (!row)
349
+ return "queued";
350
+ if (row.state === "delivered")
351
+ return "delivered";
352
+ const machine = connectedMachine(accountId, row.machine_id);
353
+ if (!machine)
354
+ return "queued";
355
+ const command = JSON.parse(row.message);
356
+ send(machine.socket, command);
357
+ const ts = now();
358
+ options.db
359
+ .prepare(`UPDATE relay_dispatch_outbox
360
+ SET state = 'delivered', delivered_at = ?, updated_at = ?
361
+ WHERE account_id = ? AND request_id = ? AND state = 'queued'`)
362
+ .run(ts, ts, accountId, requestId);
363
+ options.db
364
+ .prepare(`UPDATE relay_admissions
365
+ SET dispatch = 'delivered', updated_at = ?
366
+ WHERE account_id = ? AND request_id = ?`)
367
+ .run(ts, accountId, requestId);
368
+ if (command.type === "machine:prompt") {
369
+ markAdmissionStarted(accountId, requestId, ts);
370
+ const session = setSessionStatus(command.sessionId, "running");
371
+ if (session)
372
+ broadcastControllers(accountId, { type: "server:session", session });
373
+ }
374
+ return "delivered";
375
+ }
376
+ function deliverQueuedCommandsForMachine(connection) {
377
+ const rows = options.db
378
+ .prepare(`SELECT * FROM relay_dispatch_outbox
379
+ WHERE account_id = ? AND machine_id = ? AND state = 'queued'
380
+ ORDER BY created_at ASC`)
381
+ .all(connection.accountId, connection.machineId);
382
+ for (const row of rows) {
383
+ deliverOutboxCommand(connection.accountId, row.request_id);
384
+ }
385
+ }
226
386
  function broadcastControllers(accountId, message) {
227
387
  const controllers = controllersByAccount.get(accountId);
228
388
  if (!controllers)
@@ -309,8 +469,28 @@ export function createRelayContext(options) {
309
469
  VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`)
310
470
  .run(params.accountId, params.sessionId, params.machineId, params.messageId ?? null, params.turnId, seqRow.nextSeq, params.turnSeq ?? null, JSON.stringify(params.payload), createdAt, params.occurredAt ?? null);
311
471
  const eventId = Number(result.lastInsertRowid);
312
- if (shouldAdvanceSessionHead(params, eventId, createdAt)) {
313
- options.db.prepare("UPDATE sessions SET current_head = ?, last_turn_id = ?, updated_at = ? WHERE id = ?").run(`event:${eventId}`, params.turnId, createdAt, params.sessionId);
472
+ if (params.updateSession === false) {
473
+ // Keep late closed-session events addressable without changing the
474
+ // session projection or workspace ordering.
475
+ }
476
+ else if (shouldAdvanceSessionHead(params, eventId, createdAt)) {
477
+ const order = logicalEventOrder({
478
+ id: eventId,
479
+ createdAt,
480
+ messageId: params.messageId,
481
+ occurredAt: params.occurredAt,
482
+ seq: params.turnSeq,
483
+ turnSeq: params.turnSeq,
484
+ });
485
+ options.db.prepare(`UPDATE sessions
486
+ SET current_head = ?,
487
+ last_turn_id = ?,
488
+ head_basis_event_id = ?,
489
+ head_basis_message_id = ?,
490
+ head_basis_logical_time = ?,
491
+ head_basis_turn_seq = ?,
492
+ updated_at = ?
493
+ WHERE id = ?`).run(`event:${eventId}`, params.turnId, eventId, params.messageId ?? null, order.time, order.seq, createdAt, params.sessionId);
314
494
  }
315
495
  else {
316
496
  options.db.prepare("UPDATE sessions SET updated_at = ? WHERE id = ?").run(createdAt, params.sessionId);
@@ -330,19 +510,24 @@ export function createRelayContext(options) {
330
510
  }
331
511
  function shouldAdvanceSessionHead(params, eventId, createdAt) {
332
512
  const session = options.db
333
- .prepare("SELECT current_head FROM sessions WHERE account_id = ? AND id = ? AND machine_id = ?")
513
+ .prepare(`SELECT current_head, last_turn_id, status, head_basis_event_id, head_basis_message_id,
514
+ head_basis_logical_time, head_basis_turn_seq
515
+ FROM sessions
516
+ WHERE account_id = ? AND id = ? AND machine_id = ?`)
334
517
  .get(params.accountId, params.sessionId, params.machineId);
335
518
  const currentHead = session?.current_head;
519
+ if (session?.status === "closed")
520
+ return false;
336
521
  if (!currentHead)
337
522
  return true;
338
- const currentEventId = /^event:(\d+)$/.exec(currentHead)?.[1];
339
- if (!currentEventId)
340
- return !isHistoricalBackfillEvent(params);
341
- const current = options.db
342
- .prepare("SELECT * FROM session_events WHERE account_id = ? AND session_id = ? AND machine_id = ? AND id = ?")
343
- .get(params.accountId, params.sessionId, params.machineId, Number(currentEventId));
344
- if (!current)
345
- return !isHistoricalBackfillEvent(params);
523
+ if (typeof session?.head_basis_message_id === "string" &&
524
+ session.head_basis_message_id.startsWith(REWRITE_HEAD_BASIS_PREFIX) &&
525
+ params.source === "machine") {
526
+ return false;
527
+ }
528
+ if (session?.status === "running" && params.source === "machine" && session.last_turn_id && params.turnId !== session.last_turn_id) {
529
+ return false;
530
+ }
346
531
  const nextOrder = logicalEventOrder({
347
532
  id: eventId,
348
533
  createdAt,
@@ -351,7 +536,34 @@ export function createRelayContext(options) {
351
536
  seq: params.turnSeq,
352
537
  turnSeq: params.turnSeq,
353
538
  });
354
- const currentOrder = logicalEventOrder({
539
+ const currentOrder = sessionHeadBasisOrder(session) ?? currentHeadEventOrder(params, currentHead);
540
+ if (!currentOrder)
541
+ return !isHistoricalBackfillEvent(params);
542
+ if (nextOrder.time !== currentOrder.time)
543
+ return nextOrder.time > currentOrder.time;
544
+ if (nextOrder.seq !== currentOrder.seq)
545
+ return nextOrder.seq > currentOrder.seq;
546
+ return nextOrder.id > currentOrder.id;
547
+ }
548
+ function sessionHeadBasisOrder(session) {
549
+ if (session.head_basis_logical_time === null || session.head_basis_turn_seq === null)
550
+ return undefined;
551
+ return {
552
+ time: session.head_basis_logical_time,
553
+ seq: session.head_basis_turn_seq,
554
+ id: session.head_basis_event_id ?? 0,
555
+ };
556
+ }
557
+ function currentHeadEventOrder(params, currentHead) {
558
+ const currentEventId = /^event:(\d+)$/.exec(currentHead)?.[1];
559
+ if (!currentEventId)
560
+ return undefined;
561
+ const current = options.db
562
+ .prepare("SELECT * FROM session_events WHERE account_id = ? AND session_id = ? AND machine_id = ? AND id = ?")
563
+ .get(params.accountId, params.sessionId, params.machineId, Number(currentEventId));
564
+ if (!current)
565
+ return undefined;
566
+ return logicalEventOrder({
355
567
  id: current.id,
356
568
  createdAt: current.created_at,
357
569
  messageId: current.message_id ?? undefined,
@@ -359,11 +571,6 @@ export function createRelayContext(options) {
359
571
  seq: current.seq,
360
572
  turnSeq: current.turn_seq ?? undefined,
361
573
  });
362
- if (nextOrder.time !== currentOrder.time)
363
- return nextOrder.time > currentOrder.time;
364
- if (nextOrder.seq !== currentOrder.seq)
365
- return nextOrder.seq > currentOrder.seq;
366
- return nextOrder.id > currentOrder.id;
367
574
  }
368
575
  function logicalEventOrder(input) {
369
576
  if (input.occurredAt !== undefined) {
@@ -421,7 +628,15 @@ export function createRelayContext(options) {
421
628
  }
422
629
  function setSessionStatus(sessionId, status) {
423
630
  const ts = now();
631
+ const previous = options.db.prepare("SELECT * FROM sessions WHERE id = ?").get(sessionId);
424
632
  options.db.prepare("UPDATE sessions SET status = ?, updated_at = ? WHERE id = ?").run(status, ts, sessionId);
633
+ if (status === "closed" && previous) {
634
+ markSessionRuntimeBindingsClosed(options.db, {
635
+ accountId: previous.account_id,
636
+ sessionId,
637
+ ts,
638
+ });
639
+ }
425
640
  const row = options.db.prepare("SELECT * FROM sessions WHERE id = ?").get(sessionId);
426
641
  return row ? sessionSnapshot(row) : undefined;
427
642
  }
@@ -453,6 +668,7 @@ export function createRelayContext(options) {
453
668
  closeRevokedControllerConnections,
454
669
  closeRevokedMachineConnection,
455
670
  connectedMachine,
671
+ controllerDeviceOnline,
456
672
  controllersByAccount,
457
673
  createPairingForAccount,
458
674
  db: options.db,
@@ -462,21 +678,30 @@ export function createRelayContext(options) {
462
678
  findUsableControllerInvite,
463
679
  insertEvent,
464
680
  aliasedRuntimeEventHasRequestEvents,
681
+ activeSessionClaim,
682
+ claimSessionTurn,
465
683
  isCommandPending,
684
+ isSessionCommandPending,
466
685
  isFullControllerToken,
467
686
  machineCapabilities,
468
687
  machineMessageProcessed,
469
688
  machinesByKey,
470
689
  markCommandPending,
471
690
  markMachineMessageProcessed,
691
+ markTokenSeen,
472
692
  now,
473
693
  parseJson,
474
694
  previousCommandResponse,
695
+ previousAdmissionAck,
475
696
  recordTurnAlias,
476
697
  rememberCommandResponse,
477
698
  requireFullControllerToken,
478
699
  requireHttpToken,
479
700
  resumeOfflineSessionsForMachine,
701
+ deliverOutboxCommand,
702
+ deliverQueuedCommandsForMachine,
703
+ finishSessionClaim,
704
+ markAdmissionStarted,
480
705
  scopedTokenPublic,
481
706
  send,
482
707
  sendAck,
@@ -1,8 +1,8 @@
1
1
  import type { DatabaseSync } from "node:sqlite";
2
- import type { MachineSnapshot, ServerMessage, SessionSnapshot } from "@happy-elves/shared";
2
+ import type { MachineSnapshot, ServerMessage, SessionSnapshot } from "../../../packages/shared/dist/index.js";
3
3
  import type { EventRow, MachineConnection, MachineRow, SessionRow } from "./types.js";
4
4
  export declare function createRelayRepositories(db: DatabaseSync, connectedMachine: (accountId: string, machineId: string) => MachineConnection | undefined, eventReplayLimit: number): {
5
- eventSnapshot: (row: EventRow) => import("@happy-elves/shared").EncryptedSessionEvent;
5
+ eventSnapshot: (row: EventRow) => import("../../../packages/shared/dist/index.js").EncryptedSessionEvent;
6
6
  machineCapabilities: (accountId: string, machineId: string) => MachineSnapshot["capabilities"] | undefined;
7
7
  machineSnapshot: (row: MachineRow) => MachineSnapshot;
8
8
  scopedSessionRow: (accountId: string, sessionId: string) => SessionRow | undefined;
@@ -28,8 +28,35 @@ export function createRelayRepositories(db, connectedMachine, eventReplayLimit)
28
28
  const capabilities = machineCapabilities(accountId, machineId);
29
29
  return capabilities?.agents.find((agent) => agent.id === agentId)?.historyModel;
30
30
  }
31
+ function sessionStatusForProjection(row) {
32
+ if (row.status !== "failed")
33
+ return row.status;
34
+ const latestPromptAdmission = db
35
+ .prepare(`SELECT turn_id, terminal_status
36
+ FROM relay_admissions
37
+ WHERE account_id = ? AND session_id = ? AND kind = 'prompt' AND finished_at IS NOT NULL
38
+ ORDER BY finished_at DESC, updated_at DESC
39
+ LIMIT 1`)
40
+ .get(row.account_id, row.id);
41
+ if (latestPromptAdmission?.terminal_status !== "completed")
42
+ return row.status;
43
+ const terminalTurnId = latestPromptAdmission.turn_id;
44
+ if (!terminalTurnId)
45
+ return "completed";
46
+ if (terminalTurnId === row.last_turn_id || terminalTurnId === row.current_head)
47
+ return "completed";
48
+ const alias = db
49
+ .prepare(`SELECT 1 FROM session_turn_aliases
50
+ WHERE account_id = ? AND session_id = ? AND machine_id = ?
51
+ AND request_turn_id = ?
52
+ AND runtime_turn_id IN (?, ?)
53
+ LIMIT 1`)
54
+ .get(row.account_id, row.id, row.machine_id, terminalTurnId, row.last_turn_id ?? "", row.current_head ?? "");
55
+ return alias ? "completed" : row.status;
56
+ }
31
57
  function sessionSnapshot(row) {
32
- return projectSessionSnapshot(row, sessionCapabilitiesForMachine, sessionHistoryModelForMachine);
58
+ const status = sessionStatusForProjection(row);
59
+ return projectSessionSnapshot(status === row.status ? row : { ...row, status }, sessionCapabilitiesForMachine, sessionHistoryModelForMachine);
33
60
  }
34
61
  function machineSnapshot(row) {
35
62
  return projectMachineSnapshot(row, (accountId, machineId) => connectedMachine(accountId, machineId) !== undefined);
@@ -0,0 +1,25 @@
1
+ import type { DatabaseSync } from "node:sqlite";
2
+ import type { SessionRuntimeBindingRow, SessionRow } from "./types.js";
3
+ export declare function normalizeRuntimeSessionIds(values: readonly unknown[]): string[];
4
+ export declare function upsertSessionRuntimeBindings(db: DatabaseSync, input: {
5
+ accountId: string;
6
+ machineId: string;
7
+ agent: string;
8
+ sessionId: string;
9
+ runtimeSessionIds: readonly unknown[];
10
+ status: "active" | "closed";
11
+ ts: number;
12
+ }): void;
13
+ export declare function findSessionRuntimeBinding(db: DatabaseSync, input: {
14
+ accountId: string;
15
+ machineId: string;
16
+ agent: string;
17
+ runtimeSessionId: string;
18
+ }): (SessionRuntimeBindingRow & {
19
+ session_status: SessionRow["status"] | null;
20
+ }) | undefined;
21
+ export declare function markSessionRuntimeBindingsClosed(db: DatabaseSync, input: {
22
+ accountId: string;
23
+ sessionId: string;
24
+ ts: number;
25
+ }): void;
@@ -0,0 +1,49 @@
1
+ export function normalizeRuntimeSessionIds(values) {
2
+ const ids = [];
3
+ const seen = new Set();
4
+ for (const value of values) {
5
+ if (typeof value !== "string")
6
+ continue;
7
+ const id = value.trim();
8
+ if (!id || id.startsWith("event:") || seen.has(id))
9
+ continue;
10
+ seen.add(id);
11
+ ids.push(id);
12
+ }
13
+ return ids;
14
+ }
15
+ export function upsertSessionRuntimeBindings(db, input) {
16
+ const ids = normalizeRuntimeSessionIds(input.runtimeSessionIds);
17
+ for (const runtimeSessionId of ids) {
18
+ db.prepare(`INSERT INTO session_runtime_bindings
19
+ (account_id, machine_id, agent, runtime_session_id, session_id, status, created_at, updated_at)
20
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?)
21
+ ON CONFLICT(account_id, machine_id, agent, runtime_session_id)
22
+ DO UPDATE SET
23
+ session_id = excluded.session_id,
24
+ status = excluded.status,
25
+ updated_at = excluded.updated_at`).run(input.accountId, input.machineId, input.agent, runtimeSessionId, input.sessionId, input.status, input.ts, input.ts);
26
+ }
27
+ }
28
+ export function findSessionRuntimeBinding(db, input) {
29
+ const runtimeSessionId = input.runtimeSessionId.trim();
30
+ if (!runtimeSessionId)
31
+ return undefined;
32
+ return db.prepare(`SELECT bindings.*, sessions.status AS session_status
33
+ FROM session_runtime_bindings bindings
34
+ LEFT JOIN sessions
35
+ ON sessions.id = bindings.session_id
36
+ AND sessions.account_id = bindings.account_id
37
+ AND sessions.machine_id = bindings.machine_id
38
+ WHERE bindings.account_id = ?
39
+ AND bindings.machine_id = ?
40
+ AND bindings.agent = ?
41
+ AND bindings.runtime_session_id = ?
42
+ LIMIT 1`).get(input.accountId, input.machineId, input.agent, runtimeSessionId);
43
+ }
44
+ export function markSessionRuntimeBindingsClosed(db, input) {
45
+ db.prepare(`UPDATE session_runtime_bindings
46
+ SET status = 'closed', updated_at = ?
47
+ WHERE account_id = ? AND session_id = ?`).run(input.ts, input.accountId, input.sessionId);
48
+ }
49
+ //# sourceMappingURL=runtime-bindings.js.map
@@ -1,4 +1,4 @@
1
- import type { ServerMessage } from "@happy-elves/shared";
1
+ import type { ServerMessage } from "../../../packages/shared/dist/index.js";
2
2
  import type { ControllerConnection, ScopedTokenScope, TokenRecord } from "./types.js";
3
3
  export declare function tokenScope(record: TokenRecord): ScopedTokenScope | null;
4
4
  export declare function isFullControllerToken(record: TokenRecord): boolean;