@cydm/happy-elves 0.1.0-beta.312 → 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 (324) 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 +25 -2
  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/types.d.ts +12 -2
  20. package/apps/cli/dist/commands/lib/usage.js +67 -72
  21. package/apps/cli/dist/commands/lib/workspace.js +3 -10
  22. package/apps/cli/dist/commands/loop.js +2 -2
  23. package/apps/cli/dist/commands/queue.d.ts +2 -0
  24. package/apps/cli/dist/commands/queue.js +95 -0
  25. package/apps/cli/dist/commands/relay.d.ts +1 -1
  26. package/apps/cli/dist/commands/relay.js +302 -2
  27. package/apps/cli/dist/commands/session.js +11 -199
  28. package/apps/cli/dist/commands/sidechat.d.ts +2 -0
  29. package/apps/cli/dist/commands/sidechat.js +72 -0
  30. package/apps/cli/dist/commands/token.js +26 -10
  31. package/apps/cli/dist/commands/turn.js +92 -14
  32. package/apps/cli/package.json +1 -1
  33. package/apps/daemon/dist/artifact/handler.d.ts +17 -0
  34. package/apps/daemon/dist/artifact/handler.js +858 -0
  35. package/apps/daemon/dist/artifact/pitch-review-sdk.d.ts +1 -0
  36. package/apps/daemon/dist/artifact/pitch-review-sdk.js +63 -0
  37. package/apps/daemon/dist/artifact/store.d.ts +141 -0
  38. package/apps/daemon/dist/artifact/store.js +652 -0
  39. package/apps/daemon/dist/artifact/vendor/lavish-axi/LICENSE +21 -0
  40. package/apps/daemon/dist/artifact/vendor/lavish-axi/artifact-sdk.js +2729 -0
  41. package/apps/daemon/dist/artifact/vendor/lavish-axi/mermaid-node.js +83 -0
  42. package/apps/daemon/dist/artifact/vendor/lavish-axi/table-cell.js +168 -0
  43. package/apps/daemon/dist/config.js +34 -0
  44. package/apps/daemon/dist/direct/server.d.ts +8 -0
  45. package/apps/daemon/dist/direct/server.js +1118 -0
  46. package/apps/daemon/dist/direct/state.d.ts +10 -0
  47. package/apps/daemon/dist/direct/state.js +8 -0
  48. package/apps/daemon/dist/direct/tickets.d.ts +65 -0
  49. package/apps/daemon/dist/direct/tickets.js +242 -0
  50. package/apps/daemon/dist/gateway/handler.js +18 -7
  51. package/apps/daemon/dist/loop/runner.js +70 -5
  52. package/apps/daemon/dist/loop/store.js +7 -16
  53. package/apps/daemon/dist/memory/handler.js +38 -16
  54. package/apps/daemon/dist/memory/settings.d.ts +11 -0
  55. package/apps/daemon/dist/memory/settings.js +56 -0
  56. package/apps/daemon/dist/orchestration/crew-queue.d.ts +28 -0
  57. package/apps/daemon/dist/orchestration/crew-queue.js +834 -0
  58. package/apps/daemon/dist/orchestration/handler.d.ts +31 -0
  59. package/apps/daemon/dist/orchestration/handler.js +1456 -0
  60. package/apps/daemon/dist/orchestration/queue-state.d.ts +49 -0
  61. package/apps/daemon/dist/orchestration/queue-state.js +172 -0
  62. package/apps/daemon/dist/orchestration/runner.d.ts +2 -0
  63. package/apps/daemon/dist/orchestration/runner.js +449 -0
  64. package/apps/daemon/dist/orchestration/store-file.d.ts +3 -0
  65. package/apps/daemon/dist/orchestration/store-file.js +20 -0
  66. package/apps/daemon/dist/orchestration/store.d.ts +285 -0
  67. package/apps/daemon/dist/orchestration/store.js +1529 -0
  68. package/apps/daemon/dist/orchestration/wake-identity.d.ts +13 -0
  69. package/apps/daemon/dist/orchestration/wake-identity.js +20 -0
  70. package/apps/daemon/dist/orchestration/watcher.d.ts +22 -0
  71. package/apps/daemon/dist/orchestration/watcher.js +302 -0
  72. package/apps/daemon/dist/pair.js +1 -1
  73. package/apps/daemon/dist/paths.d.ts +4 -1
  74. package/apps/daemon/dist/paths.js +4 -1
  75. package/apps/daemon/dist/process.d.ts +1 -0
  76. package/apps/daemon/dist/process.js +11 -4
  77. package/apps/daemon/dist/relay/admission.d.ts +14 -0
  78. package/apps/daemon/dist/relay/admission.js +231 -24
  79. package/apps/daemon/dist/relay/connection.d.ts +2 -0
  80. package/apps/daemon/dist/relay/connection.js +468 -18
  81. package/apps/daemon/dist/relay/devtools.js +78 -2
  82. package/apps/daemon/dist/relay/inbound-prompt.d.ts +14 -0
  83. package/apps/daemon/dist/relay/inbound-prompt.js +151 -0
  84. package/apps/daemon/dist/relay/prompt-admission-store.d.ts +49 -0
  85. package/apps/daemon/dist/relay/prompt-admission-store.js +348 -0
  86. package/apps/daemon/dist/relay/register.js +65 -27
  87. package/apps/daemon/dist/relay/remote-command.d.ts +22 -0
  88. package/apps/daemon/dist/relay/remote-command.js +128 -0
  89. package/apps/daemon/dist/relay/send.d.ts +10 -2
  90. package/apps/daemon/dist/relay/send.js +311 -8
  91. package/apps/daemon/dist/runtime/headless-binding.d.ts +13 -0
  92. package/apps/daemon/dist/runtime/headless-binding.js +32 -0
  93. package/apps/daemon/dist/runtime/headless-event-projector.d.ts +38 -0
  94. package/apps/daemon/dist/runtime/headless-event-projector.js +1018 -0
  95. package/apps/daemon/dist/runtime/headless-history-reader.d.ts +13 -0
  96. package/apps/daemon/dist/runtime/headless-history-reader.js +64 -0
  97. package/apps/daemon/dist/runtime/headless-manager.d.ts +50 -0
  98. package/apps/daemon/dist/runtime/headless-manager.js +238 -0
  99. package/apps/daemon/dist/runtime/headless-official-tool-bridge.d.ts +4 -0
  100. package/apps/daemon/dist/runtime/headless-official-tool-bridge.js +95 -0
  101. package/apps/daemon/dist/runtime/headless-server-request.d.ts +17 -0
  102. package/apps/daemon/dist/runtime/headless-server-request.js +32 -0
  103. package/apps/daemon/dist/runtime/headless-session-context.d.ts +11 -0
  104. package/apps/daemon/dist/runtime/headless-session-context.js +41 -0
  105. package/apps/daemon/dist/runtime/headless-session-history.d.ts +13 -0
  106. package/apps/daemon/dist/runtime/headless-session-history.js +271 -0
  107. package/apps/daemon/dist/runtime/headless-session-primitives.d.ts +33 -0
  108. package/apps/daemon/dist/runtime/headless-session-primitives.js +64 -0
  109. package/apps/daemon/dist/runtime/headless-turn-inspector.d.ts +8 -0
  110. package/apps/daemon/dist/runtime/headless-turn-inspector.js +116 -0
  111. package/apps/daemon/dist/runtime/headless-turn-runner.d.ts +27 -0
  112. package/apps/daemon/dist/runtime/headless-turn-runner.js +387 -0
  113. package/apps/daemon/dist/runtime.d.ts +9 -4
  114. package/apps/daemon/dist/runtime.js +83 -61
  115. package/apps/daemon/dist/schedule/handler.js +18 -7
  116. package/apps/daemon/dist/session/create-session.js +7 -1
  117. package/apps/daemon/dist/session/events.d.ts +7 -1
  118. package/apps/daemon/dist/session/events.js +111 -14
  119. package/apps/daemon/dist/session/he-official/approval.d.ts +12 -0
  120. package/apps/daemon/dist/session/he-official/approval.js +52 -0
  121. package/apps/daemon/dist/session/he-official/artifact-commands.d.ts +6 -0
  122. package/apps/daemon/dist/session/he-official/artifact-commands.js +293 -0
  123. package/apps/daemon/dist/session/he-official/common.d.ts +390 -0
  124. package/apps/daemon/dist/session/he-official/common.js +311 -0
  125. package/apps/daemon/dist/session/he-official/delegate-commands.d.ts +5 -0
  126. package/apps/daemon/dist/session/he-official/delegate-commands.js +424 -0
  127. package/apps/daemon/dist/session/he-official/options.d.ts +4 -0
  128. package/apps/daemon/dist/session/he-official/options.js +72 -0
  129. package/apps/daemon/dist/session/he-official/orchestration-commands.d.ts +74 -0
  130. package/apps/daemon/dist/session/he-official/orchestration-commands.js +381 -0
  131. package/apps/daemon/dist/session/he-official/result.d.ts +34 -0
  132. package/apps/daemon/dist/session/he-official/result.js +292 -0
  133. package/apps/daemon/dist/session/he-official/session-commands.d.ts +20 -0
  134. package/apps/daemon/dist/session/he-official/session-commands.js +132 -0
  135. package/apps/daemon/dist/session/he-official/trace.d.ts +65 -0
  136. package/apps/daemon/dist/session/he-official/trace.js +210 -0
  137. package/apps/daemon/dist/session/he-official/turn-commands.d.ts +31 -0
  138. package/apps/daemon/dist/session/he-official/turn-commands.js +315 -0
  139. package/apps/daemon/dist/session/he-official-tools.d.ts +6 -0
  140. package/apps/daemon/dist/session/he-official-tools.js +97 -0
  141. package/apps/daemon/dist/session/history-backfill.d.ts +45 -0
  142. package/apps/daemon/dist/session/history-backfill.js +139 -0
  143. package/apps/daemon/dist/session/lifecycle.d.ts +8 -35
  144. package/apps/daemon/dist/session/lifecycle.js +406 -434
  145. package/apps/daemon/dist/session/metadata.d.ts +3 -2
  146. package/apps/daemon/dist/session/metadata.js +82 -10
  147. package/apps/daemon/dist/session/primitives.js +67 -65
  148. package/apps/daemon/dist/session/prompt.d.ts +16 -3
  149. package/apps/daemon/dist/session/prompt.js +637 -48
  150. package/apps/daemon/dist/session/reconcile.d.ts +1 -1
  151. package/apps/daemon/dist/session/reconcile.js +108 -107
  152. package/apps/daemon/dist/session/runtime-read.d.ts +7 -0
  153. package/apps/daemon/dist/session/runtime-read.js +23 -0
  154. package/apps/daemon/dist/session/runtime-truth.d.ts +26 -0
  155. package/apps/daemon/dist/session/runtime-truth.js +453 -0
  156. package/apps/daemon/dist/session/sidechat.d.ts +11 -0
  157. package/apps/daemon/dist/session/sidechat.js +231 -0
  158. package/apps/daemon/dist/session/store.d.ts +20 -0
  159. package/apps/daemon/dist/session/store.js +219 -0
  160. package/apps/daemon/dist/start.js +31 -2
  161. package/apps/daemon/dist/state.d.ts +21 -1
  162. package/apps/daemon/dist/state.js +35 -0
  163. package/apps/daemon/dist/types.d.ts +50 -12
  164. package/apps/daemon/package.json +1 -1
  165. package/apps/relay/dist/auth.js +12 -0
  166. package/apps/relay/dist/control-plane-store.d.ts +229 -0
  167. package/apps/relay/dist/control-plane-store.js +263 -0
  168. package/apps/relay/dist/db.d.ts +1 -2
  169. package/apps/relay/dist/db.js +53 -391
  170. package/apps/relay/dist/direct-ticket-grants.d.ts +1 -0
  171. package/apps/relay/dist/direct-ticket-grants.js +16 -0
  172. package/apps/relay/dist/http-routes.js +182 -925
  173. package/apps/relay/dist/http-schemas.d.ts +57 -172
  174. package/apps/relay/dist/http-schemas.js +48 -112
  175. package/apps/relay/dist/index.js +50 -5
  176. package/apps/relay/dist/packet-store.d.ts +73 -0
  177. package/apps/relay/dist/packet-store.js +265 -0
  178. package/apps/relay/dist/relay-context.d.ts +57 -120
  179. package/apps/relay/dist/relay-context.js +154 -650
  180. package/apps/relay/dist/relay-migration.d.ts +26 -0
  181. package/apps/relay/dist/relay-migration.js +315 -0
  182. package/apps/relay/dist/retention.js +1 -2
  183. package/apps/relay/dist/types.d.ts +36 -133
  184. package/apps/relay/dist/websocket.d.ts +24 -0
  185. package/apps/relay/dist/websocket.js +707 -99
  186. package/package.json +7 -5
  187. package/packages/agent-sdk/dist/index.d.ts +7 -420
  188. package/packages/agent-sdk/dist/index.js +12 -183
  189. package/packages/client/dist/account.d.ts +5 -21
  190. package/packages/client/dist/account.js +142 -74
  191. package/packages/client/dist/client.d.ts +29 -5
  192. package/packages/client/dist/client.js +619 -89
  193. package/packages/client/dist/command-contracts.d.ts +6 -0
  194. package/packages/client/dist/command-contracts.js +20 -0
  195. package/packages/client/dist/direct.d.ts +12 -0
  196. package/packages/client/dist/direct.js +427 -0
  197. package/packages/client/dist/index.d.ts +1 -1
  198. package/packages/client/dist/parsers.d.ts +2 -1
  199. package/packages/client/dist/parsers.js +31 -17
  200. package/packages/client/dist/product-materializer.d.ts +27 -0
  201. package/packages/client/dist/product-materializer.js +465 -0
  202. package/packages/client/dist/transport.d.ts +31 -0
  203. package/packages/client/dist/transport.js +388 -153
  204. package/packages/client/dist/types.d.ts +216 -10
  205. package/packages/client/dist/validation.d.ts +0 -1
  206. package/packages/client/dist/validation.js +0 -9
  207. package/packages/client/dist/workspace-shared-config.d.ts +23 -0
  208. package/packages/client/dist/workspace-shared-config.js +487 -0
  209. package/packages/headless-runtime/dist/claude-provider.d.ts +20 -0
  210. package/packages/headless-runtime/dist/claude-provider.js +1092 -0
  211. package/packages/{runtime-cli → headless-runtime}/dist/claude-session-store.d.ts +1 -1
  212. package/packages/{runtime-cli → headless-runtime}/dist/claude-session-store.js +33 -12
  213. package/packages/headless-runtime/dist/cli.d.ts +3 -0
  214. package/packages/headless-runtime/dist/cli.js +1243 -0
  215. package/packages/headless-runtime/dist/client.d.ts +75 -0
  216. package/packages/headless-runtime/dist/client.js +490 -0
  217. package/packages/headless-runtime/dist/codex-provider.d.ts +9 -0
  218. package/packages/headless-runtime/dist/codex-provider.js +1278 -0
  219. package/packages/headless-runtime/dist/core.d.ts +304 -0
  220. package/packages/headless-runtime/dist/core.js +2589 -0
  221. package/packages/headless-runtime/dist/event-log.d.ts +11 -0
  222. package/packages/headless-runtime/dist/event-log.js +257 -0
  223. package/packages/headless-runtime/dist/history-index.d.ts +28 -0
  224. package/packages/headless-runtime/dist/history-index.js +72 -0
  225. package/packages/headless-runtime/dist/host-tools.d.ts +21 -0
  226. package/packages/headless-runtime/dist/host-tools.js +252 -0
  227. package/packages/headless-runtime/dist/host.d.ts +63 -0
  228. package/packages/headless-runtime/dist/host.js +423 -0
  229. package/packages/headless-runtime/dist/index.d.ts +44 -0
  230. package/packages/headless-runtime/dist/index.js +487 -0
  231. package/packages/headless-runtime/dist/ipc.d.ts +4 -0
  232. package/packages/headless-runtime/dist/ipc.js +28 -0
  233. package/packages/headless-runtime/dist/mock-scenario.d.ts +7 -0
  234. package/packages/headless-runtime/dist/mock-scenario.js +65 -0
  235. package/packages/headless-runtime/dist/model-catalog.d.ts +21 -0
  236. package/packages/headless-runtime/dist/model-catalog.js +271 -0
  237. package/packages/headless-runtime/dist/provider-command.d.ts +10 -0
  238. package/packages/headless-runtime/dist/provider-command.js +432 -0
  239. package/packages/headless-runtime/dist/provider-turn-metadata.d.ts +9 -0
  240. package/packages/headless-runtime/dist/provider-turn-metadata.js +76 -0
  241. package/packages/headless-runtime/dist/public-response.d.ts +9 -0
  242. package/packages/headless-runtime/dist/public-response.js +112 -0
  243. package/packages/headless-runtime/dist/runtime-projection-store.d.ts +49 -0
  244. package/packages/headless-runtime/dist/runtime-projection-store.js +318 -0
  245. package/packages/headless-runtime/dist/trace-log.d.ts +31 -0
  246. package/packages/headless-runtime/dist/trace-log.js +106 -0
  247. package/packages/pie-provider/dist/index.js +919 -692
  248. package/packages/runtime/dist/headless.d.ts +575 -0
  249. package/packages/runtime/dist/headless.js +3 -0
  250. package/packages/runtime/dist/index.d.ts +68 -112
  251. package/packages/shared/dist/crypto.d.ts +1 -0
  252. package/packages/shared/dist/crypto.js +5 -0
  253. package/packages/shared/dist/diagnostics.d.ts +31 -0
  254. package/packages/shared/dist/diagnostics.js +81 -0
  255. package/packages/shared/dist/file-lock.d.ts +29 -0
  256. package/packages/shared/dist/file-lock.js +301 -0
  257. package/packages/shared/dist/he-official-tools.d.ts +78 -0
  258. package/packages/shared/dist/he-official-tools.js +737 -0
  259. package/packages/shared/dist/index.d.ts +5 -0
  260. package/packages/shared/dist/index.js +5 -0
  261. package/packages/shared/dist/orchestration-routing.d.ts +10 -0
  262. package/packages/shared/dist/orchestration-routing.js +113 -0
  263. package/packages/shared/dist/packet-relay.d.ts +220 -0
  264. package/packages/shared/dist/packet-relay.js +120 -0
  265. package/packages/shared/dist/protocol-schemas.d.ts +1838 -61
  266. package/packages/shared/dist/protocol-schemas.js +599 -7
  267. package/packages/shared/dist/protocol-types.d.ts +510 -7
  268. package/packages/shared/dist/protocol.d.ts +558 -3
  269. package/packages/shared/dist/protocol.js +651 -4
  270. package/packages/shared/dist/relay-scope.d.ts +32 -0
  271. package/packages/shared/dist/relay-scope.js +23 -0
  272. package/packages/shared/dist/session-state.d.ts +1 -1
  273. package/apps/daemon/dist/runtime/external-provider.d.ts +0 -20
  274. package/apps/daemon/dist/runtime/external-provider.js +0 -920
  275. package/apps/daemon/dist/session/runtime-handle.d.ts +0 -7
  276. package/apps/daemon/dist/session/runtime-handle.js +0 -48
  277. package/apps/relay/dist/connections.d.ts +0 -13
  278. package/apps/relay/dist/connections.js +0 -11
  279. package/apps/relay/dist/controller-handlers.d.ts +0 -79
  280. package/apps/relay/dist/controller-handlers.js +0 -777
  281. package/apps/relay/dist/machine-handlers.d.ts +0 -58
  282. package/apps/relay/dist/machine-handlers.js +0 -975
  283. package/apps/relay/dist/projections.d.ts +0 -7
  284. package/apps/relay/dist/projections.js +0 -125
  285. package/apps/relay/dist/repositories.d.ts +0 -13
  286. package/apps/relay/dist/repositories.js +0 -98
  287. package/apps/relay/dist/runtime-bindings.d.ts +0 -25
  288. package/apps/relay/dist/runtime-bindings.js +0 -49
  289. package/apps/relay/dist/scope.d.ts +0 -20
  290. package/apps/relay/dist/scope.js +0 -60
  291. package/packages/runtime-acpx/dist/index.d.ts +0 -11
  292. package/packages/runtime-acpx/dist/index.js +0 -120
  293. package/packages/runtime-cli/dist/async-queue.d.ts +0 -10
  294. package/packages/runtime-cli/dist/async-queue.js +0 -32
  295. package/packages/runtime-cli/dist/claude-history.d.ts +0 -7
  296. package/packages/runtime-cli/dist/claude-history.js +0 -344
  297. package/packages/runtime-cli/dist/claude-json.d.ts +0 -29
  298. package/packages/runtime-cli/dist/claude-json.js +0 -29
  299. package/packages/runtime-cli/dist/claude-rename.d.ts +0 -6
  300. package/packages/runtime-cli/dist/claude-rename.js +0 -15
  301. package/packages/runtime-cli/dist/claude-turn.d.ts +0 -14
  302. package/packages/runtime-cli/dist/claude-turn.js +0 -122
  303. package/packages/runtime-cli/dist/codex-app-server.d.ts +0 -59
  304. package/packages/runtime-cli/dist/codex-app-server.js +0 -418
  305. package/packages/runtime-cli/dist/codex-approvals.d.ts +0 -8
  306. package/packages/runtime-cli/dist/codex-approvals.js +0 -33
  307. package/packages/runtime-cli/dist/codex-history.d.ts +0 -17
  308. package/packages/runtime-cli/dist/codex-history.js +0 -711
  309. package/packages/runtime-cli/dist/codex-json-rpc.d.ts +0 -30
  310. package/packages/runtime-cli/dist/codex-json-rpc.js +0 -150
  311. package/packages/runtime-cli/dist/codex-lifecycle.d.ts +0 -25
  312. package/packages/runtime-cli/dist/codex-lifecycle.js +0 -72
  313. package/packages/runtime-cli/dist/codex-protocol.d.ts +0 -6
  314. package/packages/runtime-cli/dist/codex-protocol.js +0 -53
  315. package/packages/runtime-cli/dist/command-resolver.d.ts +0 -24
  316. package/packages/runtime-cli/dist/command-resolver.js +0 -101
  317. package/packages/runtime-cli/dist/history-merge.d.ts +0 -18
  318. package/packages/runtime-cli/dist/history-merge.js +0 -274
  319. package/packages/runtime-cli/dist/index.d.ts +0 -11
  320. package/packages/runtime-cli/dist/index.js +0 -350
  321. package/packages/runtime-cli/dist/permissions.d.ts +0 -6
  322. package/packages/runtime-cli/dist/permissions.js +0 -22
  323. package/packages/runtime-cli/dist/session-store.d.ts +0 -33
  324. 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,11 +126,15 @@ 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]);
@@ -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) {