lattice-orchestrator 0.7.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 (440) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +58 -0
  3. package/config/logrotate.conf +15 -0
  4. package/dist/cli-parser.d.ts +11 -0
  5. package/dist/cli-parser.d.ts.map +1 -0
  6. package/dist/cli-parser.js +48 -0
  7. package/dist/cli-parser.js.map +1 -0
  8. package/dist/lattice-server.d.ts +70 -0
  9. package/dist/lattice-server.d.ts.map +1 -0
  10. package/dist/lattice-server.js +969 -0
  11. package/dist/lattice-server.js.map +1 -0
  12. package/dist/mcp-server/index.d.ts +3 -0
  13. package/dist/mcp-server/index.d.ts.map +1 -0
  14. package/dist/mcp-server/index.js +190 -0
  15. package/dist/mcp-server/index.js.map +1 -0
  16. package/dist/mcp-server/lattice-tools.d.ts +15 -0
  17. package/dist/mcp-server/lattice-tools.d.ts.map +1 -0
  18. package/dist/mcp-server/lattice-tools.js +366 -0
  19. package/dist/mcp-server/lattice-tools.js.map +1 -0
  20. package/dist/middleware/cors-setup.d.ts +7 -0
  21. package/dist/middleware/cors-setup.d.ts.map +1 -0
  22. package/dist/middleware/cors-setup.js +8 -0
  23. package/dist/middleware/cors-setup.js.map +1 -0
  24. package/dist/middleware/error-handler.d.ts +4 -0
  25. package/dist/middleware/error-handler.d.ts.map +1 -0
  26. package/dist/middleware/error-handler.js +27 -0
  27. package/dist/middleware/error-handler.js.map +1 -0
  28. package/dist/middleware/query-parser.d.ts +11 -0
  29. package/dist/middleware/query-parser.d.ts.map +1 -0
  30. package/dist/middleware/query-parser.js +68 -0
  31. package/dist/middleware/query-parser.js.map +1 -0
  32. package/dist/middleware/request-logger.d.ts +4 -0
  33. package/dist/middleware/request-logger.d.ts.map +1 -0
  34. package/dist/middleware/request-logger.js +6 -0
  35. package/dist/middleware/request-logger.js.map +1 -0
  36. package/dist/process-daemon/index.d.ts +14 -0
  37. package/dist/process-daemon/index.d.ts.map +1 -0
  38. package/dist/process-daemon/index.js +51 -0
  39. package/dist/process-daemon/index.js.map +1 -0
  40. package/dist/process-daemon/process-daemon.d.ts +101 -0
  41. package/dist/process-daemon/process-daemon.d.ts.map +1 -0
  42. package/dist/process-daemon/process-daemon.js +846 -0
  43. package/dist/process-daemon/process-daemon.js.map +1 -0
  44. package/dist/process-daemon/process-manager-client.d.ts +123 -0
  45. package/dist/process-daemon/process-manager-client.d.ts.map +1 -0
  46. package/dist/process-daemon/process-manager-client.js +329 -0
  47. package/dist/process-daemon/process-manager-client.js.map +1 -0
  48. package/dist/process-daemon/process-manager-interface.d.ts +61 -0
  49. package/dist/process-daemon/process-manager-interface.d.ts.map +1 -0
  50. package/dist/process-daemon/process-manager-interface.js +8 -0
  51. package/dist/process-daemon/process-manager-interface.js.map +1 -0
  52. package/dist/process-daemon/test-daemon.d.ts +12 -0
  53. package/dist/process-daemon/test-daemon.d.ts.map +1 -0
  54. package/dist/process-daemon/test-daemon.js +81 -0
  55. package/dist/process-daemon/test-daemon.js.map +1 -0
  56. package/dist/process-daemon/types.d.ts +97 -0
  57. package/dist/process-daemon/types.d.ts.map +1 -0
  58. package/dist/process-daemon/types.js +8 -0
  59. package/dist/process-daemon/types.js.map +1 -0
  60. package/dist/routes/analysis.routes.d.ts +13 -0
  61. package/dist/routes/analysis.routes.d.ts.map +1 -0
  62. package/dist/routes/analysis.routes.js +520 -0
  63. package/dist/routes/analysis.routes.js.map +1 -0
  64. package/dist/routes/config.routes.d.ts +4 -0
  65. package/dist/routes/config.routes.d.ts.map +1 -0
  66. package/dist/routes/config.routes.js +27 -0
  67. package/dist/routes/config.routes.js.map +1 -0
  68. package/dist/routes/conversation.routes.d.ts +43 -0
  69. package/dist/routes/conversation.routes.d.ts.map +1 -0
  70. package/dist/routes/conversation.routes.js +79 -0
  71. package/dist/routes/conversation.routes.js.map +1 -0
  72. package/dist/routes/filesystem.routes.d.ts +4 -0
  73. package/dist/routes/filesystem.routes.d.ts.map +1 -0
  74. package/dist/routes/filesystem.routes.js +86 -0
  75. package/dist/routes/filesystem.routes.js.map +1 -0
  76. package/dist/routes/insights.routes.d.ts +17 -0
  77. package/dist/routes/insights.routes.d.ts.map +1 -0
  78. package/dist/routes/insights.routes.js +633 -0
  79. package/dist/routes/insights.routes.js.map +1 -0
  80. package/dist/routes/lattice.routes.d.ts +10 -0
  81. package/dist/routes/lattice.routes.d.ts.map +1 -0
  82. package/dist/routes/lattice.routes.js +123 -0
  83. package/dist/routes/lattice.routes.js.map +1 -0
  84. package/dist/routes/license.routes.d.ts +3 -0
  85. package/dist/routes/license.routes.d.ts.map +1 -0
  86. package/dist/routes/license.routes.js +95 -0
  87. package/dist/routes/license.routes.js.map +1 -0
  88. package/dist/routes/log.routes.d.ts +3 -0
  89. package/dist/routes/log.routes.d.ts.map +1 -0
  90. package/dist/routes/log.routes.js +184 -0
  91. package/dist/routes/log.routes.js.map +1 -0
  92. package/dist/routes/pending-question.routes.d.ts +9 -0
  93. package/dist/routes/pending-question.routes.d.ts.map +1 -0
  94. package/dist/routes/pending-question.routes.js +162 -0
  95. package/dist/routes/pending-question.routes.js.map +1 -0
  96. package/dist/routes/permission.routes.d.ts +18 -0
  97. package/dist/routes/permission.routes.d.ts.map +1 -0
  98. package/dist/routes/permission.routes.js +370 -0
  99. package/dist/routes/permission.routes.js.map +1 -0
  100. package/dist/routes/process-events.routes.d.ts +9 -0
  101. package/dist/routes/process-events.routes.d.ts.map +1 -0
  102. package/dist/routes/process-events.routes.js +141 -0
  103. package/dist/routes/process-events.routes.js.map +1 -0
  104. package/dist/routes/prototype.routes.d.ts +9 -0
  105. package/dist/routes/prototype.routes.d.ts.map +1 -0
  106. package/dist/routes/prototype.routes.js +757 -0
  107. package/dist/routes/prototype.routes.js.map +1 -0
  108. package/dist/routes/question.routes.d.ts +8 -0
  109. package/dist/routes/question.routes.d.ts.map +1 -0
  110. package/dist/routes/question.routes.js +83 -0
  111. package/dist/routes/question.routes.js.map +1 -0
  112. package/dist/routes/session-control.routes.d.ts +29 -0
  113. package/dist/routes/session-control.routes.d.ts.map +1 -0
  114. package/dist/routes/session-control.routes.js +455 -0
  115. package/dist/routes/session-control.routes.js.map +1 -0
  116. package/dist/routes/session-lifecycle.routes.d.ts +21 -0
  117. package/dist/routes/session-lifecycle.routes.d.ts.map +1 -0
  118. package/dist/routes/session-lifecycle.routes.js +256 -0
  119. package/dist/routes/session-lifecycle.routes.js.map +1 -0
  120. package/dist/routes/session-query.routes.d.ts +25 -0
  121. package/dist/routes/session-query.routes.d.ts.map +1 -0
  122. package/dist/routes/session-query.routes.js +363 -0
  123. package/dist/routes/session-query.routes.js.map +1 -0
  124. package/dist/routes/session-stream.routes.d.ts +21 -0
  125. package/dist/routes/session-stream.routes.d.ts.map +1 -0
  126. package/dist/routes/session-stream.routes.js +235 -0
  127. package/dist/routes/session-stream.routes.js.map +1 -0
  128. package/dist/routes/streaming.routes.d.ts +4 -0
  129. package/dist/routes/streaming.routes.d.ts.map +1 -0
  130. package/dist/routes/streaming.routes.js +33 -0
  131. package/dist/routes/streaming.routes.js.map +1 -0
  132. package/dist/routes/system.routes.d.ts +7 -0
  133. package/dist/routes/system.routes.d.ts.map +1 -0
  134. package/dist/routes/system.routes.js +214 -0
  135. package/dist/routes/system.routes.js.map +1 -0
  136. package/dist/routes/walkthrough.routes.d.ts +19 -0
  137. package/dist/routes/walkthrough.routes.d.ts.map +1 -0
  138. package/dist/routes/walkthrough.routes.js +688 -0
  139. package/dist/routes/walkthrough.routes.js.map +1 -0
  140. package/dist/routes/working-directories.routes.d.ts +4 -0
  141. package/dist/routes/working-directories.routes.d.ts.map +1 -0
  142. package/dist/routes/working-directories.routes.js +25 -0
  143. package/dist/routes/working-directories.routes.js.map +1 -0
  144. package/dist/server.d.ts +3 -0
  145. package/dist/server.d.ts.map +1 -0
  146. package/dist/server.js +34 -0
  147. package/dist/server.js.map +1 -0
  148. package/dist/services/ToolMetricsService.d.ts +53 -0
  149. package/dist/services/ToolMetricsService.d.ts.map +1 -0
  150. package/dist/services/ToolMetricsService.js +230 -0
  151. package/dist/services/ToolMetricsService.js.map +1 -0
  152. package/dist/services/claude-router-service.d.ts +19 -0
  153. package/dist/services/claude-router-service.d.ts.map +1 -0
  154. package/dist/services/claude-router-service.js +160 -0
  155. package/dist/services/claude-router-service.js.map +1 -0
  156. package/dist/services/commands-service.d.ts +20 -0
  157. package/dist/services/commands-service.d.ts.map +1 -0
  158. package/dist/services/commands-service.js +115 -0
  159. package/dist/services/commands-service.js.map +1 -0
  160. package/dist/services/connection-debug-logger.d.ts +85 -0
  161. package/dist/services/connection-debug-logger.d.ts.map +1 -0
  162. package/dist/services/connection-debug-logger.js +221 -0
  163. package/dist/services/connection-debug-logger.js.map +1 -0
  164. package/dist/services/debug-log.d.ts +6 -0
  165. package/dist/services/debug-log.d.ts.map +1 -0
  166. package/dist/services/debug-log.js +27 -0
  167. package/dist/services/debug-log.js.map +1 -0
  168. package/dist/services/gemini-service.d.ts +35 -0
  169. package/dist/services/gemini-service.d.ts.map +1 -0
  170. package/dist/services/gemini-service.js +256 -0
  171. package/dist/services/gemini-service.js.map +1 -0
  172. package/dist/services/infrastructure/config-service.d.ts +79 -0
  173. package/dist/services/infrastructure/config-service.d.ts.map +1 -0
  174. package/dist/services/infrastructure/config-service.js +431 -0
  175. package/dist/services/infrastructure/config-service.js.map +1 -0
  176. package/dist/services/infrastructure/cost-tracker.d.ts +112 -0
  177. package/dist/services/infrastructure/cost-tracker.d.ts.map +1 -0
  178. package/dist/services/infrastructure/cost-tracker.js +423 -0
  179. package/dist/services/infrastructure/cost-tracker.js.map +1 -0
  180. package/dist/services/infrastructure/file-system-service.d.ts +61 -0
  181. package/dist/services/infrastructure/file-system-service.d.ts.map +1 -0
  182. package/dist/services/infrastructure/file-system-service.js +348 -0
  183. package/dist/services/infrastructure/file-system-service.js.map +1 -0
  184. package/dist/services/infrastructure/log-formatter.d.ts +5 -0
  185. package/dist/services/infrastructure/log-formatter.d.ts.map +1 -0
  186. package/dist/services/infrastructure/log-formatter.js +77 -0
  187. package/dist/services/infrastructure/log-formatter.js.map +1 -0
  188. package/dist/services/infrastructure/log-stream-buffer.d.ts +11 -0
  189. package/dist/services/infrastructure/log-stream-buffer.d.ts.map +1 -0
  190. package/dist/services/infrastructure/log-stream-buffer.js +36 -0
  191. package/dist/services/infrastructure/log-stream-buffer.js.map +1 -0
  192. package/dist/services/infrastructure/logger.d.ts +71 -0
  193. package/dist/services/infrastructure/logger.d.ts.map +1 -0
  194. package/dist/services/infrastructure/logger.js +215 -0
  195. package/dist/services/infrastructure/logger.js.map +1 -0
  196. package/dist/services/infrastructure/service-registry.d.ts +86 -0
  197. package/dist/services/infrastructure/service-registry.d.ts.map +1 -0
  198. package/dist/services/infrastructure/service-registry.js +162 -0
  199. package/dist/services/infrastructure/service-registry.js.map +1 -0
  200. package/dist/services/infrastructure/stream-manager.d.ts +87 -0
  201. package/dist/services/infrastructure/stream-manager.d.ts.map +1 -0
  202. package/dist/services/infrastructure/stream-manager.js +436 -0
  203. package/dist/services/infrastructure/stream-manager.js.map +1 -0
  204. package/dist/services/infrastructure/timing.d.ts +72 -0
  205. package/dist/services/infrastructure/timing.d.ts.map +1 -0
  206. package/dist/services/infrastructure/timing.js +115 -0
  207. package/dist/services/infrastructure/timing.js.map +1 -0
  208. package/dist/services/insights/anthropic-service.d.ts +224 -0
  209. package/dist/services/insights/anthropic-service.d.ts.map +1 -0
  210. package/dist/services/insights/anthropic-service.js +1062 -0
  211. package/dist/services/insights/anthropic-service.js.map +1 -0
  212. package/dist/services/insights/insight-audit-repository.d.ts +119 -0
  213. package/dist/services/insights/insight-audit-repository.d.ts.map +1 -0
  214. package/dist/services/insights/insight-audit-repository.js +242 -0
  215. package/dist/services/insights/insight-audit-repository.js.map +1 -0
  216. package/dist/services/insights/insight-queue.d.ts +99 -0
  217. package/dist/services/insights/insight-queue.d.ts.map +1 -0
  218. package/dist/services/insights/insight-queue.js +277 -0
  219. package/dist/services/insights/insight-queue.js.map +1 -0
  220. package/dist/services/insights/insights-computer.d.ts +132 -0
  221. package/dist/services/insights/insights-computer.d.ts.map +1 -0
  222. package/dist/services/insights/insights-computer.js +936 -0
  223. package/dist/services/insights/insights-computer.js.map +1 -0
  224. package/dist/services/insights/insights-coordinator.d.ts +165 -0
  225. package/dist/services/insights/insights-coordinator.d.ts.map +1 -0
  226. package/dist/services/insights/insights-coordinator.js +1678 -0
  227. package/dist/services/insights/insights-coordinator.js.map +1 -0
  228. package/dist/services/insights/insights-event-log.d.ts +196 -0
  229. package/dist/services/insights/insights-event-log.d.ts.map +1 -0
  230. package/dist/services/insights/insights-event-log.js +319 -0
  231. package/dist/services/insights/insights-event-log.js.map +1 -0
  232. package/dist/services/lattice-service.d.ts +77 -0
  233. package/dist/services/lattice-service.d.ts.map +1 -0
  234. package/dist/services/lattice-service.js +195 -0
  235. package/dist/services/lattice-service.js.map +1 -0
  236. package/dist/services/license-service.d.ts +69 -0
  237. package/dist/services/license-service.d.ts.map +1 -0
  238. package/dist/services/license-service.js +330 -0
  239. package/dist/services/license-service.js.map +1 -0
  240. package/dist/services/mcp-config-generator.d.ts +32 -0
  241. package/dist/services/mcp-config-generator.d.ts.map +1 -0
  242. package/dist/services/mcp-config-generator.js +126 -0
  243. package/dist/services/mcp-config-generator.js.map +1 -0
  244. package/dist/services/message-filter.d.ts +22 -0
  245. package/dist/services/message-filter.d.ts.map +1 -0
  246. package/dist/services/message-filter.js +57 -0
  247. package/dist/services/message-filter.js.map +1 -0
  248. package/dist/services/notification-service.d.ts +45 -0
  249. package/dist/services/notification-service.d.ts.map +1 -0
  250. package/dist/services/notification-service.js +184 -0
  251. package/dist/services/notification-service.js.map +1 -0
  252. package/dist/services/pending-question-service.d.ts +97 -0
  253. package/dist/services/pending-question-service.d.ts.map +1 -0
  254. package/dist/services/pending-question-service.js +223 -0
  255. package/dist/services/pending-question-service.js.map +1 -0
  256. package/dist/services/permission-event-log.d.ts +136 -0
  257. package/dist/services/permission-event-log.d.ts.map +1 -0
  258. package/dist/services/permission-event-log.js +252 -0
  259. package/dist/services/permission-event-log.js.map +1 -0
  260. package/dist/services/permission-pattern-matcher.d.ts +82 -0
  261. package/dist/services/permission-pattern-matcher.d.ts.map +1 -0
  262. package/dist/services/permission-pattern-matcher.js +294 -0
  263. package/dist/services/permission-pattern-matcher.js.map +1 -0
  264. package/dist/services/permission-tracker.d.ts +67 -0
  265. package/dist/services/permission-tracker.d.ts.map +1 -0
  266. package/dist/services/permission-tracker.js +162 -0
  267. package/dist/services/permission-tracker.js.map +1 -0
  268. package/dist/services/process/claude-process-manager.d.ts +142 -0
  269. package/dist/services/process/claude-process-manager.d.ts.map +1 -0
  270. package/dist/services/process/claude-process-manager.js +1218 -0
  271. package/dist/services/process/claude-process-manager.js.map +1 -0
  272. package/dist/services/process/conversation-status-manager.d.ts +110 -0
  273. package/dist/services/process/conversation-status-manager.d.ts.map +1 -0
  274. package/dist/services/process/conversation-status-manager.js +349 -0
  275. package/dist/services/process/conversation-status-manager.js.map +1 -0
  276. package/dist/services/process/json-lines-parser.d.ts +19 -0
  277. package/dist/services/process/json-lines-parser.d.ts.map +1 -0
  278. package/dist/services/process/json-lines-parser.js +59 -0
  279. package/dist/services/process/json-lines-parser.js.map +1 -0
  280. package/dist/services/process/process-event-log.d.ts +263 -0
  281. package/dist/services/process/process-event-log.d.ts.map +1 -0
  282. package/dist/services/process/process-event-log.js +509 -0
  283. package/dist/services/process/process-event-log.js.map +1 -0
  284. package/dist/services/process/process-manager-factory.d.ts +109 -0
  285. package/dist/services/process/process-manager-factory.d.ts.map +1 -0
  286. package/dist/services/process/process-manager-factory.js +338 -0
  287. package/dist/services/process/process-manager-factory.js.map +1 -0
  288. package/dist/services/question-tracker.d.ts +51 -0
  289. package/dist/services/question-tracker.d.ts.map +1 -0
  290. package/dist/services/question-tracker.js +111 -0
  291. package/dist/services/question-tracker.js.map +1 -0
  292. package/dist/services/sessions/claude-history-reader.d.ts +139 -0
  293. package/dist/services/sessions/claude-history-reader.d.ts.map +1 -0
  294. package/dist/services/sessions/claude-history-reader.js +864 -0
  295. package/dist/services/sessions/claude-history-reader.js.map +1 -0
  296. package/dist/services/sessions/conversation-cache.d.ts +98 -0
  297. package/dist/services/sessions/conversation-cache.d.ts.map +1 -0
  298. package/dist/services/sessions/conversation-cache.js +329 -0
  299. package/dist/services/sessions/conversation-cache.js.map +1 -0
  300. package/dist/services/sessions/session-activity-watcher.d.ts +67 -0
  301. package/dist/services/sessions/session-activity-watcher.d.ts.map +1 -0
  302. package/dist/services/sessions/session-activity-watcher.js +236 -0
  303. package/dist/services/sessions/session-activity-watcher.js.map +1 -0
  304. package/dist/services/sessions/session-analysis-service.d.ts +72 -0
  305. package/dist/services/sessions/session-analysis-service.d.ts.map +1 -0
  306. package/dist/services/sessions/session-analysis-service.js +373 -0
  307. package/dist/services/sessions/session-analysis-service.js.map +1 -0
  308. package/dist/services/sessions/session-branch-service.d.ts +76 -0
  309. package/dist/services/sessions/session-branch-service.d.ts.map +1 -0
  310. package/dist/services/sessions/session-branch-service.js +355 -0
  311. package/dist/services/sessions/session-branch-service.js.map +1 -0
  312. package/dist/services/sessions/session-info-service.d.ts +455 -0
  313. package/dist/services/sessions/session-info-service.d.ts.map +1 -0
  314. package/dist/services/sessions/session-info-service.js +1640 -0
  315. package/dist/services/sessions/session-info-service.js.map +1 -0
  316. package/dist/services/sessions/session-marks-repository.d.ts +78 -0
  317. package/dist/services/sessions/session-marks-repository.d.ts.map +1 -0
  318. package/dist/services/sessions/session-marks-repository.js +263 -0
  319. package/dist/services/sessions/session-marks-repository.js.map +1 -0
  320. package/dist/services/sessions/session-marks-service.d.ts +137 -0
  321. package/dist/services/sessions/session-marks-service.d.ts.map +1 -0
  322. package/dist/services/sessions/session-marks-service.js +562 -0
  323. package/dist/services/sessions/session-marks-service.js.map +1 -0
  324. package/dist/services/sessions/session-review-service.d.ts +98 -0
  325. package/dist/services/sessions/session-review-service.d.ts.map +1 -0
  326. package/dist/services/sessions/session-review-service.js +629 -0
  327. package/dist/services/sessions/session-review-service.js.map +1 -0
  328. package/dist/services/sessions/turn-capture-service.d.ts +83 -0
  329. package/dist/services/sessions/turn-capture-service.d.ts.map +1 -0
  330. package/dist/services/sessions/turn-capture-service.js +477 -0
  331. package/dist/services/sessions/turn-capture-service.js.map +1 -0
  332. package/dist/services/sessions/turn-repository.d.ts +48 -0
  333. package/dist/services/sessions/turn-repository.d.ts.map +1 -0
  334. package/dist/services/sessions/turn-repository.js +103 -0
  335. package/dist/services/sessions/turn-repository.js.map +1 -0
  336. package/dist/services/walkthrough-service.d.ts +226 -0
  337. package/dist/services/walkthrough-service.d.ts.map +1 -0
  338. package/dist/services/walkthrough-service.js +1112 -0
  339. package/dist/services/walkthrough-service.js.map +1 -0
  340. package/dist/services/walkthrough-skill-prompt.d.ts +34 -0
  341. package/dist/services/walkthrough-skill-prompt.d.ts.map +1 -0
  342. package/dist/services/walkthrough-skill-prompt.js +313 -0
  343. package/dist/services/walkthrough-skill-prompt.js.map +1 -0
  344. package/dist/services/web-push-service.d.ts +48 -0
  345. package/dist/services/web-push-service.d.ts.map +1 -0
  346. package/dist/services/web-push-service.js +186 -0
  347. package/dist/services/web-push-service.js.map +1 -0
  348. package/dist/services/working-directories-service.d.ts +19 -0
  349. package/dist/services/working-directories-service.d.ts.map +1 -0
  350. package/dist/services/working-directories-service.js +103 -0
  351. package/dist/services/working-directories-service.js.map +1 -0
  352. package/dist/types/config.d.ts +122 -0
  353. package/dist/types/config.d.ts.map +1 -0
  354. package/dist/types/config.js +21 -0
  355. package/dist/types/config.js.map +1 -0
  356. package/dist/types/express.d.ts +5 -0
  357. package/dist/types/express.d.ts.map +1 -0
  358. package/dist/types/express.js +2 -0
  359. package/dist/types/express.js.map +1 -0
  360. package/dist/types/index.d.ts +400 -0
  361. package/dist/types/index.d.ts.map +1 -0
  362. package/dist/types/index.js +41 -0
  363. package/dist/types/index.js.map +1 -0
  364. package/dist/types/insights.d.ts +176 -0
  365. package/dist/types/insights.d.ts.map +1 -0
  366. package/dist/types/insights.js +23 -0
  367. package/dist/types/insights.js.map +1 -0
  368. package/dist/types/license.d.ts +70 -0
  369. package/dist/types/license.d.ts.map +1 -0
  370. package/dist/types/license.js +5 -0
  371. package/dist/types/license.js.map +1 -0
  372. package/dist/types/router-config.d.ts +13 -0
  373. package/dist/types/router-config.d.ts.map +1 -0
  374. package/dist/types/router-config.js +2 -0
  375. package/dist/types/router-config.js.map +1 -0
  376. package/dist/utils/constants.d.ts +26 -0
  377. package/dist/utils/constants.d.ts.map +1 -0
  378. package/dist/utils/constants.js +28 -0
  379. package/dist/utils/constants.js.map +1 -0
  380. package/dist/utils/machine-id.d.ts +7 -0
  381. package/dist/utils/machine-id.d.ts.map +1 -0
  382. package/dist/utils/machine-id.js +76 -0
  383. package/dist/utils/machine-id.js.map +1 -0
  384. package/dist/utils/server-startup.d.ts +11 -0
  385. package/dist/utils/server-startup.d.ts.map +1 -0
  386. package/dist/utils/server-startup.js +9 -0
  387. package/dist/utils/server-startup.js.map +1 -0
  388. package/dist/utils/update-check.d.ts +13 -0
  389. package/dist/utils/update-check.d.ts.map +1 -0
  390. package/dist/utils/update-check.js +90 -0
  391. package/dist/utils/update-check.js.map +1 -0
  392. package/dist/web/assets/ArchivedCardPrototype-S9ifiasa.js +5 -0
  393. package/dist/web/assets/BannerGallery-B__rJV6F.js +1 -0
  394. package/dist/web/assets/BannerPrototype-DBKP9Uiu.js +52 -0
  395. package/dist/web/assets/CodeHikeExperiment-B8jjWAFy.js +15 -0
  396. package/dist/web/assets/ContextTooltipVariations-DzklAFam.js +1 -0
  397. package/dist/web/assets/FontShowcasePrototype-KIMEWeP2.js +13 -0
  398. package/dist/web/assets/GeometricGallery-DddlWhHK.js +1 -0
  399. package/dist/web/assets/HistoryWalkthroughPrototype-DeniRRdw.js +18 -0
  400. package/dist/web/assets/InlineWalkthroughPrototype-Csd5r_Hk.js +1 -0
  401. package/dist/web/assets/MarkButtonPrototype-CxhxE0RP.js +1 -0
  402. package/dist/web/assets/MenuStylesPrototype-D7neA6YM.js +1 -0
  403. package/dist/web/assets/MomentCardVariations-2GT7GyFn.js +1 -0
  404. package/dist/web/assets/MomentHeaderVariations-DhGEw4XC.js +1 -0
  405. package/dist/web/assets/NarrativeWalkthroughDemo-B5C566fu.js +389 -0
  406. package/dist/web/assets/OutcomeVariations-BrZfsVcs.js +1 -0
  407. package/dist/web/assets/PermissionPatternPickerPrototype-CBOhe2Me.js +1 -0
  408. package/dist/web/assets/PermissionPrototype-BcF-a5an.js +1 -0
  409. package/dist/web/assets/PipelineGallery-BJhyM0rx.js +1 -0
  410. package/dist/web/assets/ScopeHeaderPrototype-GD1HNfaO.js +1 -0
  411. package/dist/web/assets/ScopeHeaderStylesPrototype-aa4uNJJ1.js +1 -0
  412. package/dist/web/assets/ScrollycodingPrototype-CKW1bf72.js +70 -0
  413. package/dist/web/assets/SectionHeaderVariations-DM8vUwfj.js +1 -0
  414. package/dist/web/assets/SemanticGallery-CtQEo7St.js +1 -0
  415. package/dist/web/assets/SessionCardPrototype-CgHCIMHe.js +1 -0
  416. package/dist/web/assets/SessionSidebarVariations-DMQL3Azj.js +3 -0
  417. package/dist/web/assets/SessionStartPrototype-Cwsv01Rr.js +1 -0
  418. package/dist/web/assets/SmartMenuPrototype-Br37Qbs_.js +1 -0
  419. package/dist/web/assets/StyleGallery-rZgrploB.js +1 -0
  420. package/dist/web/assets/TimelineCardPrototype-lzPc5mhe.js +19 -0
  421. package/dist/web/assets/ToolbarPrototype-Dm4BNZra.js +1 -0
  422. package/dist/web/assets/TooltipExperiment-Dy8QzTIP.js +13 -0
  423. package/dist/web/assets/WalkthroughCTAPrototype-uHoovujd.js +1 -0
  424. package/dist/web/assets/WalkthroughHeaderVariations-Do7Di1g1.js +1 -0
  425. package/dist/web/assets/WalkthroughShowcase-sGmRoPoM.js +112 -0
  426. package/dist/web/assets/arrow-right-D46Nx1mC.js +1 -0
  427. package/dist/web/assets/brain-BXIZKtOZ.js +1 -0
  428. package/dist/web/assets/grid-3x3-Cb81B62m.js +1 -0
  429. package/dist/web/assets/main-B1fyog77.js +321 -0
  430. package/dist/web/assets/main-C2PK2Klg.css +1 -0
  431. package/dist/web/assets/semantic-variations-Bd-W7ea2.js +1 -0
  432. package/dist/web/assets/target-Cf92wDTW.js +1 -0
  433. package/dist/web/favicon.png +0 -0
  434. package/dist/web/favicon.svg +22 -0
  435. package/dist/web/icon-192x192.png +0 -0
  436. package/dist/web/icon-512x512.png +0 -0
  437. package/dist/web/index.html +45 -0
  438. package/dist/web/manifest.json +61 -0
  439. package/package.json +192 -0
  440. package/scripts/postinstall.js +60 -0
@@ -0,0 +1,969 @@
1
+ import express from 'express';
2
+ import * as path from 'path';
3
+ import { fileURLToPath } from 'url';
4
+ import { dirname } from 'path';
5
+ import { displayServerStartup } from './utils/server-startup.js';
6
+ // Get the directory of this module for serving static files
7
+ const __filename = fileURLToPath(import.meta.url);
8
+ const __dirname = dirname(__filename);
9
+ import { createProcessManager } from './services/process/process-manager-factory.js';
10
+ import { StreamManager } from './services/infrastructure/stream-manager.js';
11
+ import { ClaudeHistoryReader } from './services/sessions/claude-history-reader.js';
12
+ import { PermissionTracker } from './services/permission-tracker.js';
13
+ import { QuestionTracker } from './services/question-tracker.js';
14
+ import { PendingQuestionService } from './services/pending-question-service.js';
15
+ import { MCPConfigGenerator } from './services/mcp-config-generator.js';
16
+ import { FileSystemService } from './services/infrastructure/file-system-service.js';
17
+ import { ConfigService } from './services/infrastructure/config-service.js';
18
+ import { SessionInfoService } from './services/sessions/session-info-service.js';
19
+ import { ConversationStatusManager } from './services/process/conversation-status-manager.js';
20
+ import { WorkingDirectoriesService } from './services/working-directories-service.js';
21
+ import { ToolMetricsService } from './services/ToolMetricsService.js';
22
+ import { NotificationService } from './services/notification-service.js';
23
+ import { WebPushService } from './services/web-push-service.js';
24
+ import { geminiService } from './services/gemini-service.js';
25
+ import { anthropicService } from './services/insights/anthropic-service.js';
26
+ import { ClaudeRouterService } from './services/claude-router-service.js';
27
+ import { LatticeError } from './types/index.js';
28
+ import { createLogger } from './services/infrastructure/logger.js';
29
+ import { createConversationRoutes } from './routes/conversation.routes.js';
30
+ import { createSystemRoutes } from './routes/system.routes.js';
31
+ import { createPermissionRoutes } from './routes/permission.routes.js';
32
+ import { createQuestionRoutes } from './routes/question.routes.js';
33
+ import { createPendingQuestionRoutes } from './routes/pending-question.routes.js';
34
+ import { createFileSystemRoutes } from './routes/filesystem.routes.js';
35
+ import { createLogRoutes } from './routes/log.routes.js';
36
+ import { createStreamingRoutes } from './routes/streaming.routes.js';
37
+ import { createWorkingDirectoriesRoutes } from './routes/working-directories.routes.js';
38
+ import { createConfigRoutes } from './routes/config.routes.js';
39
+ import { createInsightsRoutes } from './routes/insights.routes.js';
40
+ import { createLatticeRoutes } from './routes/lattice.routes.js';
41
+ import { LatticeService } from './services/lattice-service.js';
42
+ import { TurnCaptureService } from './services/sessions/turn-capture-service.js';
43
+ import { createLicenseRoutes } from './routes/license.routes.js';
44
+ import { createAnalysisRoutes } from './routes/analysis.routes.js';
45
+ import { createWalkthroughRoutes } from './routes/walkthrough.routes.js';
46
+ import { createPrototypeRoutes } from './routes/prototype.routes.js';
47
+ import processEventsRouter from './routes/process-events.routes.js';
48
+ import { errorHandler } from './middleware/error-handler.js';
49
+ import { requestLogger } from './middleware/request-logger.js';
50
+ import { createCorsMiddleware } from './middleware/cors-setup.js';
51
+ import { queryParser } from './middleware/query-parser.js';
52
+ import { checkForUpdatesOnStartup } from './utils/update-check.js';
53
+ import { registerStateProvider, startPeriodicStateLogging } from './services/connection-debug-logger.js';
54
+ import { serviceRegistry } from './services/infrastructure/service-registry.js';
55
+ // ViteExpress will be imported dynamically in initialize() if needed
56
+ let ViteExpress;
57
+ /**
58
+ * Main CUI server class
59
+ */
60
+ export class LatticeServer {
61
+ app;
62
+ server;
63
+ processManager; // Initialized in initialize()
64
+ streamManager;
65
+ historyReader;
66
+ permissionTracker;
67
+ questionTracker;
68
+ pendingQuestionService;
69
+ mcpConfigGenerator;
70
+ fileSystemService;
71
+ configService;
72
+ sessionInfoService;
73
+ conversationStatusManager;
74
+ workingDirectoriesService;
75
+ toolMetricsService;
76
+ notificationService;
77
+ webPushService;
78
+ routerService;
79
+ turnCaptureService;
80
+ logger;
81
+ port;
82
+ host;
83
+ configOverrides;
84
+ orphanCleanupInterval;
85
+ constructor(configOverrides) {
86
+ this.app = express();
87
+ this.configOverrides = configOverrides;
88
+ this.logger = createLogger('LatticeServer');
89
+ // TEST: Add debug log right at the start
90
+ this.logger.debug('🔍 TEST: LatticeServer constructor started - this should be visible if debug logging works');
91
+ // Initialize config service first
92
+ this.configService = ConfigService.getInstance();
93
+ // Will be set after config is loaded
94
+ this.port = 0;
95
+ this.host = '';
96
+ this.logger.debug('Initializing LatticeServer', {
97
+ nodeEnv: process.env.NODE_ENV,
98
+ configOverrides
99
+ });
100
+ // Initialize services
101
+ this.logger.debug('Initializing services');
102
+ // Use singleton to ensure event handlers get the same initialized instance
103
+ this.sessionInfoService = SessionInfoService.getInstance();
104
+ this.historyReader = new ClaudeHistoryReader(this.sessionInfoService);
105
+ this.conversationStatusManager = new ConversationStatusManager();
106
+ this.toolMetricsService = new ToolMetricsService();
107
+ this.fileSystemService = new FileSystemService();
108
+ // processManager is initialized in initialize() to support daemon mode
109
+ this.streamManager = new StreamManager();
110
+ this.permissionTracker = new PermissionTracker();
111
+ this.questionTracker = new QuestionTracker();
112
+ this.pendingQuestionService = PendingQuestionService.getInstance();
113
+ this.mcpConfigGenerator = new MCPConfigGenerator(this.fileSystemService);
114
+ this.workingDirectoriesService = new WorkingDirectoriesService(this.historyReader, this.logger);
115
+ this.notificationService = new NotificationService();
116
+ this.webPushService = WebPushService.getInstance();
117
+ this.turnCaptureService = TurnCaptureService.getInstance();
118
+ // Wire up services that don't depend on processManager
119
+ this.permissionTracker.setNotificationService(this.notificationService);
120
+ this.permissionTracker.setConversationStatusManager(this.conversationStatusManager);
121
+ this.permissionTracker.setHistoryReader(this.historyReader);
122
+ this.logger.debug('Services initialized (processManager deferred to initialize())');
123
+ this.setupMiddleware();
124
+ // Routes and processManager integration are set up in initialize()
125
+ }
126
+ /**
127
+ * Get the Express app instance
128
+ */
129
+ getApp() {
130
+ return this.app;
131
+ }
132
+ /**
133
+ * Get the configured port
134
+ */
135
+ getPort() {
136
+ return this.port;
137
+ }
138
+ /**
139
+ * Get the configured host
140
+ */
141
+ getHost() {
142
+ return this.host;
143
+ }
144
+ /**
145
+ * Initialize services without starting the HTTP server
146
+ */
147
+ async initialize() {
148
+ this.logger.debug('Initialize method called');
149
+ try {
150
+ // =========================================================================
151
+ // PHASE 1: Register services with dependency graph
152
+ // This declares the initialization order - actual init happens below
153
+ // =========================================================================
154
+ serviceRegistry.register('ConfigService');
155
+ serviceRegistry.register('SessionInfoService', { dependsOn: ['ConfigService'] });
156
+ serviceRegistry.register('PendingQuestionService', { dependsOn: ['SessionInfoService'] });
157
+ serviceRegistry.register('ProcessManager', { dependsOn: ['SessionInfoService'] });
158
+ serviceRegistry.register('GeminiService', { dependsOn: ['ConfigService'] });
159
+ serviceRegistry.register('AnthropicService', { dependsOn: ['ConfigService'] });
160
+ serviceRegistry.register('CostTracker', { dependsOn: ['ConfigService'] });
161
+ serviceRegistry.register('InsightsCoordinator', {
162
+ dependsOn: ['SessionInfoService', 'AnthropicService']
163
+ });
164
+ // =========================================================================
165
+ // PHASE 2: Initialize services in dependency order
166
+ // =========================================================================
167
+ // Initialize configuration first
168
+ this.logger.debug('Initializing configuration');
169
+ await this.configService.initialize();
170
+ serviceRegistry.markInitialized('ConfigService');
171
+ // Set the invocation cwd if provided via CLI
172
+ if (this.configOverrides?.cwd) {
173
+ this.configService.setInvocationCwd(this.configOverrides.cwd);
174
+ }
175
+ const config = this.configService.getConfig();
176
+ // Initialize session info service
177
+ this.logger.debug('Initializing session info service');
178
+ await this.sessionInfoService.initialize();
179
+ serviceRegistry.markInitialized('SessionInfoService');
180
+ this.logger.debug('Session info service initialized successfully');
181
+ // Initialize pending question service (uses same DB as session info)
182
+ this.logger.debug('Initializing pending question service');
183
+ await this.pendingQuestionService.initialize();
184
+ serviceRegistry.markInitialized('PendingQuestionService');
185
+ this.logger.debug('Pending question service initialized successfully');
186
+ // Initialize process manager (skip if already set, e.g. by tests)
187
+ if (!this.processManager) {
188
+ this.logger.debug('Initializing process manager');
189
+ this.processManager = await createProcessManager({
190
+ historyReader: this.historyReader,
191
+ statusTracker: this.conversationStatusManager,
192
+ toolMetricsService: this.toolMetricsService,
193
+ sessionInfoService: this.sessionInfoService,
194
+ fileSystemService: this.fileSystemService
195
+ });
196
+ }
197
+ else {
198
+ this.logger.debug('Process manager already set, skipping initialization');
199
+ }
200
+ this.processManager.setNotificationService(this.notificationService);
201
+ this.processManager.setConversationStatusManager(this.conversationStatusManager);
202
+ // Set up event listeners now that processManager exists
203
+ this.setupProcessManagerIntegration();
204
+ this.setupPermissionTrackerIntegration();
205
+ this.setupQuestionTrackerIntegration();
206
+ serviceRegistry.markInitialized('ProcessManager');
207
+ this.logger.debug('Process manager initialized successfully');
208
+ this.logger.debug('Initializing Gemini service');
209
+ await geminiService.initialize();
210
+ serviceRegistry.markInitialized('GeminiService');
211
+ this.logger.debug('Gemini service initialized successfully');
212
+ this.logger.debug('Initializing Anthropic service');
213
+ await anthropicService.initialize();
214
+ serviceRegistry.markInitialized('AnthropicService');
215
+ this.logger.debug('Anthropic service initialized successfully');
216
+ // Initialize cost tracker for LLM usage monitoring
217
+ this.logger.debug('Initializing cost tracker');
218
+ const { getCostTracker } = await import('./services/infrastructure/cost-tracker.js');
219
+ await getCostTracker().initialize();
220
+ serviceRegistry.markInitialized('CostTracker');
221
+ this.logger.debug('Cost tracker initialized successfully');
222
+ // Initialize insights coordinator (unified event-driven system)
223
+ this.logger.debug('Initializing insights coordinator');
224
+ const { initializeInsightsCoordinator, getInsightsCoordinator } = await import('./services/insights/insights-coordinator.js');
225
+ initializeInsightsCoordinator();
226
+ serviceRegistry.markInitialized('InsightsCoordinator');
227
+ // Wire up session-ended to expedite insight patches
228
+ this.conversationStatusManager.on('session-ended', ({ claudeSessionId }) => {
229
+ // handleSessionEnded is async - fire and forget but log errors
230
+ getInsightsCoordinator().handleSessionEnded(claudeSessionId).catch(err => {
231
+ this.logger.error('Failed to handle session ended for insights', {
232
+ sessionId: claudeSessionId.slice(0, 8),
233
+ error: err.message
234
+ });
235
+ });
236
+ });
237
+ this.logger.debug('Insights coordinator initialized successfully');
238
+ // Initialize router service if configured
239
+ await this.initializeOrReloadRouter(config);
240
+ // Apply overrides if provided (for tests and CLI options)
241
+ this.port = this.configOverrides?.port ?? config.server.port;
242
+ this.host = this.configOverrides?.host ?? config.server.host;
243
+ this.logger.info('Configuration loaded', {
244
+ machineId: config.machine_id,
245
+ port: this.port,
246
+ host: this.host,
247
+ overrides: this.configOverrides ? Object.keys(this.configOverrides) : []
248
+ });
249
+ // Set up routes after services are initialized
250
+ // This allows tests to override services before routes are created
251
+ this.logger.debug('Setting up routes');
252
+ this.setupRoutes();
253
+ // Register connection state provider for debug logging
254
+ const conversationStatusManager = this.conversationStatusManager;
255
+ const streamManager = this.streamManager;
256
+ const processManager = this.processManager;
257
+ registerStateProvider({
258
+ getConnectionState: () => ({
259
+ conversationStatusManager: {
260
+ activeSessions: conversationStatusManager.getStats().activeSessions,
261
+ },
262
+ streamManager: {
263
+ activeSessions: streamManager.getActiveSessions(),
264
+ clientCounts: Object.fromEntries(streamManager.getActiveSessions().map(s => [s, streamManager.getClientCount(s)])),
265
+ },
266
+ processManager: {
267
+ activeSessions: processManager.getActiveSessions(),
268
+ },
269
+ }),
270
+ });
271
+ startPeriodicStateLogging(30000); // Check every 30 seconds
272
+ // Generate MCP config before starting server
273
+ try {
274
+ const mcpConfigPath = await this.mcpConfigGenerator.generateConfig(this.port);
275
+ this.processManager.setMCPConfigPath(mcpConfigPath);
276
+ this.logger.debug('MCP config generated and set', { path: mcpConfigPath });
277
+ }
278
+ catch (error) {
279
+ const isNonProduction = process.env.NODE_ENV === 'test' || process.env.NODE_ENV === 'development';
280
+ if (isNonProduction) {
281
+ this.logger.warn('MCP config generation failed in non-production environment, proceeding without MCP', {
282
+ error: error instanceof Error ? error.message : String(error),
283
+ nodeEnv: process.env.NODE_ENV
284
+ });
285
+ // Don't set MCP config path - conversations will run without MCP
286
+ }
287
+ else {
288
+ this.logger.error('MCP config generation failed in production environment', {
289
+ error: error instanceof Error ? error.message : String(error)
290
+ });
291
+ throw new LatticeError('MCP_CONFIG_REQUIRED', `MCP server files are required in production but not found: ${error instanceof Error ? error.message : String(error)}`, 500);
292
+ }
293
+ }
294
+ // Subscribe to configuration changes to hot-reload router when needed
295
+ this.configService.onChange(async (newConfig) => {
296
+ try {
297
+ await this.initializeOrReloadRouter(newConfig);
298
+ }
299
+ catch (error) {
300
+ this.logger.error('Failed to reload router after config change', error);
301
+ }
302
+ });
303
+ // Check for updates (non-blocking, just logs if update available)
304
+ checkForUpdatesOnStartup();
305
+ }
306
+ catch (error) {
307
+ this.logger.error('Failed to initialize server:', error, {
308
+ errorType: error instanceof Error ? error.constructor.name : typeof error,
309
+ errorMessage: error instanceof Error ? error.message : String(error)
310
+ });
311
+ if (error instanceof LatticeError) {
312
+ throw error;
313
+ }
314
+ else {
315
+ throw new LatticeError('SERVER_INIT_FAILED', `Server initialization failed: ${error}`, 500);
316
+ }
317
+ }
318
+ }
319
+ /**
320
+ * Start the server
321
+ */
322
+ async start() {
323
+ this.logger.debug('Start method called');
324
+ try {
325
+ // Initialize all services
326
+ await this.initialize();
327
+ // Start Express server
328
+ const isDev = process.env.NODE_ENV === 'development';
329
+ this.logger.debug('Creating HTTP server listener', {
330
+ useViteExpress: isDev,
331
+ environment: process.env.NODE_ENV
332
+ });
333
+ // Import ViteExpress dynamically if in development mode
334
+ if (isDev && !ViteExpress) {
335
+ const viteExpressModule = await import('vite-express');
336
+ ViteExpress = viteExpressModule.default;
337
+ }
338
+ await new Promise((resolve, reject) => {
339
+ // Use ViteExpress only in development
340
+ if (isDev && ViteExpress) {
341
+ try {
342
+ this.server = this.app.listen(this.port, this.host, () => {
343
+ this.logger.debug('Server successfully bound to port (dev mode)', {
344
+ port: this.port,
345
+ host: this.host,
346
+ address: this.server?.address()
347
+ });
348
+ // Display startup info now that server is actually listening
349
+ displayServerStartup({
350
+ host: this.host,
351
+ port: this.port,
352
+ logger: this.logger
353
+ });
354
+ // Configure and bind ViteExpress AFTER server is listening
355
+ ViteExpress.config({
356
+ mode: 'development',
357
+ viteConfigFile: 'vite.config.mts'
358
+ });
359
+ ViteExpress.bind(this.app, this.server);
360
+ this.logger.info(`CUI development server running on http://${this.host}:${this.port}`);
361
+ resolve();
362
+ });
363
+ }
364
+ catch (error) {
365
+ this.logger.error('Failed to start ViteExpress server', error);
366
+ reject(error);
367
+ }
368
+ }
369
+ else {
370
+ // Production/test mode - regular Express server
371
+ this.server = this.app.listen(this.port, this.host, () => {
372
+ this.logger.debug('Server successfully bound to port', {
373
+ port: this.port,
374
+ host: this.host,
375
+ address: this.server?.address(),
376
+ mode: process.env.NODE_ENV || 'production'
377
+ });
378
+ // Display startup info now that server is actually listening
379
+ displayServerStartup({
380
+ host: this.host,
381
+ port: this.port,
382
+ logger: this.logger
383
+ });
384
+ resolve();
385
+ });
386
+ }
387
+ if (this.server) {
388
+ this.server.on('error', (error) => {
389
+ this.logger.error('Failed to start HTTP server:', error, {
390
+ errorCode: error.code,
391
+ errorSyscall: error.syscall,
392
+ port: this.port,
393
+ host: this.host
394
+ });
395
+ reject(new LatticeError('HTTP_SERVER_START_FAILED', `Failed to start HTTP server: ${error.message}`, 500));
396
+ });
397
+ }
398
+ });
399
+ }
400
+ catch (error) {
401
+ this.logger.error('Failed to start server:', error, {
402
+ errorType: error instanceof Error ? error.constructor.name : typeof error,
403
+ errorMessage: error instanceof Error ? error.message : String(error)
404
+ });
405
+ // Attempt cleanup on startup failure
406
+ await this.cleanup();
407
+ if (error instanceof LatticeError) {
408
+ throw error;
409
+ }
410
+ else {
411
+ throw new LatticeError('SERVER_START_FAILED', `Server startup failed: ${error}`, 500);
412
+ }
413
+ }
414
+ }
415
+ /**
416
+ * Stop the server gracefully
417
+ */
418
+ async stop() {
419
+ this.logger.debug('Stop method called', {
420
+ hasServer: !!this.server,
421
+ activeSessions: this.processManager.getActiveSessions().length,
422
+ connectedClients: this.streamManager.getTotalClientCount()
423
+ });
424
+ if (this.routerService) {
425
+ await this.routerService.stop();
426
+ }
427
+ // Stop all active Claude processes (only in direct mode - daemon keeps them alive)
428
+ if (this.processManager.mode === 'direct') {
429
+ const activeSessions = this.processManager.getActiveSessions();
430
+ if (activeSessions.length > 0) {
431
+ this.logger.info(`Stopping ${activeSessions.length} active sessions...`);
432
+ this.logger.debug('Active sessions to stop', { sessionIds: activeSessions });
433
+ const stopResults = await Promise.allSettled(activeSessions.map(streamingId => this.processManager.stopConversation(streamingId)
434
+ .catch(error => this.logger.error(`Error stopping session ${streamingId}:`, error))));
435
+ this.logger.debug('Session stop results', {
436
+ total: stopResults.length,
437
+ fulfilled: stopResults.filter(r => r.status === 'fulfilled').length,
438
+ rejected: stopResults.filter(r => r.status === 'rejected').length
439
+ });
440
+ }
441
+ }
442
+ else {
443
+ this.logger.info('Daemon mode: keeping Claude processes alive through restart');
444
+ }
445
+ // Stop orphan cleanup interval
446
+ if (this.orphanCleanupInterval) {
447
+ clearInterval(this.orphanCleanupInterval);
448
+ this.orphanCleanupInterval = undefined;
449
+ }
450
+ // Disconnect from daemon to stop reconnection loop
451
+ this.processManager.disconnect();
452
+ // Disconnect all streaming clients (sends close events and ends responses)
453
+ this.logger.debug('Disconnecting all streaming clients');
454
+ this.streamManager.disconnectAll();
455
+ // Clean up MCP config
456
+ this.logger.debug('Cleaning up MCP config');
457
+ this.mcpConfigGenerator.cleanup();
458
+ // Close HTTP server to release port
459
+ if (this.server) {
460
+ this.logger.debug('Closing HTTP server');
461
+ // Force close all connections after ending SSE streams
462
+ // This ensures we don't wait for clients that haven't acknowledged the close
463
+ if (typeof this.server.closeAllConnections === 'function') {
464
+ this.server.closeAllConnections();
465
+ }
466
+ // Close with timeout - don't block shutdown forever
467
+ await new Promise((resolve) => {
468
+ const timeout = setTimeout(() => {
469
+ this.logger.warn('HTTP server close timed out after 2s, forcing shutdown');
470
+ resolve();
471
+ }, 2000);
472
+ this.server.close(() => {
473
+ clearTimeout(timeout);
474
+ this.logger.info('HTTP server closed successfully');
475
+ resolve();
476
+ });
477
+ });
478
+ }
479
+ }
480
+ /**
481
+ * Cleanup resources during failed startup
482
+ */
483
+ async cleanup() {
484
+ this.logger.info('Performing cleanup after startup failure...');
485
+ this.logger.debug('Cleanup initiated', {
486
+ hasServer: !!this.server,
487
+ hasActiveStreams: this.streamManager.getTotalClientCount() > 0
488
+ });
489
+ try {
490
+ // Close HTTP server if it was started
491
+ if (this.server) {
492
+ await new Promise((resolve) => {
493
+ this.server.close(() => {
494
+ this.logger.info('HTTP server closed during cleanup');
495
+ resolve();
496
+ });
497
+ });
498
+ }
499
+ // Disconnect streaming clients
500
+ this.streamManager.disconnectAll();
501
+ this.logger.info('Cleanup completed');
502
+ }
503
+ catch (error) {
504
+ this.logger.error('Error during cleanup:', error, {
505
+ errorType: error instanceof Error ? error.constructor.name : typeof error
506
+ });
507
+ }
508
+ }
509
+ setupMiddleware() {
510
+ this.app.use(createCorsMiddleware());
511
+ this.app.use(express.json({ limit: '10mb' }));
512
+ // Static file serving
513
+ const isDev = process.env.NODE_ENV === 'development';
514
+ if (!isDev) {
515
+ // In production/test, serve built static files
516
+ // In production, __dirname will be /path/to/node_modules/cui-server/dist
517
+ // We need to serve from dist/web
518
+ const staticPath = path.join(__dirname, 'web');
519
+ this.logger.debug('Serving static files from', { path: staticPath });
520
+ this.app.use(express.static(staticPath));
521
+ }
522
+ // In development, ViteExpress handles static file serving
523
+ // Request logging
524
+ this.app.use(requestLogger);
525
+ // Query parameter parsing - convert strings to proper types
526
+ this.app.use(queryParser);
527
+ }
528
+ setupRoutes() {
529
+ // System routes (includes health check) - before auth
530
+ this.app.use('/api/system', createSystemRoutes(this.processManager, this.historyReader, this.conversationStatusManager, this.streamManager));
531
+ this.app.use('/', createSystemRoutes(this.processManager, this.historyReader, this.conversationStatusManager, this.streamManager)); // For /health at root
532
+ // Permission routes (needed for MCP server communication)
533
+ this.app.use('/api/permissions', createPermissionRoutes(this.permissionTracker));
534
+ // API routes
535
+ // Insights routes first: has specific paths like /activity-check
536
+ // Conversation routes second: has /:sessionId catch-all that would match anything
537
+ this.app.use('/api/conversations', createInsightsRoutes(this.historyReader, this.sessionInfoService));
538
+ this.app.use('/api/conversations', createConversationRoutes(this.processManager, this.historyReader, this.conversationStatusManager, this.sessionInfoService, this.toolMetricsService));
539
+ this.app.use('/api/filesystem', createFileSystemRoutes(this.fileSystemService));
540
+ this.app.use('/api/logs', createLogRoutes());
541
+ this.app.use('/api/stream', createStreamingRoutes(this.streamManager));
542
+ this.app.use('/api/working-directories', createWorkingDirectoriesRoutes(this.workingDirectoriesService));
543
+ this.app.use('/api/config', createConfigRoutes(this.configService));
544
+ this.app.use('/api/questions', createQuestionRoutes(this.questionTracker, this.processManager));
545
+ this.app.use('/api/pending-questions', createPendingQuestionRoutes(this.pendingQuestionService, this.processManager, this.historyReader));
546
+ // Lattice orchestrator routes
547
+ const latticeService = LatticeService.getInstance({
548
+ processManager: this.processManager,
549
+ historyReader: this.historyReader,
550
+ statusManager: this.conversationStatusManager
551
+ });
552
+ this.app.use('/api/lattice', createLatticeRoutes(latticeService));
553
+ // License routes
554
+ this.app.use('/api/license', createLicenseRoutes());
555
+ // Post-session analysis routes
556
+ this.app.use('/api/analysis', createAnalysisRoutes());
557
+ // Walkthrough generation routes
558
+ this.app.use('/api/walkthrough', createWalkthroughRoutes({
559
+ historyReader: this.historyReader,
560
+ processManager: this.processManager,
561
+ streamManager: this.streamManager,
562
+ conversationStatusManager: this.conversationStatusManager,
563
+ }));
564
+ // Process event log routes (observability)
565
+ this.app.use('/api/process-events', processEventsRouter);
566
+ // Prototype routes (experimental features)
567
+ this.app.use('/api/prototype', createPrototypeRoutes());
568
+ // React Router catch-all - must be after all API routes
569
+ const isDev = process.env.NODE_ENV === 'development';
570
+ if (!isDev) {
571
+ // In production/test, serve index.html for all non-API routes
572
+ this.app.get('*', (req, res) => {
573
+ res.sendFile(path.join(__dirname, 'web', 'index.html'));
574
+ });
575
+ }
576
+ // In development, ViteExpress handles React routing
577
+ // Error handling - MUST be last
578
+ this.app.use(errorHandler);
579
+ }
580
+ setupProcessManagerIntegration() {
581
+ this.logger.debug('Setting up ProcessManager integration with StreamManager');
582
+ // Set up tool metrics service to listen to claude messages
583
+ this.toolMetricsService.listenToClaudeMessages(this.processManager);
584
+ // Local map to track streamingId -> sessionId (populated from system_init messages)
585
+ // This is a simple, reliable source of truth that doesn't depend on external services
586
+ const streamingSessionMap = new Map();
587
+ // Repopulate from daemon's active sessions on server restart
588
+ // This handles the case where the server restarts while sessions are still running
589
+ const existingMappings = this.processManager.getActiveSessionMappings();
590
+ for (const { streamingId, sessionId } of existingMappings) {
591
+ streamingSessionMap.set(streamingId, sessionId);
592
+ }
593
+ if (existingMappings.length > 0) {
594
+ this.logger.info('[SESSION-MAP] Repopulated from daemon active sessions', {
595
+ count: existingMappings.length,
596
+ mappings: existingMappings.map(m => ({
597
+ streamingId: m.streamingId.slice(0, 8),
598
+ sessionId: m.sessionId.slice(0, 8)
599
+ }))
600
+ });
601
+ }
602
+ // Start buffering events when a process spawns
603
+ // This handles the race condition where events are broadcast before the SSE client connects
604
+ this.processManager.on('process-spawned', ({ streamingId }) => {
605
+ this.logger.info('[BUFFERING] Process spawned, starting event buffering', { streamingId: streamingId.slice(0, 8) });
606
+ this.streamManager.startBuffering(streamingId);
607
+ });
608
+ // Forward Claude messages to stream
609
+ this.processManager.on('claude-message', ({ streamingId, message }) => {
610
+ this.logger.debug('Received claude-message event', {
611
+ streamingId,
612
+ messageType: message?.type,
613
+ messageSubtype: message?.subtype,
614
+ hasContent: !!message?.content,
615
+ contentLength: message?.content?.length || 0,
616
+ messageKeys: message ? Object.keys(message) : []
617
+ });
618
+ // Capture sessionId from system init messages (this is our source of truth)
619
+ if (message && message.type === 'system' && message.subtype === 'init' && message.session_id) {
620
+ streamingSessionMap.set(streamingId, message.session_id);
621
+ this.logger.info('[SESSION-MAP] Captured sessionId from system_init', {
622
+ streamingId: streamingId.slice(0, 8),
623
+ sessionId: message.session_id.slice(0, 8),
624
+ mapSize: streamingSessionMap.size
625
+ });
626
+ }
627
+ // Skip broadcasting system init messages as they're now included in API response
628
+ if (message && message.type === 'system' && message.subtype === 'init') {
629
+ this.logger.debug('Skipping broadcast of system init message (included in API response)', {
630
+ streamingId,
631
+ sessionId: message.session_id
632
+ });
633
+ return;
634
+ }
635
+ // Detect AskUserQuestion tool_use and register with QuestionTracker + persist to DB
636
+ // Debug: log all assistant messages to see what structure we're getting
637
+ if (message && message.type === 'assistant') {
638
+ this.logger.debug('Assistant message received', {
639
+ streamingId,
640
+ hasMessage: !!message.message,
641
+ hasContent: !!message.message?.content,
642
+ contentIsArray: Array.isArray(message.message?.content),
643
+ contentLength: Array.isArray(message.message?.content) ? message.message.content.length : 0
644
+ });
645
+ }
646
+ if (message && message.type === 'assistant' && message.message?.content) {
647
+ const content = message.message.content;
648
+ if (Array.isArray(content)) {
649
+ for (const block of content) {
650
+ // Debug: log each block to see tool_use blocks
651
+ if (block.type === 'tool_use') {
652
+ this.logger.info('Tool use block detected', {
653
+ streamingId,
654
+ toolName: block.name,
655
+ blockId: block.id
656
+ });
657
+ }
658
+ if (block.type === 'tool_use' && block.name === 'AskUserQuestion') {
659
+ // Debug: log session state when AskUserQuestion arrives
660
+ const activeSessions = this.conversationStatusManager.getActiveSessionIds();
661
+ this.logger.info('AskUserQuestion detected - checking session state', {
662
+ incomingStreamingId: streamingId,
663
+ activeSessions,
664
+ activeCount: activeSessions.length
665
+ });
666
+ const input = block.input;
667
+ if (input.questions) {
668
+ // Add to in-memory tracker (for active session UI)
669
+ const questionRequest = this.questionTracker.addQuestionRequest(block.id, input.questions, streamingId);
670
+ // Persist to DB (for recovery after timeout/disconnect)
671
+ // Use local streamingSessionMap as primary source (populated from system_init)
672
+ // Fall back to other sources if needed
673
+ let claudeSessionId = streamingSessionMap.get(streamingId);
674
+ if (!claudeSessionId) {
675
+ claudeSessionId = this.conversationStatusManager.getSessionId(streamingId);
676
+ if (claudeSessionId) {
677
+ this.logger.debug('Using conversationStatusManager sessionId fallback', { streamingId, claudeSessionId });
678
+ }
679
+ }
680
+ if (!claudeSessionId) {
681
+ claudeSessionId = this.processManager.getClaudeSessionId(streamingId);
682
+ if (claudeSessionId) {
683
+ this.logger.debug('Using processManager sessionId fallback', { streamingId, claudeSessionId });
684
+ }
685
+ }
686
+ if (claudeSessionId) {
687
+ this.pendingQuestionService.addQuestion(questionRequest.id, claudeSessionId, streamingId, block.id, input.questions);
688
+ this.logger.info('AskUserQuestion persisted for recovery', {
689
+ questionId: questionRequest.id,
690
+ sessionId: claudeSessionId,
691
+ streamingId,
692
+ questionCount: input.questions.length
693
+ });
694
+ // Stop the session immediately to prevent Claude from continuing
695
+ // The session will be resumed when the user answers the question
696
+ this.logger.info('Stopping session to await user answer', { streamingId, claudeSessionId });
697
+ this.processManager.stopConversation(streamingId).catch((err) => {
698
+ this.logger.warn('Failed to stop session after AskUserQuestion', {
699
+ streamingId,
700
+ error: err instanceof Error ? err.message : String(err)
701
+ });
702
+ });
703
+ }
704
+ else {
705
+ this.logger.warn('AskUserQuestion NOT persisted - claudeSessionId not found for streamingId', {
706
+ questionId: questionRequest.id,
707
+ streamingId,
708
+ questionCount: input.questions.length,
709
+ activeSessionCount: this.conversationStatusManager.getActiveSessionIds().length
710
+ });
711
+ }
712
+ }
713
+ }
714
+ }
715
+ }
716
+ }
717
+ // Stream other Claude messages as normal
718
+ this.logger.debug('Broadcasting message to StreamManager', {
719
+ streamingId,
720
+ messageType: message?.type,
721
+ messageSubtype: message?.subtype
722
+ });
723
+ this.streamManager.broadcast(streamingId, message);
724
+ });
725
+ // Handle process closure
726
+ this.processManager.on('process-closed', ({ streamingId, code }) => {
727
+ // Derive termination reason from exit code
728
+ const terminationReason = code === 0 ? 'normal_completion' :
729
+ code === 143 ? 'user_stop' : // SIGTERM = 128 + 15
730
+ code === 137 ? 'force_killed' : // SIGKILL = 128 + 9
731
+ 'process_crash';
732
+ this.logger.info('[PROCESS-CLOSED] Received process-closed event', {
733
+ streamingId: streamingId.slice(0, 8),
734
+ exitCode: code,
735
+ terminationReason,
736
+ clientCount: this.streamManager.getClientCount(streamingId),
737
+ wasSuccessful: code === 0
738
+ });
739
+ // Capture turn BEFORE cleaning up (need sessionId from map)
740
+ // Use local streamingSessionMap as primary source (populated from system_init)
741
+ // Fall back to conversationStatusManager if map is empty (e.g., after server restart)
742
+ let sessionIdForTurn = streamingSessionMap.get(streamingId);
743
+ if (!sessionIdForTurn) {
744
+ sessionIdForTurn = this.conversationStatusManager.getSessionId(streamingId);
745
+ if (sessionIdForTurn) {
746
+ this.logger.debug('[TURN-CAPTURE] Used fallback sessionId from conversationStatusManager', {
747
+ streamingId: streamingId.slice(0, 8),
748
+ sessionId: sessionIdForTurn.slice(0, 8)
749
+ });
750
+ }
751
+ }
752
+ if (sessionIdForTurn) {
753
+ // Fire and forget - don't block cleanup on turn capture
754
+ this.turnCaptureService.captureTurn(sessionIdForTurn, code, terminationReason)
755
+ .then(turn => {
756
+ if (turn) {
757
+ // Emit SSE event for real-time UI updates
758
+ import('./services/sessions/session-activity-watcher.js').then(({ getSessionActivityWatcher }) => {
759
+ getSessionActivityWatcher().emitTurnCaptured({
760
+ sessionId: sessionIdForTurn,
761
+ turn: {
762
+ id: turn.id,
763
+ turnNumber: turn.turnNumber,
764
+ timestamp: turn.timestamp,
765
+ headline: turn.headline,
766
+ actions: turn.actions,
767
+ tag: turn.tag,
768
+ icon: turn.icon,
769
+ toolCount: turn.toolCount,
770
+ }
771
+ });
772
+ });
773
+ }
774
+ })
775
+ .catch(err => {
776
+ this.logger.debug('Turn capture failed (non-blocking)', { error: err });
777
+ });
778
+ }
779
+ else {
780
+ this.logger.warn('[TURN-CAPTURE] Could not find sessionId for turn capture', {
781
+ streamingId: streamingId.slice(0, 8),
782
+ exitCode: code,
783
+ terminationReason,
784
+ mapSize: streamingSessionMap.size
785
+ });
786
+ }
787
+ // Check for pending questions BEFORE unregistering (we need the sessionId mapping)
788
+ // If there are pending questions, this was likely an AskUserQuestion timeout
789
+ const pendingQuestions = this.pendingQuestionService.getPendingByStreamingId(streamingId);
790
+ if (pendingQuestions.length > 0) {
791
+ this.logger.info('Session closed with pending AskUserQuestion - questions preserved for later resume', {
792
+ streamingId,
793
+ pendingQuestionCount: pendingQuestions.length,
794
+ questionIds: pendingQuestions.map(q => q.id)
795
+ });
796
+ // Questions remain in DB with status='pending' for later retrieval
797
+ // The in-memory tracker will be cleaned up below, but DB persists
798
+ }
799
+ // Clean up local session map
800
+ streamingSessionMap.delete(streamingId);
801
+ // Unregister session from status tracker
802
+ this.logger.debug('Unregistering session from status tracker', { streamingId });
803
+ this.conversationStatusManager.unregisterActiveSession(streamingId);
804
+ // Clean up conversation context (handled automatically in unregisterActiveSession)
805
+ // Clean up permissions for this streaming session
806
+ const removedCount = this.permissionTracker.removePermissionsByStreamingId(streamingId);
807
+ if (removedCount > 0) {
808
+ this.logger.debug('Cleaned up permissions for closed session', {
809
+ streamingId,
810
+ removedPermissions: removedCount
811
+ });
812
+ }
813
+ // Check for in-memory questions BEFORE removing them
814
+ // If there are pending questions, we need to keep them for error suppression
815
+ // They'll be cleaned up when answered or expired, not on session close
816
+ const inMemoryQuestions = this.questionTracker.getQuestionsByStreamingId(streamingId);
817
+ if (inMemoryQuestions.length > 0) {
818
+ this.logger.info('Preserving in-memory questions for error suppression (awaiting user answer)', {
819
+ streamingId,
820
+ inMemoryQuestionCount: inMemoryQuestions.length,
821
+ questionIds: inMemoryQuestions.map(q => q.id)
822
+ });
823
+ }
824
+ else {
825
+ // No pending questions - safe to clean up
826
+ const removedQuestions = this.questionTracker.removeQuestionsByStreamingId(streamingId);
827
+ if (removedQuestions > 0) {
828
+ this.logger.debug('Cleaned up in-memory questions for closed session', {
829
+ streamingId,
830
+ removedQuestions
831
+ });
832
+ }
833
+ }
834
+ this.streamManager.closeSession(streamingId);
835
+ });
836
+ // Handle process errors
837
+ this.processManager.on('process-error', ({ streamingId, error }) => {
838
+ this.logger.info('[PROCESS-ERROR] Received process-error event', {
839
+ streamingId: streamingId.slice(0, 8),
840
+ error: error?.toString().slice(0, 200),
841
+ clientCount: this.streamManager.getClientCount(streamingId)
842
+ });
843
+ // Check if there's a pending question for this streaming session
844
+ // If so, suppress the error - the session was intentionally stopped to wait for user answer
845
+ const pendingQuestions = this.questionTracker.getQuestionsByStreamingId(streamingId);
846
+ if (pendingQuestions.length > 0) {
847
+ this.logger.info('Suppressing process error due to pending AskUserQuestion', {
848
+ streamingId,
849
+ pendingQuestionCount: pendingQuestions.length,
850
+ questionIds: pendingQuestions.map(q => q.id)
851
+ });
852
+ // Still unregister the session but don't broadcast the error
853
+ this.conversationStatusManager.unregisterActiveSession(streamingId);
854
+ return;
855
+ }
856
+ // Unregister session from status tracker on error
857
+ this.logger.debug('Unregistering session from status tracker due to error', { streamingId });
858
+ this.conversationStatusManager.unregisterActiveSession(streamingId);
859
+ // Clean up conversation context on error (handled automatically in unregisterActiveSession)
860
+ const errorEvent = {
861
+ type: 'error',
862
+ error: error.toString(),
863
+ streamingId: streamingId,
864
+ timestamp: new Date().toISOString()
865
+ };
866
+ this.logger.debug('Broadcasting error event to clients', {
867
+ streamingId,
868
+ errorEventKeys: Object.keys(errorEvent)
869
+ });
870
+ this.streamManager.broadcast(streamingId, errorEvent);
871
+ });
872
+ // Start periodic cleanup of orphaned SSE sessions (every 60 seconds)
873
+ // This catches edge cases where process-closed event didn't fire or was missed
874
+ this.orphanCleanupInterval = setInterval(() => {
875
+ const activeProcessIds = new Set(this.processManager.getActiveSessions());
876
+ const cleaned = this.streamManager.cleanupOrphanedSessions(activeProcessIds);
877
+ if (cleaned > 0) {
878
+ this.logger.info('Periodic orphan cleanup removed stale SSE sessions', { count: cleaned });
879
+ }
880
+ }, 60_000);
881
+ this.logger.debug('ProcessManager integration setup complete', {
882
+ totalEventListeners: this.processManager.listenerCount('claude-message') +
883
+ this.processManager.listenerCount('process-closed') +
884
+ this.processManager.listenerCount('process-error')
885
+ });
886
+ }
887
+ setupPermissionTrackerIntegration() {
888
+ this.logger.debug('Setting up PermissionTracker integration');
889
+ // Forward permission events to stream
890
+ this.permissionTracker.on('permission_request', (request) => {
891
+ this.logger.debug('Permission request event received', {
892
+ id: request.id,
893
+ toolName: request.toolName,
894
+ streamingId: request.streamingId
895
+ });
896
+ // Broadcast to the appropriate streaming session
897
+ if (request.streamingId && request.streamingId !== 'unknown') {
898
+ const event = {
899
+ type: 'permission_request',
900
+ data: request,
901
+ streamingId: request.streamingId,
902
+ timestamp: new Date().toISOString()
903
+ };
904
+ this.streamManager.broadcast(request.streamingId, event);
905
+ }
906
+ });
907
+ this.logger.debug('PermissionTracker integration setup complete');
908
+ }
909
+ setupQuestionTrackerIntegration() {
910
+ this.logger.debug('Setting up QuestionTracker integration');
911
+ // Forward question events to stream
912
+ this.questionTracker.on('question_request', (request) => {
913
+ // Log at info level to diagnose question flow issues
914
+ this.logger.info('Question request event received, broadcasting to stream', {
915
+ id: request.id,
916
+ toolUseId: request.toolUseId,
917
+ streamingId: request.streamingId,
918
+ questionCount: request.questions.length,
919
+ clientCount: this.streamManager.getClientCount(request.streamingId)
920
+ });
921
+ // Broadcast to the appropriate streaming session
922
+ if (request.streamingId && request.streamingId !== 'unknown') {
923
+ const event = {
924
+ type: 'question_request',
925
+ data: request,
926
+ streamingId: request.streamingId,
927
+ timestamp: new Date().toISOString()
928
+ };
929
+ this.streamManager.broadcast(request.streamingId, event);
930
+ }
931
+ });
932
+ this.logger.debug('QuestionTracker integration setup complete');
933
+ }
934
+ async initializeOrReloadRouter(config) {
935
+ // If router is disabled, ensure it is stopped
936
+ if (!config.router?.enabled) {
937
+ if (this.routerService) {
938
+ this.logger.info('Router disabled in configuration, stopping router service');
939
+ await this.routerService.stop();
940
+ this.routerService = undefined;
941
+ this.processManager.setRouterService(undefined);
942
+ }
943
+ else {
944
+ this.logger.info('Router service is disabled');
945
+ }
946
+ return;
947
+ }
948
+ // If router is enabled
949
+ try {
950
+ // If there is an existing router, stop it first
951
+ if (this.routerService) {
952
+ this.logger.info('Reloading router service due to configuration change...');
953
+ await this.routerService.stop();
954
+ this.routerService = undefined;
955
+ }
956
+ else {
957
+ this.logger.debug('Router service is enabled, attempting to initialize...');
958
+ }
959
+ this.routerService = new ClaudeRouterService(config.router);
960
+ await this.routerService.initialize();
961
+ this.processManager.setRouterService(this.routerService);
962
+ this.logger.info('Router service initialized');
963
+ }
964
+ catch (error) {
965
+ this.logger.error('Router initialization failed, continuing without router', error);
966
+ }
967
+ }
968
+ }
969
+ //# sourceMappingURL=lattice-server.js.map