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,688 @@
1
+ /**
2
+ * Walkthrough Routes - API for generating AI-narrated code walkthroughs
3
+ *
4
+ * Two generation modes:
5
+ * 1. Inline (legacy): POST /generate - Single LLM call, fast but annotations don't work
6
+ * 2. Agentic: POST /spawn - Spawns hidden Claude session with walkthrough skill
7
+ */
8
+ import { Router } from 'express';
9
+ import path from 'path';
10
+ import os from 'os';
11
+ import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'fs';
12
+ import { WalkthroughService, validateWalkthrough, fixLinkedPhraseLines } from '../services/walkthrough-service.js';
13
+ import { SessionInfoService } from '../services/sessions/session-info-service.js';
14
+ import { buildWalkthroughSkillPrompt, buildWalkthroughInitialPrompt, formatPrecomputedDataFile } from '../services/walkthrough-skill-prompt.js';
15
+ import { createLogger } from '../services/infrastructure/logger.js';
16
+ import { asStreamingId, asClaudeSessionId } from '../types/index.js';
17
+ const logger = createLogger('WalkthroughRoutes');
18
+ // Directory for walkthrough output files
19
+ const WALKTHROUGH_DIR = path.join(os.homedir(), '.claudia', 'walkthroughs');
20
+ // Track active walkthrough generations (scopeId -> generation info)
21
+ const activeWalkthroughGenerations = new Map();
22
+ export function createWalkthroughRoutes(deps) {
23
+ const { historyReader, processManager, streamManager, conversationStatusManager } = deps;
24
+ const router = Router();
25
+ const walkthroughService = new WalkthroughService(historyReader);
26
+ // Ensure walkthrough directory exists
27
+ if (!existsSync(WALKTHROUGH_DIR)) {
28
+ mkdirSync(WALKTHROUGH_DIR, { recursive: true });
29
+ }
30
+ /**
31
+ * GET /api/walkthrough/list
32
+ *
33
+ * List all generated walkthroughs across all sessions.
34
+ * Returns metadata about each walkthrough including session info.
35
+ *
36
+ * IMPORTANT: This must be defined BEFORE /:sessionId/* routes to avoid
37
+ * "list" being interpreted as a sessionId.
38
+ */
39
+ router.get('/list', async (_req, res, next) => {
40
+ try {
41
+ const walkthroughs = await listAllWalkthroughs(historyReader);
42
+ res.json({ walkthroughs });
43
+ }
44
+ catch (error) {
45
+ logger.error('Failed to list walkthroughs', {
46
+ error: error instanceof Error ? error.message : String(error),
47
+ });
48
+ next(error);
49
+ }
50
+ });
51
+ /**
52
+ * POST /api/walkthrough/:sessionId/spawn
53
+ *
54
+ * Spawn a hidden Claude session to generate a walkthrough.
55
+ * The session runs with the walkthrough skill and writes output to a file.
56
+ *
57
+ * Request body:
58
+ * - scopeId: string - Identifier for this walkthrough scope
59
+ * - editIndices: number[] - Which edit calls to include
60
+ * - writeIndices: number[] - Which write calls to include
61
+ *
62
+ * Response:
63
+ * - streamingId: string - ID of the spawned session
64
+ * - outputPath: string - Where the walkthrough will be written
65
+ */
66
+ router.post('/:sessionId/spawn', async (req, res, next) => {
67
+ const { sessionId } = req.params;
68
+ const { scopeId, editIndices, writeIndices } = req.body || {};
69
+ if (!scopeId) {
70
+ return res.status(400).json({ error: 'scopeId is required' });
71
+ }
72
+ // Check if already generating
73
+ const existing = activeWalkthroughGenerations.get(scopeId);
74
+ if (existing) {
75
+ logger.info('Walkthrough generation already in progress', {
76
+ scopeId,
77
+ streamingId: existing.streamingId,
78
+ elapsedMs: Date.now() - existing.startedAt,
79
+ });
80
+ return res.json({
81
+ status: 'in_progress',
82
+ streamingId: existing.streamingId,
83
+ outputPath: getOutputPath(sessionId, scopeId),
84
+ });
85
+ }
86
+ try {
87
+ // Find the session JSONL file path
88
+ const sessionJsonlPath = await historyReader.getSessionFilePath(sessionId);
89
+ if (!sessionJsonlPath) {
90
+ return res.status(404).json({ error: 'Session file not found' });
91
+ }
92
+ const outputPath = getOutputPath(sessionId, scopeId);
93
+ const workingDirectory = path.dirname(sessionJsonlPath);
94
+ // Pre-compute file change data, filtered by scope if provided
95
+ const scope = (editIndices?.length || writeIndices?.length)
96
+ ? { editIndices, writeIndices }
97
+ : undefined;
98
+ logger.info('Pre-computing walkthrough data', { sessionId, hasScope: !!scope });
99
+ const precomputedData = await walkthroughService.precomputeWalkthroughData(sessionId, scope);
100
+ // Write full pre-computed data to a file the model can read
101
+ const precomputedDataPath = path.join(WALKTHROUGH_DIR, `${sessionId}-${scopeId}-data.md`);
102
+ const dataFileContent = formatPrecomputedDataFile(precomputedData);
103
+ writeFileSync(precomputedDataPath, dataFileContent);
104
+ logger.info('Wrote pre-computed data file', {
105
+ path: precomputedDataPath,
106
+ sizeBytes: dataFileContent.length,
107
+ fileCount: precomputedData.files.length,
108
+ });
109
+ // Build the skill context with pre-computed data
110
+ const context = {
111
+ targetSessionId: sessionId,
112
+ scopeId,
113
+ editIndices: editIndices || [],
114
+ writeIndices: writeIndices || [],
115
+ outputPath,
116
+ sessionJsonlPath,
117
+ precomputedData,
118
+ precomputedDataPath,
119
+ };
120
+ const systemPrompt = buildWalkthroughSkillPrompt(context);
121
+ const initialPrompt = buildWalkthroughInitialPrompt(context);
122
+ logger.info('Spawning walkthrough generation session', {
123
+ targetSessionId: sessionId,
124
+ scopeId,
125
+ editCount: context.editIndices.length,
126
+ writeCount: context.writeIndices.length,
127
+ outputPath,
128
+ sessionJsonlPath,
129
+ workingDirectory,
130
+ });
131
+ // Spawn a hidden Claude session with Opus for quality walkthroughs
132
+ const result = await processManager.startConversation({
133
+ workingDirectory,
134
+ initialPrompt,
135
+ systemPrompt,
136
+ model: 'claude-opus-4-5-20251101',
137
+ permissionMode: 'bypassPermissions', // Let it read/write freely
138
+ });
139
+ // Track this generation
140
+ const streamingId = asStreamingId(result.streamingId);
141
+ const claudeSessionId = asClaudeSessionId(result.systemInit.session_id);
142
+ logger.info('Walkthrough session spawned successfully', {
143
+ streamingId,
144
+ claudeSessionId,
145
+ scopeId,
146
+ targetSessionId: sessionId,
147
+ });
148
+ // Mark session as archived immediately so it doesn't appear in sidebar
149
+ // Walkthrough generations are internal - users access them via the walkthrough UI
150
+ const sessionInfo = SessionInfoService.getInstance();
151
+ try {
152
+ await sessionInfo.updateSessionInfo(claudeSessionId, { archived: true });
153
+ logger.debug('Walkthrough session marked as archived (hidden from sidebar)', { claudeSessionId });
154
+ }
155
+ catch (e) {
156
+ logger.warn('Failed to archive walkthrough session', { claudeSessionId, error: e });
157
+ }
158
+ // Register with conversation status manager for tracking (but won't show in sidebar due to archived: true)
159
+ conversationStatusManager.registerActiveSession(streamingId, claudeSessionId, {
160
+ initialPrompt: `[Walkthrough] Generating for scope: ${scopeId}`,
161
+ workingDirectory: result.systemInit.cwd,
162
+ model: result.systemInit.model,
163
+ });
164
+ activeWalkthroughGenerations.set(scopeId, {
165
+ streamingId,
166
+ targetSessionId: sessionId,
167
+ scopeId,
168
+ startedAt: Date.now(),
169
+ });
170
+ // Listen for session completion to broadcast event
171
+ const handleProcessEnd = () => {
172
+ const generation = activeWalkthroughGenerations.get(scopeId);
173
+ if (generation?.streamingId === streamingId) {
174
+ activeWalkthroughGenerations.delete(scopeId);
175
+ const durationMs = Date.now() - generation.startedAt;
176
+ logger.info('Walkthrough generation completed', {
177
+ scopeId,
178
+ targetSessionId: sessionId,
179
+ durationMs,
180
+ });
181
+ // Validate the generated walkthrough
182
+ let validationPassed = false;
183
+ let validationErrors = [];
184
+ let validationWarnings = [];
185
+ if (existsSync(outputPath)) {
186
+ try {
187
+ const content = readFileSync(outputPath, 'utf-8');
188
+ const walkthrough = JSON.parse(content);
189
+ const validation = validateWalkthrough(walkthrough);
190
+ validationPassed = validation.passed;
191
+ validationErrors = validation.errors;
192
+ validationWarnings = validation.warnings;
193
+ logger.info('Post-generation validation', {
194
+ scopeId,
195
+ targetSessionId: sessionId,
196
+ passed: validationPassed,
197
+ errorCount: validationErrors.length,
198
+ warningCount: validationWarnings.length,
199
+ errors: validationErrors,
200
+ });
201
+ }
202
+ catch (parseError) {
203
+ validationErrors = ['Failed to parse generated walkthrough JSON'];
204
+ logger.error('Failed to parse generated walkthrough', {
205
+ scopeId,
206
+ targetSessionId: sessionId,
207
+ error: parseError instanceof Error ? parseError.message : String(parseError),
208
+ });
209
+ }
210
+ }
211
+ else {
212
+ validationErrors = ['Output file not created'];
213
+ logger.warn('Walkthrough output file not created', { scopeId, outputPath });
214
+ }
215
+ // Broadcast completion event with validation results
216
+ streamManager.broadcast(streamingId, {
217
+ type: validationPassed ? 'walkthrough_complete' : 'walkthrough_validation_failed',
218
+ targetSessionId: sessionId,
219
+ scopeId,
220
+ outputPath,
221
+ validation: {
222
+ passed: validationPassed,
223
+ errors: validationErrors,
224
+ warnings: validationWarnings,
225
+ },
226
+ durationMs,
227
+ timestamp: new Date().toISOString(),
228
+ });
229
+ }
230
+ };
231
+ // Set up cleanup when process ends
232
+ logger.info('Setting up process-end listener', { streamingId, scopeId });
233
+ processManager.on('process-end', ({ streamingId: endedId }) => {
234
+ logger.info('process-end event received', { endedId, expectedId: streamingId, matches: endedId === streamingId });
235
+ if (endedId === streamingId) {
236
+ handleProcessEnd();
237
+ }
238
+ });
239
+ res.json({
240
+ status: 'started',
241
+ streamingId,
242
+ outputPath,
243
+ });
244
+ }
245
+ catch (error) {
246
+ logger.error('Failed to spawn walkthrough generation', {
247
+ sessionId,
248
+ scopeId,
249
+ error: error instanceof Error ? error.message : String(error),
250
+ });
251
+ next(error);
252
+ }
253
+ });
254
+ /**
255
+ * GET /api/walkthrough/:sessionId/status/:scopeId
256
+ *
257
+ * Check the status of a walkthrough generation.
258
+ * File-first: if output exists, it's complete (handles server restarts)
259
+ */
260
+ router.get('/:sessionId/status/:scopeId', async (req, res) => {
261
+ const { sessionId, scopeId } = req.params;
262
+ const outputPath = getOutputPath(sessionId, scopeId);
263
+ // File-first: if output exists, it's complete regardless of in-memory state
264
+ // This handles server restarts during generation
265
+ if (existsSync(outputPath)) {
266
+ // Clean up stale in-memory tracking if present
267
+ if (activeWalkthroughGenerations.has(scopeId)) {
268
+ logger.info('Cleaning up stale generation tracking (file exists)', { scopeId });
269
+ activeWalkthroughGenerations.delete(scopeId);
270
+ }
271
+ // Include validation results so frontend can show warnings/errors
272
+ let validation = { passed: true, errors: [], warnings: [] };
273
+ try {
274
+ const content = readFileSync(outputPath, 'utf-8');
275
+ const walkthrough = JSON.parse(content);
276
+ validation = validateWalkthrough(walkthrough);
277
+ }
278
+ catch (error) {
279
+ validation = { passed: false, errors: ['Failed to parse walkthrough'], warnings: [] };
280
+ }
281
+ return res.json({
282
+ status: validation.passed ? 'complete' : 'complete_with_errors',
283
+ outputPath,
284
+ validation,
285
+ });
286
+ }
287
+ // Check in-memory tracking for in-progress generations
288
+ const generation = activeWalkthroughGenerations.get(scopeId);
289
+ if (generation) {
290
+ // Verify the session is still running
291
+ const isRunning = processManager.isSessionActive(generation.streamingId);
292
+ logger.debug('Checking generation status', {
293
+ scopeId,
294
+ streamingId: generation.streamingId,
295
+ isRunning,
296
+ elapsedMs: Date.now() - generation.startedAt,
297
+ });
298
+ if (!isRunning) {
299
+ // Session ended without writing file - clean up
300
+ logger.warn('Generation session ended without output', {
301
+ scopeId,
302
+ streamingId: generation.streamingId,
303
+ elapsedMs: Date.now() - generation.startedAt,
304
+ });
305
+ activeWalkthroughGenerations.delete(scopeId);
306
+ return res.json({
307
+ status: 'not_started',
308
+ outputPath,
309
+ });
310
+ }
311
+ return res.json({
312
+ status: 'in_progress',
313
+ streamingId: generation.streamingId,
314
+ elapsedMs: Date.now() - generation.startedAt,
315
+ outputPath,
316
+ });
317
+ }
318
+ return res.json({
319
+ status: 'not_started',
320
+ outputPath,
321
+ });
322
+ });
323
+ /**
324
+ * GET /api/walkthrough/:sessionId/result/:scopeId
325
+ *
326
+ * Get the generated walkthrough (reads from output file).
327
+ * Automatically injects computed diffs from the database for the full diff view.
328
+ * Optionally validates the walkthrough and includes validation results.
329
+ */
330
+ router.get('/:sessionId/result/:scopeId', async (req, res) => {
331
+ const { sessionId, scopeId } = req.params;
332
+ const includeValidation = req.query.validate === 'true';
333
+ const outputPath = getOutputPath(sessionId, scopeId);
334
+ if (!existsSync(outputPath)) {
335
+ return res.status(404).json({ error: 'Walkthrough not found' });
336
+ }
337
+ try {
338
+ const content = readFileSync(outputPath, 'utf-8');
339
+ let walkthrough = JSON.parse(content);
340
+ // Fix linkedPhrase line numbers (LLMs often produce off-by-one errors)
341
+ walkthrough = fixLinkedPhraseLines(walkthrough);
342
+ // Inject computed diffs from database for full diff view
343
+ walkthrough = injectComputedDiffs(walkthrough, sessionId);
344
+ if (includeValidation) {
345
+ const validation = validateWalkthrough(walkthrough);
346
+ return res.json({ walkthrough, validation });
347
+ }
348
+ res.json(walkthrough);
349
+ }
350
+ catch (error) {
351
+ logger.error('Failed to read walkthrough file', {
352
+ sessionId,
353
+ scopeId,
354
+ outputPath,
355
+ error: error instanceof Error ? error.message : String(error),
356
+ });
357
+ res.status(500).json({ error: 'Failed to read walkthrough file' });
358
+ }
359
+ });
360
+ /**
361
+ * GET /api/walkthrough/:sessionId/validate/:scopeId
362
+ *
363
+ * Validate an existing walkthrough against quality requirements.
364
+ */
365
+ router.get('/:sessionId/validate/:scopeId', async (req, res) => {
366
+ const { sessionId, scopeId } = req.params;
367
+ const outputPath = getOutputPath(sessionId, scopeId);
368
+ if (!existsSync(outputPath)) {
369
+ return res.status(404).json({ error: 'Walkthrough not found' });
370
+ }
371
+ try {
372
+ const content = readFileSync(outputPath, 'utf-8');
373
+ const walkthrough = JSON.parse(content);
374
+ const validation = validateWalkthrough(walkthrough);
375
+ logger.info('Validated walkthrough', {
376
+ sessionId,
377
+ scopeId,
378
+ passed: validation.passed,
379
+ errorCount: validation.errors.length,
380
+ warningCount: validation.warnings.length,
381
+ });
382
+ res.json(validation);
383
+ }
384
+ catch (error) {
385
+ logger.error('Failed to validate walkthrough', {
386
+ sessionId,
387
+ scopeId,
388
+ outputPath,
389
+ error: error instanceof Error ? error.message : String(error),
390
+ });
391
+ res.status(500).json({ error: 'Failed to validate walkthrough' });
392
+ }
393
+ });
394
+ /**
395
+ * POST /api/walkthrough/:sessionId/generate (LEGACY)
396
+ *
397
+ * Generate a walkthrough with a single LLM call.
398
+ * Kept for backwards compatibility but annotations don't work reliably.
399
+ */
400
+ router.post('/:sessionId/generate', async (req, res, next) => {
401
+ const { sessionId } = req.params;
402
+ const { scopeId, editIndices, writeIndices } = req.body || {};
403
+ try {
404
+ logger.info('Generating walkthrough (inline mode)', { sessionId, scopeId, editCount: editIndices?.length, writeCount: writeIndices?.length });
405
+ const walkthrough = await walkthroughService.generateWalkthrough(sessionId, { editIndices, writeIndices });
406
+ res.json(walkthrough);
407
+ }
408
+ catch (error) {
409
+ logger.error('Failed to generate walkthrough', {
410
+ sessionId,
411
+ error: error instanceof Error ? error.message : String(error),
412
+ });
413
+ next(error);
414
+ }
415
+ });
416
+ /**
417
+ * GET /api/walkthrough/:sessionId/scope
418
+ *
419
+ * Analyze the session and suggest conceptual groupings for walkthroughs.
420
+ * Uses Haiku for fast analysis (~2-3s). Results are cached.
421
+ *
422
+ * Query params:
423
+ * refresh=true - Force re-analysis, ignore cache
424
+ *
425
+ * Response includes:
426
+ * cachedAt: ISO timestamp when analysis was generated (if from cache)
427
+ * cachedAtTurn: Turn count when analysis was generated (if from cache)
428
+ * currentTurnCount: Current session turn count
429
+ * isStale: true if session has more turns than when cached
430
+ */
431
+ router.get('/:sessionId/scope', async (req, res, next) => {
432
+ const { sessionId } = req.params;
433
+ // Express may parse query as boolean or string depending on qs settings
434
+ const forceRefresh = req.query.refresh === 'true' || req.query.refresh === true;
435
+ const sessionInfoService = SessionInfoService.getInstance();
436
+ try {
437
+ // Get current session turn count
438
+ const details = await historyReader.fetchConversationDirect(sessionId);
439
+ const currentTurnCount = details?.messages?.filter((m) => m.type === 'user').length || 0;
440
+ // Check cache
441
+ const cached = sessionInfoService.getWalkthroughScopeCache(sessionId);
442
+ // Return cached if not forcing refresh
443
+ if (!forceRefresh && cached) {
444
+ const isStale = currentTurnCount > cached.turnCount;
445
+ logger.info('Returning cached walkthrough scope', {
446
+ sessionId,
447
+ cachedAtTurn: cached.turnCount,
448
+ currentTurnCount,
449
+ isStale
450
+ });
451
+ return res.json({
452
+ ...cached.analysis,
453
+ cachedAt: cached.generatedAt,
454
+ cachedAtTurn: cached.turnCount,
455
+ currentTurnCount,
456
+ isStale,
457
+ });
458
+ }
459
+ // Extract previous groupings for stability (skip 'complete-session')
460
+ let previousGroupings;
461
+ if (cached?.analysis) {
462
+ const cachedAnalysis = cached.analysis;
463
+ if (cachedAnalysis.options) {
464
+ previousGroupings = cachedAnalysis.options
465
+ .filter(o => o.id !== 'complete-session')
466
+ .map(o => ({
467
+ id: o.id,
468
+ title: o.title,
469
+ description: o.description,
470
+ editIndices: o.editIndices || [],
471
+ writeIndices: o.writeIndices || [],
472
+ }));
473
+ }
474
+ }
475
+ logger.info('Analyzing walkthrough scope', {
476
+ sessionId,
477
+ forceRefresh,
478
+ previousGroupingCount: previousGroupings?.length || 0,
479
+ });
480
+ const analysis = await walkthroughService.analyzeScope(sessionId, previousGroupings);
481
+ // Cache the result
482
+ sessionInfoService.setWalkthroughScopeCache(sessionId, currentTurnCount, analysis);
483
+ res.json({
484
+ ...analysis,
485
+ cachedAt: new Date().toISOString(),
486
+ cachedAtTurn: currentTurnCount,
487
+ currentTurnCount,
488
+ isStale: false,
489
+ });
490
+ }
491
+ catch (error) {
492
+ logger.error('Failed to analyze walkthrough scope', {
493
+ sessionId,
494
+ error: error instanceof Error ? error.message : String(error),
495
+ });
496
+ next(error);
497
+ }
498
+ });
499
+ /**
500
+ * GET /api/walkthrough/:sessionId/preview
501
+ *
502
+ * Quick preview - stats about the session's changes.
503
+ */
504
+ router.get('/:sessionId/preview', async (req, res, next) => {
505
+ const { sessionId } = req.params;
506
+ try {
507
+ const details = await historyReader.fetchConversationDirect(sessionId);
508
+ if (!details || !details.messages) {
509
+ return res.status(404).json({ error: 'Session not found' });
510
+ }
511
+ const messages = details.messages;
512
+ // Count edits and writes
513
+ let editCount = 0;
514
+ let writeCount = 0;
515
+ const filesModified = new Set();
516
+ for (const msg of messages) {
517
+ if (msg.type === 'assistant') {
518
+ const content = msg.message.content;
519
+ if (Array.isArray(content)) {
520
+ for (const block of content) {
521
+ if (block.type === 'tool_use') {
522
+ if (block.name === 'Edit' && block.input) {
523
+ editCount++;
524
+ filesModified.add(block.input.file_path);
525
+ }
526
+ else if (block.name === 'Write' && block.input) {
527
+ writeCount++;
528
+ filesModified.add(block.input.file_path);
529
+ }
530
+ }
531
+ }
532
+ }
533
+ }
534
+ }
535
+ // Get first user message as title
536
+ let userRequest = '';
537
+ for (const msg of messages) {
538
+ if (msg.type === 'user') {
539
+ const content = msg.message.content;
540
+ if (typeof content === 'string') {
541
+ userRequest = content.slice(0, 200);
542
+ break;
543
+ }
544
+ }
545
+ }
546
+ res.json({
547
+ sessionId,
548
+ editCount,
549
+ writeCount,
550
+ totalChanges: editCount + writeCount,
551
+ filesModified: Array.from(filesModified).map((f) => f.replace(/^\/home\/jason\/(claudia|cui-custom)\//, '')),
552
+ userRequest,
553
+ canGenerate: editCount + writeCount > 0,
554
+ });
555
+ }
556
+ catch (error) {
557
+ logger.error('Failed to preview walkthrough', {
558
+ sessionId,
559
+ error: error instanceof Error ? error.message : String(error),
560
+ });
561
+ next(error);
562
+ }
563
+ });
564
+ return router;
565
+ }
566
+ async function listAllWalkthroughs(historyReader) {
567
+ const { readdirSync, statSync } = await import('fs');
568
+ const sessionInfo = SessionInfoService.getInstance();
569
+ if (!existsSync(WALKTHROUGH_DIR)) {
570
+ return [];
571
+ }
572
+ const files = readdirSync(WALKTHROUGH_DIR).filter(f => f.endsWith('.json') && !f.includes('-data'));
573
+ const walkthroughs = [];
574
+ for (const file of files) {
575
+ try {
576
+ const filePath = path.join(WALKTHROUGH_DIR, file);
577
+ const stat = statSync(filePath);
578
+ const content = readFileSync(filePath, 'utf-8');
579
+ const walkthrough = JSON.parse(content);
580
+ // Parse filename: {sessionId}-{scopeId}.json
581
+ const baseName = file.replace('.json', '');
582
+ // Session IDs are UUIDs (36 chars), scope IDs follow
583
+ const sessionId = baseName.slice(0, 36);
584
+ const scopeId = baseName.slice(37); // Skip the hyphen after UUID
585
+ // Get session info for context (both are async)
586
+ const session = await sessionInfo.getSessionInfo(sessionId);
587
+ const insights = await sessionInfo.getInsights(sessionId);
588
+ walkthroughs.push({
589
+ sessionId,
590
+ scopeId,
591
+ title: walkthrough.title || scopeId,
592
+ summary: walkthrough.summary || '',
593
+ generatedAt: stat.mtime.toISOString(),
594
+ fileSizeKb: Math.round(stat.size / 1024),
595
+ sectionCount: walkthrough.sections?.length || 0,
596
+ sessionPurpose: insights?.purpose || undefined,
597
+ sessionName: session?.custom_name || undefined,
598
+ url: `/session/${sessionId}/walkthrough?scope=${encodeURIComponent(scopeId)}`,
599
+ });
600
+ }
601
+ catch (error) {
602
+ logger.warn('Failed to parse walkthrough file', { file, error });
603
+ }
604
+ }
605
+ // Sort by generation date, newest first
606
+ walkthroughs.sort((a, b) => new Date(b.generatedAt).getTime() - new Date(a.generatedAt).getTime());
607
+ return walkthroughs;
608
+ }
609
+ /**
610
+ * Get the output file path for a walkthrough
611
+ */
612
+ function getOutputPath(sessionId, scopeId) {
613
+ const safeScope = scopeId.replace(/[^a-zA-Z0-9_-]/g, '_');
614
+ return path.join(WALKTHROUGH_DIR, `${sessionId}-${safeScope}.json`);
615
+ }
616
+ /**
617
+ * Compute file diffs from the turn_file_changes table.
618
+ * Returns a map of file path -> computed diff data.
619
+ */
620
+ function computeFileDiffs(sessionId) {
621
+ const sessionInfo = SessionInfoService.getInstance();
622
+ const fileChanges = sessionInfo.getFileChanges(sessionId);
623
+ const diffsByFile = new Map();
624
+ for (const change of fileChanges) {
625
+ const relativePath = change.filePath
626
+ .replace(/^\/home\/jason\/(claudia|cui-custom)\//, '')
627
+ .replace(/^\/home\/jason\//, '~/');
628
+ if (!diffsByFile.has(change.filePath)) {
629
+ diffsByFile.set(change.filePath, {
630
+ file: change.filePath,
631
+ relativePath,
632
+ allBefore: '',
633
+ allAfter: '',
634
+ linesAdded: 0,
635
+ linesRemoved: 0,
636
+ editCount: 0,
637
+ writeCount: 0,
638
+ });
639
+ }
640
+ const diff = diffsByFile.get(change.filePath);
641
+ // Accumulate before/after content
642
+ if (change.oldString) {
643
+ diff.allBefore += (diff.allBefore ? '\n// ---\n' : '') + change.oldString;
644
+ }
645
+ diff.allAfter += (diff.allAfter ? '\n// ---\n' : '') + change.newString;
646
+ // Count changes
647
+ if (change.toolName === 'Edit') {
648
+ diff.editCount++;
649
+ }
650
+ else {
651
+ diff.writeCount++;
652
+ }
653
+ // Compute line stats
654
+ const newLines = (change.newString.match(/\n/g) || []).length + 1;
655
+ const oldLines = change.oldString ? (change.oldString.match(/\n/g) || []).length + 1 : 0;
656
+ if (change.toolName === 'Write') {
657
+ diff.linesAdded += newLines;
658
+ }
659
+ else {
660
+ diff.linesAdded += Math.max(0, newLines - oldLines);
661
+ diff.linesRemoved += Math.max(0, oldLines - newLines);
662
+ }
663
+ }
664
+ return diffsByFile;
665
+ }
666
+ /**
667
+ * Inject computed diffs into a walkthrough response.
668
+ * Adds `computedDiffs` field with aggregated file change data.
669
+ */
670
+ function injectComputedDiffs(walkthrough, sessionId) {
671
+ const diffs = computeFileDiffs(sessionId);
672
+ // Convert to array for JSON
673
+ const computedDiffs = Array.from(diffs.values()).map(d => ({
674
+ file: d.relativePath,
675
+ fullPath: d.file,
676
+ allBefore: d.allBefore,
677
+ allAfter: d.allAfter,
678
+ linesAdded: d.linesAdded,
679
+ linesRemoved: d.linesRemoved,
680
+ editCount: d.editCount,
681
+ writeCount: d.writeCount,
682
+ }));
683
+ return {
684
+ ...walkthrough,
685
+ computedDiffs,
686
+ };
687
+ }
688
+ //# sourceMappingURL=walkthrough.routes.js.map