@masuidrive/procman 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (315) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +149 -0
  3. package/dist/src/cli/commands/clear-log.d.ts +10 -0
  4. package/dist/src/cli/commands/clear-log.d.ts.map +1 -0
  5. package/dist/src/cli/commands/clear-log.js +77 -0
  6. package/dist/src/cli/commands/clear-log.js.map +1 -0
  7. package/dist/src/cli/commands/exit.d.ts +10 -0
  8. package/dist/src/cli/commands/exit.d.ts.map +1 -0
  9. package/dist/src/cli/commands/exit.js +65 -0
  10. package/dist/src/cli/commands/exit.js.map +1 -0
  11. package/dist/src/cli/commands/help.d.ts +10 -0
  12. package/dist/src/cli/commands/help.d.ts.map +1 -0
  13. package/dist/src/cli/commands/help.js +340 -0
  14. package/dist/src/cli/commands/help.js.map +1 -0
  15. package/dist/src/cli/commands/list.d.ts +11 -0
  16. package/dist/src/cli/commands/list.d.ts.map +1 -0
  17. package/dist/src/cli/commands/list.js +130 -0
  18. package/dist/src/cli/commands/list.js.map +1 -0
  19. package/dist/src/cli/commands/load.d.ts +11 -0
  20. package/dist/src/cli/commands/load.d.ts.map +1 -0
  21. package/dist/src/cli/commands/load.js +250 -0
  22. package/dist/src/cli/commands/load.js.map +1 -0
  23. package/dist/src/cli/commands/log.d.ts +18 -0
  24. package/dist/src/cli/commands/log.d.ts.map +1 -0
  25. package/dist/src/cli/commands/log.js +282 -0
  26. package/dist/src/cli/commands/log.js.map +1 -0
  27. package/dist/src/cli/commands/restart.d.ts +11 -0
  28. package/dist/src/cli/commands/restart.d.ts.map +1 -0
  29. package/dist/src/cli/commands/restart.js +99 -0
  30. package/dist/src/cli/commands/restart.js.map +1 -0
  31. package/dist/src/cli/commands/start.d.ts +11 -0
  32. package/dist/src/cli/commands/start.d.ts.map +1 -0
  33. package/dist/src/cli/commands/start.js +105 -0
  34. package/dist/src/cli/commands/start.js.map +1 -0
  35. package/dist/src/cli/commands/stop.d.ts +12 -0
  36. package/dist/src/cli/commands/stop.d.ts.map +1 -0
  37. package/dist/src/cli/commands/stop.js +105 -0
  38. package/dist/src/cli/commands/stop.js.map +1 -0
  39. package/dist/src/cli/index.d.ts +3 -0
  40. package/dist/src/cli/index.d.ts.map +1 -0
  41. package/dist/src/cli/index.js +28 -0
  42. package/dist/src/cli/index.js.map +1 -0
  43. package/dist/src/cli/parser.d.ts +14 -0
  44. package/dist/src/cli/parser.d.ts.map +1 -0
  45. package/dist/src/cli/parser.js +131 -0
  46. package/dist/src/cli/parser.js.map +1 -0
  47. package/dist/src/cli/signal-handler.d.ts +51 -0
  48. package/dist/src/cli/signal-handler.d.ts.map +1 -0
  49. package/dist/src/cli/signal-handler.js +129 -0
  50. package/dist/src/cli/signal-handler.js.map +1 -0
  51. package/dist/src/cli/utils/error-handler.d.ts +39 -0
  52. package/dist/src/cli/utils/error-handler.d.ts.map +1 -0
  53. package/dist/src/cli/utils/error-handler.js +200 -0
  54. package/dist/src/cli/utils/error-handler.js.map +1 -0
  55. package/dist/src/cli/utils/error-utils.d.ts +16 -0
  56. package/dist/src/cli/utils/error-utils.d.ts.map +1 -0
  57. package/dist/src/cli/utils/error-utils.js +48 -0
  58. package/dist/src/cli/utils/error-utils.js.map +1 -0
  59. package/dist/src/cli/utils/ipc-client.d.ts +80 -0
  60. package/dist/src/cli/utils/ipc-client.d.ts.map +1 -0
  61. package/dist/src/cli/utils/ipc-client.js +275 -0
  62. package/dist/src/cli/utils/ipc-client.js.map +1 -0
  63. package/dist/src/config/config-loader.d.ts +74 -0
  64. package/dist/src/config/config-loader.d.ts.map +1 -0
  65. package/dist/src/config/config-loader.js +229 -0
  66. package/dist/src/config/config-loader.js.map +1 -0
  67. package/dist/src/config/config-normalizer.d.ts +135 -0
  68. package/dist/src/config/config-normalizer.d.ts.map +1 -0
  69. package/dist/src/config/config-normalizer.js +309 -0
  70. package/dist/src/config/config-normalizer.js.map +1 -0
  71. package/dist/src/config/config-reporter.d.ts +183 -0
  72. package/dist/src/config/config-reporter.d.ts.map +1 -0
  73. package/dist/src/config/config-reporter.js +311 -0
  74. package/dist/src/config/config-reporter.js.map +1 -0
  75. package/dist/src/config/config-validator.d.ts +163 -0
  76. package/dist/src/config/config-validator.d.ts.map +1 -0
  77. package/dist/src/config/config-validator.js +489 -0
  78. package/dist/src/config/config-validator.js.map +1 -0
  79. package/dist/src/config/config-watcher.d.ts +161 -0
  80. package/dist/src/config/config-watcher.d.ts.map +1 -0
  81. package/dist/src/config/config-watcher.js +245 -0
  82. package/dist/src/config/config-watcher.js.map +1 -0
  83. package/dist/src/config/index.d.ts +36 -0
  84. package/dist/src/config/index.d.ts.map +1 -0
  85. package/dist/src/config/index.js +41 -0
  86. package/dist/src/config/index.js.map +1 -0
  87. package/dist/src/config/secure-config-loader.d.ts +77 -0
  88. package/dist/src/config/secure-config-loader.d.ts.map +1 -0
  89. package/dist/src/config/secure-config-loader.js +326 -0
  90. package/dist/src/config/secure-config-loader.js.map +1 -0
  91. package/dist/src/daemon/base-socket-connection.d.ts +66 -0
  92. package/dist/src/daemon/base-socket-connection.d.ts.map +1 -0
  93. package/dist/src/daemon/base-socket-connection.js +192 -0
  94. package/dist/src/daemon/base-socket-connection.js.map +1 -0
  95. package/dist/src/daemon/component-manager.d.ts +180 -0
  96. package/dist/src/daemon/component-manager.d.ts.map +1 -0
  97. package/dist/src/daemon/component-manager.js +794 -0
  98. package/dist/src/daemon/component-manager.js.map +1 -0
  99. package/dist/src/daemon/crash-recovery.d.ts +71 -0
  100. package/dist/src/daemon/crash-recovery.d.ts.map +1 -0
  101. package/dist/src/daemon/crash-recovery.js +282 -0
  102. package/dist/src/daemon/crash-recovery.js.map +1 -0
  103. package/dist/src/daemon/daemon-main.d.ts +18 -0
  104. package/dist/src/daemon/daemon-main.d.ts.map +1 -0
  105. package/dist/src/daemon/daemon-main.js +160 -0
  106. package/dist/src/daemon/daemon-main.js.map +1 -0
  107. package/dist/src/daemon/daemon-state-manager.d.ts +111 -0
  108. package/dist/src/daemon/daemon-state-manager.d.ts.map +1 -0
  109. package/dist/src/daemon/daemon-state-manager.js +194 -0
  110. package/dist/src/daemon/daemon-state-manager.js.map +1 -0
  111. package/dist/src/daemon/data-directory.d.ts +51 -0
  112. package/dist/src/daemon/data-directory.d.ts.map +1 -0
  113. package/dist/src/daemon/data-directory.js +136 -0
  114. package/dist/src/daemon/data-directory.js.map +1 -0
  115. package/dist/src/daemon/index.d.ts +20 -0
  116. package/dist/src/daemon/index.d.ts.map +1 -0
  117. package/dist/src/daemon/index.js +24 -0
  118. package/dist/src/daemon/index.js.map +1 -0
  119. package/dist/src/daemon/ipc-client-base.d.ts +153 -0
  120. package/dist/src/daemon/ipc-client-base.d.ts.map +1 -0
  121. package/dist/src/daemon/ipc-client-base.js +476 -0
  122. package/dist/src/daemon/ipc-client-base.js.map +1 -0
  123. package/dist/src/daemon/ipc-command-handler.d.ts +107 -0
  124. package/dist/src/daemon/ipc-command-handler.d.ts.map +1 -0
  125. package/dist/src/daemon/ipc-command-handler.js +483 -0
  126. package/dist/src/daemon/ipc-command-handler.js.map +1 -0
  127. package/dist/src/daemon/ipc-factory.d.ts +92 -0
  128. package/dist/src/daemon/ipc-factory.d.ts.map +1 -0
  129. package/dist/src/daemon/ipc-factory.js +210 -0
  130. package/dist/src/daemon/ipc-factory.js.map +1 -0
  131. package/dist/src/daemon/ipc-server-base.d.ts +158 -0
  132. package/dist/src/daemon/ipc-server-base.d.ts.map +1 -0
  133. package/dist/src/daemon/ipc-server-base.js +491 -0
  134. package/dist/src/daemon/ipc-server-base.js.map +1 -0
  135. package/dist/src/daemon/message-protocol.d.ts +132 -0
  136. package/dist/src/daemon/message-protocol.d.ts.map +1 -0
  137. package/dist/src/daemon/message-protocol.js +252 -0
  138. package/dist/src/daemon/message-protocol.js.map +1 -0
  139. package/dist/src/daemon/named-pipe-client.d.ts +61 -0
  140. package/dist/src/daemon/named-pipe-client.d.ts.map +1 -0
  141. package/dist/src/daemon/named-pipe-client.js +221 -0
  142. package/dist/src/daemon/named-pipe-client.js.map +1 -0
  143. package/dist/src/daemon/named-pipe-server.d.ts +40 -0
  144. package/dist/src/daemon/named-pipe-server.d.ts.map +1 -0
  145. package/dist/src/daemon/named-pipe-server.js +102 -0
  146. package/dist/src/daemon/named-pipe-server.js.map +1 -0
  147. package/dist/src/daemon/orphan-detector.d.ts +66 -0
  148. package/dist/src/daemon/orphan-detector.d.ts.map +1 -0
  149. package/dist/src/daemon/orphan-detector.js +208 -0
  150. package/dist/src/daemon/orphan-detector.js.map +1 -0
  151. package/dist/src/daemon/pid-manager.d.ts +49 -0
  152. package/dist/src/daemon/pid-manager.d.ts.map +1 -0
  153. package/dist/src/daemon/pid-manager.js +110 -0
  154. package/dist/src/daemon/pid-manager.js.map +1 -0
  155. package/dist/src/daemon/procman-daemon.d.ts +188 -0
  156. package/dist/src/daemon/procman-daemon.d.ts.map +1 -0
  157. package/dist/src/daemon/procman-daemon.js +802 -0
  158. package/dist/src/daemon/procman-daemon.js.map +1 -0
  159. package/dist/src/daemon/reconnection-system.d.ts +113 -0
  160. package/dist/src/daemon/reconnection-system.d.ts.map +1 -0
  161. package/dist/src/daemon/reconnection-system.js +223 -0
  162. package/dist/src/daemon/reconnection-system.js.map +1 -0
  163. package/dist/src/daemon/resource-manager.d.ts +204 -0
  164. package/dist/src/daemon/resource-manager.d.ts.map +1 -0
  165. package/dist/src/daemon/resource-manager.js +423 -0
  166. package/dist/src/daemon/resource-manager.js.map +1 -0
  167. package/dist/src/daemon/signal-handler.d.ts +58 -0
  168. package/dist/src/daemon/signal-handler.d.ts.map +1 -0
  169. package/dist/src/daemon/signal-handler.js +142 -0
  170. package/dist/src/daemon/signal-handler.js.map +1 -0
  171. package/dist/src/daemon/simple-resource-manager.d.ts +95 -0
  172. package/dist/src/daemon/simple-resource-manager.d.ts.map +1 -0
  173. package/dist/src/daemon/simple-resource-manager.js +180 -0
  174. package/dist/src/daemon/simple-resource-manager.js.map +1 -0
  175. package/dist/src/daemon/unix-socket-client.d.ts +69 -0
  176. package/dist/src/daemon/unix-socket-client.d.ts.map +1 -0
  177. package/dist/src/daemon/unix-socket-client.js +313 -0
  178. package/dist/src/daemon/unix-socket-client.js.map +1 -0
  179. package/dist/src/daemon/unix-socket-server.d.ts +61 -0
  180. package/dist/src/daemon/unix-socket-server.d.ts.map +1 -0
  181. package/dist/src/daemon/unix-socket-server.js +262 -0
  182. package/dist/src/daemon/unix-socket-server.js.map +1 -0
  183. package/dist/src/daemon/zombie-reaper.d.ts +83 -0
  184. package/dist/src/daemon/zombie-reaper.d.ts.map +1 -0
  185. package/dist/src/daemon/zombie-reaper.js +278 -0
  186. package/dist/src/daemon/zombie-reaper.js.map +1 -0
  187. package/dist/src/process-manager/index.d.ts +13 -0
  188. package/dist/src/process-manager/index.d.ts.map +1 -0
  189. package/dist/src/process-manager/index.js +11 -0
  190. package/dist/src/process-manager/index.js.map +1 -0
  191. package/dist/src/process-manager/interfaces/index.d.ts +31 -0
  192. package/dist/src/process-manager/interfaces/index.d.ts.map +1 -0
  193. package/dist/src/process-manager/interfaces/index.js +14 -0
  194. package/dist/src/process-manager/interfaces/index.js.map +1 -0
  195. package/dist/src/process-manager/interfaces/process-group.d.ts +200 -0
  196. package/dist/src/process-manager/interfaces/process-group.d.ts.map +1 -0
  197. package/dist/src/process-manager/interfaces/process-group.js +10 -0
  198. package/dist/src/process-manager/interfaces/process-group.js.map +1 -0
  199. package/dist/src/process-manager/interfaces/process-lifecycle.d.ts +97 -0
  200. package/dist/src/process-manager/interfaces/process-lifecycle.d.ts.map +1 -0
  201. package/dist/src/process-manager/interfaces/process-lifecycle.js +10 -0
  202. package/dist/src/process-manager/interfaces/process-lifecycle.js.map +1 -0
  203. package/dist/src/process-manager/interfaces/process-monitor.d.ts +118 -0
  204. package/dist/src/process-manager/interfaces/process-monitor.d.ts.map +1 -0
  205. package/dist/src/process-manager/interfaces/process-monitor.js +10 -0
  206. package/dist/src/process-manager/interfaces/process-monitor.js.map +1 -0
  207. package/dist/src/process-manager/interfaces/process-persistence.d.ts +125 -0
  208. package/dist/src/process-manager/interfaces/process-persistence.d.ts.map +1 -0
  209. package/dist/src/process-manager/interfaces/process-persistence.js +10 -0
  210. package/dist/src/process-manager/interfaces/process-persistence.js.map +1 -0
  211. package/dist/src/process-manager/managed-process-info.d.ts +307 -0
  212. package/dist/src/process-manager/managed-process-info.d.ts.map +1 -0
  213. package/dist/src/process-manager/managed-process-info.js +650 -0
  214. package/dist/src/process-manager/managed-process-info.js.map +1 -0
  215. package/dist/src/process-manager/process-group-manager.d.ts +103 -0
  216. package/dist/src/process-manager/process-group-manager.d.ts.map +1 -0
  217. package/dist/src/process-manager/process-group-manager.js +400 -0
  218. package/dist/src/process-manager/process-group-manager.js.map +1 -0
  219. package/dist/src/process-manager/process-lifecycle-manager.d.ts +68 -0
  220. package/dist/src/process-manager/process-lifecycle-manager.d.ts.map +1 -0
  221. package/dist/src/process-manager/process-lifecycle-manager.js +372 -0
  222. package/dist/src/process-manager/process-lifecycle-manager.js.map +1 -0
  223. package/dist/src/process-manager/process-manager.d.ts +296 -0
  224. package/dist/src/process-manager/process-manager.d.ts.map +1 -0
  225. package/dist/src/process-manager/process-manager.js +659 -0
  226. package/dist/src/process-manager/process-manager.js.map +1 -0
  227. package/dist/src/process-manager/process-monitor.d.ts +95 -0
  228. package/dist/src/process-manager/process-monitor.d.ts.map +1 -0
  229. package/dist/src/process-manager/process-monitor.js +357 -0
  230. package/dist/src/process-manager/process-monitor.js.map +1 -0
  231. package/dist/src/process-manager/process-persistence.d.ts +68 -0
  232. package/dist/src/process-manager/process-persistence.d.ts.map +1 -0
  233. package/dist/src/process-manager/process-persistence.js +364 -0
  234. package/dist/src/process-manager/process-persistence.js.map +1 -0
  235. package/dist/src/process-manager/utils/mutex.d.ts +82 -0
  236. package/dist/src/process-manager/utils/mutex.d.ts.map +1 -0
  237. package/dist/src/process-manager/utils/mutex.js +172 -0
  238. package/dist/src/process-manager/utils/mutex.js.map +1 -0
  239. package/dist/src/services/index.d.ts +8 -0
  240. package/dist/src/services/index.d.ts.map +1 -0
  241. package/dist/src/services/index.js +8 -0
  242. package/dist/src/services/index.js.map +1 -0
  243. package/dist/src/services/log-manager-config.d.ts +65 -0
  244. package/dist/src/services/log-manager-config.d.ts.map +1 -0
  245. package/dist/src/services/log-manager-config.js +145 -0
  246. package/dist/src/services/log-manager-config.js.map +1 -0
  247. package/dist/src/services/log-manager-factory.d.ts +134 -0
  248. package/dist/src/services/log-manager-factory.d.ts.map +1 -0
  249. package/dist/src/services/log-manager-factory.js +203 -0
  250. package/dist/src/services/log-manager-factory.js.map +1 -0
  251. package/dist/src/services/log-manager.d.ts +170 -0
  252. package/dist/src/services/log-manager.d.ts.map +1 -0
  253. package/dist/src/services/log-manager.js +1199 -0
  254. package/dist/src/services/log-manager.js.map +1 -0
  255. package/dist/src/services/log-path-validator.d.ts +121 -0
  256. package/dist/src/services/log-path-validator.d.ts.map +1 -0
  257. package/dist/src/services/log-path-validator.js +302 -0
  258. package/dist/src/services/log-path-validator.js.map +1 -0
  259. package/dist/src/services/process-log-integration.d.ts +62 -0
  260. package/dist/src/services/process-log-integration.d.ts.map +1 -0
  261. package/dist/src/services/process-log-integration.js +157 -0
  262. package/dist/src/services/process-log-integration.js.map +1 -0
  263. package/dist/src/shared/config.d.ts +67 -0
  264. package/dist/src/shared/config.d.ts.map +1 -0
  265. package/dist/src/shared/config.js +92 -0
  266. package/dist/src/shared/config.js.map +1 -0
  267. package/dist/src/shared/constants-streaming.d.ts +39 -0
  268. package/dist/src/shared/constants-streaming.d.ts.map +1 -0
  269. package/dist/src/shared/constants-streaming.js +39 -0
  270. package/dist/src/shared/constants-streaming.js.map +1 -0
  271. package/dist/src/shared/constants.d.ts +60 -0
  272. package/dist/src/shared/constants.d.ts.map +1 -0
  273. package/dist/src/shared/constants.js +71 -0
  274. package/dist/src/shared/constants.js.map +1 -0
  275. package/dist/src/shared/errors.d.ts +70 -0
  276. package/dist/src/shared/errors.d.ts.map +1 -0
  277. package/dist/src/shared/errors.js +101 -0
  278. package/dist/src/shared/errors.js.map +1 -0
  279. package/dist/src/shared/index.d.ts +14 -0
  280. package/dist/src/shared/index.d.ts.map +1 -0
  281. package/dist/src/shared/index.js +22 -0
  282. package/dist/src/shared/index.js.map +1 -0
  283. package/dist/src/shared/ipc.d.ts +402 -0
  284. package/dist/src/shared/ipc.d.ts.map +1 -0
  285. package/dist/src/shared/ipc.js +85 -0
  286. package/dist/src/shared/ipc.js.map +1 -0
  287. package/dist/src/shared/logger.d.ts +38 -0
  288. package/dist/src/shared/logger.d.ts.map +1 -0
  289. package/dist/src/shared/logger.js +139 -0
  290. package/dist/src/shared/logger.js.map +1 -0
  291. package/dist/src/shared/logs.d.ts +53 -0
  292. package/dist/src/shared/logs.d.ts.map +1 -0
  293. package/dist/src/shared/logs.js +26 -0
  294. package/dist/src/shared/logs.js.map +1 -0
  295. package/dist/src/shared/process.d.ts +102 -0
  296. package/dist/src/shared/process.d.ts.map +1 -0
  297. package/dist/src/shared/process.js +55 -0
  298. package/dist/src/shared/process.js.map +1 -0
  299. package/dist/src/shared/types.d.ts +15 -0
  300. package/dist/src/shared/types.d.ts.map +1 -0
  301. package/dist/src/shared/types.js +8 -0
  302. package/dist/src/shared/types.js.map +1 -0
  303. package/dist/src/types/index.d.ts +19 -0
  304. package/dist/src/types/index.d.ts.map +1 -0
  305. package/dist/src/types/index.js +5 -0
  306. package/dist/src/types/index.js.map +1 -0
  307. package/dist/src/utils/event-cleanup.d.ts +30 -0
  308. package/dist/src/utils/event-cleanup.d.ts.map +1 -0
  309. package/dist/src/utils/event-cleanup.js +32 -0
  310. package/dist/src/utils/event-cleanup.js.map +1 -0
  311. package/dist/src/utils/memory/memory-monitor.d.ts +126 -0
  312. package/dist/src/utils/memory/memory-monitor.d.ts.map +1 -0
  313. package/dist/src/utils/memory/memory-monitor.js +246 -0
  314. package/dist/src/utils/memory/memory-monitor.js.map +1 -0
  315. package/package.json +74 -0
@@ -0,0 +1,802 @@
1
+ /**
2
+ * Main daemon class for procman
3
+ *
4
+ * Orchestrates daemon components using specialized managers.
5
+ * Follows Single Responsibility Principle by delegating to:
6
+ * - DaemonStateManager: State management and transitions
7
+ * - ComponentManager: Component lifecycle management
8
+ * - SignalHandler: Process signal handling
9
+ * - DataDirectory & PIDManager: File system management
10
+ */
11
+ import { EventEmitter } from 'events';
12
+ import { DataDirectory } from './data-directory.js';
13
+ import { PIDManager } from './pid-manager.js';
14
+ import { DaemonStateManager, DaemonState } from './daemon-state-manager.js';
15
+ import { ComponentManager } from './component-manager.js';
16
+ import { SignalHandler } from './signal-handler.js';
17
+ import { MemoryMonitor } from '../utils/memory/memory-monitor.js';
18
+ import path from 'path';
19
+ // Re-export DaemonState for backward compatibility
20
+ export { DaemonState };
21
+ /**
22
+ * Recovery constants
23
+ */
24
+ const RECOVERY_CONSTANTS = {
25
+ MAX_RECOVERY_ATTEMPTS: 3,
26
+ RECOVERY_DELAY_MS: 5000,
27
+ };
28
+ /**
29
+ * Main daemon class that coordinates all procman components
30
+ */
31
+ export class ProcmanDaemon extends EventEmitter {
32
+ dataDirectory;
33
+ pidManager;
34
+ stateManager;
35
+ componentManager;
36
+ signalHandler;
37
+ memoryMonitor;
38
+ currentConfig;
39
+ configFilePath;
40
+ recoveryAttempts = 0;
41
+ maxRecoveryAttempts = RECOVERY_CONSTANTS.MAX_RECOVERY_ATTEMPTS;
42
+ isShuttingDown = false; // Add shutdown flag
43
+ constructor() {
44
+ super();
45
+ this.dataDirectory = new DataDirectory(process.env.PROCMAN_SOCKET_PATH);
46
+ this.pidManager = new PIDManager(this.dataDirectory);
47
+ this.stateManager = new DaemonStateManager();
48
+ this.componentManager = new ComponentManager(this.dataDirectory);
49
+ this.signalHandler = new SignalHandler();
50
+ this.memoryMonitor = new MemoryMonitor({
51
+ intervalMs: 30000, // 30 seconds (PM2 standard)
52
+ warningThreshold: 100 * 1024 * 1024, // 100MB
53
+ criticalThreshold: 200 * 1024 * 1024, // 200MB
54
+ enableLogging: process.env.NODE_ENV !== 'test', // Disable logging in test environment
55
+ });
56
+ this.setupEventListeners();
57
+ }
58
+ /**
59
+ * Get current daemon state
60
+ */
61
+ getState() {
62
+ return this.stateManager.getCurrentState();
63
+ }
64
+ /**
65
+ * Check if daemon is currently running
66
+ */
67
+ isRunning() {
68
+ return this.stateManager.isRunning();
69
+ }
70
+ /**
71
+ * Check if daemon is ready to handle requests
72
+ * Performs comprehensive health checks on all components
73
+ */
74
+ async isReady() {
75
+ if (!this.isRunning()) {
76
+ return false;
77
+ }
78
+ try {
79
+ const healthCheck = await this.componentManager.performHealthChecks();
80
+ return healthCheck.healthy;
81
+ }
82
+ catch (error) {
83
+ console.error('Health check failed:', error);
84
+ return false;
85
+ }
86
+ }
87
+ /**
88
+ * Get detailed health status of all components
89
+ */
90
+ async getHealthStatus() {
91
+ const healthCheck = await this.componentManager.performHealthChecks();
92
+ const memoryHealthInfo = this.memoryMonitor.getHealthInfo();
93
+ return {
94
+ ready: healthCheck.healthy && this.isRunning(),
95
+ components: healthCheck.details,
96
+ memory: memoryHealthInfo,
97
+ };
98
+ }
99
+ /**
100
+ * Start the daemon
101
+ */
102
+ async start() {
103
+ const startTime = Date.now();
104
+ console.error('[DEBUG-PROCMAN-DAEMON] Starting daemon initialization...');
105
+ console.error('[DEBUG-PROCMAN-DAEMON] Current state check:', JSON.stringify({
106
+ currentState: this.getState(),
107
+ canStart: this.stateManager.canStart(),
108
+ processId: process.pid,
109
+ timestamp: new Date().toISOString(),
110
+ }, null, 2));
111
+ if (!this.stateManager.canStart()) {
112
+ throw new Error(`Cannot start daemon: current state is ${this.getState()}`);
113
+ }
114
+ console.error('[DEBUG-PROCMAN-DAEMON] Transitioning to STARTING state...');
115
+ this.stateManager.transitionTo(DaemonState.STARTING);
116
+ try {
117
+ console.error('[DEBUG-PROCMAN-DAEMON] Step 1: Performing environment checks...');
118
+ // Perform environment checks before any other operations
119
+ await this.performEnvironmentChecks();
120
+ console.error('[DEBUG-PROCMAN-DAEMON] ✓ Environment checks completed');
121
+ console.error('[DEBUG-PROCMAN-DAEMON] Step 2: Ensuring no daemon running...');
122
+ // Check for existing daemon
123
+ await this.pidManager.ensureNoDaemonRunning();
124
+ console.error('[DEBUG-PROCMAN-DAEMON] ✓ Daemon uniqueness verified');
125
+ console.error('[DEBUG-PROCMAN-DAEMON] Step 3: Initializing data directory...');
126
+ // Initialize data directory
127
+ await this.dataDirectory.ensureDataDirectory();
128
+ console.error('[DEBUG-PROCMAN-DAEMON] ✓ Data directory ready');
129
+ console.error('[DEBUG-PROCMAN-DAEMON] Step 4: Writing PID file...');
130
+ // Write PID file
131
+ await this.pidManager.writePIDFile();
132
+ console.error('[DEBUG-PROCMAN-DAEMON] ✓ PID file written');
133
+ console.error('[DEBUG-PROCMAN-DAEMON] Step 5: Setting up signal handlers...');
134
+ // Setup signal handlers
135
+ this.signalHandler.setupHandlers();
136
+ console.error('[DEBUG-PROCMAN-DAEMON] ✓ Signal handlers configured');
137
+ console.error('[DEBUG-PROCMAN-DAEMON] Step 6: Initializing all components...');
138
+ // Initialize components
139
+ await this.componentManager.initializeAll();
140
+ console.error('[DEBUG-PROCMAN-DAEMON] ✓ All components initialized');
141
+ // Perform final readiness check with retries
142
+ console.error('[DEBUG-PROCMAN-DAEMON] Step 7: Performing final readiness verification...');
143
+ let readinessAttempts = 0;
144
+ const maxReadinessAttempts = 10;
145
+ const readinessCheckInterval = 500;
146
+ console.error('[DEBUG-PROCMAN-DAEMON] Readiness check parameters:', JSON.stringify({
147
+ maxAttempts: maxReadinessAttempts,
148
+ intervalMs: readinessCheckInterval,
149
+ totalMaxTimeMs: maxReadinessAttempts * readinessCheckInterval,
150
+ }, null, 2));
151
+ while (readinessAttempts < maxReadinessAttempts) {
152
+ const checkStartTime = Date.now();
153
+ console.error(`[DEBUG-PROCMAN-DAEMON] Readiness attempt ${readinessAttempts + 1}/${maxReadinessAttempts}...`);
154
+ try {
155
+ const healthCheck = await this.componentManager.performHealthChecks();
156
+ const checkDuration = Date.now() - checkStartTime;
157
+ if (healthCheck.healthy) {
158
+ console.error('[DEBUG-PROCMAN-DAEMON] ✓ Readiness verification successful!');
159
+ console.error('[DEBUG-PROCMAN-DAEMON] Readiness success stats:', JSON.stringify({
160
+ attempts: readinessAttempts + 1,
161
+ checkDurationMs: checkDuration,
162
+ healthCheckDetails: healthCheck.details,
163
+ }, null, 2));
164
+ console.log(`Daemon readiness verified after ${readinessAttempts + 1} attempts`);
165
+ break;
166
+ }
167
+ else {
168
+ console.error('[DEBUG-PROCMAN-DAEMON] ✗ Readiness check failed');
169
+ console.error('[DEBUG-PROCMAN-DAEMON] Health check failure details:', JSON.stringify({
170
+ attempt: readinessAttempts + 1,
171
+ maxAttempts: maxReadinessAttempts,
172
+ checkDurationMs: checkDuration,
173
+ healthCheckDetails: healthCheck.details,
174
+ }, null, 2));
175
+ console.log(`Readiness check ${readinessAttempts + 1}/${maxReadinessAttempts} failed:`, healthCheck.details);
176
+ readinessAttempts++;
177
+ if (readinessAttempts < maxReadinessAttempts) {
178
+ console.error(`[DEBUG-PROCMAN-DAEMON] Waiting ${readinessCheckInterval}ms before retry...`);
179
+ await new Promise((resolve) => setTimeout(resolve, readinessCheckInterval));
180
+ }
181
+ }
182
+ }
183
+ catch (error) {
184
+ const checkDuration = Date.now() - checkStartTime;
185
+ console.error('[DEBUG-PROCMAN-DAEMON] ✗ Readiness check exception');
186
+ console.error('[DEBUG-PROCMAN-DAEMON] Exception details:', JSON.stringify({
187
+ attempt: readinessAttempts + 1,
188
+ checkDurationMs: checkDuration,
189
+ errorMessage: error instanceof Error ? error.message : String(error),
190
+ errorStack: error instanceof Error ? error.stack : undefined,
191
+ }, null, 2));
192
+ console.log(`Readiness check ${readinessAttempts + 1}/${maxReadinessAttempts} failed with error:`, error);
193
+ readinessAttempts++;
194
+ if (readinessAttempts < maxReadinessAttempts) {
195
+ await new Promise((resolve) => setTimeout(resolve, readinessCheckInterval));
196
+ }
197
+ }
198
+ }
199
+ if (readinessAttempts >= maxReadinessAttempts) {
200
+ console.error('[DEBUG-PROCMAN-DAEMON] ✗ Final readiness verification failed after all attempts');
201
+ console.error('[DEBUG-PROCMAN-DAEMON] Readiness failure summary:', JSON.stringify({
202
+ totalAttempts: readinessAttempts,
203
+ maxAttempts: maxReadinessAttempts,
204
+ totalTimeSpentMs: readinessAttempts * readinessCheckInterval,
205
+ currentState: this.getState(),
206
+ }, null, 2));
207
+ throw new Error('Daemon components initialized but failed final readiness verification');
208
+ }
209
+ // All checks passed - transition to running state
210
+ console.error('[DEBUG-PROCMAN-DAEMON] Step 8: Transitioning to RUNNING state...');
211
+ this.stateManager.transitionTo(DaemonState.RUNNING);
212
+ this.recoveryAttempts = 0; // Reset recovery counter on successful start
213
+ // Start memory monitoring
214
+ console.error('[DEBUG-PROCMAN-DAEMON] Step 9: Starting memory monitoring...');
215
+ this.memoryMonitor.start();
216
+ console.error('[DEBUG-PROCMAN-DAEMON] ✓ Memory monitoring started');
217
+ const totalStartupTime = Date.now() - startTime;
218
+ console.error('[DEBUG-PROCMAN-DAEMON] ✓ DAEMON STARTUP COMPLETED SUCCESSFULLY!');
219
+ console.error('[DEBUG-PROCMAN-DAEMON] Final startup stats:', JSON.stringify({
220
+ totalStartupTimeMs: totalStartupTime,
221
+ currentState: this.getState(),
222
+ processId: process.pid,
223
+ readinessAttempts: readinessAttempts,
224
+ timestamp: new Date().toISOString(),
225
+ }, null, 2));
226
+ console.log('Daemon started successfully and is ready to handle requests');
227
+ }
228
+ catch (error) {
229
+ const totalStartupTime = Date.now() - startTime;
230
+ console.error('[DEBUG-PROCMAN-DAEMON] ✗ DAEMON STARTUP FAILED');
231
+ console.error('[DEBUG-PROCMAN-DAEMON] Startup failure stats:', JSON.stringify({
232
+ totalStartupTimeMs: totalStartupTime,
233
+ currentState: this.getState(),
234
+ processId: process.pid,
235
+ errorMessage: error instanceof Error ? error.message : String(error),
236
+ errorStack: error instanceof Error ? error.stack : undefined,
237
+ }, null, 2));
238
+ this.stateManager.forceError();
239
+ console.error('[DEBUG-PROCMAN-DAEMON] Performing startup cleanup...');
240
+ // Cleanup on startup failure with better error handling
241
+ await this.performStartupCleanup();
242
+ console.error('[DEBUG-PROCMAN-DAEMON] Startup cleanup completed');
243
+ throw error;
244
+ }
245
+ }
246
+ /**
247
+ * Stop the daemon
248
+ */
249
+ async stop() {
250
+ if (!this.stateManager.canStop()) {
251
+ throw new Error(`Cannot stop daemon: current state is ${this.getState()}`);
252
+ }
253
+ this.stateManager.transitionTo(DaemonState.STOPPING);
254
+ try {
255
+ // Stop memory monitoring first
256
+ console.error('[DEBUG-PROCMAN-DAEMON] Stopping memory monitoring...');
257
+ this.memoryMonitor.stop();
258
+ console.error('[DEBUG-PROCMAN-DAEMON] ✓ Memory monitoring stopped');
259
+ // Stop components with proper error handling
260
+ await this.componentManager.cleanupAll();
261
+ // Remove signal handlers
262
+ this.signalHandler.cleanupHandlers();
263
+ // Clean up PID file
264
+ await this.pidManager.cleanup();
265
+ this.stateManager.transitionTo(DaemonState.STOPPED);
266
+ }
267
+ catch (error) {
268
+ this.stateManager.forceError();
269
+ // Still try to cleanup critical resources
270
+ await this.performEmergencyCleanup();
271
+ throw error;
272
+ }
273
+ }
274
+ /**
275
+ * Restart the daemon
276
+ */
277
+ async restart() {
278
+ if (this.isRunning()) {
279
+ await this.stop();
280
+ }
281
+ await this.start();
282
+ }
283
+ /**
284
+ * Graceful shutdown with extended capabilities and state preservation
285
+ *
286
+ * @param reason The reason for shutdown
287
+ * @param timeoutMs Maximum time to wait for graceful shutdown (default: 30s)
288
+ */
289
+ async shutdown(reason = 'manual', timeoutMs = 30000) {
290
+ if (this.isShuttingDown) {
291
+ console.log('[ProcmanDaemon] Shutdown already in progress, waiting...');
292
+ return;
293
+ }
294
+ this.isShuttingDown = true;
295
+ const shutdownStart = Date.now();
296
+ console.log(`[ProcmanDaemon] Beginning graceful shutdown (reason: ${reason}, timeout: ${timeoutMs}ms)`);
297
+ try {
298
+ // Phase 1: Set shutdown flag and reject new connections (5s timeout)
299
+ await this.executeWithTimeout(async () => {
300
+ console.log('[ProcmanDaemon] Phase 1: Setting shutdown flag and rejecting new connections...');
301
+ this.emit('shutdownStarted', reason);
302
+ const ipcServer = this.getIPCServer();
303
+ if (ipcServer) {
304
+ // Reject new connections by stopping the server from accepting
305
+ // Note: We don't stop the server yet to allow existing connections to drain
306
+ this.emit('newConnectionsRejected');
307
+ }
308
+ }, 5000, 'Phase 1: Shutdown initialization');
309
+ // Phase 2: Save shutdown state (5s timeout)
310
+ await this.executeWithTimeout(async () => {
311
+ console.log('[ProcmanDaemon] Phase 2: Saving shutdown state...');
312
+ await this.saveShutdownState(reason);
313
+ }, 5000, 'Phase 2: State preservation');
314
+ // Phase 3: Drain active connections (10s timeout)
315
+ await this.executeWithTimeout(async () => {
316
+ console.log('[ProcmanDaemon] Phase 3: Draining active connections...');
317
+ await this.drainActiveConnections();
318
+ }, 10000, 'Phase 3: Connection draining');
319
+ // Phase 4: Stop processes gracefully (15s timeout)
320
+ await this.executeWithTimeout(async () => {
321
+ console.log('[ProcmanDaemon] Phase 4: Stopping managed processes...');
322
+ await this.stopManagedProcesses();
323
+ }, 15000, 'Phase 4: Process termination');
324
+ // Phase 5: Cleanup resources (5s timeout)
325
+ await this.executeWithTimeout(async () => {
326
+ console.log('[ProcmanDaemon] Phase 5: Final resource cleanup...');
327
+ await this.stop(); // Use existing stop method for final cleanup
328
+ }, 5000, 'Phase 5: Resource cleanup');
329
+ const totalTime = Date.now() - shutdownStart;
330
+ console.log(`[ProcmanDaemon] Graceful shutdown completed successfully in ${totalTime}ms`);
331
+ this.emit('shutdownCompleted', reason, totalTime);
332
+ }
333
+ catch (error) {
334
+ const totalTime = Date.now() - shutdownStart;
335
+ console.error(`[ProcmanDaemon] Graceful shutdown failed after ${totalTime}ms:`, error);
336
+ // Force shutdown if graceful shutdown fails
337
+ console.log('[ProcmanDaemon] Attempting forced shutdown...');
338
+ await this.performEmergencyCleanup();
339
+ this.emit('shutdownFailed', reason, error, totalTime);
340
+ throw error;
341
+ }
342
+ finally {
343
+ this.isShuttingDown = false;
344
+ }
345
+ }
346
+ /**
347
+ * Save shutdown state to disk for recovery/analysis
348
+ */
349
+ async saveShutdownState(reason) {
350
+ try {
351
+ const processManager = this.getProcessManager();
352
+ const state = {
353
+ timestamp: new Date().toISOString(),
354
+ reason,
355
+ processId: process.pid,
356
+ memoryUsage: process.memoryUsage(),
357
+ processes: processManager ? await this.getAllProcessStatuses() : [],
358
+ activeConnections: this.getActiveConnectionCount(),
359
+ uptime: process.uptime(),
360
+ version: process.version,
361
+ platform: process.platform,
362
+ arch: process.arch,
363
+ };
364
+ const statePath = path.join(this.dataDirectory.getDataDir(), 'shutdown-state.json');
365
+ const fs = await import('fs');
366
+ // Ensure directory exists before writing
367
+ const dir = path.dirname(statePath);
368
+ await fs.promises.mkdir(dir, { recursive: true });
369
+ await fs.promises.writeFile(statePath, JSON.stringify(state, null, 2), 'utf-8');
370
+ console.log(`[ProcmanDaemon] Shutdown state saved to: ${statePath}`);
371
+ }
372
+ catch (error) {
373
+ // Non-critical error - log but don't fail shutdown
374
+ console.error('[ProcmanDaemon] Failed to save shutdown state:', error);
375
+ }
376
+ }
377
+ /**
378
+ * Get count of active IPC connections
379
+ */
380
+ getActiveConnectionCount() {
381
+ const ipcServer = this.getIPCServer();
382
+ if (!ipcServer) {
383
+ return 0;
384
+ }
385
+ return ipcServer.getConnections().length;
386
+ }
387
+ /**
388
+ * Drain active IPC connections gracefully
389
+ */
390
+ async drainActiveConnections() {
391
+ const ipcServer = this.getIPCServer();
392
+ if (!ipcServer) {
393
+ console.log('[ProcmanDaemon] No IPC server to drain connections from');
394
+ return;
395
+ }
396
+ const connections = ipcServer.getConnections();
397
+ if (connections.length === 0) {
398
+ console.log('[ProcmanDaemon] No active connections to drain');
399
+ return;
400
+ }
401
+ console.log(`[ProcmanDaemon] Draining ${connections.length} active connections...`);
402
+ // Send shutdown notice to all connections
403
+ ipcServer.broadcast({
404
+ id: `shutdown-notice-${Date.now()}`,
405
+ type: 'ping', // Use existing command type for compatibility
406
+ payload: {
407
+ shutdownNotice: true,
408
+ reason: 'graceful-shutdown',
409
+ gracePeriodMs: 8000, // Give clients 8 seconds to cleanup
410
+ },
411
+ timestamp: Date.now(),
412
+ });
413
+ // Wait for connections to close gracefully
414
+ const drainStartTime = Date.now();
415
+ const maxDrainTime = 8000; // 8 seconds for clients to disconnect
416
+ while (ipcServer.getConnections().length > 0 &&
417
+ Date.now() - drainStartTime < maxDrainTime) {
418
+ await new Promise((resolve) => setTimeout(resolve, 100)); // Check every 100ms
419
+ }
420
+ const remainingConnections = ipcServer.getConnections().length;
421
+ if (remainingConnections > 0) {
422
+ console.warn(`[ProcmanDaemon] ${remainingConnections} connections did not close gracefully, will force close`);
423
+ }
424
+ else {
425
+ console.log('[ProcmanDaemon] All connections drained successfully');
426
+ }
427
+ }
428
+ /**
429
+ * Stop all managed processes gracefully
430
+ */
431
+ async stopManagedProcesses() {
432
+ const processManager = this.getProcessManager();
433
+ if (!processManager) {
434
+ console.log('[ProcmanDaemon] No process manager to stop processes from');
435
+ return;
436
+ }
437
+ const allProcesses = processManager.getAllProcessInfo();
438
+ if (allProcesses.length === 0) {
439
+ console.log('[ProcmanDaemon] No managed processes to stop');
440
+ return;
441
+ }
442
+ console.log(`[ProcmanDaemon] Stopping ${allProcesses.length} managed processes gracefully...`);
443
+ const processNames = allProcesses.map((p) => p.name);
444
+ await processManager.stopProcesses(processNames);
445
+ console.log('[ProcmanDaemon] All managed processes stopped');
446
+ }
447
+ /**
448
+ * Execute a function with timeout
449
+ */
450
+ async executeWithTimeout(fn, timeoutMs, phaseName) {
451
+ return Promise.race([
452
+ fn(),
453
+ new Promise((_, reject) => setTimeout(() => reject(new Error(`${phaseName} timed out after ${timeoutMs}ms`)), timeoutMs)),
454
+ ]);
455
+ }
456
+ /**
457
+ * Format bytes to human-readable string
458
+ */
459
+ formatBytes(bytes) {
460
+ const units = ['B', 'KB', 'MB', 'GB'];
461
+ let size = Number(bytes);
462
+ let unitIndex = 0;
463
+ if (!isFinite(size) || size < 0) {
464
+ return '0B';
465
+ }
466
+ while (size >= 1024 && unitIndex < units.length - 1) {
467
+ size /= 1024;
468
+ unitIndex++;
469
+ }
470
+ return `${size.toFixed(1)}${units[unitIndex]}`;
471
+ }
472
+ /**
473
+ * Perform environment checks before daemon startup
474
+ */
475
+ async performEnvironmentChecks() {
476
+ // Check 1: Verify HOME environment variable is set
477
+ const homeDir = process.env.HOME || process.env.USERPROFILE;
478
+ if (!homeDir) {
479
+ // Try to detect home directory using os.homedir()
480
+ try {
481
+ const os = await import('os');
482
+ const detectedHome = os.homedir();
483
+ if (!detectedHome) {
484
+ throw new Error('HOME environment variable is not set and could not detect home directory');
485
+ }
486
+ // Set HOME for this process and child processes
487
+ process.env.HOME = detectedHome;
488
+ console.log(`HOME environment variable was missing, set to: ${detectedHome}`);
489
+ }
490
+ catch (error) {
491
+ throw new Error(`Failed to determine home directory: ${error instanceof Error ? error.message : 'Unknown error'}`);
492
+ }
493
+ }
494
+ // Check 2: Verify data directory path can be resolved
495
+ try {
496
+ const resolvedPath = this.dataDirectory.resolveDataDir();
497
+ if (!resolvedPath || resolvedPath.includes('~')) {
498
+ throw new Error(`Failed to expand socket path: ${resolvedPath}. HOME environment variable may not be set.`);
499
+ }
500
+ }
501
+ catch (error) {
502
+ throw new Error(`Failed to resolve data directory path: ${error instanceof Error ? error.message : 'Unknown error'}`);
503
+ }
504
+ // Check 3: Verify socket path can be resolved
505
+ try {
506
+ const socketPath = await this.dataDirectory.getSocketPath();
507
+ if (!socketPath) {
508
+ throw new Error('Failed to resolve socket path');
509
+ }
510
+ // On Unix systems, verify the path doesn't contain unresolved ~ characters
511
+ if (process.platform !== 'win32' && socketPath.includes('~')) {
512
+ throw new Error(`Socket path contains unresolved tilde: ${socketPath}`);
513
+ }
514
+ }
515
+ catch (error) {
516
+ throw new Error(`Failed to resolve socket path: ${error instanceof Error ? error.message : 'Unknown error'}`);
517
+ }
518
+ // Check 4: Verify we can create the data directory (dry run check)
519
+ try {
520
+ await this.dataDirectory.validateDataDirectory();
521
+ // If validation passes, directory already exists with correct permissions
522
+ }
523
+ catch {
524
+ // Directory doesn't exist or has wrong permissions - that's OK, we'll create it later
525
+ // But we should verify we have permission to create it
526
+ const path = await import('path');
527
+ const fs = await import('fs');
528
+ const parentDir = path.dirname(this.dataDirectory.getDataDir());
529
+ try {
530
+ await fs.promises.access(parentDir, fs.constants.W_OK);
531
+ }
532
+ catch (accessError) {
533
+ throw new Error(`Cannot write to parent directory ${parentDir}: ${accessError instanceof Error ? accessError.message : 'Permission denied'}`);
534
+ }
535
+ }
536
+ // Check 5: Verify basic Node.js runtime environment
537
+ if (!process.pid) {
538
+ throw new Error('Invalid process environment: PID not available');
539
+ }
540
+ // Check 6: Verify required modules can be loaded
541
+ try {
542
+ await import('fs');
543
+ await import('path');
544
+ await import('os');
545
+ }
546
+ catch (error) {
547
+ throw new Error(`Failed to load required Node.js modules: ${error instanceof Error ? error.message : 'Unknown error'}`);
548
+ }
549
+ console.log('Environment checks passed successfully');
550
+ }
551
+ /**
552
+ * Attempt error recovery
553
+ */
554
+ async attemptRecovery() {
555
+ if (!this.stateManager.isInError()) {
556
+ return true; // Already recovered
557
+ }
558
+ if (this.recoveryAttempts >= this.maxRecoveryAttempts) {
559
+ this.emit('recoveryFailed', new Error('Maximum recovery attempts exceeded'));
560
+ return false;
561
+ }
562
+ this.recoveryAttempts++;
563
+ this.emit('recoveryStarted');
564
+ try {
565
+ this.stateManager.beginRecovery();
566
+ // Perform recovery steps
567
+ await this.performRecoverySteps();
568
+ this.stateManager.completeRecovery();
569
+ this.emit('recoveryCompleted');
570
+ return true;
571
+ }
572
+ catch (error) {
573
+ this.stateManager.failRecovery();
574
+ this.emit('recoveryFailed', error);
575
+ // Wait before next attempt
576
+ await new Promise((resolve) => setTimeout(resolve, RECOVERY_CONSTANTS.RECOVERY_DELAY_MS));
577
+ return false;
578
+ }
579
+ }
580
+ /**
581
+ * Load configuration and apply it
582
+ */
583
+ async loadConfig(configFilePath) {
584
+ const configLoader = this.componentManager.getComponent('configLoader');
585
+ const processManager = this.componentManager.getComponent('processManager');
586
+ const logManager = this.componentManager.getComponent('logManager');
587
+ if (!configLoader) {
588
+ throw new Error('ConfigLoader not initialized');
589
+ }
590
+ if (!processManager) {
591
+ throw new Error('ProcessManager not initialized');
592
+ }
593
+ this.configFilePath = configFilePath;
594
+ const config = await configLoader.load(configFilePath);
595
+ this.currentConfig = config.apps;
596
+ // Stop all existing processes
597
+ const allProcesses = processManager.getAllProcessInfo();
598
+ if (allProcesses.length > 0) {
599
+ const processNames = allProcesses.map((p) => p.name);
600
+ await processManager.stopProcesses(processNames);
601
+ }
602
+ // Configure new processes
603
+ for (const app of config.apps) {
604
+ processManager.configureProcess(app);
605
+ // Setup log manager for this app if log files are configured
606
+ if (logManager && (app.log_file || app.out_file || app.error_file)) {
607
+ logManager.setupAppLogs(app.name, {
608
+ logFile: app.log_file,
609
+ outFile: app.out_file,
610
+ errorFile: app.error_file,
611
+ namespace: app.namespace,
612
+ });
613
+ }
614
+ }
615
+ return config.apps;
616
+ }
617
+ /**
618
+ * Get current configuration
619
+ */
620
+ getConfig() {
621
+ return this.currentConfig;
622
+ }
623
+ /**
624
+ * Get component instances (for backward compatibility)
625
+ */
626
+ getConfigLoader() {
627
+ return this.componentManager.getComponent('configLoader');
628
+ }
629
+ getProcessManager() {
630
+ return this.componentManager.getComponent('processManager');
631
+ }
632
+ getLogManager() {
633
+ return this.componentManager.getComponent('logManager');
634
+ }
635
+ getIPCServer() {
636
+ return this.componentManager.getComponent('ipcServer');
637
+ }
638
+ /**
639
+ * Get all process statuses (moved from old implementation)
640
+ */
641
+ async getAllProcessStatuses() {
642
+ const processManager = this.getProcessManager();
643
+ if (!processManager) {
644
+ return [];
645
+ }
646
+ const processInfos = processManager.getAllProcessInfo();
647
+ const statusPromises = processInfos.map(async (info) => {
648
+ // Get process stats from monitor
649
+ const stats = await processManager.monitor.getProcessStats(info.name);
650
+ return {
651
+ name: info.name,
652
+ namespace: info.namespace || 'default',
653
+ pid: info.pid,
654
+ status: info.status,
655
+ uptime: info.uptime,
656
+ memory: stats?.memory || 0,
657
+ cpu: stats?.cpu || 0,
658
+ restarts: info.restarts,
659
+ };
660
+ });
661
+ return Promise.all(statusPromises);
662
+ }
663
+ /**
664
+ * Setup event listeners for internal managers
665
+ */
666
+ setupEventListeners() {
667
+ // Forward state manager events
668
+ this.stateManager.on('stateChange', (event) => {
669
+ this.emit('stateChange', event.to);
670
+ });
671
+ this.stateManager.on('enterError', () => {
672
+ // Attempt automatic recovery
673
+ setTimeout(() => {
674
+ this.attemptRecovery().catch((error) => {
675
+ console.error('Automatic recovery failed:', error);
676
+ });
677
+ }, 1000);
678
+ });
679
+ // Forward component manager events
680
+ this.componentManager.on('componentStarted', (componentName) => {
681
+ this.emit('componentStarted', componentName);
682
+ });
683
+ this.componentManager.on('componentStopped', (componentName) => {
684
+ this.emit('componentStopped', componentName);
685
+ });
686
+ this.componentManager.on('componentError', (componentName, error) => {
687
+ console.error(`Component ${componentName} error:`, error);
688
+ this.emit('error', error);
689
+ // Trigger error state if not already in error
690
+ if (!this.stateManager.isInError()) {
691
+ this.stateManager.forceError();
692
+ }
693
+ });
694
+ // Setup signal handler events with enhanced shutdown
695
+ this.signalHandler.on('gracefulShutdown', async (signal) => {
696
+ console.log(`Received ${signal}, shutting down gracefully...`);
697
+ try {
698
+ await this.shutdown('signal');
699
+ process.exit(0);
700
+ }
701
+ catch (error) {
702
+ console.error('Error during graceful shutdown:', error);
703
+ process.exit(1);
704
+ }
705
+ });
706
+ this.signalHandler.on('uncaughtException', async (error) => {
707
+ console.error('Uncaught exception in daemon:', error);
708
+ this.emit('error', error);
709
+ // Force error state and attempt recovery
710
+ if (!this.stateManager.isInError()) {
711
+ this.stateManager.forceError();
712
+ }
713
+ });
714
+ // Setup memory monitor event handlers
715
+ this.memoryMonitor.on('memoryCritical', (usage, threshold) => {
716
+ console.warn(`[ProcmanDaemon] Memory critical threshold exceeded: ${this.formatBytes(usage.rss)} > ${this.formatBytes(threshold)}`);
717
+ });
718
+ this.memoryMonitor.on('memoryWarning', (usage, threshold) => {
719
+ console.warn(`[ProcmanDaemon] Memory warning threshold exceeded: ${this.formatBytes(usage.rss)} > ${this.formatBytes(threshold)}`);
720
+ });
721
+ this.memoryMonitor.on('error', (error) => {
722
+ console.error('[ProcmanDaemon] Memory monitor error:', error);
723
+ this.emit('error', error);
724
+ });
725
+ }
726
+ /**
727
+ * Perform startup cleanup on failure
728
+ */
729
+ async performStartupCleanup() {
730
+ const cleanupTasks = [];
731
+ // Cleanup PID file
732
+ cleanupTasks.push(this.pidManager.cleanup().catch((error) => {
733
+ console.error('Failed to cleanup PID file during startup failure:', error);
734
+ }));
735
+ // Cleanup signal handlers
736
+ try {
737
+ this.signalHandler.cleanupHandlers();
738
+ }
739
+ catch (error) {
740
+ console.error('Failed to cleanup signal handlers during startup failure:', error);
741
+ }
742
+ // Cleanup any partially initialized components
743
+ cleanupTasks.push(this.componentManager.cleanupAll().catch((error) => {
744
+ console.error('Failed to cleanup components during startup failure:', error);
745
+ }));
746
+ // Wait for all cleanup tasks to complete
747
+ await Promise.all(cleanupTasks);
748
+ }
749
+ /**
750
+ * Perform emergency cleanup when normal stop fails
751
+ */
752
+ async performEmergencyCleanup() {
753
+ console.log('Performing emergency cleanup...');
754
+ // Try to cleanup critical resources without throwing errors
755
+ try {
756
+ await this.pidManager.cleanup();
757
+ }
758
+ catch (error) {
759
+ console.error('Emergency PID cleanup failed:', error);
760
+ }
761
+ try {
762
+ this.signalHandler.cleanupHandlers();
763
+ }
764
+ catch (error) {
765
+ console.error('Emergency signal handler cleanup failed:', error);
766
+ }
767
+ }
768
+ /**
769
+ * Perform recovery steps when in RECOVERING state
770
+ */
771
+ async performRecoverySteps() {
772
+ // Step 1: Try to reinitialize components
773
+ try {
774
+ await this.componentManager.cleanupAll();
775
+ }
776
+ catch (error) {
777
+ console.log('Component cleanup during recovery failed (expected):', error);
778
+ }
779
+ // Step 2: Reinitialize components
780
+ await this.componentManager.initializeAll();
781
+ // Step 3: Reapply current configuration if available
782
+ if (this.configFilePath) {
783
+ try {
784
+ await this.loadConfig(this.configFilePath);
785
+ }
786
+ catch (error) {
787
+ console.error('Failed to reload configuration during recovery:', error);
788
+ throw error;
789
+ }
790
+ }
791
+ }
792
+ /**
793
+ * Override EventEmitter methods for type safety
794
+ */
795
+ emit(event, ...args) {
796
+ return super.emit(event, ...args);
797
+ }
798
+ on(event, listener) {
799
+ return super.on(event, listener);
800
+ }
801
+ }
802
+ //# sourceMappingURL=procman-daemon.js.map