@cydm/happy-elves 0.1.0-beta.311 → 0.1.0-beta.313

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 (327) hide show
  1. package/apps/cli/dist/commands/app.js +8 -0
  2. package/apps/cli/dist/commands/artifact.d.ts +2 -0
  3. package/apps/cli/dist/commands/artifact.js +97 -0
  4. package/apps/cli/dist/commands/daemon.js +9 -10
  5. package/apps/cli/dist/commands/dispatch.d.ts +2 -0
  6. package/apps/cli/dist/commands/dispatch.js +130 -0
  7. package/apps/cli/dist/commands/lib/args.js +33 -3
  8. package/apps/cli/dist/commands/lib/bootstrap-daemon.js +9 -2
  9. package/apps/cli/dist/commands/lib/config.js +52 -0
  10. package/apps/cli/dist/commands/lib/index.d.ts +1 -0
  11. package/apps/cli/dist/commands/lib/index.js +1 -0
  12. package/apps/cli/dist/commands/lib/local-daemon.js +25 -9
  13. package/apps/cli/dist/commands/lib/loop-store.js +7 -16
  14. package/apps/cli/dist/commands/lib/relay-db-audit.js +19 -32
  15. package/apps/cli/dist/commands/lib/relay-debug.d.ts +84 -0
  16. package/apps/cli/dist/commands/lib/relay-debug.js +190 -0
  17. package/apps/cli/dist/commands/lib/scope.js +2 -2
  18. package/apps/cli/dist/commands/lib/session-output.js +99 -3
  19. package/apps/cli/dist/commands/lib/status.js +15 -3
  20. package/apps/cli/dist/commands/lib/types.d.ts +12 -2
  21. package/apps/cli/dist/commands/lib/usage.js +67 -72
  22. package/apps/cli/dist/commands/lib/workspace.js +3 -10
  23. package/apps/cli/dist/commands/loop.js +2 -2
  24. package/apps/cli/dist/commands/queue.d.ts +2 -0
  25. package/apps/cli/dist/commands/queue.js +95 -0
  26. package/apps/cli/dist/commands/relay.d.ts +1 -1
  27. package/apps/cli/dist/commands/relay.js +302 -2
  28. package/apps/cli/dist/commands/session.js +11 -199
  29. package/apps/cli/dist/commands/sidechat.d.ts +2 -0
  30. package/apps/cli/dist/commands/sidechat.js +72 -0
  31. package/apps/cli/dist/commands/token.js +26 -10
  32. package/apps/cli/dist/commands/turn.js +92 -14
  33. package/apps/cli/package.json +1 -1
  34. package/apps/daemon/dist/artifact/handler.d.ts +17 -0
  35. package/apps/daemon/dist/artifact/handler.js +858 -0
  36. package/apps/daemon/dist/artifact/pitch-review-sdk.d.ts +1 -0
  37. package/apps/daemon/dist/artifact/pitch-review-sdk.js +63 -0
  38. package/apps/daemon/dist/artifact/store.d.ts +141 -0
  39. package/apps/daemon/dist/artifact/store.js +652 -0
  40. package/apps/daemon/dist/artifact/vendor/lavish-axi/LICENSE +21 -0
  41. package/apps/daemon/dist/artifact/vendor/lavish-axi/artifact-sdk.js +2729 -0
  42. package/apps/daemon/dist/artifact/vendor/lavish-axi/mermaid-node.js +83 -0
  43. package/apps/daemon/dist/artifact/vendor/lavish-axi/table-cell.js +168 -0
  44. package/apps/daemon/dist/config.js +34 -0
  45. package/apps/daemon/dist/direct/server.d.ts +8 -0
  46. package/apps/daemon/dist/direct/server.js +1118 -0
  47. package/apps/daemon/dist/direct/state.d.ts +10 -0
  48. package/apps/daemon/dist/direct/state.js +8 -0
  49. package/apps/daemon/dist/direct/tickets.d.ts +65 -0
  50. package/apps/daemon/dist/direct/tickets.js +242 -0
  51. package/apps/daemon/dist/gateway/handler.js +18 -7
  52. package/apps/daemon/dist/loop/runner.js +70 -5
  53. package/apps/daemon/dist/loop/store.js +7 -16
  54. package/apps/daemon/dist/memory/handler.js +38 -16
  55. package/apps/daemon/dist/memory/settings.d.ts +11 -0
  56. package/apps/daemon/dist/memory/settings.js +56 -0
  57. package/apps/daemon/dist/orchestration/crew-queue.d.ts +28 -0
  58. package/apps/daemon/dist/orchestration/crew-queue.js +834 -0
  59. package/apps/daemon/dist/orchestration/handler.d.ts +31 -0
  60. package/apps/daemon/dist/orchestration/handler.js +1456 -0
  61. package/apps/daemon/dist/orchestration/queue-state.d.ts +49 -0
  62. package/apps/daemon/dist/orchestration/queue-state.js +172 -0
  63. package/apps/daemon/dist/orchestration/runner.d.ts +2 -0
  64. package/apps/daemon/dist/orchestration/runner.js +449 -0
  65. package/apps/daemon/dist/orchestration/store-file.d.ts +3 -0
  66. package/apps/daemon/dist/orchestration/store-file.js +20 -0
  67. package/apps/daemon/dist/orchestration/store.d.ts +285 -0
  68. package/apps/daemon/dist/orchestration/store.js +1529 -0
  69. package/apps/daemon/dist/orchestration/wake-identity.d.ts +13 -0
  70. package/apps/daemon/dist/orchestration/wake-identity.js +20 -0
  71. package/apps/daemon/dist/orchestration/watcher.d.ts +22 -0
  72. package/apps/daemon/dist/orchestration/watcher.js +302 -0
  73. package/apps/daemon/dist/pair.js +1 -1
  74. package/apps/daemon/dist/paths.d.ts +4 -1
  75. package/apps/daemon/dist/paths.js +4 -1
  76. package/apps/daemon/dist/process.d.ts +1 -0
  77. package/apps/daemon/dist/process.js +11 -4
  78. package/apps/daemon/dist/relay/admission.d.ts +14 -0
  79. package/apps/daemon/dist/relay/admission.js +231 -24
  80. package/apps/daemon/dist/relay/connection.d.ts +2 -0
  81. package/apps/daemon/dist/relay/connection.js +468 -18
  82. package/apps/daemon/dist/relay/devtools.js +78 -2
  83. package/apps/daemon/dist/relay/inbound-prompt.d.ts +14 -0
  84. package/apps/daemon/dist/relay/inbound-prompt.js +151 -0
  85. package/apps/daemon/dist/relay/prompt-admission-store.d.ts +49 -0
  86. package/apps/daemon/dist/relay/prompt-admission-store.js +348 -0
  87. package/apps/daemon/dist/relay/register.js +65 -27
  88. package/apps/daemon/dist/relay/remote-command.d.ts +22 -0
  89. package/apps/daemon/dist/relay/remote-command.js +128 -0
  90. package/apps/daemon/dist/relay/send.d.ts +10 -2
  91. package/apps/daemon/dist/relay/send.js +311 -8
  92. package/apps/daemon/dist/runtime/headless-binding.d.ts +13 -0
  93. package/apps/daemon/dist/runtime/headless-binding.js +32 -0
  94. package/apps/daemon/dist/runtime/headless-event-projector.d.ts +38 -0
  95. package/apps/daemon/dist/runtime/headless-event-projector.js +1018 -0
  96. package/apps/daemon/dist/runtime/headless-history-reader.d.ts +13 -0
  97. package/apps/daemon/dist/runtime/headless-history-reader.js +64 -0
  98. package/apps/daemon/dist/runtime/headless-manager.d.ts +50 -0
  99. package/apps/daemon/dist/runtime/headless-manager.js +238 -0
  100. package/apps/daemon/dist/runtime/headless-official-tool-bridge.d.ts +4 -0
  101. package/apps/daemon/dist/runtime/headless-official-tool-bridge.js +95 -0
  102. package/apps/daemon/dist/runtime/headless-server-request.d.ts +17 -0
  103. package/apps/daemon/dist/runtime/headless-server-request.js +32 -0
  104. package/apps/daemon/dist/runtime/headless-session-context.d.ts +11 -0
  105. package/apps/daemon/dist/runtime/headless-session-context.js +41 -0
  106. package/apps/daemon/dist/runtime/headless-session-history.d.ts +13 -0
  107. package/apps/daemon/dist/runtime/headless-session-history.js +271 -0
  108. package/apps/daemon/dist/runtime/headless-session-primitives.d.ts +33 -0
  109. package/apps/daemon/dist/runtime/headless-session-primitives.js +64 -0
  110. package/apps/daemon/dist/runtime/headless-turn-inspector.d.ts +8 -0
  111. package/apps/daemon/dist/runtime/headless-turn-inspector.js +116 -0
  112. package/apps/daemon/dist/runtime/headless-turn-runner.d.ts +27 -0
  113. package/apps/daemon/dist/runtime/headless-turn-runner.js +387 -0
  114. package/apps/daemon/dist/runtime.d.ts +9 -4
  115. package/apps/daemon/dist/runtime.js +83 -61
  116. package/apps/daemon/dist/schedule/handler.js +18 -7
  117. package/apps/daemon/dist/session/create-session.js +7 -1
  118. package/apps/daemon/dist/session/events.d.ts +7 -1
  119. package/apps/daemon/dist/session/events.js +111 -14
  120. package/apps/daemon/dist/session/he-official/approval.d.ts +12 -0
  121. package/apps/daemon/dist/session/he-official/approval.js +52 -0
  122. package/apps/daemon/dist/session/he-official/artifact-commands.d.ts +6 -0
  123. package/apps/daemon/dist/session/he-official/artifact-commands.js +293 -0
  124. package/apps/daemon/dist/session/he-official/common.d.ts +390 -0
  125. package/apps/daemon/dist/session/he-official/common.js +311 -0
  126. package/apps/daemon/dist/session/he-official/delegate-commands.d.ts +5 -0
  127. package/apps/daemon/dist/session/he-official/delegate-commands.js +424 -0
  128. package/apps/daemon/dist/session/he-official/options.d.ts +4 -0
  129. package/apps/daemon/dist/session/he-official/options.js +72 -0
  130. package/apps/daemon/dist/session/he-official/orchestration-commands.d.ts +74 -0
  131. package/apps/daemon/dist/session/he-official/orchestration-commands.js +381 -0
  132. package/apps/daemon/dist/session/he-official/result.d.ts +34 -0
  133. package/apps/daemon/dist/session/he-official/result.js +292 -0
  134. package/apps/daemon/dist/session/he-official/session-commands.d.ts +20 -0
  135. package/apps/daemon/dist/session/he-official/session-commands.js +132 -0
  136. package/apps/daemon/dist/session/he-official/trace.d.ts +65 -0
  137. package/apps/daemon/dist/session/he-official/trace.js +210 -0
  138. package/apps/daemon/dist/session/he-official/turn-commands.d.ts +31 -0
  139. package/apps/daemon/dist/session/he-official/turn-commands.js +315 -0
  140. package/apps/daemon/dist/session/he-official-tools.d.ts +6 -0
  141. package/apps/daemon/dist/session/he-official-tools.js +97 -0
  142. package/apps/daemon/dist/session/history-backfill.d.ts +45 -0
  143. package/apps/daemon/dist/session/history-backfill.js +139 -0
  144. package/apps/daemon/dist/session/lifecycle.d.ts +8 -35
  145. package/apps/daemon/dist/session/lifecycle.js +406 -434
  146. package/apps/daemon/dist/session/metadata.d.ts +3 -2
  147. package/apps/daemon/dist/session/metadata.js +82 -10
  148. package/apps/daemon/dist/session/primitives.js +67 -65
  149. package/apps/daemon/dist/session/prompt.d.ts +16 -3
  150. package/apps/daemon/dist/session/prompt.js +637 -48
  151. package/apps/daemon/dist/session/reconcile.d.ts +1 -1
  152. package/apps/daemon/dist/session/reconcile.js +108 -107
  153. package/apps/daemon/dist/session/runtime-read.d.ts +7 -0
  154. package/apps/daemon/dist/session/runtime-read.js +23 -0
  155. package/apps/daemon/dist/session/runtime-truth.d.ts +26 -0
  156. package/apps/daemon/dist/session/runtime-truth.js +453 -0
  157. package/apps/daemon/dist/session/sidechat.d.ts +11 -0
  158. package/apps/daemon/dist/session/sidechat.js +231 -0
  159. package/apps/daemon/dist/session/store.d.ts +20 -0
  160. package/apps/daemon/dist/session/store.js +219 -0
  161. package/apps/daemon/dist/start.js +31 -2
  162. package/apps/daemon/dist/state.d.ts +21 -1
  163. package/apps/daemon/dist/state.js +35 -0
  164. package/apps/daemon/dist/types.d.ts +50 -12
  165. package/apps/daemon/package.json +1 -1
  166. package/apps/relay/dist/auth.js +12 -0
  167. package/apps/relay/dist/control-plane-store.d.ts +229 -0
  168. package/apps/relay/dist/control-plane-store.js +263 -0
  169. package/apps/relay/dist/db.d.ts +1 -2
  170. package/apps/relay/dist/db.js +53 -391
  171. package/apps/relay/dist/direct-ticket-grants.d.ts +1 -0
  172. package/apps/relay/dist/direct-ticket-grants.js +16 -0
  173. package/apps/relay/dist/http-routes.js +182 -925
  174. package/apps/relay/dist/http-schemas.d.ts +57 -172
  175. package/apps/relay/dist/http-schemas.js +48 -112
  176. package/apps/relay/dist/index.js +50 -5
  177. package/apps/relay/dist/packet-store.d.ts +73 -0
  178. package/apps/relay/dist/packet-store.js +265 -0
  179. package/apps/relay/dist/relay-context.d.ts +57 -120
  180. package/apps/relay/dist/relay-context.js +154 -650
  181. package/apps/relay/dist/relay-migration.d.ts +26 -0
  182. package/apps/relay/dist/relay-migration.js +315 -0
  183. package/apps/relay/dist/retention.js +1 -2
  184. package/apps/relay/dist/types.d.ts +36 -133
  185. package/apps/relay/dist/websocket.d.ts +24 -0
  186. package/apps/relay/dist/websocket.js +707 -99
  187. package/package.json +7 -5
  188. package/packages/agent-sdk/dist/index.d.ts +7 -420
  189. package/packages/agent-sdk/dist/index.js +12 -183
  190. package/packages/client/dist/account.d.ts +5 -21
  191. package/packages/client/dist/account.js +142 -74
  192. package/packages/client/dist/client.d.ts +29 -5
  193. package/packages/client/dist/client.js +619 -89
  194. package/packages/client/dist/command-contracts.d.ts +6 -0
  195. package/packages/client/dist/command-contracts.js +20 -0
  196. package/packages/client/dist/direct.d.ts +12 -0
  197. package/packages/client/dist/direct.js +427 -0
  198. package/packages/client/dist/index.d.ts +1 -1
  199. package/packages/client/dist/parsers.d.ts +2 -1
  200. package/packages/client/dist/parsers.js +31 -17
  201. package/packages/client/dist/product-materializer.d.ts +27 -0
  202. package/packages/client/dist/product-materializer.js +465 -0
  203. package/packages/client/dist/transport.d.ts +31 -0
  204. package/packages/client/dist/transport.js +388 -153
  205. package/packages/client/dist/types.d.ts +216 -10
  206. package/packages/client/dist/validation.d.ts +0 -1
  207. package/packages/client/dist/validation.js +0 -9
  208. package/packages/client/dist/workspace-shared-config.d.ts +23 -0
  209. package/packages/client/dist/workspace-shared-config.js +487 -0
  210. package/packages/headless-runtime/dist/claude-provider.d.ts +20 -0
  211. package/packages/headless-runtime/dist/claude-provider.js +1092 -0
  212. package/packages/{runtime-cli → headless-runtime}/dist/claude-session-store.d.ts +1 -1
  213. package/packages/{runtime-cli → headless-runtime}/dist/claude-session-store.js +33 -12
  214. package/packages/headless-runtime/dist/cli.d.ts +3 -0
  215. package/packages/headless-runtime/dist/cli.js +1243 -0
  216. package/packages/headless-runtime/dist/client.d.ts +75 -0
  217. package/packages/headless-runtime/dist/client.js +490 -0
  218. package/packages/headless-runtime/dist/codex-provider.d.ts +9 -0
  219. package/packages/headless-runtime/dist/codex-provider.js +1278 -0
  220. package/packages/headless-runtime/dist/core.d.ts +304 -0
  221. package/packages/headless-runtime/dist/core.js +2589 -0
  222. package/packages/headless-runtime/dist/event-log.d.ts +11 -0
  223. package/packages/headless-runtime/dist/event-log.js +257 -0
  224. package/packages/headless-runtime/dist/history-index.d.ts +28 -0
  225. package/packages/headless-runtime/dist/history-index.js +72 -0
  226. package/packages/headless-runtime/dist/host-tools.d.ts +21 -0
  227. package/packages/headless-runtime/dist/host-tools.js +252 -0
  228. package/packages/headless-runtime/dist/host.d.ts +63 -0
  229. package/packages/headless-runtime/dist/host.js +423 -0
  230. package/packages/headless-runtime/dist/index.d.ts +44 -0
  231. package/packages/headless-runtime/dist/index.js +487 -0
  232. package/packages/headless-runtime/dist/ipc.d.ts +4 -0
  233. package/packages/headless-runtime/dist/ipc.js +28 -0
  234. package/packages/headless-runtime/dist/mock-scenario.d.ts +7 -0
  235. package/packages/headless-runtime/dist/mock-scenario.js +65 -0
  236. package/packages/headless-runtime/dist/model-catalog.d.ts +21 -0
  237. package/packages/headless-runtime/dist/model-catalog.js +271 -0
  238. package/packages/headless-runtime/dist/provider-command.d.ts +10 -0
  239. package/packages/headless-runtime/dist/provider-command.js +432 -0
  240. package/packages/headless-runtime/dist/provider-turn-metadata.d.ts +9 -0
  241. package/packages/headless-runtime/dist/provider-turn-metadata.js +76 -0
  242. package/packages/headless-runtime/dist/public-response.d.ts +9 -0
  243. package/packages/headless-runtime/dist/public-response.js +112 -0
  244. package/packages/headless-runtime/dist/runtime-projection-store.d.ts +49 -0
  245. package/packages/headless-runtime/dist/runtime-projection-store.js +318 -0
  246. package/packages/headless-runtime/dist/trace-log.d.ts +31 -0
  247. package/packages/headless-runtime/dist/trace-log.js +106 -0
  248. package/packages/pie-provider/dist/index.js +919 -692
  249. package/packages/runtime/dist/headless.d.ts +575 -0
  250. package/packages/runtime/dist/headless.js +3 -0
  251. package/packages/runtime/dist/index.d.ts +68 -112
  252. package/packages/shared/dist/args.d.ts +1 -0
  253. package/packages/shared/dist/args.js +8 -2
  254. package/packages/shared/dist/crypto.d.ts +1 -0
  255. package/packages/shared/dist/crypto.js +5 -0
  256. package/packages/shared/dist/diagnostics.d.ts +31 -0
  257. package/packages/shared/dist/diagnostics.js +81 -0
  258. package/packages/shared/dist/file-lock.d.ts +29 -0
  259. package/packages/shared/dist/file-lock.js +301 -0
  260. package/packages/shared/dist/he-official-tools.d.ts +78 -0
  261. package/packages/shared/dist/he-official-tools.js +737 -0
  262. package/packages/shared/dist/index.d.ts +5 -0
  263. package/packages/shared/dist/index.js +5 -0
  264. package/packages/shared/dist/orchestration-routing.d.ts +10 -0
  265. package/packages/shared/dist/orchestration-routing.js +113 -0
  266. package/packages/shared/dist/packet-relay.d.ts +220 -0
  267. package/packages/shared/dist/packet-relay.js +120 -0
  268. package/packages/shared/dist/protocol-schemas.d.ts +1838 -61
  269. package/packages/shared/dist/protocol-schemas.js +599 -7
  270. package/packages/shared/dist/protocol-types.d.ts +510 -7
  271. package/packages/shared/dist/protocol.d.ts +558 -3
  272. package/packages/shared/dist/protocol.js +651 -4
  273. package/packages/shared/dist/relay-scope.d.ts +32 -0
  274. package/packages/shared/dist/relay-scope.js +23 -0
  275. package/packages/shared/dist/session-state.d.ts +1 -1
  276. package/apps/daemon/dist/runtime/external-provider.d.ts +0 -20
  277. package/apps/daemon/dist/runtime/external-provider.js +0 -920
  278. package/apps/daemon/dist/session/runtime-handle.d.ts +0 -7
  279. package/apps/daemon/dist/session/runtime-handle.js +0 -48
  280. package/apps/relay/dist/connections.d.ts +0 -13
  281. package/apps/relay/dist/connections.js +0 -11
  282. package/apps/relay/dist/controller-handlers.d.ts +0 -79
  283. package/apps/relay/dist/controller-handlers.js +0 -777
  284. package/apps/relay/dist/machine-handlers.d.ts +0 -58
  285. package/apps/relay/dist/machine-handlers.js +0 -975
  286. package/apps/relay/dist/projections.d.ts +0 -7
  287. package/apps/relay/dist/projections.js +0 -125
  288. package/apps/relay/dist/repositories.d.ts +0 -13
  289. package/apps/relay/dist/repositories.js +0 -98
  290. package/apps/relay/dist/runtime-bindings.d.ts +0 -25
  291. package/apps/relay/dist/runtime-bindings.js +0 -49
  292. package/apps/relay/dist/scope.d.ts +0 -20
  293. package/apps/relay/dist/scope.js +0 -60
  294. package/packages/runtime-acpx/dist/index.d.ts +0 -11
  295. package/packages/runtime-acpx/dist/index.js +0 -120
  296. package/packages/runtime-cli/dist/async-queue.d.ts +0 -10
  297. package/packages/runtime-cli/dist/async-queue.js +0 -32
  298. package/packages/runtime-cli/dist/claude-history.d.ts +0 -7
  299. package/packages/runtime-cli/dist/claude-history.js +0 -344
  300. package/packages/runtime-cli/dist/claude-json.d.ts +0 -29
  301. package/packages/runtime-cli/dist/claude-json.js +0 -29
  302. package/packages/runtime-cli/dist/claude-rename.d.ts +0 -6
  303. package/packages/runtime-cli/dist/claude-rename.js +0 -15
  304. package/packages/runtime-cli/dist/claude-turn.d.ts +0 -14
  305. package/packages/runtime-cli/dist/claude-turn.js +0 -122
  306. package/packages/runtime-cli/dist/codex-app-server.d.ts +0 -59
  307. package/packages/runtime-cli/dist/codex-app-server.js +0 -418
  308. package/packages/runtime-cli/dist/codex-approvals.d.ts +0 -8
  309. package/packages/runtime-cli/dist/codex-approvals.js +0 -33
  310. package/packages/runtime-cli/dist/codex-history.d.ts +0 -17
  311. package/packages/runtime-cli/dist/codex-history.js +0 -711
  312. package/packages/runtime-cli/dist/codex-json-rpc.d.ts +0 -30
  313. package/packages/runtime-cli/dist/codex-json-rpc.js +0 -150
  314. package/packages/runtime-cli/dist/codex-lifecycle.d.ts +0 -25
  315. package/packages/runtime-cli/dist/codex-lifecycle.js +0 -72
  316. package/packages/runtime-cli/dist/codex-protocol.d.ts +0 -6
  317. package/packages/runtime-cli/dist/codex-protocol.js +0 -53
  318. package/packages/runtime-cli/dist/command-resolver.d.ts +0 -24
  319. package/packages/runtime-cli/dist/command-resolver.js +0 -101
  320. package/packages/runtime-cli/dist/history-merge.d.ts +0 -18
  321. package/packages/runtime-cli/dist/history-merge.js +0 -274
  322. package/packages/runtime-cli/dist/index.d.ts +0 -11
  323. package/packages/runtime-cli/dist/index.js +0 -350
  324. package/packages/runtime-cli/dist/permissions.d.ts +0 -6
  325. package/packages/runtime-cli/dist/permissions.js +0 -22
  326. package/packages/runtime-cli/dist/session-store.d.ts +0 -33
  327. package/packages/runtime-cli/dist/session-store.js +0 -93
@@ -4,15 +4,19 @@ import { handleAccount } from "./account.js";
4
4
  import { handleCollect } from "./collect.js";
5
5
  import { handleConfig } from "./config.js";
6
6
  import { handleDaemon } from "./daemon.js";
7
+ import { handleDispatch } from "./dispatch.js";
8
+ import { handleArtifact } from "./artifact.js";
7
9
  import { handleGateway } from "./gateway.js";
8
10
  import { handleLoop } from "./loop.js";
9
11
  import { handleMachine } from "./machine.js";
10
12
  import { handleMemory } from "./memory.js";
13
+ import { handleQueue } from "./queue.js";
11
14
  import { handleRelay } from "./relay.js";
12
15
  import { handleRelease } from "./release.js";
13
16
  import { handleSchedule } from "./schedule.js";
14
17
  import { handleRemote } from "./remote.js";
15
18
  import { handleSession } from "./session.js";
19
+ import { handleSidechat } from "./sidechat.js";
16
20
  import { handleToken } from "./token.js";
17
21
  import { handleTurn } from "./turn.js";
18
22
  import { handleWorkspace } from "./workspace.js";
@@ -25,6 +29,10 @@ const domainHandlers = [
25
29
  handleToken,
26
30
  handleGateway,
27
31
  handleLoop,
32
+ handleDispatch,
33
+ handleQueue,
34
+ handleArtifact,
35
+ handleSidechat,
28
36
  handleDaemon,
29
37
  handleRelay,
30
38
  handleRelease,
@@ -0,0 +1,2 @@
1
+ import type { CommandInput } from "./command.js";
2
+ export declare function handleArtifact({ domain, action, positional, flags }: CommandInput): Promise<boolean>;
@@ -0,0 +1,97 @@
1
+ import { CliError, ControllerClient, ok, readConfig, requirePositional, requireString, wantsJson, } from "./lib/index.js";
2
+ export async function handleArtifact({ domain, action, positional, flags }) {
3
+ if (domain !== "artifact")
4
+ return false;
5
+ const config = await readConfig(flags);
6
+ const client = new ControllerClient(config);
7
+ if (action === "register") {
8
+ const machineId = requireString(flags, "machine");
9
+ const consumerSessionId = requireString(flags, "consumer-session");
10
+ const file = requireString(flags, "file");
11
+ const publish = typeof flags.publish === "string" ? flags.publish : undefined;
12
+ if (publish !== undefined && publish !== "relay") {
13
+ throw new CliError(`Unsupported --publish value: ${publish}`, "INVALID_ARGUMENT");
14
+ }
15
+ const result = await client.artifactRegister({
16
+ machineId,
17
+ consumerSessionId,
18
+ file,
19
+ ...(typeof flags["artifact-id"] === "string" ? { artifactId: flags["artifact-id"] } : {}),
20
+ ...(typeof flags["task-id"] === "string" ? { taskId: flags["task-id"] } : {}),
21
+ ...(typeof flags["crew-session"] === "string" ? { crewSessionId: flags["crew-session"] } : {}),
22
+ ...(typeof flags["turn-id"] === "string" ? { turnId: flags["turn-id"] } : {}),
23
+ ...(typeof flags.title === "string" ? { title: flags.title } : {}),
24
+ ...(typeof flags["request-id"] === "string" ? { requestId: flags["request-id"] } : {}),
25
+ ...(publish === "relay" ? { publish: "relay" } : {}),
26
+ });
27
+ if (!wantsJson(flags)) {
28
+ console.log(`${result.artifactId} rev:${result.revision} ${result.admission}/${result.publishState} ${result.url}`);
29
+ if (result.publishState === "failed")
30
+ process.exitCode = 1;
31
+ return true;
32
+ }
33
+ ok("artifact.register", result, { requestId: result.requestId, machineId }, result.publishState !== "failed");
34
+ if (result.publishState === "failed")
35
+ process.exitCode = 1;
36
+ return true;
37
+ }
38
+ if (action === "list") {
39
+ const machineId = requireString(flags, "machine");
40
+ const result = await client.artifactList({
41
+ machineId,
42
+ ...(typeof flags["consumer-session"] === "string" ? { consumerSessionId: flags["consumer-session"] } : {}),
43
+ ...(typeof flags["task-id"] === "string" ? { taskId: flags["task-id"] } : {}),
44
+ ...(typeof flags["request-id"] === "string" ? { requestId: flags["request-id"] } : {}),
45
+ });
46
+ if (!wantsJson(flags)) {
47
+ if (result.records.length === 0)
48
+ console.log("No artifacts.");
49
+ else
50
+ for (const record of result.records) {
51
+ console.log(`${record.artifactId} rev:${record.revision} ${record.publishState} consumer:${record.consumerSessionId} task:${record.taskId ?? "-"}`);
52
+ }
53
+ return true;
54
+ }
55
+ ok("artifact.list", result, { requestId: result.requestId, machineId });
56
+ return true;
57
+ }
58
+ if (action === "status") {
59
+ const machineId = requireString(flags, "machine");
60
+ const artifactId = requirePositional(positional[0], "artifactId");
61
+ const result = await client.artifactStatus({
62
+ machineId,
63
+ artifactId,
64
+ ...(typeof flags["request-id"] === "string" ? { requestId: flags["request-id"] } : {}),
65
+ });
66
+ if (!wantsJson(flags)) {
67
+ const artifact = result.artifact;
68
+ console.log(artifact ? `${artifact.artifactId} rev:${artifact.revision} ${artifact.publishState} feedback:${artifact.feedbackCursor ?? "-"}` : "Artifact not found.");
69
+ return true;
70
+ }
71
+ ok("artifact.status", result, { requestId: result.requestId, machineId });
72
+ return true;
73
+ }
74
+ if (action === "feedback" && positional[0] === "list") {
75
+ const machineId = requireString(flags, "machine");
76
+ const artifactId = requirePositional(positional[1], "artifactId");
77
+ const result = await client.artifactFeedbackList({
78
+ machineId,
79
+ artifactId,
80
+ ...(typeof flags.after === "string" ? { after: flags.after } : {}),
81
+ ...(typeof flags["request-id"] === "string" ? { requestId: flags["request-id"] } : {}),
82
+ });
83
+ if (!wantsJson(flags)) {
84
+ if (result.records.length === 0)
85
+ console.log("No feedback.");
86
+ else
87
+ for (const record of result.records) {
88
+ console.log(`${record.feedbackCursor} ${record.kind} rev:${record.revision} ${record.prompt}`);
89
+ }
90
+ return true;
91
+ }
92
+ ok("artifact.feedback.list", result, { requestId: result.requestId, machineId });
93
+ return true;
94
+ }
95
+ return false;
96
+ }
97
+ //# sourceMappingURL=artifact.js.map
@@ -1,6 +1,6 @@
1
1
  import os from "node:os";
2
2
  import path from "node:path";
3
- import { CliError, compactText, ControllerClient, configDir, configPath, daemonPidPath, deriveOrchestration, ensureDaemonRunning, idleSessionStatuses, localDaemonStatus, ok, parsePairingClaimResponse, randomId, readConfig, readDaemonConfig, readLocalAuditLog, readRelayJson, redactedDaemonConfig, requirePositional, requireRelayUrl, requireString, restartDaemonForNewConfig, showMachine, spawnDaemonStart, stopLocalDaemon, throwRelayHttpError, waitForMachineProjection, wantsJson, writeDaemonConfig } from "./lib/index.js";
3
+ import { CliError, compactText, ControllerClient, configDir, configPath, deriveOrchestration, ensureDaemonRunning, idleSessionStatuses, localDaemonStatus, ok, parsePairingClaimResponse, randomId, readConfig, readDaemonConfig, readLocalAuditLog, readRelayJson, redactedDaemonConfig, requirePositional, requireRelayUrl, requireString, restartDaemonForNewConfig, showMachine, stopLocalDaemon, throwRelayHttpError, waitForMachineProjection, wantsJson, writeDaemonConfig } from "./lib/index.js";
4
4
  export async function handleDaemon({ domain, action, flags }) {
5
5
  if (domain === "daemon" && action === "pair") {
6
6
  const relayUrl = requireRelayUrl(flags);
@@ -205,10 +205,10 @@ export async function handleDaemon({ domain, action, flags }) {
205
205
  ok("daemon.start", { ...status, started: false });
206
206
  return true;
207
207
  }
208
- await readDaemonConfig();
209
- const startArgs = typeof flags.relay === "string" ? ["--relay", flags.relay] : [];
210
- const pid = spawnDaemonStart(startArgs);
211
- ok("daemon.start", { pid, pidPath: daemonPidPath, started: true });
208
+ const daemonConfig = await readDaemonConfig();
209
+ const relayUrl = typeof flags.relay === "string" ? requireRelayUrl(flags) : daemonConfig.relayUrl;
210
+ const started = await ensureDaemonRunning(relayUrl);
211
+ ok("daemon.start", { ...started.local, started: started.started, startedPid: started.startedPid, startupLogPath: path.join(configDir, "daemon.startup.log") });
212
212
  return true;
213
213
  }
214
214
  if (domain === "daemon" && action === "stop") {
@@ -216,11 +216,10 @@ export async function handleDaemon({ domain, action, flags }) {
216
216
  return true;
217
217
  }
218
218
  if (domain === "daemon" && action === "restart") {
219
- await readDaemonConfig();
220
- const stop = await stopLocalDaemon();
221
- const startArgs = typeof flags.relay === "string" ? ["--relay", flags.relay] : [];
222
- const pid = spawnDaemonStart(startArgs);
223
- ok("daemon.restart", { stop, startedPid: pid, pidPath: daemonPidPath });
219
+ const daemonConfig = await readDaemonConfig();
220
+ const relayUrl = typeof flags.relay === "string" ? requireRelayUrl(flags) : daemonConfig.relayUrl;
221
+ const restarted = await restartDaemonForNewConfig(relayUrl);
222
+ ok("daemon.restart", { stop: restarted.stopped, ...restarted.local, startedPid: restarted.startedPid, startupLogPath: path.join(configDir, "daemon.startup.log") });
224
223
  return true;
225
224
  }
226
225
  if (domain === "daemon" && action === "status" && flags.local === true) {
@@ -0,0 +1,2 @@
1
+ import type { CommandInput } from "./command.js";
2
+ export declare function handleDispatch({ domain, action, positional, flags }: CommandInput): Promise<boolean>;
@@ -0,0 +1,130 @@
1
+ import { CliError, ControllerClient, ok, parsePermissionMode, readConfig, readPromptTextFile, requirePositional, requireString, wantsJson, } from "./lib/index.js";
2
+ export async function handleDispatch({ domain, action, positional, flags }) {
3
+ if (domain !== "dispatch")
4
+ return false;
5
+ const config = await readConfig(flags);
6
+ const client = new ControllerClient(config);
7
+ if (action === "run") {
8
+ const machineId = requireString(flags, "machine");
9
+ const consumerSessionId = requireString(flags, "consumer-session");
10
+ const agent = requireString(flags, "agent");
11
+ const cwd = requireString(flags, "cwd");
12
+ const briefFile = requireString(flags, "brief-file");
13
+ const brief = await readPromptTextFile(briefFile);
14
+ if (!brief.trim())
15
+ throw new CliError("--brief-file is empty", "MISSING_ARGUMENT");
16
+ if (typeof flags["crew-session"] === "string" && typeof flags["fork-from-crew"] === "string") {
17
+ throw new CliError("--crew-session and --fork-from-crew are mutually exclusive", "INVALID_ARGUMENT");
18
+ }
19
+ const routeDecision = routeDecisionFromFlags(flags);
20
+ const permissionMode = parsePermissionMode(flags["permission-mode"] ?? flags.permission);
21
+ const result = await client.dispatchRun({
22
+ machineId,
23
+ consumerSessionId,
24
+ agent,
25
+ cwd,
26
+ brief,
27
+ ...(typeof flags["task-id"] === "string" ? { taskId: flags["task-id"] } : {}),
28
+ ...(typeof flags["request-id"] === "string" ? { requestId: flags["request-id"] } : {}),
29
+ ...(typeof flags["crew-session"] === "string" ? { crewSessionId: flags["crew-session"] } : {}),
30
+ ...(typeof flags["fork-from-crew"] === "string" ? { forkFromCrewSessionId: flags["fork-from-crew"] } : {}),
31
+ ...(typeof flags["fork-checkpoint"] === "string" ? { forkCheckpointId: flags["fork-checkpoint"] } : {}),
32
+ ...(routeDecision ? { routeDecision } : {}),
33
+ ...(permissionMode ? { permissionMode } : {}),
34
+ ...(typeof flags.model === "string" ? { model: flags.model } : {}),
35
+ ...(typeof flags["thinking-level"] === "string" ? { thinkingLevel: flags["thinking-level"] } : {}),
36
+ subscribe: flags.subscribe !== false,
37
+ });
38
+ if (!wantsJson(flags)) {
39
+ console.log(`${result.taskId} ${result.admission}/${result.dispatch} owner:${result.consumerMachineId ?? "-"} crewMachine:${result.crewMachineId ?? machineId} crew:${result.crewSessionId ?? "-"} turn:${result.turnId ?? "-"}`);
40
+ return true;
41
+ }
42
+ ok("dispatch.run", result, {
43
+ requestId: result.requestId,
44
+ machineId: result.consumerMachineId ?? machineId,
45
+ consumerMachineId: result.consumerMachineId ?? machineId,
46
+ crewMachineId: result.crewMachineId ?? machineId,
47
+ sessionId: result.crewSessionId,
48
+ turnId: result.turnId,
49
+ }, result.dispatch !== "failed");
50
+ return true;
51
+ }
52
+ if (action === "status") {
53
+ const machineId = requireString(flags, "machine");
54
+ const taskId = requirePositional(positional[0], "taskId");
55
+ const result = await client.dispatchStatus({
56
+ machineId,
57
+ taskId,
58
+ ...(typeof flags["request-id"] === "string" ? { requestId: flags["request-id"] } : {}),
59
+ });
60
+ if (!wantsJson(flags)) {
61
+ const admission = result.admission;
62
+ const attention = result.attention;
63
+ console.log(`${result.taskId} admission:${admission?.admission ?? "-"} dispatch:${admission?.dispatch ?? "-"} attention:${attention?.status ?? "-"}`);
64
+ return true;
65
+ }
66
+ ok("dispatch.status", result, { requestId: result.requestId, machineId });
67
+ return true;
68
+ }
69
+ if (action === "list") {
70
+ const machineId = requireString(flags, "machine");
71
+ const result = await client.dispatchList({
72
+ machineId,
73
+ ...(typeof flags["consumer-session"] === "string" ? { consumerSessionId: flags["consumer-session"] } : {}),
74
+ ...(typeof flags["request-id"] === "string" ? { requestId: flags["request-id"] } : {}),
75
+ });
76
+ if (!wantsJson(flags)) {
77
+ for (const record of result.records) {
78
+ const attention = record.attention;
79
+ const reason = attention?.reasons.at(-1) ?? record.error ?? record.briefPreview ?? "";
80
+ console.log([
81
+ record.taskId,
82
+ `dispatch:${record.dispatch}`,
83
+ `attention:${attention?.status ?? "-"}`,
84
+ `crew:${record.crewSessionId ?? "-"}`,
85
+ reason ? `reason:${reason}` : "",
86
+ ].filter(Boolean).join(" "));
87
+ }
88
+ return true;
89
+ }
90
+ ok("dispatch.list", result, { requestId: result.requestId, machineId });
91
+ return true;
92
+ }
93
+ return false;
94
+ }
95
+ function routeDecisionFromFlags(flags) {
96
+ const raw = flags["route-decision"];
97
+ const ifBusy = flags["if-busy"];
98
+ if (ifBusy !== undefined && ifBusy !== "queue") {
99
+ throw new CliError("--if-busy must be queue", "INVALID_ARGUMENT");
100
+ }
101
+ if (typeof raw !== "string") {
102
+ if (ifBusy === "queue" && typeof flags["crew-session"] === "string" && typeof flags["fork-from-crew"] !== "string") {
103
+ return { kind: "reuse", crewSessionId: flags["crew-session"], ifBusy };
104
+ }
105
+ if (ifBusy === "queue")
106
+ throw new CliError("--if-busy queue requires --crew-session or --route-decision reuse", "INVALID_ARGUMENT");
107
+ return undefined;
108
+ }
109
+ if (raw === "new") {
110
+ if (ifBusy === "queue")
111
+ throw new CliError("--if-busy queue is only valid with --route-decision reuse", "INVALID_ARGUMENT");
112
+ return { kind: "new" };
113
+ }
114
+ if (raw === "reuse") {
115
+ const crewSessionId = requireString(flags, "crew-session");
116
+ return { kind: "reuse", crewSessionId, ...(ifBusy === "queue" ? { ifBusy } : {}) };
117
+ }
118
+ if (ifBusy === "queue")
119
+ throw new CliError("--if-busy queue is only valid with --route-decision reuse", "INVALID_ARGUMENT");
120
+ if (raw === "fork") {
121
+ const crewSessionId = requireString(flags, "fork-from-crew");
122
+ return {
123
+ kind: "fork",
124
+ crewSessionId,
125
+ ...(typeof flags["fork-checkpoint"] === "string" ? { forkCheckpointId: flags["fork-checkpoint"] } : {}),
126
+ };
127
+ }
128
+ throw new CliError("--route-decision must be one of new, reuse, or fork", "INVALID_ARGUMENT");
129
+ }
130
+ //# sourceMappingURL=dispatch.js.map
@@ -2,21 +2,28 @@ import { parseFlags as parseSharedFlags } from "../../../../../packages/shared/d
2
2
  import { CliError } from "../../errors.js";
3
3
  const valueFlags = new Set([
4
4
  "agent",
5
+ "account",
5
6
  "app-id",
7
+ "artifact-id",
6
8
  "at",
7
9
  "channel",
8
10
  "code",
9
11
  "conversation",
12
+ "consumer-session",
10
13
  "cron",
11
14
  "controller",
15
+ "crew-session",
12
16
  "cwd",
13
17
  "date",
14
18
  "device-id",
15
19
  "device-name",
20
+ "brief-file",
16
21
  "every-ms",
17
22
  "execution",
23
+ "file",
18
24
  "from",
19
25
  "host",
26
+ "if-busy",
20
27
  "domain",
21
28
  "invite-secret",
22
29
  "inbound",
@@ -33,6 +40,7 @@ const valueFlags = new Set([
33
40
  "memory-top-n",
34
41
  "name",
35
42
  "model",
43
+ "thinking-level",
36
44
  "mode",
37
45
  "output",
38
46
  "path",
@@ -40,18 +48,20 @@ const valueFlags = new Set([
40
48
  "permission",
41
49
  "permission-mode",
42
50
  "profile",
51
+ "prefix",
43
52
  "project",
53
+ "publish",
44
54
  "query",
45
55
  "prompt",
46
56
  "prompt-file",
47
57
  "every",
48
58
  "reason",
59
+ "request-id",
49
60
  "release-tag",
50
61
  "reaction-emoji",
51
62
  "relay",
63
+ "route-decision",
52
64
  "root",
53
- "runtime-limit",
54
- "runtime-session",
55
65
  "shell",
56
66
  "actions",
57
67
  "ack-timeout",
@@ -65,16 +75,23 @@ const valueFlags = new Set([
65
75
  "session",
66
76
  "secret",
67
77
  "since",
78
+ "slot",
79
+ "slot-secret",
68
80
  "source",
81
+ "status",
82
+ "stream",
69
83
  "stop-on",
84
+ "strategy",
70
85
  "tail",
71
86
  "tag",
72
87
  "tags",
88
+ "task-id",
73
89
  "text",
74
90
  "text-file",
75
91
  "timeout",
76
92
  "timeout-ms",
77
93
  "timezone",
94
+ "through",
78
95
  "wait-timeout-ms",
79
96
  "inactivity-timeout",
80
97
  "runtime-timeout",
@@ -84,7 +101,9 @@ const valueFlags = new Set([
84
101
  "title",
85
102
  "url",
86
103
  "turn",
104
+ "turn-id",
87
105
  "until",
106
+ "import-token",
88
107
  "reviewer-tag",
89
108
  "dogfood-tag",
90
109
  ]);
@@ -107,17 +126,28 @@ const booleanFlags = new Set([
107
126
  "no-open",
108
127
  "no-start",
109
128
  "no-wait",
129
+ "preserve-secret",
110
130
  "repair-head",
131
+ "skip-local-daemon",
111
132
  "strict",
112
133
  "summary",
134
+ "subscribe",
113
135
  "verbose",
114
136
  "wait",
137
+ "decode",
115
138
  "manual",
116
139
  ]);
117
140
  const knownFlags = new Set([...valueFlags, ...booleanFlags]);
118
141
  const dashPrefixedValueFlags = new Set(["secret"]);
142
+ const repeatableValueFlags = new Set([
143
+ "tag",
144
+ "tags",
145
+ "release-tag",
146
+ "reviewer-tag",
147
+ "dogfood-tag",
148
+ ]);
119
149
  export function parseCliFlags(argv) {
120
- const parsed = parseSharedFlags(argv, { valueFlags, dashPrefixedValueFlags });
150
+ const parsed = parseSharedFlags(argv, { valueFlags, dashPrefixedValueFlags, repeatableValueFlags });
121
151
  const unknown = Object.keys(parsed.flags).filter((flag) => !knownFlags.has(flag));
122
152
  if (unknown.length > 0) {
123
153
  throw new CliError(`Unknown flag: --${unknown[0]}`, "UNKNOWN_FLAG");
@@ -1,5 +1,6 @@
1
+ import path from "node:path";
1
2
  import { CliError } from "../../errors.js";
2
- import { startDaemonTimeoutMs } from "./paths.js";
3
+ import { configDir, startDaemonTimeoutMs } from "./paths.js";
3
4
  import { readDaemonConfig } from "./config.js";
4
5
  import { daemonBinaryUpdatedAfterStart, daemonConfigUpdatedAfterStart, localDaemonStatus, spawnDaemonStart, stopLocalDaemon } from "./local-daemon.js";
5
6
  export async function ensureDaemonRunning(relayUrl, cwd = process.cwd()) {
@@ -19,9 +20,15 @@ export async function ensureDaemonRunning(relayUrl, cwd = process.cwd()) {
19
20
  const local = await localDaemonStatus();
20
21
  if (local.running)
21
22
  return { local, started: true, startedPid };
23
+ try {
24
+ process.kill(startedPid, 0);
25
+ }
26
+ catch {
27
+ throw new CliError(`Daemon exited before becoming locally ready. Startup output: ${path.join(configDir, "daemon.startup.log")}`, "DAEMON_START_FAILED");
28
+ }
22
29
  await new Promise((resolve) => setTimeout(resolve, 250));
23
30
  }
24
- throw new CliError("Daemon did not become ready in time. Run happy-elves daemon doctor and happy-elves daemon logs.", "DAEMON_START_FAILED");
31
+ throw new CliError(`Daemon did not become locally ready in time. Startup output: ${path.join(configDir, "daemon.startup.log")}`, "DAEMON_START_FAILED");
25
32
  }
26
33
  export async function restartDaemonForNewConfig(relayUrl, cwd = process.cwd()) {
27
34
  const stopped = await stopLocalDaemon();
@@ -2,6 +2,7 @@ import fs from "node:fs/promises";
2
2
  import path from "node:path";
3
3
  import { CliError } from "../../errors.js";
4
4
  import { configDir, configPath } from "./paths.js";
5
+ const daemonProviderKinds = new Set(["mock", "codex", "claude", "pie"]);
5
6
  export function requireString(flags, key) {
6
7
  const value = flags[key];
7
8
  if (typeof value !== "string" || !value.trim()) {
@@ -53,10 +54,41 @@ function assertControllerConfigShape(value) {
53
54
  throw new CliError("Controller config is invalid.", "CONFIG_INVALID");
54
55
  }
55
56
  const candidate = value;
57
+ const previousRelayUrls = Array.isArray(candidate.previousRelayUrls)
58
+ ? candidate.previousRelayUrls.filter((item) => typeof item === "string" && item.length > 0)
59
+ : undefined;
60
+ const relayMigration = parseRelayMigrationConfig(candidate.relayMigration);
56
61
  return {
57
62
  relayUrl: assertRelayUrl(assertStringField(candidate, "relayUrl", "Controller"), "Controller"),
58
63
  controllerToken: assertStringField(candidate, "controllerToken", "Controller"),
59
64
  accountSecret: assertStringField(candidate, "accountSecret", "Controller"),
65
+ ...(previousRelayUrls && previousRelayUrls.length > 0 ? { previousRelayUrls } : {}),
66
+ ...(relayMigration ? { relayMigration } : {}),
67
+ };
68
+ }
69
+ function parseRelayMigrationConfig(value) {
70
+ if (!value || typeof value !== "object" || Array.isArray(value))
71
+ return undefined;
72
+ const candidate = value;
73
+ const migrationId = candidate.migrationId;
74
+ const state = candidate.state;
75
+ const fromRelayUrl = candidate.fromRelayUrl;
76
+ const toRelayUrl = candidate.toRelayUrl;
77
+ const updatedAt = candidate.updatedAt;
78
+ if (typeof migrationId !== "string" ||
79
+ typeof state !== "string" ||
80
+ !["rebound", "migrated", "draining", "drained", "cutover"].includes(state) ||
81
+ typeof fromRelayUrl !== "string" ||
82
+ typeof toRelayUrl !== "string" ||
83
+ typeof updatedAt !== "string") {
84
+ return undefined;
85
+ }
86
+ return {
87
+ migrationId,
88
+ state: state,
89
+ fromRelayUrl,
90
+ toRelayUrl,
91
+ updatedAt,
60
92
  };
61
93
  }
62
94
  function assertDaemonConfigShape(value) {
@@ -72,6 +104,7 @@ function assertDaemonConfigShape(value) {
72
104
  runtimeEnv[key] = runtimeValue;
73
105
  }
74
106
  }
107
+ const providers = parseProviders(candidate.providers);
75
108
  return {
76
109
  relayUrl: assertRelayUrl(assertStringField(candidate, "relayUrl", "Daemon"), "Daemon"),
77
110
  accountId: assertStringField(candidate, "accountId", "Daemon"),
@@ -79,9 +112,26 @@ function assertDaemonConfigShape(value) {
79
112
  machineName: assertStringField(candidate, "machineName", "Daemon"),
80
113
  machineToken: assertStringField(candidate, "machineToken", "Daemon"),
81
114
  accountSecret: assertStringField(candidate, "accountSecret", "Daemon"),
115
+ ...(providers ? { providers } : {}),
82
116
  ...(Object.keys(runtimeEnv).length > 0 ? { runtimeEnv } : {}),
83
117
  };
84
118
  }
119
+ function parseProviders(value) {
120
+ if (value === undefined)
121
+ return undefined;
122
+ if (!Array.isArray(value) || value.length === 0) {
123
+ throw new CliError("Daemon config providers must be a non-empty array.", "CONFIG_INVALID");
124
+ }
125
+ const providers = [];
126
+ for (const item of value) {
127
+ if (typeof item !== "string" || !daemonProviderKinds.has(item)) {
128
+ throw new CliError("Daemon config providers must contain only mock, codex, claude, or pie.", "CONFIG_INVALID");
129
+ }
130
+ if (!providers.includes(item))
131
+ providers.push(item);
132
+ }
133
+ return providers;
134
+ }
85
135
  async function readJsonConfigFile(filePath, label) {
86
136
  try {
87
137
  return JSON.parse(stripJsonBom(await fs.readFile(filePath, "utf8")));
@@ -108,6 +158,7 @@ export async function readConfig(flags) {
108
158
  }
109
159
  const stored = assertControllerConfigShape(await readJsonConfigFile(configPath, "Controller"));
110
160
  return {
161
+ ...stored,
111
162
  relayUrl: assertRelayUrl(relayUrl ?? stored.relayUrl, "Controller"),
112
163
  controllerToken: controllerToken ?? stored.controllerToken,
113
164
  accountSecret: accountSecret ?? stored.accountSecret,
@@ -129,6 +180,7 @@ export function redactedDaemonConfig(config) {
129
180
  accountId: config.accountId,
130
181
  machineId: config.machineId,
131
182
  machineName: config.machineName,
183
+ ...(config.providers && config.providers.length > 0 ? { providers: config.providers } : {}),
132
184
  hasMachineToken: Boolean(config.machineToken),
133
185
  hasAccountSecret: Boolean(config.accountSecret),
134
186
  ...(config.runtimeEnv ? { runtimeEnv: Object.fromEntries(Object.keys(config.runtimeEnv).map((key) => [key, true])) } : {}),
@@ -16,6 +16,7 @@ export * from "./local-daemon.js";
16
16
  export * from "./loop-store.js";
17
17
  export * from "./paths.js";
18
18
  export * from "./relay-db-audit.js";
19
+ export * from "./relay-debug.js";
19
20
  export * from "./relay-http.js";
20
21
  export * from "./scope.js";
21
22
  export * from "./session-output.js";
@@ -16,6 +16,7 @@ export * from "./local-daemon.js";
16
16
  export * from "./loop-store.js";
17
17
  export * from "./paths.js";
18
18
  export * from "./relay-db-audit.js";
19
+ export * from "./relay-debug.js";
19
20
  export * from "./relay-http.js";
20
21
  export * from "./scope.js";
21
22
  export * from "./session-output.js";
@@ -1,5 +1,6 @@
1
1
  import { execFileSync, spawn } from "node:child_process";
2
2
  import fs from "node:fs/promises";
3
+ import { appendFileSync, closeSync, mkdirSync, openSync } from "node:fs";
3
4
  import path from "node:path";
4
5
  import { configDir, daemonPidPath } from "./paths.js";
5
6
  function daemonCliPath() {
@@ -117,15 +118,30 @@ export async function daemonConfigUpdatedAfterStart(status) {
117
118
  }
118
119
  }
119
120
  export function spawnDaemonStart(args, cwd = process.cwd()) {
120
- const child = spawn(process.execPath, [daemonCliPath(), "start", ...args], {
121
- cwd,
122
- env: { ...process.env, HAPPY_ELVES_HOME: configDir },
123
- detached: true,
124
- stdio: "ignore",
125
- windowsHide: true,
126
- });
127
- child.unref();
128
- return child.pid ?? 0;
121
+ const logPath = path.join(configDir, "daemon.startup.log");
122
+ mkdirSync(configDir, { recursive: true });
123
+ const logFd = openSync(logPath, "a", 0o600);
124
+ try {
125
+ appendFileSync(logFd, `\n[${new Date().toISOString()}] Starting daemon (${process.version})\n`);
126
+ const child = spawn(process.execPath, [daemonCliPath(), "start", ...args], {
127
+ cwd,
128
+ env: { ...process.env, HAPPY_ELVES_HOME: configDir },
129
+ detached: true,
130
+ stdio: ["ignore", logFd, logFd],
131
+ windowsHide: true,
132
+ });
133
+ child.once("error", (error) => {
134
+ try {
135
+ appendFileSync(logPath, `Daemon spawn failed: ${error.message}\n`);
136
+ }
137
+ catch { /* Parent still reports a failed start. */ }
138
+ });
139
+ child.unref();
140
+ return child.pid ?? 0;
141
+ }
142
+ finally {
143
+ closeSync(logFd);
144
+ }
129
145
  }
130
146
  export async function stopLocalDaemon(timeoutMs = 5000) {
131
147
  const status = await localDaemonStatus();
@@ -1,4 +1,5 @@
1
1
  import fs from "node:fs/promises";
2
+ import { RecoverableFileLockError, withRecoverableFileLock } from "../../../../../packages/shared/dist/file-lock.js";
2
3
  import { CliError } from "../../errors.js";
3
4
  import { configDir, loopStoreLockPath, loopStorePath } from "./paths.js";
4
5
  function emptyLoopStore() {
@@ -28,24 +29,14 @@ async function writeLoopStore(store) {
28
29
  }
29
30
  async function withLoopStoreLock(operation) {
30
31
  await fs.mkdir(configDir, { recursive: true });
31
- const deadline = Date.now() + 5000;
32
- let handle;
33
- while (!handle) {
34
- try {
35
- handle = await fs.open(loopStoreLockPath, "wx", 0o600);
36
- }
37
- catch (error) {
38
- if (error.code !== "EEXIST" || Date.now() > deadline)
39
- throw error;
40
- await new Promise((resolve) => setTimeout(resolve, 25));
41
- }
42
- }
43
- await handle.close();
44
32
  try {
45
- return await operation();
33
+ return await withRecoverableFileLock({ lockPath: loopStoreLockPath, label: "happy-elves loop store" }, operation);
46
34
  }
47
- finally {
48
- await fs.unlink(loopStoreLockPath).catch(() => { });
35
+ catch (error) {
36
+ if (error instanceof RecoverableFileLockError) {
37
+ throw new CliError(error.message, error.code);
38
+ }
39
+ throw error;
49
40
  }
50
41
  }
51
42
  export function parseStopOn(value) {