circuschief 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (319) hide show
  1. package/package.json +33 -0
  2. package/packages/server/bin/cli.js +4 -0
  3. package/packages/server/src/agents/AgentGateway.js +64 -0
  4. package/packages/server/src/agents/BaseAgent.js +41 -0
  5. package/packages/server/src/agents/LoggingAgentWrapper.js +73 -0
  6. package/packages/server/src/agents/adapters/ClaudeCodeAdapter.js +33 -0
  7. package/packages/server/src/agents/adapters/CodexAdapter.js +26 -0
  8. package/packages/server/src/agents/types.js +43 -0
  9. package/packages/server/src/agents/vcr/CassetteStore.js +111 -0
  10. package/packages/server/src/agents/vcr/VCRAgentAdapter.js +126 -0
  11. package/packages/server/src/agents/vcr/VCRSummaryWrapper.js +71 -0
  12. package/packages/server/src/api/canvas-helpers.js +249 -0
  13. package/packages/server/src/api/canvas-trash-routes.js +205 -0
  14. package/packages/server/src/api/canvas.js +331 -0
  15. package/packages/server/src/api/commandButtons.js +312 -0
  16. package/packages/server/src/api/commands.js +169 -0
  17. package/packages/server/src/api/filesystem.js +62 -0
  18. package/packages/server/src/api/git.js +85 -0
  19. package/packages/server/src/api/index.js +44 -0
  20. package/packages/server/src/api/kanban.js +342 -0
  21. package/packages/server/src/api/metrics.js +194 -0
  22. package/packages/server/src/api/projects-helpers.js +43 -0
  23. package/packages/server/src/api/projects-session-helpers.js +295 -0
  24. package/packages/server/src/api/projects.js +384 -0
  25. package/packages/server/src/api/providers.js +249 -0
  26. package/packages/server/src/api/quickResponses.js +129 -0
  27. package/packages/server/src/api/sessions-archive.js +69 -0
  28. package/packages/server/src/api/sessions-commands.js +220 -0
  29. package/packages/server/src/api/sessions-conversations.js +168 -0
  30. package/packages/server/src/api/sessions-draft.js +72 -0
  31. package/packages/server/src/api/sessions-lifecycle.js +190 -0
  32. package/packages/server/src/api/sessions-messages.js +141 -0
  33. package/packages/server/src/api/sessions-notes.js +51 -0
  34. package/packages/server/src/api/sessions-patch.js +252 -0
  35. package/packages/server/src/api/sessions-streaming.js +86 -0
  36. package/packages/server/src/api/sessions.js +269 -0
  37. package/packages/server/src/api/settings.js +194 -0
  38. package/packages/server/src/api/templates.js +63 -0
  39. package/packages/server/src/app.js +51 -0
  40. package/packages/server/src/database.js +58 -0
  41. package/packages/server/src/db/AgentCallLogRepository.js +322 -0
  42. package/packages/server/src/db/AttachmentRepository.js +191 -0
  43. package/packages/server/src/db/BaseRepository.js +39 -0
  44. package/packages/server/src/db/CanvasItemRepository.js +315 -0
  45. package/packages/server/src/db/CommandButtonRepository.js +75 -0
  46. package/packages/server/src/db/CommandRunRepository.js +219 -0
  47. package/packages/server/src/db/ConversationRepository.js +379 -0
  48. package/packages/server/src/db/DatabaseManager.js +91 -0
  49. package/packages/server/src/db/KanbanBoardRepository.js +92 -0
  50. package/packages/server/src/db/KanbanCardRepository.js +286 -0
  51. package/packages/server/src/db/KanbanLaneRepository.js +279 -0
  52. package/packages/server/src/db/MessageRepository.js +156 -0
  53. package/packages/server/src/db/ProjectDefaultsRepository.js +173 -0
  54. package/packages/server/src/db/ProjectRepository.js +110 -0
  55. package/packages/server/src/db/ProviderRepository.js +307 -0
  56. package/packages/server/src/db/QuickResponseRepository.js +186 -0
  57. package/packages/server/src/db/SessionNoteRepository.js +60 -0
  58. package/packages/server/src/db/SessionRepository.js +314 -0
  59. package/packages/server/src/db/SessionSummaryRepository.js +200 -0
  60. package/packages/server/src/db/SessionTemplateRepository.js +171 -0
  61. package/packages/server/src/db/SettingsRepository.js +211 -0
  62. package/packages/server/src/db/TodoRepository.js +132 -0
  63. package/packages/server/src/db/WorkLogRepository.js +122 -0
  64. package/packages/server/src/db/conversation-helpers.js +119 -0
  65. package/packages/server/src/db/index.js +100 -0
  66. package/packages/server/src/db/migrations/canvasItemsMigrations.js +109 -0
  67. package/packages/server/src/db/migrations/conversationsMigrations.js +183 -0
  68. package/packages/server/src/db/migrations/index.js +199 -0
  69. package/packages/server/src/db/migrations/kanbanMigrations.js +99 -0
  70. package/packages/server/src/db/migrations/migrationUtils.js +55 -0
  71. package/packages/server/src/db/migrations/miscMigrations.js +242 -0
  72. package/packages/server/src/db/migrations/projectsMigrations.js +95 -0
  73. package/packages/server/src/db/migrations/sessionsMigrations.js +282 -0
  74. package/packages/server/src/db/session-helpers.js +150 -0
  75. package/packages/server/src/index.js +106 -0
  76. package/packages/server/src/logger.js +22 -0
  77. package/packages/server/src/middleware/sessionLookup.js +57 -0
  78. package/packages/server/src/middleware/upload.js +94 -0
  79. package/packages/server/src/schema.sql +363 -0
  80. package/packages/server/src/services/agentCallLogger.js +116 -0
  81. package/packages/server/src/services/canvasStore.js +56 -0
  82. package/packages/server/src/services/childSessionContext.js +61 -0
  83. package/packages/server/src/services/commandRunner.js +422 -0
  84. package/packages/server/src/services/conversationContext.js +72 -0
  85. package/packages/server/src/services/diffService.js +172 -0
  86. package/packages/server/src/services/draftSessionService.js +181 -0
  87. package/packages/server/src/services/encryption.js +134 -0
  88. package/packages/server/src/services/ghService.js +169 -0
  89. package/packages/server/src/services/gitService.js +520 -0
  90. package/packages/server/src/services/gitSessionSetup.js +48 -0
  91. package/packages/server/src/services/hookService.js +60 -0
  92. package/packages/server/src/services/kanbanService.js +262 -0
  93. package/packages/server/src/services/kanbanTriggers.js +273 -0
  94. package/packages/server/src/services/nodeSpawnHelper.js +63 -0
  95. package/packages/server/src/services/prStatusService.js +204 -0
  96. package/packages/server/src/services/prUrlService.js +224 -0
  97. package/packages/server/src/services/providerTestService.js +81 -0
  98. package/packages/server/src/services/scheduleService.js +110 -0
  99. package/packages/server/src/services/schedulerService.js +281 -0
  100. package/packages/server/src/services/sessionDuplicator.js +63 -0
  101. package/packages/server/src/services/sessionErrors.js +173 -0
  102. package/packages/server/src/services/sessionExecution.js +378 -0
  103. package/packages/server/src/services/sessionManager.js +356 -0
  104. package/packages/server/src/services/sessionPrompts.js +427 -0
  105. package/packages/server/src/services/sessionProvider.js +107 -0
  106. package/packages/server/src/services/slashCommandDiscovery.js +258 -0
  107. package/packages/server/src/services/slashCommandPluginDiscovery.js +216 -0
  108. package/packages/server/src/services/slashCommandService.js +306 -0
  109. package/packages/server/src/services/streamEventCallbacks.js +170 -0
  110. package/packages/server/src/services/streamEventHandler.js +488 -0
  111. package/packages/server/src/services/streamUsageHandler.js +228 -0
  112. package/packages/server/src/services/summaryBroadcast.js +61 -0
  113. package/packages/server/src/services/summaryClaudeClient.js +180 -0
  114. package/packages/server/src/services/summaryPrompts.js +169 -0
  115. package/packages/server/src/services/summaryService.js +552 -0
  116. package/packages/server/src/services/summaryStaleCheck.js +35 -0
  117. package/packages/server/src/services/systemMonitor.js +281 -0
  118. package/packages/server/src/services/templateTriggerService.js +197 -0
  119. package/packages/server/src/services/terminalOutput.js +160 -0
  120. package/packages/server/src/services/todoStore.js +58 -0
  121. package/packages/server/src/services/usageTracker.js +69 -0
  122. package/packages/server/src/services/withConcurrencyGuard.js +110 -0
  123. package/packages/server/src/websocket.js +10 -0
  124. package/packages/server/src/ws/WebSocketManager.js +240 -0
  125. package/packages/server/src/ws/index.js +50 -0
  126. package/packages/shared/package.json +27 -0
  127. package/packages/shared/src/constants.js +44 -0
  128. package/packages/shared/src/contracts/canvas.js +25 -0
  129. package/packages/shared/src/contracts/commandButtons.js +36 -0
  130. package/packages/shared/src/contracts/kanban.js +142 -0
  131. package/packages/shared/src/contracts/projects.js +63 -0
  132. package/packages/shared/src/contracts/providers.js +81 -0
  133. package/packages/shared/src/contracts/quickResponses.js +44 -0
  134. package/packages/shared/src/contracts/sessions.js +112 -0
  135. package/packages/shared/src/contracts/templates.js +51 -0
  136. package/packages/shared/src/index.js +5 -0
  137. package/packages/shared/src/protocol.js +76 -0
  138. package/packages/shared/src/routeParams.js +36 -0
  139. package/packages/shared/src/types.js +167 -0
  140. package/packages/shared/src/utils.js +101 -0
  141. package/packages/web/dist/assets/ActiveSessionsView-BQc76Jc8.js +1 -0
  142. package/packages/web/dist/assets/ActiveSessionsView-ofSvx-K1.css +1 -0
  143. package/packages/web/dist/assets/AgentLogsView-CTCjHjsu.js +2 -0
  144. package/packages/web/dist/assets/AgentLogsView-D90PnQVk.css +1 -0
  145. package/packages/web/dist/assets/ApiClient-Dbs1H78V.js +1 -0
  146. package/packages/web/dist/assets/ArchiveConfirmModal-CCxSZ52u.js +1 -0
  147. package/packages/web/dist/assets/ArchiveConfirmModal-CQZeuYBz.css +1 -0
  148. package/packages/web/dist/assets/CommandButtonDetailView-CF_-LXpU.js +1 -0
  149. package/packages/web/dist/assets/CommandButtonDetailView-DBm3rzhw.css +1 -0
  150. package/packages/web/dist/assets/EffortLevelSelector-BQaQmU2d.css +1 -0
  151. package/packages/web/dist/assets/EffortLevelSelector-DPofLvm-.js +1 -0
  152. package/packages/web/dist/assets/GeneralSettingsView-BCf53fpC.css +1 -0
  153. package/packages/web/dist/assets/GeneralSettingsView-BY1G-Kv8.js +1 -0
  154. package/packages/web/dist/assets/InterpolationHelp-CgdbNcJB.js +1 -0
  155. package/packages/web/dist/assets/InterpolationHelp-iNxTxmhs.css +1 -0
  156. package/packages/web/dist/assets/MarkdownEditor-CqT1U8lo.js +2 -0
  157. package/packages/web/dist/assets/MarkdownEditor-enuH2yvP.css +1 -0
  158. package/packages/web/dist/assets/ModelSelector-BBn_Ve0D.js +1 -0
  159. package/packages/web/dist/assets/ModelSelector-DPPD-92R.css +1 -0
  160. package/packages/web/dist/assets/NewSessionView-Bo5l49nu.js +3 -0
  161. package/packages/web/dist/assets/NewSessionView-Byoi1XdQ.css +1 -0
  162. package/packages/web/dist/assets/PathChooser-BoMGzeg2.css +1 -0
  163. package/packages/web/dist/assets/PathChooser-Cx9gQ-Qt.js +1 -0
  164. package/packages/web/dist/assets/ProjectEditView-BFuscj-V.js +1 -0
  165. package/packages/web/dist/assets/ProjectEditView-DNwBUNRk.css +1 -0
  166. package/packages/web/dist/assets/ProjectListView-C55H1JHQ.css +1 -0
  167. package/packages/web/dist/assets/ProjectListView-Dj0jBZ46.js +1 -0
  168. package/packages/web/dist/assets/ProjectNewView-Brdp-xUu.js +1 -0
  169. package/packages/web/dist/assets/ProjectNewView-CpgE4R-l.css +1 -0
  170. package/packages/web/dist/assets/ProvidersView-B_QQF3RM.css +1 -0
  171. package/packages/web/dist/assets/ProvidersView-Cxc-1skq.js +1 -0
  172. package/packages/web/dist/assets/QuickResponseSettings-B2eVAtHW.js +1 -0
  173. package/packages/web/dist/assets/QuickResponseSettings-B8188A1D.css +1 -0
  174. package/packages/web/dist/assets/QuickResponsesPanel-DIBQFj0W.css +1 -0
  175. package/packages/web/dist/assets/QuickResponsesPanel-lU8pW2B0.js +1 -0
  176. package/packages/web/dist/assets/ResizableTextarea-B5nAA0RV.css +1 -0
  177. package/packages/web/dist/assets/ResizableTextarea-DSy1mWGY.js +1 -0
  178. package/packages/web/dist/assets/SessionCard-BvjLwVYg.js +1 -0
  179. package/packages/web/dist/assets/SessionCard-D20G3bX8.css +1 -0
  180. package/packages/web/dist/assets/SessionDetailView-BQbPg-RJ.js +36 -0
  181. package/packages/web/dist/assets/SessionDetailView-BrMG4p2-.css +1 -0
  182. package/packages/web/dist/assets/SessionFormOptions-BgqFR-5f.js +1 -0
  183. package/packages/web/dist/assets/SessionFormOptions-BuLlDF-7.css +1 -0
  184. package/packages/web/dist/assets/SessionListView-BAIBtJF7.css +1 -0
  185. package/packages/web/dist/assets/SessionListView-CYIHI8qF.js +1 -0
  186. package/packages/web/dist/assets/SessionLogStream-B-FwUMJQ.js +18 -0
  187. package/packages/web/dist/assets/SessionLogStream-zPUTiGbe.css +1 -0
  188. package/packages/web/dist/assets/SettingsView-DC8-hTQ-.css +1 -0
  189. package/packages/web/dist/assets/SettingsView-fZxpiGp7.js +1 -0
  190. package/packages/web/dist/assets/SlashCommandWizard-BB30cSvo.css +1 -0
  191. package/packages/web/dist/assets/SlashCommandWizard-BgaOw9W3.js +1 -0
  192. package/packages/web/dist/assets/SummarySettingsView-DcsmSVJI.css +1 -0
  193. package/packages/web/dist/assets/SummarySettingsView-eeu1Xq86.js +1 -0
  194. package/packages/web/dist/assets/TemplateDetailView-DEPKSwDo.js +1 -0
  195. package/packages/web/dist/assets/TemplateDetailView-DT2m06W7.css +1 -0
  196. package/packages/web/dist/assets/apl-B4CMkyY2.js +1 -0
  197. package/packages/web/dist/assets/asciiarmor-Df11BRmG.js +1 -0
  198. package/packages/web/dist/assets/asn1-EdZsLKOL.js +1 -0
  199. package/packages/web/dist/assets/asterisk-B-8jnY81.js +1 -0
  200. package/packages/web/dist/assets/brainfuck-C4LP7Hcl.js +1 -0
  201. package/packages/web/dist/assets/clike-B9uivgTg.js +1 -0
  202. package/packages/web/dist/assets/clojure-BMjYHr_A.js +1 -0
  203. package/packages/web/dist/assets/cmake-BQqOBYOt.js +1 -0
  204. package/packages/web/dist/assets/cobol-CWcv1MsR.js +1 -0
  205. package/packages/web/dist/assets/coffeescript-S37ZYGWr.js +1 -0
  206. package/packages/web/dist/assets/commandButtons-DNSHH8IA.js +4 -0
  207. package/packages/web/dist/assets/commonlisp-DBKNyK5s.js +1 -0
  208. package/packages/web/dist/assets/crystal-SjHAIU92.js +1 -0
  209. package/packages/web/dist/assets/css-BnMrqG3P.js +1 -0
  210. package/packages/web/dist/assets/cypher-C_CwsFkJ.js +1 -0
  211. package/packages/web/dist/assets/d-pRatUO7H.js +1 -0
  212. package/packages/web/dist/assets/diff-DbItnlRl.js +1 -0
  213. package/packages/web/dist/assets/dockerfile-BKs6k2Af.js +1 -0
  214. package/packages/web/dist/assets/dtd-DF_7sFjM.js +1 -0
  215. package/packages/web/dist/assets/dylan-DwRh75JA.js +1 -0
  216. package/packages/web/dist/assets/ebnf-CDyGwa7X.js +1 -0
  217. package/packages/web/dist/assets/ecl-Cabwm37j.js +1 -0
  218. package/packages/web/dist/assets/eiffel-CnydiIhH.js +1 -0
  219. package/packages/web/dist/assets/elm-vLlmbW-K.js +1 -0
  220. package/packages/web/dist/assets/erlang-BNw1qcRV.js +1 -0
  221. package/packages/web/dist/assets/factor-kuTfRLto.js +1 -0
  222. package/packages/web/dist/assets/fcl-Kvtd6kyn.js +1 -0
  223. package/packages/web/dist/assets/forth-Ffai-XNe.js +1 -0
  224. package/packages/web/dist/assets/fortran-DYz_wnZ1.js +1 -0
  225. package/packages/web/dist/assets/gas-Bneqetm1.js +1 -0
  226. package/packages/web/dist/assets/gherkin-heZmZLOM.js +1 -0
  227. package/packages/web/dist/assets/groovy-D9Dt4D0W.js +1 -0
  228. package/packages/web/dist/assets/haskell-BWDZoCOh.js +1 -0
  229. package/packages/web/dist/assets/haxe-H-WmDvRZ.js +1 -0
  230. package/packages/web/dist/assets/http-DBlCnlav.js +1 -0
  231. package/packages/web/dist/assets/idl-BEugSyMb.js +1 -0
  232. package/packages/web/dist/assets/index-BZlHgDSz.js +1 -0
  233. package/packages/web/dist/assets/index-BhWX8AfE.js +2 -0
  234. package/packages/web/dist/assets/index-Bi3XvF_f.js +1 -0
  235. package/packages/web/dist/assets/index-BqXoPf_D.js +1 -0
  236. package/packages/web/dist/assets/index-CAuTOZSD.js +1 -0
  237. package/packages/web/dist/assets/index-CKYk-fkb.js +1 -0
  238. package/packages/web/dist/assets/index-CTumW_tV.js +318 -0
  239. package/packages/web/dist/assets/index-CVOJVSsC.js +82 -0
  240. package/packages/web/dist/assets/index-CXK2Z3_z.js +1 -0
  241. package/packages/web/dist/assets/index-CYllQ3Vd.js +1 -0
  242. package/packages/web/dist/assets/index-CpsfI08O.js +1 -0
  243. package/packages/web/dist/assets/index-DQkhDeTA.js +3 -0
  244. package/packages/web/dist/assets/index-DWP8iCBp.js +1 -0
  245. package/packages/web/dist/assets/index-DkVb9W_J.js +1 -0
  246. package/packages/web/dist/assets/index-DmKHPbIa.js +1 -0
  247. package/packages/web/dist/assets/index-DrlQi03X.js +1 -0
  248. package/packages/web/dist/assets/index-gmCCsCQ1.css +1 -0
  249. package/packages/web/dist/assets/index-prTEzzgO.js +1 -0
  250. package/packages/web/dist/assets/index-wqgejMCM.js +1 -0
  251. package/packages/web/dist/assets/index-yh0ZHIWw.js +7 -0
  252. package/packages/web/dist/assets/javascript-qCveANmP.js +1 -0
  253. package/packages/web/dist/assets/julia-DuME0IfC.js +1 -0
  254. package/packages/web/dist/assets/livescript-BwQOo05w.js +1 -0
  255. package/packages/web/dist/assets/lua-BgMRiT3U.js +1 -0
  256. package/packages/web/dist/assets/mathematica-DTrFuWx2.js +1 -0
  257. package/packages/web/dist/assets/mbox-CNhZ1qSd.js +1 -0
  258. package/packages/web/dist/assets/mirc-CjQqDB4T.js +1 -0
  259. package/packages/web/dist/assets/mllike-CXdrOF99.js +1 -0
  260. package/packages/web/dist/assets/modelica-Dc1JOy9r.js +1 -0
  261. package/packages/web/dist/assets/mscgen-BA5vi2Kp.js +1 -0
  262. package/packages/web/dist/assets/mumps-BT43cFF4.js +1 -0
  263. package/packages/web/dist/assets/nginx-DdIZxoE0.js +1 -0
  264. package/packages/web/dist/assets/nsis-LdVXkNf5.js +1 -0
  265. package/packages/web/dist/assets/ntriples-BfvgReVJ.js +1 -0
  266. package/packages/web/dist/assets/octave-Ck1zUtKM.js +1 -0
  267. package/packages/web/dist/assets/oz-BzwKVEFT.js +1 -0
  268. package/packages/web/dist/assets/pascal--L3eBynH.js +1 -0
  269. package/packages/web/dist/assets/perl-CdXCOZ3F.js +1 -0
  270. package/packages/web/dist/assets/pig-CevX1Tat.js +1 -0
  271. package/packages/web/dist/assets/powershell-CFHJl5sT.js +1 -0
  272. package/packages/web/dist/assets/projects-DbBQQH-V.js +1 -0
  273. package/packages/web/dist/assets/properties-C78fOPTZ.js +1 -0
  274. package/packages/web/dist/assets/protobuf-ChK-085T.js +1 -0
  275. package/packages/web/dist/assets/providers-ceCc4xRU.js +1 -0
  276. package/packages/web/dist/assets/pug-DukmZTjD.js +1 -0
  277. package/packages/web/dist/assets/puppet-DMA9R1ak.js +1 -0
  278. package/packages/web/dist/assets/python-BuPzkPfP.js +1 -0
  279. package/packages/web/dist/assets/q-pXgVlZs6.js +1 -0
  280. package/packages/web/dist/assets/r-DUYO_cvP.js +1 -0
  281. package/packages/web/dist/assets/rpm-CTu-6PCP.js +1 -0
  282. package/packages/web/dist/assets/ruby-B2Rjki9n.js +1 -0
  283. package/packages/web/dist/assets/sas-B4kiWyti.js +1 -0
  284. package/packages/web/dist/assets/scheme-C41bIUwD.js +1 -0
  285. package/packages/web/dist/assets/sessions-D681M81k.js +1 -0
  286. package/packages/web/dist/assets/settings-D0evez2V.js +1 -0
  287. package/packages/web/dist/assets/shell-CjFT_Tl9.js +1 -0
  288. package/packages/web/dist/assets/sieve-C3Gn_uJK.js +1 -0
  289. package/packages/web/dist/assets/simple-mode-GW_nhZxv.js +1 -0
  290. package/packages/web/dist/assets/smalltalk-CnHTOXQT.js +1 -0
  291. package/packages/web/dist/assets/solr-DehyRSwq.js +1 -0
  292. package/packages/web/dist/assets/sparql-DkYu6x3z.js +1 -0
  293. package/packages/web/dist/assets/spreadsheet-BCZA_wO0.js +1 -0
  294. package/packages/web/dist/assets/sql-D0XecflT.js +1 -0
  295. package/packages/web/dist/assets/stex-C3f8Ysf7.js +1 -0
  296. package/packages/web/dist/assets/style-BTin-zR_.css +1 -0
  297. package/packages/web/dist/assets/stylus-B533Al4x.js +1 -0
  298. package/packages/web/dist/assets/swift-BzpIVaGY.js +1 -0
  299. package/packages/web/dist/assets/tcl-DVfN8rqt.js +1 -0
  300. package/packages/web/dist/assets/textile-CnDTJFAw.js +1 -0
  301. package/packages/web/dist/assets/tiddlywiki-DO-Gjzrf.js +1 -0
  302. package/packages/web/dist/assets/tiki-DGYXhP31.js +1 -0
  303. package/packages/web/dist/assets/toml-Bm5Em-hy.js +1 -0
  304. package/packages/web/dist/assets/troff-wAsdV37c.js +1 -0
  305. package/packages/web/dist/assets/ttcn-CfJYG6tj.js +1 -0
  306. package/packages/web/dist/assets/ttcn-cfg-B9xdYoR4.js +1 -0
  307. package/packages/web/dist/assets/turtle-B1tBg_DP.js +1 -0
  308. package/packages/web/dist/assets/vb-CmGdzxic.js +1 -0
  309. package/packages/web/dist/assets/vbscript-BuJXcnF6.js +1 -0
  310. package/packages/web/dist/assets/velocity-D8B20fx6.js +1 -0
  311. package/packages/web/dist/assets/verilog-C6RDOZhf.js +1 -0
  312. package/packages/web/dist/assets/vhdl-lSbBsy5d.js +1 -0
  313. package/packages/web/dist/assets/webidl-ZXfAyPTL.js +1 -0
  314. package/packages/web/dist/assets/xquery-CQfU5ijd.js +1 -0
  315. package/packages/web/dist/assets/yacas-BJ4BC0dw.js +1 -0
  316. package/packages/web/dist/assets/z80-Hz9HOZM7.js +1 -0
  317. package/packages/web/dist/favicon.png +0 -0
  318. package/packages/web/dist/index.html +17 -0
  319. package/packages/web/dist/logo.png +0 -0
@@ -0,0 +1,228 @@
1
+ import { sessions, conversations } from '../database.js';
2
+ import { broadcastToSession, broadcastToProject } from '../websocket.js';
3
+ import { WS_MESSAGE_TYPES } from '../../../shared/src/index.js';
4
+ import { updateTurnUsage, currentTurnUsage, estimatedOutputTokens, estimateTokens } from './usageTracker.js';
5
+ import { activeConversationIds, currentModels } from './streamEventHandler.js';
6
+
7
+ // ── Stream usage helpers ────────────────────────────────────────────────────
8
+ // Extracted from streamEventHandler.js to keep it under the max-lines limit.
9
+
10
+ /**
11
+ * Handle stream_event > message_start — initial usage (input tokens)
12
+ * @param {string} sessionId
13
+ * @param {Object} event
14
+ */
15
+ export function handleMessageStart(sessionId, event) {
16
+ const usage = event.event?.message?.usage;
17
+ if (usage) {
18
+ const conversationId = activeConversationIds.get(sessionId);
19
+ const turnUsage = updateTurnUsage(conversationId, usage, 'message_start');
20
+ broadcastToSession(sessionId, WS_MESSAGE_TYPES.SESSION_USAGE_UPDATE, {
21
+ sessionId,
22
+ conversationId,
23
+ usage: turnUsage,
24
+ isFinal: false,
25
+ });
26
+ }
27
+ }
28
+
29
+ /**
30
+ * Handle stream_event > message_delta — streaming output tokens
31
+ * @param {string} sessionId
32
+ * @param {Object} event
33
+ */
34
+ export function handleMessageDelta(sessionId, event) {
35
+ const usage = event.event?.usage;
36
+ if (usage) {
37
+ const conversationId = activeConversationIds.get(sessionId);
38
+ const turnUsage = updateTurnUsage(conversationId, usage, 'message_delta');
39
+ broadcastToSession(sessionId, WS_MESSAGE_TYPES.SESSION_USAGE_UPDATE, {
40
+ sessionId,
41
+ conversationId,
42
+ usage: turnUsage,
43
+ isFinal: false,
44
+ });
45
+ }
46
+ }
47
+
48
+ /**
49
+ * Handle text_delta within content_block_delta — accumulate text and estimate tokens
50
+ * @param {string} sessionId
51
+ * @param {Object} delta
52
+ * @param {Map} textAccumulators
53
+ */
54
+ export function handleTextDelta(sessionId, delta, textAccumulators) {
55
+ // Accumulate text content
56
+ const current = textAccumulators.get(sessionId) || '';
57
+ const accumulated = current + delta.text;
58
+ textAccumulators.set(sessionId, accumulated);
59
+
60
+ broadcastToSession(sessionId, WS_MESSAGE_TYPES.SESSION_PARTIAL, {
61
+ sessionId,
62
+ text: accumulated,
63
+ });
64
+
65
+ // Estimate tokens from streamed content for real-time output token updates
66
+ const conversationId = activeConversationIds.get(sessionId);
67
+ if (!conversationId) return;
68
+
69
+ const currentEstimate = estimatedOutputTokens.get(conversationId) || 0;
70
+ const newEstimate = currentEstimate + estimateTokens(delta.text);
71
+ estimatedOutputTokens.set(conversationId, newEstimate);
72
+
73
+ // Get current turn usage and add estimated output
74
+ const turnData = currentTurnUsage.get(conversationId) || {
75
+ inputTokens: 0,
76
+ outputTokens: 0,
77
+ lastMessageOutput: 0,
78
+ cacheReadInputTokens: 0,
79
+ cacheCreationInputTokens: 0,
80
+ };
81
+
82
+ // Broadcast usage update with estimated tokens
83
+ const broadcastUsage = {
84
+ inputTokens: turnData.inputTokens,
85
+ outputTokens: turnData.outputTokens + Math.max(turnData.lastMessageOutput, newEstimate),
86
+ cacheReadInputTokens: turnData.cacheReadInputTokens,
87
+ cacheCreationInputTokens: turnData.cacheCreationInputTokens,
88
+ };
89
+
90
+ broadcastToSession(sessionId, WS_MESSAGE_TYPES.SESSION_USAGE_UPDATE, {
91
+ sessionId,
92
+ conversationId,
93
+ usage: broadcastUsage,
94
+ isFinal: false,
95
+ isEstimate: true, // Flag so UI can show "~" prefix if desired
96
+ });
97
+ }
98
+
99
+ /**
100
+ * Resolve a token field from modelUsageEntry (camelCase) or event.usage (snake_case).
101
+ */
102
+ function resolveTokenField(modelUsageEntry, eventUsage, keys) {
103
+ return modelUsageEntry?.[keys.camel] || eventUsage?.[keys.snake] || 0;
104
+ }
105
+
106
+ /**
107
+ * Extract turn usage from result event's modelUsage or usage fields
108
+ * @param {string} sessionId
109
+ * @param {Object} event
110
+ * @returns {Object} turnUsage
111
+ */
112
+ export function extractTurnUsage(sessionId, event) {
113
+ // Extract from modelUsage if available (has more detail)
114
+ const modelUsageEntry = event.modelUsage
115
+ ? Object.values(event.modelUsage)[0]
116
+ : null;
117
+
118
+ // Use the model from system.init (stored in currentModels) rather than modelUsage keys
119
+ // because modelUsage can contain multiple models when sub-agents are used (e.g., Opus using Haiku)
120
+ // and Object.keys()[0] would pick the wrong model
121
+ const primaryModel = currentModels.get(sessionId) || Object.keys(event.modelUsage || {})[0] || null;
122
+
123
+ return {
124
+ inputTokens: resolveTokenField(modelUsageEntry, event.usage, { camel: 'inputTokens', snake: 'input_tokens' }),
125
+ outputTokens: resolveTokenField(modelUsageEntry, event.usage, { camel: 'outputTokens', snake: 'output_tokens' }),
126
+ cacheReadInputTokens: resolveTokenField(modelUsageEntry, event.usage, { camel: 'cacheReadInputTokens', snake: 'cache_read_input_tokens' }),
127
+ cacheCreationInputTokens: resolveTokenField(modelUsageEntry, event.usage, { camel: 'cacheCreationInputTokens', snake: 'cache_creation_input_tokens' }),
128
+ webSearchRequests: modelUsageEntry?.webSearchRequests || 0,
129
+ contextWindow: modelUsageEntry?.contextWindow || 200000,
130
+ model: primaryModel,
131
+ };
132
+ }
133
+
134
+ /**
135
+ * Build cumulative session-level usage by adding turn usage to existing session usage
136
+ * @param {string} sessionId
137
+ * @param {Object} turnUsage
138
+ * @returns {Object} cumulativeSessionUsage
139
+ */
140
+ export function buildCumulativeSessionUsage(sessionId, turnUsage) {
141
+ const currentSession = sessions.getById(sessionId);
142
+ return {
143
+ inputTokens: (currentSession.inputTokens || 0) + turnUsage.inputTokens,
144
+ outputTokens: (currentSession.outputTokens || 0) + turnUsage.outputTokens,
145
+ cacheReadInputTokens: (currentSession.cacheReadInputTokens || 0) + turnUsage.cacheReadInputTokens,
146
+ cacheCreationInputTokens: (currentSession.cacheCreationInputTokens || 0) + turnUsage.cacheCreationInputTokens,
147
+ webSearchRequests: (currentSession.webSearchRequests || 0) + turnUsage.webSearchRequests,
148
+ contextWindow: turnUsage.contextWindow,
149
+ };
150
+ }
151
+
152
+ /**
153
+ * Update conversation with cumulative usage from turn
154
+ * @param {string|undefined} conversationId
155
+ * @param {Object|null} currentConversation
156
+ * @param {Object} turnUsage
157
+ * @returns {Object|null} updatedConversation
158
+ */
159
+ export function updateConversationUsage(conversationId, currentConversation, turnUsage) {
160
+ if (!currentConversation) return null;
161
+
162
+ const cumulativeConversationUsage = {
163
+ inputTokens: (currentConversation.inputTokens || 0) + turnUsage.inputTokens,
164
+ outputTokens: (currentConversation.outputTokens || 0) + turnUsage.outputTokens,
165
+ cacheReadInputTokens: (currentConversation.cacheReadInputTokens || 0) + turnUsage.cacheReadInputTokens,
166
+ cacheCreationInputTokens: (currentConversation.cacheCreationInputTokens || 0) + turnUsage.cacheCreationInputTokens,
167
+ webSearchRequests: (currentConversation.webSearchRequests || 0) + turnUsage.webSearchRequests,
168
+ contextWindow: turnUsage.contextWindow,
169
+ };
170
+
171
+ return conversations.updateUsage(conversationId, cumulativeConversationUsage);
172
+ }
173
+
174
+ /**
175
+ * Handle final usage stats from result event — update conversation and session usage
176
+ * @param {string} sessionId
177
+ * @param {Object} event
178
+ */
179
+ export function handleResultUsage(sessionId, event) {
180
+ const turnUsage = extractTurnUsage(sessionId, event);
181
+
182
+ // Get the conversation ID for this session's current turn
183
+ const conversationId = activeConversationIds.get(sessionId);
184
+ const currentConversation = conversationId ? conversations.getById(conversationId) : null;
185
+
186
+ // Update conversation with cumulative usage (add to existing)
187
+ const updatedConversation = updateConversationUsage(conversationId, currentConversation, turnUsage);
188
+
189
+ // Also update session-level usage (aggregate of all conversations) for backward compatibility
190
+ const cumulativeSessionUsage = buildCumulativeSessionUsage(sessionId, turnUsage);
191
+ const updatedSession = sessions.updateUsage(sessionId, cumulativeSessionUsage);
192
+
193
+ // Broadcast final usage update with conversationId
194
+ broadcastToSession(sessionId, WS_MESSAGE_TYPES.SESSION_USAGE_UPDATE, {
195
+ sessionId,
196
+ conversationId,
197
+ usage: updatedConversation ? {
198
+ inputTokens: updatedConversation.inputTokens,
199
+ outputTokens: updatedConversation.outputTokens,
200
+ cacheReadInputTokens: updatedConversation.cacheReadInputTokens,
201
+ cacheCreationInputTokens: updatedConversation.cacheCreationInputTokens,
202
+ webSearchRequests: updatedConversation.webSearchRequests,
203
+ contextWindow: updatedConversation.contextWindow,
204
+ } : cumulativeSessionUsage,
205
+ turnUsage,
206
+ isFinal: true,
207
+ });
208
+
209
+ // Also broadcast session update for session list
210
+ broadcastToProject(updatedSession.projectId, WS_MESSAGE_TYPES.SESSION_UPDATED, {
211
+ projectId: updatedSession.projectId,
212
+ sessionId,
213
+ session: updatedSession,
214
+ });
215
+
216
+ // Broadcast conversation update for real-time UI updates
217
+ if (updatedConversation) {
218
+ broadcastToSession(sessionId, WS_MESSAGE_TYPES.CONVERSATION_UPDATED, {
219
+ sessionId,
220
+ conversation: updatedConversation,
221
+ });
222
+ }
223
+
224
+ // Clean up turn usage and estimated tokens
225
+ currentTurnUsage.delete(conversationId);
226
+ estimatedOutputTokens.delete(conversationId);
227
+ activeConversationIds.delete(sessionId);
228
+ }
@@ -0,0 +1,61 @@
1
+ /**
2
+ * Broadcast helpers for summary-related WebSocket events.
3
+ * Consolidates repeated broadcast patterns from summaryService.
4
+ */
5
+
6
+ import { broadcastToSession, broadcastToProject } from '../websocket.js';
7
+ import { WS_MESSAGE_TYPES } from '../../../shared/src/index.js';
8
+
9
+ /**
10
+ * Broadcast summary update to session and project subscribers
11
+ * @param {string} sessionId - The session ID
12
+ * @param {string|null} projectId - The project ID (null skips project broadcast)
13
+ * @param {Object} summary - The summary object
14
+ */
15
+ export function broadcastSummaryUpdate(sessionId, projectId, summary) {
16
+ broadcastToSession(sessionId, WS_MESSAGE_TYPES.SESSION_SUMMARY_UPDATED, {
17
+ sessionId,
18
+ summary,
19
+ });
20
+
21
+ if (projectId) {
22
+ broadcastToProject(projectId, WS_MESSAGE_TYPES.SESSION_SUMMARY_UPDATED, {
23
+ projectId,
24
+ sessionId,
25
+ summary,
26
+ });
27
+ }
28
+ }
29
+
30
+ /**
31
+ * Broadcast generating status to session subscribers
32
+ * @param {string} sessionId - The session ID
33
+ * @param {boolean} generating - Whether generation is in progress
34
+ */
35
+ export function broadcastGeneratingStatus(sessionId, generating) {
36
+ broadcastToSession(sessionId, WS_MESSAGE_TYPES.SESSION_SUMMARY_GENERATING, {
37
+ sessionId,
38
+ generating,
39
+ });
40
+ }
41
+
42
+ /**
43
+ * Broadcast session update to session and project subscribers
44
+ * @param {string} sessionId - The session ID
45
+ * @param {string|null} projectId - The project ID (null skips project broadcast)
46
+ * @param {Object} session - The session object
47
+ */
48
+ export function broadcastSessionUpdate(sessionId, projectId, session) {
49
+ broadcastToSession(sessionId, WS_MESSAGE_TYPES.SESSION_UPDATED, {
50
+ sessionId,
51
+ session,
52
+ });
53
+
54
+ if (projectId) {
55
+ broadcastToProject(projectId, WS_MESSAGE_TYPES.SESSION_UPDATED, {
56
+ projectId,
57
+ sessionId,
58
+ session,
59
+ });
60
+ }
61
+ }
@@ -0,0 +1,180 @@
1
+ import { query } from '@anthropic-ai/claude-agent-sdk';
2
+ import { sessions } from '../database.js';
3
+ import { agentCallLogger } from './agentCallLogger.js';
4
+ import { createVCRQueryFn } from '../agents/vcr/VCRSummaryWrapper.js';
5
+
6
+ /**
7
+ * Default JSON schema for session summary structured output
8
+ */
9
+ /**
10
+ * Process a content block from Claude's response
11
+ * @param {Object} block - Content block
12
+ * @param {Object} stateInput - Mutable state object { responseText, structuredOutput }
13
+ */
14
+ function processContentBlock(block, stateInput) {
15
+ const state = stateInput;
16
+ if (block.type === 'tool_use' && block.name === 'StructuredOutput') {
17
+ state.structuredOutput = block.input;
18
+ } else if (block.type === 'text') {
19
+ state.responseText += block.text;
20
+ }
21
+ }
22
+
23
+ /**
24
+ * Log usage metrics from a result event
25
+ * @param {string} callId - The call ID for logging
26
+ * @param {Object} event - The result event
27
+ */
28
+ function logResultUsage(callId, event) {
29
+ const modelUsageEntry = event.modelUsage
30
+ ? Object.values(event.modelUsage)[0]
31
+ : null;
32
+ if (!modelUsageEntry && !event.usage) return;
33
+
34
+ agentCallLogger.updateUsage(callId, {
35
+ inputTokens: modelUsageEntry?.inputTokens || event.usage?.input_tokens || 0,
36
+ outputTokens: modelUsageEntry?.outputTokens || event.usage?.output_tokens || 0,
37
+ thinkingTokens: 0,
38
+ cacheReadInputTokens:
39
+ modelUsageEntry?.cacheReadInputTokens ||
40
+ event.usage?.cache_read_input_tokens ||
41
+ 0,
42
+ cacheCreationInputTokens:
43
+ modelUsageEntry?.cacheCreationInputTokens ||
44
+ event.usage?.cache_creation_input_tokens ||
45
+ 0,
46
+ });
47
+ }
48
+
49
+ /**
50
+ * Build the query parameters for the Claude SDK call.
51
+ * @param {string} prompt - The prompt to send
52
+ * @param {{ systemPrompt?: string, jsonSchema?: Object }} options
53
+ * @returns {Object} queryParams ready for the SDK query function
54
+ */
55
+ function buildClaudeRequest(prompt, options) {
56
+ const { systemPrompt = null, jsonSchema = null } = options || {};
57
+ const schema = jsonSchema || SESSION_SUMMARY_SCHEMA;
58
+
59
+ return {
60
+ prompt,
61
+ options: {
62
+ cwd: process.cwd(),
63
+ permissionMode: 'bypassPermissions',
64
+ maxTurns: 1,
65
+ model: 'claude-haiku-4-5-20251001',
66
+ ...(systemPrompt && { systemPrompt }),
67
+ outputFormat: {
68
+ type: 'json_schema',
69
+ schema,
70
+ },
71
+ },
72
+ };
73
+ }
74
+
75
+ /**
76
+ * Process the Claude SDK event stream and extract the response.
77
+ * @param {AsyncIterable} eventStream - The async iterable from the SDK query
78
+ * @param {string|null} callId - The agent call logger ID (null if not logging)
79
+ * @returns {Promise<string>} The text response (JSON string)
80
+ */
81
+ async function handleClaudeResponse(eventStream, callId) {
82
+ const state = { responseText: '', structuredOutput: null };
83
+
84
+ for await (const event of eventStream) {
85
+ switch (event.type) {
86
+ case 'assistant': {
87
+ const content = event.message?.content || [];
88
+ for (const block of content) {
89
+ processContentBlock(block, state);
90
+ }
91
+ break;
92
+ }
93
+ case 'result': {
94
+ if (event.subtype === 'error') {
95
+ throw new Error(event.error || 'Claude SDK query failed');
96
+ }
97
+ if (callId) {
98
+ logResultUsage(callId, event);
99
+ }
100
+ break;
101
+ }
102
+ }
103
+ }
104
+
105
+ if (state.structuredOutput) {
106
+ return JSON.stringify(state.structuredOutput);
107
+ }
108
+ return state.responseText;
109
+ }
110
+
111
+ export const SESSION_SUMMARY_SCHEMA = {
112
+ type: 'object',
113
+ properties: {
114
+ short_summary: { type: 'string', description: '1-2 sentence preview for list view (max 150 characters)' },
115
+ full_summary: { type: 'string', description: 'Detailed summary with key accomplishments and current state (max 500 characters)' },
116
+ key_actions: { type: 'array', items: { type: 'string' }, description: 'List of key actions taken' },
117
+ files_modified: { type: 'array', items: { type: 'string' }, description: 'List of files that were modified' },
118
+ outcome: { type: 'string', enum: ['completed', 'partial', 'failed', 'ongoing'], description: 'Session outcome status' },
119
+ pr_url: { type: ['string', 'null'], description: 'GitHub PR URL if one was created' },
120
+ session_title: { type: ['string', 'null'], description: 'Concise title for this session (max 60 characters)' },
121
+ },
122
+ required: ['short_summary', 'full_summary', 'key_actions', 'files_modified', 'outcome'],
123
+ };
124
+
125
+ /**
126
+ * Call Claude via SDK and extract text response.
127
+ * Unified function that handles both default session summary schema
128
+ * and custom schemas (e.g., combined session+conversation summary).
129
+ *
130
+ * @param {string} prompt - The prompt to send
131
+ * @param {Array} recentMessages - Messages (for mock mode context)
132
+ * @param {string} sessionStatus - Session status (for mock mode context)
133
+ * @param {{ logMeta?: Object, systemPrompt?: string, jsonSchema?: Object }} options - Optional parameters
134
+ * @returns {Promise<string>} The text response (JSON string)
135
+ */
136
+ export async function callClaude(prompt, recentMessages, sessionStatus, options = {}) {
137
+ const { logMeta = null } = options || {};
138
+ // Build stable key for VCR cassette (session prompts are hardcoded strings in E2E tests)
139
+ let keyHint = null;
140
+ if (process.env.VCR_MODE && logMeta?.sessionId) {
141
+ const session = sessions.getById(logMeta.sessionId);
142
+ keyHint = session ? `${logMeta.callType}:${session.prompt}` : null;
143
+ }
144
+ // Use VCR wrapper if in VCR mode, otherwise use real SDK query
145
+ const queryFn = process.env.VCR_MODE
146
+ ? createVCRQueryFn(query, 'tests/e2e/cassettes/summaries', keyHint)
147
+ : query;
148
+
149
+ const queryParams = buildClaudeRequest(prompt, options);
150
+
151
+ // Start logging if metadata provided
152
+ let callId = null;
153
+ if (logMeta) {
154
+ callId = agentCallLogger.startCall({
155
+ sessionId: logMeta.sessionId,
156
+ conversationId: logMeta.conversationId || null,
157
+ agentType: 'summary',
158
+ model: 'claude-haiku-4-5-20251001',
159
+ callType: logMeta.callType,
160
+ promptLength: prompt.length,
161
+ });
162
+ }
163
+
164
+ try {
165
+ const result = await handleClaudeResponse(queryFn(queryParams), callId);
166
+
167
+ // Complete the logged call on success
168
+ if (callId) {
169
+ agentCallLogger.completeCall(callId, { success: true });
170
+ }
171
+
172
+ return result;
173
+ } catch (error) {
174
+ // Complete the logged call on error
175
+ if (callId) {
176
+ agentCallLogger.completeCall(callId, { success: false, error });
177
+ }
178
+ throw error;
179
+ }
180
+ }
@@ -0,0 +1,169 @@
1
+ /**
2
+ * Prompt templates and message formatting for summary generation.
3
+ * Pure functions with no side effects.
4
+ */
5
+
6
+ import { DEFAULT_SESSION_TITLE_PROMPT } from '../../../shared/src/index.js';
7
+
8
+ // Maximum retry attempts for failed parsing
9
+ export const MAX_RETRIES = 2;
10
+
11
+ // Minimum number of messages before generating a summary (skip trivial sessions)
12
+ export const MIN_MESSAGES_FOR_SUMMARY = 3;
13
+
14
+ // Maximum number of recent messages to include in generation (optimized for token efficiency)
15
+ export const MAX_MESSAGES = 10;
16
+
17
+ // Re-export from shared for backward compatibility
18
+ export { DEFAULT_SESSION_TITLE_PROMPT };
19
+
20
+ // System prompt for summary generation (static instructions that benefit from prompt caching)
21
+ export const SUMMARY_SYSTEM_PROMPT = `You are updating a session summary for a Claude Code session.
22
+
23
+ Generate an updated summary that:
24
+ 1. Preserves important context from the existing summary
25
+ 2. Incorporates new actions and progress from recent messages
26
+ 3. Updates the outcome status if changed
27
+ 4. Maintains a coherent narrative of the full session
28
+
29
+ Outcome guidelines:
30
+ - "completed": Task was fully accomplished
31
+ - "partial": Some progress made but task incomplete
32
+ - "failed": Task encountered errors and couldn't proceed
33
+ - "ongoing": Session is still active/waiting for user input`;
34
+
35
+ /**
36
+ * Format messages for the prompt
37
+ * @param {Array} messageList - List of messages
38
+ * @returns {string}
39
+ */
40
+ export function formatMessages(messageList) {
41
+ return messageList
42
+ .map((msg) => {
43
+ const role = msg.role === 'user' ? 'User' : 'Assistant';
44
+ let content = msg.content;
45
+
46
+ // Truncate very long messages (optimized for token efficiency)
47
+ if (content.length > 500) {
48
+ content = `${content.substring(0, 500) }... [truncated]`;
49
+ }
50
+
51
+ // Add tool use info if present
52
+ if (msg.toolUse && msg.toolUse.length > 0) {
53
+ const tools = msg.toolUse.map((t) => t.name).join(', ');
54
+ content += `\n[Tools used: ${tools}]`;
55
+ }
56
+
57
+ return `${role}: ${content}`;
58
+ })
59
+ .join('\n\n');
60
+ }
61
+
62
+ /**
63
+ * Build the prompt for incremental summary generation
64
+ * @param {Object|null} existingSummary - Existing summary if any
65
+ * @param {Array} recentMessages - Recent messages to summarize
66
+ * @param {string} sessionStatus - Current session status
67
+ * @param {{ projectTitlePrompt?: string|null, childContext?: string }} options - Optional parameters
68
+ * @returns {string}
69
+ */
70
+ export function buildIncrementalPrompt(existingSummary, recentMessages, sessionStatus, options = {}) {
71
+ const { projectTitlePrompt = null, childContext = '' } = options || {};
72
+ const existingContext = existingSummary
73
+ ? `EXISTING SUMMARY:
74
+ ${existingSummary.fullSummary}
75
+
76
+ Key actions so far: ${JSON.stringify(existingSummary.keyActions || [])}
77
+ Files modified: ${JSON.stringify(existingSummary.filesModified || [])}
78
+ Previous outcome: ${existingSummary.outcome}
79
+ Previous title: ${existingSummary.sessionTitle || 'Not set'}`
80
+ : 'EXISTING SUMMARY:\nNo previous summary - this is the first generation.';
81
+
82
+ const formattedMessages = formatMessages(recentMessages);
83
+
84
+ // Use custom prompt if provided, otherwise use default
85
+ const sessionTitlePrompt = projectTitlePrompt || DEFAULT_SESSION_TITLE_PROMPT;
86
+
87
+ // Return only dynamic content - static instructions are in SUMMARY_SYSTEM_PROMPT
88
+ return `Current session status: ${sessionStatus}
89
+
90
+ ${existingContext}
91
+ ${childContext}
92
+ RECENT CONVERSATION:
93
+ ${formattedMessages}
94
+
95
+ Session title guidelines:
96
+ ${sessionTitlePrompt}`;
97
+ }
98
+
99
+ /**
100
+ * Strip markdown code block wrapping (```json ... ```) from response text
101
+ * @param {string} text - Raw response text
102
+ * @returns {string} Text with code block wrapper removed if present
103
+ */
104
+ export function stripMarkdownCodeBlock(text) {
105
+ let cleaned = text.trim();
106
+ if (cleaned.startsWith('```')) {
107
+ const codeBlockMatch = cleaned.match(/^```(?:json)?\s*\n?([\s\S]*?)\n?```$/);
108
+ if (codeBlockMatch) {
109
+ cleaned = codeBlockMatch[1].trim();
110
+ console.log('[SummaryPrompts] Stripped markdown code block from response');
111
+ }
112
+ }
113
+ return cleaned;
114
+ }
115
+
116
+ /**
117
+ * Add message count and last message ID to summary data for staleness tracking
118
+ * @param {Object} summaryDataInput - Summary data to augment
119
+ * @param {Array} allMessages - All messages in session
120
+ */
121
+ export function trackMessageMetadata(summaryDataInput, allMessages) {
122
+ const summaryData = summaryDataInput;
123
+ summaryData.messageCount = allMessages.length;
124
+ const lastMessage = allMessages.length > 0 ? allMessages[allMessages.length - 1] : null;
125
+ summaryData.lastSummarizedMessageId = lastMessage ? lastMessage.id : null;
126
+ }
127
+
128
+ /**
129
+ * Parse the Claude API response into a summary object
130
+ * Handles markdown code block wrapping (```json ... ```) that Claude sometimes returns
131
+ * @param {string} responseText
132
+ * @returns {Object}
133
+ */
134
+ export function parseSummaryResponse(responseText) {
135
+ const textToParse = stripMarkdownCodeBlock(responseText);
136
+
137
+ try {
138
+ const parsed = JSON.parse(textToParse);
139
+ return {
140
+ shortSummary: parsed.short_summary || 'Summary generation failed',
141
+ fullSummary: parsed.full_summary || 'Unable to generate summary',
142
+ keyActions: Array.isArray(parsed.key_actions) ? parsed.key_actions :
143
+ (typeof parsed.key_actions === 'string' ? [parsed.key_actions] : []),
144
+ filesModified: Array.isArray(parsed.files_modified) ? parsed.files_modified :
145
+ (typeof parsed.files_modified === 'string' ? [parsed.files_modified] : []),
146
+ outcome: parsed.outcome || 'ongoing',
147
+ prUrl: parsed.pr_url || null,
148
+ sessionTitle: parsed.session_title || null,
149
+ _parseFailed: false,
150
+ };
151
+ } catch {
152
+ // If JSON parsing fails, return fallback with flag for retry logic
153
+ console.warn('[SummaryPrompts] Failed to parse summary response as JSON, using fallback');
154
+ return {
155
+ shortSummary: responseText.substring(0, 150),
156
+ fullSummary: responseText.substring(0, 500),
157
+ keyActions: [],
158
+ filesModified: [],
159
+ outcome: 'ongoing',
160
+ prUrl: null,
161
+ sessionTitle: null,
162
+ _parseFailed: true,
163
+ };
164
+ }
165
+ }
166
+
167
+ // Backward-compatible aliases for internal/test usage
168
+ export { stripMarkdownCodeBlock as _stripMarkdownCodeBlock };
169
+ export { trackMessageMetadata as _trackMessageMetadata };