@telora/daemon 0.12.33

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 (473) hide show
  1. package/.env.example +64 -0
  2. package/README.md +229 -0
  3. package/build-info.json +4 -0
  4. package/dist/activity-tracker.d.ts +13 -0
  5. package/dist/activity-tracker.d.ts.map +1 -0
  6. package/dist/activity-tracker.js +19 -0
  7. package/dist/activity-tracker.js.map +1 -0
  8. package/dist/agent-state.d.ts +45 -0
  9. package/dist/agent-state.d.ts.map +1 -0
  10. package/dist/agent-state.js +61 -0
  11. package/dist/agent-state.js.map +1 -0
  12. package/dist/audit-hooks.d.ts +12 -0
  13. package/dist/audit-hooks.d.ts.map +1 -0
  14. package/dist/audit-hooks.js +45 -0
  15. package/dist/audit-hooks.js.map +1 -0
  16. package/dist/auto-update.d.ts +42 -0
  17. package/dist/auto-update.d.ts.map +1 -0
  18. package/dist/auto-update.js +96 -0
  19. package/dist/auto-update.js.map +1 -0
  20. package/dist/branch-status.d.ts +40 -0
  21. package/dist/branch-status.d.ts.map +1 -0
  22. package/dist/branch-status.js +107 -0
  23. package/dist/branch-status.js.map +1 -0
  24. package/dist/completion-detector.d.ts +87 -0
  25. package/dist/completion-detector.d.ts.map +1 -0
  26. package/dist/completion-detector.js +160 -0
  27. package/dist/completion-detector.js.map +1 -0
  28. package/dist/completion-handler.d.ts +48 -0
  29. package/dist/completion-handler.d.ts.map +1 -0
  30. package/dist/completion-handler.js +200 -0
  31. package/dist/completion-handler.js.map +1 -0
  32. package/dist/condition-evaluators.d.ts +31 -0
  33. package/dist/condition-evaluators.d.ts.map +1 -0
  34. package/dist/condition-evaluators.js +416 -0
  35. package/dist/condition-evaluators.js.map +1 -0
  36. package/dist/config.d.ts +55 -0
  37. package/dist/config.d.ts.map +1 -0
  38. package/dist/config.js +311 -0
  39. package/dist/config.js.map +1 -0
  40. package/dist/control-state.d.ts +41 -0
  41. package/dist/control-state.d.ts.map +1 -0
  42. package/dist/control-state.js +204 -0
  43. package/dist/control-state.js.map +1 -0
  44. package/dist/crash-recovery-cleanup.d.ts +21 -0
  45. package/dist/crash-recovery-cleanup.d.ts.map +1 -0
  46. package/dist/crash-recovery-cleanup.js +198 -0
  47. package/dist/crash-recovery-cleanup.js.map +1 -0
  48. package/dist/crash-recovery-scan.d.ts +19 -0
  49. package/dist/crash-recovery-scan.d.ts.map +1 -0
  50. package/dist/crash-recovery-scan.js +145 -0
  51. package/dist/crash-recovery-scan.js.map +1 -0
  52. package/dist/crash-recovery-types.d.ts +54 -0
  53. package/dist/crash-recovery-types.d.ts.map +1 -0
  54. package/dist/crash-recovery-types.js +13 -0
  55. package/dist/crash-recovery-types.js.map +1 -0
  56. package/dist/crash-recovery.d.ts +88 -0
  57. package/dist/crash-recovery.d.ts.map +1 -0
  58. package/dist/crash-recovery.js +448 -0
  59. package/dist/crash-recovery.js.map +1 -0
  60. package/dist/daemon-logs.d.ts +19 -0
  61. package/dist/daemon-logs.d.ts.map +1 -0
  62. package/dist/daemon-logs.js +81 -0
  63. package/dist/daemon-logs.js.map +1 -0
  64. package/dist/daemon-process.d.ts +154 -0
  65. package/dist/daemon-process.d.ts.map +1 -0
  66. package/dist/daemon-process.js +427 -0
  67. package/dist/daemon-process.js.map +1 -0
  68. package/dist/dag-validator.d.ts +52 -0
  69. package/dist/dag-validator.d.ts.map +1 -0
  70. package/dist/dag-validator.js +199 -0
  71. package/dist/dag-validator.js.map +1 -0
  72. package/dist/delivery-guards.d.ts +41 -0
  73. package/dist/delivery-guards.d.ts.map +1 -0
  74. package/dist/delivery-guards.js +195 -0
  75. package/dist/delivery-guards.js.map +1 -0
  76. package/dist/delivery-lifecycle.d.ts +110 -0
  77. package/dist/delivery-lifecycle.d.ts.map +1 -0
  78. package/dist/delivery-lifecycle.js +353 -0
  79. package/dist/delivery-lifecycle.js.map +1 -0
  80. package/dist/delivery-merge.d.ts +17 -0
  81. package/dist/delivery-merge.d.ts.map +1 -0
  82. package/dist/delivery-merge.js +89 -0
  83. package/dist/delivery-merge.js.map +1 -0
  84. package/dist/dependency-resolver.d.ts +77 -0
  85. package/dist/dependency-resolver.d.ts.map +1 -0
  86. package/dist/dependency-resolver.js +337 -0
  87. package/dist/dependency-resolver.js.map +1 -0
  88. package/dist/evaluation-context.d.ts +49 -0
  89. package/dist/evaluation-context.d.ts.map +1 -0
  90. package/dist/evaluation-context.js +98 -0
  91. package/dist/evaluation-context.js.map +1 -0
  92. package/dist/git-activity.d.ts +24 -0
  93. package/dist/git-activity.d.ts.map +1 -0
  94. package/dist/git-activity.js +97 -0
  95. package/dist/git-activity.js.map +1 -0
  96. package/dist/git-branch.d.ts +33 -0
  97. package/dist/git-branch.d.ts.map +1 -0
  98. package/dist/git-branch.js +88 -0
  99. package/dist/git-branch.js.map +1 -0
  100. package/dist/git-integration.d.ts +27 -0
  101. package/dist/git-integration.d.ts.map +1 -0
  102. package/dist/git-integration.js +82 -0
  103. package/dist/git-integration.js.map +1 -0
  104. package/dist/git-merge-helpers.d.ts +48 -0
  105. package/dist/git-merge-helpers.d.ts.map +1 -0
  106. package/dist/git-merge-helpers.js +105 -0
  107. package/dist/git-merge-helpers.js.map +1 -0
  108. package/dist/git-merge-lock.d.ts +67 -0
  109. package/dist/git-merge-lock.d.ts.map +1 -0
  110. package/dist/git-merge-lock.js +157 -0
  111. package/dist/git-merge-lock.js.map +1 -0
  112. package/dist/git-merge-strategies.d.ts +39 -0
  113. package/dist/git-merge-strategies.d.ts.map +1 -0
  114. package/dist/git-merge-strategies.js +127 -0
  115. package/dist/git-merge-strategies.js.map +1 -0
  116. package/dist/git-merge.d.ts +80 -0
  117. package/dist/git-merge.d.ts.map +1 -0
  118. package/dist/git-merge.js +373 -0
  119. package/dist/git-merge.js.map +1 -0
  120. package/dist/git-state-detector.d.ts +24 -0
  121. package/dist/git-state-detector.d.ts.map +1 -0
  122. package/dist/git-state-detector.js +122 -0
  123. package/dist/git-state-detector.js.map +1 -0
  124. package/dist/git-types.d.ts +40 -0
  125. package/dist/git-types.d.ts.map +1 -0
  126. package/dist/git-types.js +23 -0
  127. package/dist/git-types.js.map +1 -0
  128. package/dist/git-utils.d.ts +28 -0
  129. package/dist/git-utils.d.ts.map +1 -0
  130. package/dist/git-utils.js +57 -0
  131. package/dist/git-utils.js.map +1 -0
  132. package/dist/git.d.ts +24 -0
  133. package/dist/git.d.ts.map +1 -0
  134. package/dist/git.js +64 -0
  135. package/dist/git.js.map +1 -0
  136. package/dist/guard-engine.d.ts +19 -0
  137. package/dist/guard-engine.d.ts.map +1 -0
  138. package/dist/guard-engine.js +21 -0
  139. package/dist/guard-engine.js.map +1 -0
  140. package/dist/guard-evaluator.d.ts +47 -0
  141. package/dist/guard-evaluator.d.ts.map +1 -0
  142. package/dist/guard-evaluator.js +193 -0
  143. package/dist/guard-evaluator.js.map +1 -0
  144. package/dist/heartbeat.d.ts +73 -0
  145. package/dist/heartbeat.d.ts.map +1 -0
  146. package/dist/heartbeat.js +306 -0
  147. package/dist/heartbeat.js.map +1 -0
  148. package/dist/index.d.ts +32 -0
  149. package/dist/index.d.ts.map +1 -0
  150. package/dist/index.js +493 -0
  151. package/dist/index.js.map +1 -0
  152. package/dist/listener-auto-advance.d.ts +29 -0
  153. package/dist/listener-auto-advance.d.ts.map +1 -0
  154. package/dist/listener-auto-advance.js +172 -0
  155. package/dist/listener-auto-advance.js.map +1 -0
  156. package/dist/listener-review.d.ts +37 -0
  157. package/dist/listener-review.d.ts.map +1 -0
  158. package/dist/listener-review.js +217 -0
  159. package/dist/listener-review.js.map +1 -0
  160. package/dist/listener.d.ts +57 -0
  161. package/dist/listener.d.ts.map +1 -0
  162. package/dist/listener.js +361 -0
  163. package/dist/listener.js.map +1 -0
  164. package/dist/log-manager.d.ts +18 -0
  165. package/dist/log-manager.d.ts.map +1 -0
  166. package/dist/log-manager.js +18 -0
  167. package/dist/log-manager.js.map +1 -0
  168. package/dist/otlp-log-parser.d.ts +21 -0
  169. package/dist/otlp-log-parser.d.ts.map +1 -0
  170. package/dist/otlp-log-parser.js +143 -0
  171. package/dist/otlp-log-parser.js.map +1 -0
  172. package/dist/otlp-metric-parser.d.ts +20 -0
  173. package/dist/otlp-metric-parser.d.ts.map +1 -0
  174. package/dist/otlp-metric-parser.js +113 -0
  175. package/dist/otlp-metric-parser.js.map +1 -0
  176. package/dist/otlp-port-manager.d.ts +26 -0
  177. package/dist/otlp-port-manager.d.ts.map +1 -0
  178. package/dist/otlp-port-manager.js +130 -0
  179. package/dist/otlp-port-manager.js.map +1 -0
  180. package/dist/otlp-receiver.d.ts +51 -0
  181. package/dist/otlp-receiver.d.ts.map +1 -0
  182. package/dist/otlp-receiver.js +663 -0
  183. package/dist/otlp-receiver.js.map +1 -0
  184. package/dist/otlp-types.d.ts +92 -0
  185. package/dist/otlp-types.d.ts.map +1 -0
  186. package/dist/otlp-types.js +133 -0
  187. package/dist/otlp-types.js.map +1 -0
  188. package/dist/output-monitor.d.ts +33 -0
  189. package/dist/output-monitor.d.ts.map +1 -0
  190. package/dist/output-monitor.js +67 -0
  191. package/dist/output-monitor.js.map +1 -0
  192. package/dist/planning-prompt-builder.d.ts +67 -0
  193. package/dist/planning-prompt-builder.d.ts.map +1 -0
  194. package/dist/planning-prompt-builder.js +515 -0
  195. package/dist/planning-prompt-builder.js.map +1 -0
  196. package/dist/prompt-builder.d.ts +14 -0
  197. package/dist/prompt-builder.d.ts.map +1 -0
  198. package/dist/prompt-builder.js +174 -0
  199. package/dist/prompt-builder.js.map +1 -0
  200. package/dist/qa-crash-recovery.d.ts +77 -0
  201. package/dist/qa-crash-recovery.d.ts.map +1 -0
  202. package/dist/qa-crash-recovery.js +243 -0
  203. package/dist/qa-crash-recovery.js.map +1 -0
  204. package/dist/qa-dev-server.d.ts +73 -0
  205. package/dist/qa-dev-server.d.ts.map +1 -0
  206. package/dist/qa-dev-server.js +279 -0
  207. package/dist/qa-dev-server.js.map +1 -0
  208. package/dist/qa-orchestrator.d.ts +79 -0
  209. package/dist/qa-orchestrator.d.ts.map +1 -0
  210. package/dist/qa-orchestrator.js +349 -0
  211. package/dist/qa-orchestrator.js.map +1 -0
  212. package/dist/qa-port-allocator.d.ts +34 -0
  213. package/dist/qa-port-allocator.d.ts.map +1 -0
  214. package/dist/qa-port-allocator.js +75 -0
  215. package/dist/qa-port-allocator.js.map +1 -0
  216. package/dist/qa-provisioner.d.ts +33 -0
  217. package/dist/qa-provisioner.d.ts.map +1 -0
  218. package/dist/qa-provisioner.js +141 -0
  219. package/dist/qa-provisioner.js.map +1 -0
  220. package/dist/qa-state.d.ts +93 -0
  221. package/dist/qa-state.d.ts.map +1 -0
  222. package/dist/qa-state.js +74 -0
  223. package/dist/qa-state.js.map +1 -0
  224. package/dist/queries/control-state.d.ts +25 -0
  225. package/dist/queries/control-state.d.ts.map +1 -0
  226. package/dist/queries/control-state.js +34 -0
  227. package/dist/queries/control-state.js.map +1 -0
  228. package/dist/queries/daemon-connection.d.ts +25 -0
  229. package/dist/queries/daemon-connection.d.ts.map +1 -0
  230. package/dist/queries/daemon-connection.js +28 -0
  231. package/dist/queries/daemon-connection.js.map +1 -0
  232. package/dist/queries/deliveries.d.ts +100 -0
  233. package/dist/queries/deliveries.d.ts.map +1 -0
  234. package/dist/queries/deliveries.js +184 -0
  235. package/dist/queries/deliveries.js.map +1 -0
  236. package/dist/queries/git-activity.d.ts +20 -0
  237. package/dist/queries/git-activity.d.ts.map +1 -0
  238. package/dist/queries/git-activity.js +22 -0
  239. package/dist/queries/git-activity.js.map +1 -0
  240. package/dist/queries/guards.d.ts +47 -0
  241. package/dist/queries/guards.d.ts.map +1 -0
  242. package/dist/queries/guards.js +138 -0
  243. package/dist/queries/guards.js.map +1 -0
  244. package/dist/queries/index.d.ts +19 -0
  245. package/dist/queries/index.d.ts.map +1 -0
  246. package/dist/queries/index.js +17 -0
  247. package/dist/queries/index.js.map +1 -0
  248. package/dist/queries/issues.d.ts +41 -0
  249. package/dist/queries/issues.d.ts.map +1 -0
  250. package/dist/queries/issues.js +67 -0
  251. package/dist/queries/issues.js.map +1 -0
  252. package/dist/queries/qa.d.ts +79 -0
  253. package/dist/queries/qa.d.ts.map +1 -0
  254. package/dist/queries/qa.js +85 -0
  255. package/dist/queries/qa.js.map +1 -0
  256. package/dist/queries/roles.d.ts +13 -0
  257. package/dist/queries/roles.d.ts.map +1 -0
  258. package/dist/queries/roles.js +39 -0
  259. package/dist/queries/roles.js.map +1 -0
  260. package/dist/queries/schemas.d.ts +777 -0
  261. package/dist/queries/schemas.d.ts.map +1 -0
  262. package/dist/queries/schemas.js +391 -0
  263. package/dist/queries/schemas.js.map +1 -0
  264. package/dist/queries/sessions.d.ts +64 -0
  265. package/dist/queries/sessions.d.ts.map +1 -0
  266. package/dist/queries/sessions.js +100 -0
  267. package/dist/queries/sessions.js.map +1 -0
  268. package/dist/queries/shared.d.ts +61 -0
  269. package/dist/queries/shared.d.ts.map +1 -0
  270. package/dist/queries/shared.js +187 -0
  271. package/dist/queries/shared.js.map +1 -0
  272. package/dist/queries/strategies.d.ts +69 -0
  273. package/dist/queries/strategies.d.ts.map +1 -0
  274. package/dist/queries/strategies.js +80 -0
  275. package/dist/queries/strategies.js.map +1 -0
  276. package/dist/queries/workflows.d.ts +17 -0
  277. package/dist/queries/workflows.d.ts.map +1 -0
  278. package/dist/queries/workflows.js +49 -0
  279. package/dist/queries/workflows.js.map +1 -0
  280. package/dist/queries/worktrees.d.ts +38 -0
  281. package/dist/queries/worktrees.d.ts.map +1 -0
  282. package/dist/queries/worktrees.js +37 -0
  283. package/dist/queries/worktrees.js.map +1 -0
  284. package/dist/self-update.d.ts +94 -0
  285. package/dist/self-update.d.ts.map +1 -0
  286. package/dist/self-update.js +438 -0
  287. package/dist/self-update.js.map +1 -0
  288. package/dist/session-lifecycle.d.ts +77 -0
  289. package/dist/session-lifecycle.d.ts.map +1 -0
  290. package/dist/session-lifecycle.js +379 -0
  291. package/dist/session-lifecycle.js.map +1 -0
  292. package/dist/shutdown-state.d.ts +17 -0
  293. package/dist/shutdown-state.d.ts.map +1 -0
  294. package/dist/shutdown-state.js +22 -0
  295. package/dist/shutdown-state.js.map +1 -0
  296. package/dist/spawn-cooldown.d.ts +14 -0
  297. package/dist/spawn-cooldown.d.ts.map +1 -0
  298. package/dist/spawn-cooldown.js +34 -0
  299. package/dist/spawn-cooldown.js.map +1 -0
  300. package/dist/spawn-environment.d.ts +35 -0
  301. package/dist/spawn-environment.d.ts.map +1 -0
  302. package/dist/spawn-environment.js +48 -0
  303. package/dist/spawn-environment.js.map +1 -0
  304. package/dist/spawner-liveness.d.ts +23 -0
  305. package/dist/spawner-liveness.d.ts.map +1 -0
  306. package/dist/spawner-liveness.js +99 -0
  307. package/dist/spawner-liveness.js.map +1 -0
  308. package/dist/spawner-resolution.d.ts +27 -0
  309. package/dist/spawner-resolution.d.ts.map +1 -0
  310. package/dist/spawner-resolution.js +99 -0
  311. package/dist/spawner-resolution.js.map +1 -0
  312. package/dist/spawner-timeout.d.ts +32 -0
  313. package/dist/spawner-timeout.d.ts.map +1 -0
  314. package/dist/spawner-timeout.js +124 -0
  315. package/dist/spawner-timeout.js.map +1 -0
  316. package/dist/spawner.d.ts +77 -0
  317. package/dist/spawner.d.ts.map +1 -0
  318. package/dist/spawner.js +734 -0
  319. package/dist/spawner.js.map +1 -0
  320. package/dist/strategy-completion.d.ts +110 -0
  321. package/dist/strategy-completion.d.ts.map +1 -0
  322. package/dist/strategy-completion.js +434 -0
  323. package/dist/strategy-completion.js.map +1 -0
  324. package/dist/strategy-engine.d.ts +47 -0
  325. package/dist/strategy-engine.d.ts.map +1 -0
  326. package/dist/strategy-engine.js +419 -0
  327. package/dist/strategy-engine.js.map +1 -0
  328. package/dist/strategy-executor.d.ts +93 -0
  329. package/dist/strategy-executor.d.ts.map +1 -0
  330. package/dist/strategy-executor.js +775 -0
  331. package/dist/strategy-executor.js.map +1 -0
  332. package/dist/strategy-lifecycle.d.ts +61 -0
  333. package/dist/strategy-lifecycle.d.ts.map +1 -0
  334. package/dist/strategy-lifecycle.js +516 -0
  335. package/dist/strategy-lifecycle.js.map +1 -0
  336. package/dist/strategy-merge.d.ts +72 -0
  337. package/dist/strategy-merge.d.ts.map +1 -0
  338. package/dist/strategy-merge.js +371 -0
  339. package/dist/strategy-merge.js.map +1 -0
  340. package/dist/strategy-prompt-builder.d.ts +62 -0
  341. package/dist/strategy-prompt-builder.d.ts.map +1 -0
  342. package/dist/strategy-prompt-builder.js +538 -0
  343. package/dist/strategy-prompt-builder.js.map +1 -0
  344. package/dist/strategy-provisioning.d.ts +16 -0
  345. package/dist/strategy-provisioning.d.ts.map +1 -0
  346. package/dist/strategy-provisioning.js +119 -0
  347. package/dist/strategy-provisioning.js.map +1 -0
  348. package/dist/strategy-team-state.d.ts +24 -0
  349. package/dist/strategy-team-state.d.ts.map +1 -0
  350. package/dist/strategy-team-state.js +43 -0
  351. package/dist/strategy-team-state.js.map +1 -0
  352. package/dist/strategy-teardown.d.ts +24 -0
  353. package/dist/strategy-teardown.d.ts.map +1 -0
  354. package/dist/strategy-teardown.js +158 -0
  355. package/dist/strategy-teardown.js.map +1 -0
  356. package/dist/strategy-worktree-state.d.ts +47 -0
  357. package/dist/strategy-worktree-state.d.ts.map +1 -0
  358. package/dist/strategy-worktree-state.js +104 -0
  359. package/dist/strategy-worktree-state.js.map +1 -0
  360. package/dist/supabase.d.ts +36 -0
  361. package/dist/supabase.d.ts.map +1 -0
  362. package/dist/supabase.js +50 -0
  363. package/dist/supabase.js.map +1 -0
  364. package/dist/task-converter.d.ts +61 -0
  365. package/dist/task-converter.d.ts.map +1 -0
  366. package/dist/task-converter.js +286 -0
  367. package/dist/task-converter.js.map +1 -0
  368. package/dist/task-dag-builder.d.ts +14 -0
  369. package/dist/task-dag-builder.d.ts.map +1 -0
  370. package/dist/task-dag-builder.js +17 -0
  371. package/dist/task-dag-builder.js.map +1 -0
  372. package/dist/team-prompt-base.d.ts +114 -0
  373. package/dist/team-prompt-base.d.ts.map +1 -0
  374. package/dist/team-prompt-base.js +531 -0
  375. package/dist/team-prompt-base.js.map +1 -0
  376. package/dist/team-prompt-variants.d.ts +27 -0
  377. package/dist/team-prompt-variants.d.ts.map +1 -0
  378. package/dist/team-prompt-variants.js +134 -0
  379. package/dist/team-prompt-variants.js.map +1 -0
  380. package/dist/team-spawner.d.ts +50 -0
  381. package/dist/team-spawner.d.ts.map +1 -0
  382. package/dist/team-spawner.js +410 -0
  383. package/dist/team-spawner.js.map +1 -0
  384. package/dist/telemetry-writer.d.ts +66 -0
  385. package/dist/telemetry-writer.d.ts.map +1 -0
  386. package/dist/telemetry-writer.js +96 -0
  387. package/dist/telemetry-writer.js.map +1 -0
  388. package/dist/trigger-executor.d.ts +56 -0
  389. package/dist/trigger-executor.d.ts.map +1 -0
  390. package/dist/trigger-executor.js +313 -0
  391. package/dist/trigger-executor.js.map +1 -0
  392. package/dist/types/config.d.ts +60 -0
  393. package/dist/types/config.d.ts.map +1 -0
  394. package/dist/types/config.js +5 -0
  395. package/dist/types/config.js.map +1 -0
  396. package/dist/types/dag.d.ts +53 -0
  397. package/dist/types/dag.d.ts.map +1 -0
  398. package/dist/types/dag.js +5 -0
  399. package/dist/types/dag.js.map +1 -0
  400. package/dist/types/delivery.d.ts +71 -0
  401. package/dist/types/delivery.d.ts.map +1 -0
  402. package/dist/types/delivery.js +5 -0
  403. package/dist/types/delivery.js.map +1 -0
  404. package/dist/types/index.d.ts +15 -0
  405. package/dist/types/index.d.ts.map +1 -0
  406. package/dist/types/index.js +15 -0
  407. package/dist/types/index.js.map +1 -0
  408. package/dist/types/issue.d.ts +22 -0
  409. package/dist/types/issue.d.ts.map +1 -0
  410. package/dist/types/issue.js +5 -0
  411. package/dist/types/issue.js.map +1 -0
  412. package/dist/types/merge.d.ts +28 -0
  413. package/dist/types/merge.d.ts.map +1 -0
  414. package/dist/types/merge.js +5 -0
  415. package/dist/types/merge.js.map +1 -0
  416. package/dist/types/session.d.ts +98 -0
  417. package/dist/types/session.d.ts.map +1 -0
  418. package/dist/types/session.js +5 -0
  419. package/dist/types/session.js.map +1 -0
  420. package/dist/types/strategy.d.ts +175 -0
  421. package/dist/types/strategy.d.ts.map +1 -0
  422. package/dist/types/strategy.js +5 -0
  423. package/dist/types/strategy.js.map +1 -0
  424. package/dist/types/workflow.d.ts +34 -0
  425. package/dist/types/workflow.d.ts.map +1 -0
  426. package/dist/types/workflow.js +9 -0
  427. package/dist/types/workflow.js.map +1 -0
  428. package/dist/types.d.ts +9 -0
  429. package/dist/types.d.ts.map +1 -0
  430. package/dist/types.js +9 -0
  431. package/dist/types.js.map +1 -0
  432. package/dist/unified-init.d.ts +16 -0
  433. package/dist/unified-init.d.ts.map +1 -0
  434. package/dist/unified-init.js +183 -0
  435. package/dist/unified-init.js.map +1 -0
  436. package/dist/unified-shell-config.d.ts +34 -0
  437. package/dist/unified-shell-config.d.ts.map +1 -0
  438. package/dist/unified-shell-config.js +238 -0
  439. package/dist/unified-shell-config.js.map +1 -0
  440. package/dist/unified-shell-status.d.ts +15 -0
  441. package/dist/unified-shell-status.d.ts.map +1 -0
  442. package/dist/unified-shell-status.js +100 -0
  443. package/dist/unified-shell-status.js.map +1 -0
  444. package/dist/unified-shell.d.ts +50 -0
  445. package/dist/unified-shell.d.ts.map +1 -0
  446. package/dist/unified-shell.js +682 -0
  447. package/dist/unified-shell.js.map +1 -0
  448. package/dist/version-check.d.ts +19 -0
  449. package/dist/version-check.d.ts.map +1 -0
  450. package/dist/version-check.js +67 -0
  451. package/dist/version-check.js.map +1 -0
  452. package/dist/workflow-engine.d.ts +95 -0
  453. package/dist/workflow-engine.d.ts.map +1 -0
  454. package/dist/workflow-engine.js +165 -0
  455. package/dist/workflow-engine.js.map +1 -0
  456. package/dist/worktree-merge.d.ts +23 -0
  457. package/dist/worktree-merge.d.ts.map +1 -0
  458. package/dist/worktree-merge.js +57 -0
  459. package/dist/worktree-merge.js.map +1 -0
  460. package/dist/worktree-safety.d.ts +48 -0
  461. package/dist/worktree-safety.d.ts.map +1 -0
  462. package/dist/worktree-safety.js +113 -0
  463. package/dist/worktree-safety.js.map +1 -0
  464. package/dist/worktree-strategy.d.ts +69 -0
  465. package/dist/worktree-strategy.d.ts.map +1 -0
  466. package/dist/worktree-strategy.js +214 -0
  467. package/dist/worktree-strategy.js.map +1 -0
  468. package/dist/worktree.d.ts +159 -0
  469. package/dist/worktree.d.ts.map +1 -0
  470. package/dist/worktree.js +512 -0
  471. package/dist/worktree.js.map +1 -0
  472. package/package.json +76 -0
  473. package/scripts/telora-daemon-wrapper.sh +31 -0
@@ -0,0 +1,682 @@
1
+ /**
2
+ * Unified daemon process shell -- the single entry point for telora-daemon.
3
+ *
4
+ * Composes daemon-core's lifecycle primitives (PID locking, signal handling,
5
+ * config loading) with one or more ExecutionEngine adapters (StrategyEngine,
6
+ * FactoryEngine). The CLI in index.ts creates engine instances based on the
7
+ * unified config and passes them here.
8
+ *
9
+ * Lifecycle sequence:
10
+ * 1. Load unified config via loadUnifiedConfig()
11
+ * 2. Apply engine filter (--engine flag) if provided
12
+ * 3. Acquire PID lock at .telora/daemon.pid
13
+ * 4. Register uncaughtException / unhandledRejection handlers
14
+ * 5. Set up signal handlers (SIGTERM, SIGINT)
15
+ * 6. For each enabled engine: build config, create instance, init, recover, start
16
+ * 7. Register SIGUSR1 (status) and SIGUSR2 (circuit breaker reset) handlers
17
+ * 8. Keep the process running indefinitely
18
+ *
19
+ * On shutdown (SIGTERM/SIGINT):
20
+ * 1. Stop all engines (stop accepting new work)
21
+ * 2. Shut down all engines in parallel (graceful cleanup)
22
+ * 3. Release PID lock
23
+ * 4. Exit
24
+ */
25
+ import { readFileSync, openSync, closeSync } from 'node:fs';
26
+ import { dirname, join, resolve } from 'node:path';
27
+ import { fileURLToPath } from 'node:url';
28
+ import { networkInterfaces } from 'node:os';
29
+ import { spawn } from 'node:child_process';
30
+ import { loadUnifiedConfig, buildEngineConfig, acquirePidLock, releasePidLock, setupSignalHandlers, PidLockError, forceCloseAllCircuitBreakers, ResourceGovernor, } from '@telora/daemon-core';
31
+ import { StrategyEngine } from './strategy-engine.js';
32
+ import { startAutoUpdateLoop } from './auto-update.js';
33
+ import { setDaemonShuttingDown } from './shutdown-state.js';
34
+ import { rotateDaemonLog, setupCanonicalLogTee, writeDaemonMeta, removeDaemonMeta, resolveDaemonLogPath, resolvePidFilePath, ensureGlobalStateDir } from './daemon-process.js';
35
+ // ---------------------------------------------------------------------------
36
+ // LAN host detection (mirrored from daemon's config.ts to avoid circular deps)
37
+ // ---------------------------------------------------------------------------
38
+ /**
39
+ * Auto-detect the first non-internal IPv4 address for LAN-accessible URLs.
40
+ * Falls back to 'localhost' if no suitable address is found.
41
+ */
42
+ function detectLanHost() {
43
+ const interfaces = networkInterfaces();
44
+ for (const ifaceEntries of Object.values(interfaces)) {
45
+ if (!ifaceEntries)
46
+ continue;
47
+ for (const iface of ifaceEntries) {
48
+ if (iface.family === 'IPv4' && !iface.internal) {
49
+ return iface.address;
50
+ }
51
+ }
52
+ }
53
+ return 'localhost';
54
+ }
55
+ // ---------------------------------------------------------------------------
56
+ // Numeric env-var helpers (mirrored from daemon/config.ts)
57
+ // ---------------------------------------------------------------------------
58
+ function resolveInt(envVal, fileVal, defaultVal) {
59
+ if (envVal !== undefined && envVal !== '') {
60
+ return parseInt(envVal, 10);
61
+ }
62
+ if (typeof fileVal === 'number') {
63
+ return fileVal;
64
+ }
65
+ return defaultVal;
66
+ }
67
+ function resolveFloat(envVal, fileVal, defaultVal) {
68
+ if (envVal !== undefined && envVal !== '') {
69
+ return parseFloat(envVal);
70
+ }
71
+ if (typeof fileVal === 'number') {
72
+ return fileVal;
73
+ }
74
+ return defaultVal;
75
+ }
76
+ // ---------------------------------------------------------------------------
77
+ // Engine config builders
78
+ // ---------------------------------------------------------------------------
79
+ /**
80
+ * Build a complete strategy engine config (DaemonConfig) from the unified
81
+ * base config and the strategy engine section. Applies the same defaults
82
+ * and env-var overrides as daemon/src/config.ts loadConfig().
83
+ */
84
+ function buildStrategyConfig(base, section, env = process.env) {
85
+ // Start with the flat merge from daemon-core
86
+ const flat = buildEngineConfig(base, section);
87
+ const fields = section.fields;
88
+ const repoPath = flat.repoPath || process.cwd();
89
+ const claudeCodePath = flat.claudeCodePath || 'claude';
90
+ const logDir = flat.logDir || resolve(repoPath, '.telora', 'logs');
91
+ const sessionTimeoutMs = flat.sessionTimeoutMs ?? 3600000;
92
+ const mcpConfigPath = flat.mcpConfigPath ?? null;
93
+ // Strategy-specific fields with env overrides
94
+ const worktreeDir = env.TELORA_WORKTREE_DIR
95
+ || (typeof fields.worktreeDir === 'string' ? fields.worktreeDir : '')
96
+ || resolve(repoPath, '.telora', 'worktrees');
97
+ const integrationBranch = env.TELORA_INTEGRATION_BRANCH
98
+ || (typeof fields.integrationBranch === 'string' ? fields.integrationBranch : '')
99
+ || 'integration';
100
+ const maxTotalSessions = resolveInt(env.MAX_TOTAL_SESSIONS, fields.maxTotalSessions, 5);
101
+ const tokenLimit = resolveInt(env.TOKEN_LIMIT, fields.tokenLimit, 200000);
102
+ const costLimit = resolveFloat(env.COST_LIMIT, fields.costLimit, 10.0);
103
+ const mergeLockTimeoutMs = resolveInt(env.MERGE_LOCK_TIMEOUT_MS, fields.mergeLockTimeoutMs, 300000);
104
+ const mergeLockContentionWarningMs = resolveInt(env.MERGE_LOCK_CONTENTION_WARNING_MS, fields.mergeLockContentionWarningMs, 30000);
105
+ // Guard failure mode
106
+ const rawPolicyFailureMode = env.TELORA_POLICY_FAILURE_MODE
107
+ || (typeof fields.policyFailureMode === 'string' ? fields.policyFailureMode : '')
108
+ || 'fail-open';
109
+ if (rawPolicyFailureMode !== 'fail-open' && rawPolicyFailureMode !== 'fail-closed') {
110
+ throw new Error(`Invalid TELORA_POLICY_FAILURE_MODE: "${rawPolicyFailureMode}". Must be "fail-open" or "fail-closed".`);
111
+ }
112
+ // Log retention
113
+ const logMaxAgeDays = resolveInt(env.LOG_MAX_AGE_DAYS, fields.logMaxAgeDays, 7);
114
+ const logMaxTotalBytes = resolveInt(env.LOG_MAX_TOTAL_BYTES, fields.logMaxTotalBytes, 1073741824);
115
+ const logMaxFiles = resolveInt(env.LOG_MAX_FILES, fields.logMaxFiles, 500);
116
+ // Telemetry
117
+ const telemetryFile = (typeof fields.telemetry === 'object' && fields.telemetry !== null)
118
+ ? fields.telemetry
119
+ : {};
120
+ const telemetry = {
121
+ enabled: env.TELORA_TELEMETRY_ENABLED !== undefined
122
+ ? env.TELORA_TELEMETRY_ENABLED !== '0' && env.TELORA_TELEMETRY_ENABLED !== 'false'
123
+ : (typeof telemetryFile.enabled === 'boolean' ? telemetryFile.enabled : true),
124
+ port: resolveInt(env.TELORA_TELEMETRY_PORT, telemetryFile.port, 4318),
125
+ flushIntervalMs: resolveInt(env.TELORA_TELEMETRY_FLUSH_INTERVAL_MS, telemetryFile.flushIntervalMs, 5000),
126
+ retentionDays: resolveInt(env.TELORA_TELEMETRY_RETENTION_DAYS, telemetryFile.retentionDays, 30),
127
+ };
128
+ // QA environment
129
+ const qaPortRangeStart = resolveInt(env.TELORA_QA_PORT_RANGE_START, fields.qaPortRangeStart, 9100);
130
+ const qaPortRangeEnd = resolveInt(env.TELORA_QA_PORT_RANGE_END, fields.qaPortRangeEnd, 9199);
131
+ const qaHost = env.TELORA_QA_HOST
132
+ || (typeof fields.qaHost === 'string' ? fields.qaHost : '')
133
+ || detectLanHost();
134
+ // Local Supabase
135
+ const localSupabaseUrl = env.TELORA_LOCAL_SUPABASE_URL
136
+ || (typeof fields.localSupabaseUrl === 'string' ? fields.localSupabaseUrl : '')
137
+ || 'http://127.0.0.1:54321';
138
+ const localSupabaseAnonKey = env.TELORA_LOCAL_SUPABASE_ANON_KEY
139
+ || (typeof fields.localSupabaseAnonKey === 'string' ? fields.localSupabaseAnonKey : '')
140
+ || null;
141
+ // Products array from base config (already resolved by loadUnifiedConfig)
142
+ const products = flat.products ?? [];
143
+ return {
144
+ // Base fields
145
+ teloraUrl: flat.teloraUrl,
146
+ trackerId: flat.trackerId,
147
+ organizationId: flat.organizationId,
148
+ productId: flat.productId,
149
+ repoPath,
150
+ products,
151
+ claudeCodePath,
152
+ logDir,
153
+ sessionTimeoutMs,
154
+ mcpConfigPath,
155
+ // Strategy-specific fields
156
+ worktreeDir,
157
+ integrationBranch,
158
+ maxTotalSessions,
159
+ tokenLimit,
160
+ costLimit,
161
+ mergeLockTimeoutMs,
162
+ mergeLockContentionWarningMs,
163
+ policyFailureMode: rawPolicyFailureMode,
164
+ logMaxAgeDays,
165
+ logMaxTotalBytes,
166
+ logMaxFiles,
167
+ telemetry,
168
+ qaPortRangeStart,
169
+ qaPortRangeEnd,
170
+ qaHost,
171
+ localSupabaseUrl,
172
+ localSupabaseAnonKey,
173
+ };
174
+ }
175
+ /**
176
+ * Build a complete factory engine config (FactoryConfig) from the unified
177
+ * base config and the factory engine section. Applies the same defaults
178
+ * and env-var overrides as factory/src/config.ts loadConfig().
179
+ */
180
+ function buildFactoryConfig(base, section, env = process.env) {
181
+ const flat = buildEngineConfig(base, section);
182
+ const fields = section.fields;
183
+ const repoPath = flat.repoPath || process.cwd();
184
+ const claudeCodePath = flat.claudeCodePath || 'claude';
185
+ // Factory uses a separate log directory by default
186
+ const logDir = flat.logDir || resolve(repoPath, '.telora', 'factory-logs');
187
+ const sessionTimeoutMs = flat.sessionTimeoutMs ?? 3600000;
188
+ const mcpConfigPath = flat.mcpConfigPath ?? null;
189
+ // Factory-specific fields with env overrides
190
+ const factoryWorktreeDir = env.TELORA_FACTORY_WORKTREE_DIR
191
+ || (typeof fields.factoryWorktreeDir === 'string' ? fields.factoryWorktreeDir : '')
192
+ || resolve(repoPath, '.telora', 'factory-worktrees');
193
+ const maxConcurrentInstances = env.FACTORY_MAX_CONCURRENT_INSTANCES
194
+ ? parseInt(env.FACTORY_MAX_CONCURRENT_INSTANCES, 10)
195
+ : (typeof fields.maxConcurrentInstances === 'number' ? fields.maxConcurrentInstances : 3);
196
+ // Telemetry: inherit from flat config (resolved by buildEngineConfig) or default
197
+ const telemetry = (flat.telemetry && typeof flat.telemetry === 'object')
198
+ ? flat.telemetry
199
+ : { enabled: true, port: 4318 };
200
+ // Products array from base config (already resolved by loadUnifiedConfig)
201
+ const products = flat.products ?? [];
202
+ return {
203
+ // Base fields
204
+ teloraUrl: flat.teloraUrl,
205
+ trackerId: flat.trackerId,
206
+ organizationId: flat.organizationId,
207
+ productId: flat.productId,
208
+ repoPath,
209
+ products,
210
+ claudeCodePath,
211
+ logDir,
212
+ sessionTimeoutMs,
213
+ mcpConfigPath,
214
+ // Factory-specific fields
215
+ factoryWorktreeDir,
216
+ maxConcurrentInstances,
217
+ telemetry,
218
+ };
219
+ }
220
+ // ---------------------------------------------------------------------------
221
+ // Status reporting
222
+ // ---------------------------------------------------------------------------
223
+ /**
224
+ * Print aggregated status from all active engines.
225
+ */
226
+ function printAggregatedStatus(engines, governor) {
227
+ console.log('\n=== Unified Daemon Status ===');
228
+ console.log(`Engines: ${engines.map(e => e.name).join(', ')}`);
229
+ console.log(`PID: ${process.pid}`);
230
+ console.log(`Uptime: ${Math.round(process.uptime())}s`);
231
+ // Resource governor utilization
232
+ if (governor) {
233
+ const util = governor.getUtilization();
234
+ console.log(`\n--- Resource Governor ---`);
235
+ console.log(` Global slots: ${util.total}/${util.max} in use`);
236
+ for (const [engine, count] of Object.entries(util.perEngine)) {
237
+ console.log(` ${engine}: ${count} slots`);
238
+ }
239
+ if (util.queueDepth > 0) {
240
+ console.log(` Queue depth: ${util.queueDepth}`);
241
+ for (const [engine, depth] of Object.entries(util.queueDepthPerEngine)) {
242
+ console.log(` ${engine}: ${depth} waiting`);
243
+ }
244
+ }
245
+ }
246
+ for (const engine of engines) {
247
+ const health = engine.healthCheck();
248
+ const resources = engine.getResourceUsage();
249
+ console.log(`\n--- ${engine.name} engine ---`);
250
+ console.log(` Status: ${health.status}`);
251
+ console.log(` Active work items: ${health.activeWorkItems}`);
252
+ console.log(` Claude processes: ${resources.activeClaudeProcesses}`);
253
+ console.log(` Active worktrees: ${resources.activeWorktrees}`);
254
+ // Print engine-specific details
255
+ const details = health.details;
256
+ for (const [key, value] of Object.entries(details)) {
257
+ if (Array.isArray(value)) {
258
+ if (value.length > 0) {
259
+ console.log(` ${key}:`);
260
+ for (const item of value) {
261
+ if (typeof item === 'object' && item !== null) {
262
+ const parts = Object.entries(item)
263
+ .map(([k, v]) => `${k}: ${String(v)}`)
264
+ .join(' | ');
265
+ console.log(` - ${parts}`);
266
+ }
267
+ else {
268
+ console.log(` - ${String(item)}`);
269
+ }
270
+ }
271
+ }
272
+ }
273
+ else if (typeof value === 'object' && value !== null) {
274
+ const entries = Object.entries(value);
275
+ if (entries.length > 0) {
276
+ console.log(` ${key}:`);
277
+ for (const [k, v] of entries) {
278
+ console.log(` ${k}: ${String(v)}`);
279
+ }
280
+ }
281
+ }
282
+ else {
283
+ console.log(` ${key}: ${String(value)}`);
284
+ }
285
+ }
286
+ }
287
+ console.log('');
288
+ }
289
+ /**
290
+ * Print a dry-run summary of the unified config.
291
+ */
292
+ function printUnifiedConfigSummary(config) {
293
+ console.log('Unified Daemon Configuration:');
294
+ console.log(` Telora URL: ${config.base.teloraUrl ?? '[not set]'}`);
295
+ console.log(` Tracker ID: ${config.base.trackerId ? '[configured]' : '[not set]'}`);
296
+ console.log(` Organization ID: ${config.base.organizationId ?? '[not set]'}`);
297
+ const products = config.base.products ?? [];
298
+ if (products.length > 0) {
299
+ console.log(` Products: ${products.length}`);
300
+ for (const p of products) {
301
+ console.log(` - ${p.id} -> ${p.repoPath}`);
302
+ }
303
+ }
304
+ else {
305
+ console.log(` Product ID: ${config.base.productId ?? '[not set]'}`);
306
+ console.log(` Repository Path: ${config.base.repoPath ?? '[cwd]'}`);
307
+ }
308
+ console.log(` Claude Code Path: ${config.base.claudeCodePath ?? 'claude'}`);
309
+ console.log(` Log Directory: ${config.base.logDir ?? '[default]'}`);
310
+ console.log(` Session Timeout: ${config.base.sessionTimeoutMs ?? 3600000}ms`);
311
+ console.log(` MCP Config Path: ${config.base.mcpConfigPath ?? '[not set]'}`);
312
+ console.log(`\n Strategy engine: ${config.strategy.enabled ? 'enabled' : 'disabled'}`);
313
+ if (config.strategy.enabled) {
314
+ const sf = config.strategy.fields;
315
+ console.log(` worktreeDir: ${String(sf.worktreeDir ?? '[default]')}`);
316
+ console.log(` integrationBranch: ${String(sf.integrationBranch ?? 'integration')}`);
317
+ console.log(` maxTotalSessions: ${String(sf.maxTotalSessions ?? 5)}`);
318
+ }
319
+ console.log(`\n Factory engine: ${config.factory.enabled ? 'enabled' : 'disabled'}`);
320
+ if (config.factory.enabled) {
321
+ const ff = config.factory.fields;
322
+ console.log(` factoryWorktreeDir: ${String(ff.factoryWorktreeDir ?? '[default]')}`);
323
+ console.log(` maxConcurrentInstances: ${String(ff.maxConcurrentInstances ?? 3)}`);
324
+ }
325
+ }
326
+ // ---------------------------------------------------------------------------
327
+ // Auto-update config resolution
328
+ // ---------------------------------------------------------------------------
329
+ const DEFAULT_AUTO_UPDATE_INTERVAL_MS = 3_600_000; // 1 hour
330
+ /**
331
+ * Resolve whether auto-update is enabled from env vars and config file.
332
+ * Env var TELORA_AUTO_UPDATE takes precedence over config file autoUpdate.enabled.
333
+ * Default: true.
334
+ */
335
+ function resolveAutoUpdateEnabled(config) {
336
+ const envVal = process.env.TELORA_AUTO_UPDATE;
337
+ if (envVal !== undefined && envVal !== '') {
338
+ return envVal !== '0' && envVal !== 'false';
339
+ }
340
+ const fileConfig = config.rawFileConfig;
341
+ if (typeof fileConfig.autoUpdate === 'object' && fileConfig.autoUpdate !== null) {
342
+ const au = fileConfig.autoUpdate;
343
+ if (typeof au.enabled === 'boolean')
344
+ return au.enabled;
345
+ }
346
+ return true;
347
+ }
348
+ /**
349
+ * Resolve auto-update check interval from env vars and config file.
350
+ * Env var TELORA_AUTO_UPDATE_INTERVAL_MS takes precedence.
351
+ * Default: 3600000 (1 hour).
352
+ */
353
+ function resolveAutoUpdateIntervalMs(config) {
354
+ const envVal = process.env.TELORA_AUTO_UPDATE_INTERVAL_MS;
355
+ if (envVal !== undefined && envVal !== '') {
356
+ const parsed = parseInt(envVal, 10);
357
+ if (!isNaN(parsed) && parsed > 0)
358
+ return parsed;
359
+ }
360
+ const fileConfig = config.rawFileConfig;
361
+ if (typeof fileConfig.autoUpdate === 'object' && fileConfig.autoUpdate !== null) {
362
+ const au = fileConfig.autoUpdate;
363
+ if (typeof au.intervalMs === 'number' && au.intervalMs > 0)
364
+ return au.intervalMs;
365
+ }
366
+ return DEFAULT_AUTO_UPDATE_INTERVAL_MS;
367
+ }
368
+ // ---------------------------------------------------------------------------
369
+ // Main entry point
370
+ // ---------------------------------------------------------------------------
371
+ /**
372
+ * Run the unified daemon process shell.
373
+ *
374
+ * This function loads configuration, acquires a PID lock, creates and
375
+ * initializes execution engines, runs crash recovery, starts the engines,
376
+ * and keeps the process running until a shutdown signal is received.
377
+ *
378
+ * @param opts CLI options (verbose, config path, dry-run, skip-recovery, engine filter).
379
+ */
380
+ export async function runUnifiedDaemon(opts) {
381
+ // ── 1. Load unified config ───────────────────────────────────────────────
382
+ const config = loadUnifiedConfig(opts.config);
383
+ // ── 2. Apply engine filter ───────────────────────────────────────────────
384
+ if (opts.engineFilter) {
385
+ if (opts.engineFilter === 'strategy') {
386
+ config.factory = { enabled: false, fields: {} };
387
+ }
388
+ else if (opts.engineFilter === 'factory') {
389
+ config.strategy = { enabled: false, fields: {} };
390
+ }
391
+ console.log(`Engine filter active: only '${opts.engineFilter}' engine enabled`);
392
+ }
393
+ // ── 3. Dry run / verbose ─────────────────────────────────────────────────
394
+ if (opts.verbose || opts.dryRun) {
395
+ printUnifiedConfigSummary(config);
396
+ }
397
+ if (opts.dryRun) {
398
+ console.log('\nDry run mode -- exiting');
399
+ return;
400
+ }
401
+ // ── 4. Resolve repo path ─────────────────────────────────────────────────
402
+ const repoPath = config.base.repoPath || process.cwd();
403
+ // ── 5. Acquire PID lock ──────────────────────────────────────────────────
404
+ ensureGlobalStateDir();
405
+ const pidFilePath = resolvePidFilePath();
406
+ try {
407
+ acquirePidLock(pidFilePath);
408
+ }
409
+ catch (err) {
410
+ if (err instanceof PidLockError) {
411
+ console.error(err.message);
412
+ process.exit(1);
413
+ }
414
+ throw err;
415
+ }
416
+ // ── 5a. Canonical log setup ─────────────────────────────────────────────
417
+ // In foreground mode (TTY), rotate the log and tee stdout/stderr to it.
418
+ // In background mode, startDaemonBackground already rotated and redirected
419
+ // stdio to the log file, so we skip rotation to avoid renaming the file
420
+ // out from under our own fd.
421
+ const logPath = resolveDaemonLogPath();
422
+ let cleanupLogTee = null;
423
+ if (process.stdout.isTTY) {
424
+ rotateDaemonLog();
425
+ cleanupLogTee = setupCanonicalLogTee();
426
+ }
427
+ writeDaemonMeta(logPath);
428
+ // ── 5b. Register top-level error handlers (early, before engine init) ──
429
+ let isShuttingDown = false;
430
+ // shutdown is assigned later in this scope once engines and governor exist.
431
+ // It will be set before the event loop yields, so async handlers will see it.
432
+ let shutdown = null;
433
+ process.on('uncaughtException', (err) => {
434
+ console.error('[FATAL] Uncaught exception:', err);
435
+ if (isShuttingDown)
436
+ return;
437
+ if (shutdown) {
438
+ void shutdown('uncaughtException').finally(() => process.exit(1));
439
+ }
440
+ else {
441
+ // Exception during init before shutdown is wired up
442
+ releasePidLock(pidFilePath);
443
+ process.exit(1);
444
+ }
445
+ });
446
+ process.on('unhandledRejection', (reason) => {
447
+ console.error('[FATAL] Unhandled rejection:', reason);
448
+ if (isShuttingDown)
449
+ return;
450
+ if (shutdown) {
451
+ void shutdown('unhandledRejection');
452
+ }
453
+ });
454
+ // ── 6. Create engine instances ───────────────────────────────────────────
455
+ const engines = [];
456
+ if (config.strategy.enabled) {
457
+ engines.push(new StrategyEngine());
458
+ }
459
+ if (config.factory.enabled) {
460
+ try {
461
+ // Dynamic import: @telora/factory may not be installed in all deployments.
462
+ // The specifier is constructed via a variable so TypeScript does not attempt
463
+ // static module resolution (the factory dist/ may not exist at typecheck time).
464
+ const factoryModulePath = '@telora/factory/factory-engine';
465
+ const factoryModule = await import(/* webpackIgnore: true */ factoryModulePath);
466
+ engines.push(new factoryModule.FactoryEngine());
467
+ }
468
+ catch (err) {
469
+ console.warn(`Factory engine is enabled but @telora/factory could not be loaded: ` +
470
+ `${err instanceof Error ? err.message : String(err)}`);
471
+ console.warn('The factory engine will be skipped. Install @telora/factory to enable it.');
472
+ }
473
+ }
474
+ if (engines.length === 0) {
475
+ console.error('No engines are enabled. Enable at least one engine in the config or remove --engine filter.');
476
+ releasePidLock(pidFilePath);
477
+ process.exit(1);
478
+ }
479
+ // ── 6b. Create and inject resource governor ─────────────────────────────
480
+ // Compute per-engine limits from config (using resolved defaults)
481
+ const engineLimits = {};
482
+ if (config.strategy.enabled && engines.some(e => e.name === 'strategy')) {
483
+ const strategyMax = typeof config.strategy.fields.maxTotalSessions === 'number'
484
+ ? config.strategy.fields.maxTotalSessions : 5;
485
+ engineLimits.strategy = strategyMax;
486
+ }
487
+ if (config.factory.enabled && engines.some(e => e.name === 'factory')) {
488
+ const factoryMax = typeof config.factory.fields.maxConcurrentInstances === 'number'
489
+ ? config.factory.fields.maxConcurrentInstances : 3;
490
+ engineLimits.factory = factoryMax;
491
+ }
492
+ // Global max: sum of per-engine limits (or env override)
493
+ const env = process.env;
494
+ const defaultGlobalMax = Object.values(engineLimits).reduce((sum, v) => sum + v, 0) || 8;
495
+ const maxGlobalSessions = env.TELORA_MAX_GLOBAL_SESSIONS
496
+ ? parseInt(env.TELORA_MAX_GLOBAL_SESSIONS, 10)
497
+ : (typeof config.rawFileConfig.maxGlobalSessions === 'number'
498
+ ? config.rawFileConfig.maxGlobalSessions : defaultGlobalMax);
499
+ const governor = new ResourceGovernor({
500
+ maxGlobalSessions,
501
+ engineLimits,
502
+ });
503
+ // Inject governor into engines via the ExecutionEngine interface
504
+ for (const engine of engines) {
505
+ engine.setGovernor?.(governor);
506
+ }
507
+ console.log(`Resource governor: max ${maxGlobalSessions} global sessions ` +
508
+ `(${Object.entries(engineLimits).map(([k, v]) => `${k}: ${v}`).join(', ')})`);
509
+ // ── 7. Set up shutdown handler ───────────────────────────────────────────
510
+ shutdown = async (signal) => {
511
+ if (isShuttingDown)
512
+ return;
513
+ isShuttingDown = true;
514
+ setDaemonShuttingDown();
515
+ console.log(`\nReceived ${signal}, shutting down gracefully...`);
516
+ // Shut down the resource governor (reject pending acquires)
517
+ governor.shutdown();
518
+ // Phase 1: Stop all engines (stop accepting new work)
519
+ for (const engine of engines) {
520
+ try {
521
+ engine.stop();
522
+ console.log(`[${engine.name}] Stopped accepting new work`);
523
+ }
524
+ catch (err) {
525
+ console.warn(`[${engine.name}] Error during stop: ${err instanceof Error ? err.message : String(err)}`);
526
+ }
527
+ }
528
+ // Phase 2: Shut down all engines in parallel (graceful cleanup)
529
+ const shutdownResults = await Promise.allSettled(engines.map(async (engine) => {
530
+ try {
531
+ await engine.shutdown();
532
+ console.log(`[${engine.name}] Shutdown complete`);
533
+ }
534
+ catch (err) {
535
+ console.warn(`[${engine.name}] Error during shutdown: ${err instanceof Error ? err.message : String(err)}`);
536
+ }
537
+ }));
538
+ // Log any rejected promises
539
+ for (let i = 0; i < shutdownResults.length; i++) {
540
+ const result = shutdownResults[i];
541
+ if (result && result.status === 'rejected') {
542
+ console.warn(`[${engines[i]?.name ?? 'unknown'}] Shutdown promise rejected: ${String(result.reason)}`);
543
+ }
544
+ }
545
+ // Phase 3: Release PID lock and clean up
546
+ cleanupLogTee?.();
547
+ removeDaemonMeta();
548
+ releasePidLock(pidFilePath);
549
+ console.log('Shutdown complete');
550
+ process.exit(0);
551
+ };
552
+ async function shutdownForUpdate() {
553
+ if (isShuttingDown)
554
+ return;
555
+ isShuttingDown = true;
556
+ setDaemonShuttingDown();
557
+ console.log('\n[auto-update] Shutting down for restart...');
558
+ governor.shutdown();
559
+ for (const engine of engines) {
560
+ try {
561
+ engine.stop();
562
+ }
563
+ catch { /* best effort */ }
564
+ }
565
+ await Promise.allSettled(engines.map(async (engine) => {
566
+ try {
567
+ await engine.shutdown();
568
+ }
569
+ catch { /* best effort */ }
570
+ }));
571
+ cleanupLogTee?.();
572
+ removeDaemonMeta();
573
+ releasePidLock(pidFilePath);
574
+ // Re-exec: spawn a new daemon process with the updated code.
575
+ // The old approach (exit code 75) required an external wrapper script
576
+ // or systemd config that was never present in normal `telora-daemon start`
577
+ // usage, so the daemon just died after a successful update.
578
+ console.log('[auto-update] Spawning new daemon process with updated code...');
579
+ const logPath = resolveDaemonLogPath();
580
+ const logFd = openSync(logPath, 'a');
581
+ const thisDir = dirname(fileURLToPath(import.meta.url));
582
+ const entryPoint = resolve(thisDir, 'index.js');
583
+ const child = spawn(process.execPath, [entryPoint, 'run'], {
584
+ detached: true,
585
+ stdio: ['ignore', logFd, logFd],
586
+ cwd: repoPath,
587
+ env: { ...process.env },
588
+ });
589
+ child.unref();
590
+ closeSync(logFd);
591
+ console.log(`[auto-update] New daemon spawned (PID ${child.pid}), exiting old process`);
592
+ process.exit(0);
593
+ }
594
+ // Register signal handlers (debounced by setupSignalHandlers)
595
+ // shutdown is guaranteed non-null here (assigned above)
596
+ setupSignalHandlers(shutdown);
597
+ // ── 8. Initialize and start engines ──────────────────────────────────────
598
+ try {
599
+ for (const engine of engines) {
600
+ console.log(`\n--- Initializing ${engine.name} engine ---`);
601
+ // Build the full config for this engine with all defaults applied
602
+ let engineConfig;
603
+ if (engine.name === 'strategy') {
604
+ engineConfig = buildStrategyConfig(config.base, config.strategy);
605
+ }
606
+ else if (engine.name === 'factory') {
607
+ engineConfig = buildFactoryConfig(config.base, config.factory);
608
+ }
609
+ else {
610
+ // Unknown engine type -- pass a basic merged config
611
+ const section = engine.name === 'strategy' ? config.strategy : config.factory;
612
+ engineConfig = buildEngineConfig(config.base, section);
613
+ }
614
+ // Init
615
+ await engine.init(engineConfig);
616
+ console.log(`[${engine.name}] Initialized`);
617
+ // Crash recovery
618
+ if (opts.skipRecovery) {
619
+ console.log(`[${engine.name}] Skipping crash recovery (--skip-recovery flag)`);
620
+ }
621
+ else {
622
+ await engine.recoverFromCrash();
623
+ console.log(`[${engine.name}] Crash recovery complete`);
624
+ }
625
+ // Start
626
+ await engine.start();
627
+ console.log(`[${engine.name}] Started`);
628
+ }
629
+ }
630
+ catch (err) {
631
+ console.error('Failed to initialize engines:', err instanceof Error ? err.message : String(err));
632
+ // Clean up: stop any engines that already started
633
+ for (const engine of engines) {
634
+ try {
635
+ engine.stop();
636
+ }
637
+ catch {
638
+ // Best effort
639
+ }
640
+ }
641
+ releasePidLock(pidFilePath);
642
+ process.exit(1);
643
+ }
644
+ // ── 9. Register SIGUSR1 (status) and SIGUSR2 (circuit breaker reset) ──
645
+ process.on('SIGUSR1', () => {
646
+ printAggregatedStatus(engines, governor);
647
+ });
648
+ process.on('SIGUSR2', () => {
649
+ forceCloseAllCircuitBreakers();
650
+ });
651
+ // ── 10. Print startup message ────────────────────────────────────────────
652
+ const engineNames = engines.map(e => e.name).join(', ');
653
+ let currentVersion = '0.0.0';
654
+ try {
655
+ const thisDir = dirname(fileURLToPath(import.meta.url));
656
+ const pkg = JSON.parse(readFileSync(join(thisDir, '..', 'package.json'), 'utf-8'));
657
+ if (pkg.version)
658
+ currentVersion = pkg.version;
659
+ }
660
+ catch { /* dev mode -- no package.json next to dist */ }
661
+ console.log(`\n[unified-daemon] v${currentVersion} Started at ${new Date().toISOString()} (PID ${process.pid})`);
662
+ console.log(`Engines: ${engineNames}`);
663
+ console.log('Press Ctrl+C to stop\n');
664
+ // ── 11. Start auto-update loop ──────────────────────────────────────────
665
+ const autoUpdateEnabled = !opts.noAutoUpdate && resolveAutoUpdateEnabled(config);
666
+ if (autoUpdateEnabled) {
667
+ const autoUpdateIntervalMs = resolveAutoUpdateIntervalMs(config);
668
+ startAutoUpdateLoop({
669
+ currentVersion,
670
+ intervalMs: autoUpdateIntervalMs,
671
+ isIdle: () => engines.every((e) => e.getResourceUsage().activeClaudeProcesses === 0),
672
+ onUpdateReady: () => {
673
+ console.log('[auto-update] Update installed, initiating restart...');
674
+ // Trigger graceful shutdown, then exit with code 75
675
+ void shutdownForUpdate();
676
+ },
677
+ });
678
+ }
679
+ // ── 12. Keep process alive ─────────────────────────────────────────────
680
+ await new Promise(() => { });
681
+ }
682
+ //# sourceMappingURL=unified-shell.js.map