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,69 @@
1
+ /** @type {Map<string, {inputTokens: number, outputTokens: number, lastMessageOutput: number, cacheReadInputTokens: number, cacheCreationInputTokens: number}>}
2
+ * Current turn usage - accumulates across multiple messages within a turn
3
+ * Keyed by conversationId (Issue #175)
4
+ * - inputTokens: MAX seen across all messages (larger context with tool results)
5
+ * - outputTokens: ACCUMULATED across all messages
6
+ * - lastMessageOutput: Current message's output (to detect resets on message_start)
7
+ */
8
+ const currentTurnUsage = new Map();
9
+
10
+ /** @type {Map<string, number>} Estimated output tokens from streamed content (for real-time updates) */
11
+ const estimatedOutputTokens = new Map();
12
+
13
+ /**
14
+ * Rough token estimation: ~4 characters per token (standard for English text)
15
+ * @param {string} text
16
+ * @returns {number} Estimated token count
17
+ */
18
+ function estimateTokens(text) {
19
+ return Math.ceil(text.length / 4);
20
+ }
21
+
22
+ /**
23
+ * Update current turn usage from stream events
24
+ * Accumulates across multiple messages within a single turn
25
+ * @param {string} conversationId
26
+ * @param {Object} usage - Usage from stream event (snake_case)
27
+ * @param {string} eventType - 'message_start' or 'message_delta'
28
+ * @returns {Object} Total turn usage (accumulated + current message)
29
+ */
30
+ function updateTurnUsage(conversationId, usage, eventType) {
31
+ const current = currentTurnUsage.get(conversationId) || {
32
+ inputTokens: 0,
33
+ outputTokens: 0,
34
+ lastMessageOutput: 0,
35
+ cacheReadInputTokens: 0,
36
+ cacheCreationInputTokens: 0,
37
+ };
38
+
39
+ if (eventType === 'message_start') {
40
+ // NEW MESSAGE STARTING
41
+ // 1. Finalize previous message's output
42
+ current.outputTokens += current.lastMessageOutput;
43
+ // 2. Reset tracker for new message
44
+ current.lastMessageOutput = 0;
45
+ // 3. Reset estimated output when actual message starts
46
+ estimatedOutputTokens.delete(conversationId);
47
+ // 4. For input tokens, keep the MAX (larger context with tool results)
48
+ current.inputTokens = Math.max(current.inputTokens, usage.input_tokens || 0);
49
+ current.cacheReadInputTokens = Math.max(current.cacheReadInputTokens, usage.cache_read_input_tokens || 0);
50
+ current.cacheCreationInputTokens = Math.max(current.cacheCreationInputTokens, usage.cache_creation_input_tokens || 0);
51
+ } else if (eventType === 'message_delta') {
52
+ // OUTPUT STREAMING - output_tokens is cumulative within this message
53
+ current.lastMessageOutput = usage.output_tokens || 0;
54
+ // Clear estimate when actual output tokens arrive
55
+ estimatedOutputTokens.delete(conversationId);
56
+ }
57
+
58
+ currentTurnUsage.set(conversationId, current);
59
+
60
+ // Return the TOTAL (accumulated + current message's output)
61
+ return {
62
+ inputTokens: current.inputTokens,
63
+ outputTokens: current.outputTokens + current.lastMessageOutput,
64
+ cacheReadInputTokens: current.cacheReadInputTokens,
65
+ cacheCreationInputTokens: current.cacheCreationInputTokens,
66
+ };
67
+ }
68
+
69
+ export { estimateTokens, updateTurnUsage, currentTurnUsage, estimatedOutputTokens };
@@ -0,0 +1,110 @@
1
+ /**
2
+ * Concurrency guard utility.
3
+ * Ensures only one async operation runs per key at a time.
4
+ * If a second call arrives while one is in-flight, it coalesces into a single
5
+ * follow-up execution after the current one completes.
6
+ */
7
+
8
+ /**
9
+ * Create a concurrency guard instance.
10
+ * Returns an object with `run` and `cleanup` methods plus access to internal state.
11
+ *
12
+ * @returns {{ run: Function, cleanup: Function, activeGenerations: Map, pendingRegenerations: Set }}
13
+ */
14
+ export function createConcurrencyGuard() {
15
+ const activeGenerations = new Map(); // key -> Promise
16
+ const pendingRegenerations = new Set(); // keys that need follow-up after current completes
17
+
18
+ /**
19
+ * Run an async function with concurrency guard.
20
+ * If a function is already running for this key, the call is coalesced
21
+ * and a single follow-up is scheduled after the current one completes.
22
+ *
23
+ * @param {string} key - The concurrency key (e.g., sessionId)
24
+ * @param {Function} fn - The async function to run
25
+ * @param {Object} options - Options
26
+ * @param {boolean} options.bypass - If true, skip the concurrency check (e.g., for user-initiated actions)
27
+ * @param {Function} options.onFollowUp - Function to call for follow-up generation after coalesced call
28
+ * @returns {Promise<*>} The result of fn()
29
+ */
30
+ async function run(key, fn, options = {}) {
31
+ const { bypass = false, onFollowUp } = options;
32
+
33
+ // Concurrency guard: if a generation is already in-flight for this key,
34
+ // queue a single follow-up instead of running concurrently
35
+ if (activeGenerations.has(key) && !bypass) {
36
+ pendingRegenerations.add(key);
37
+ return activeGenerations.get(key);
38
+ }
39
+
40
+ const promise = fn();
41
+ activeGenerations.set(key, promise);
42
+
43
+ try {
44
+ return await promise;
45
+ } finally {
46
+ activeGenerations.delete(key);
47
+ if (pendingRegenerations.has(key)) {
48
+ pendingRegenerations.delete(key);
49
+ // Schedule follow-up generation
50
+ if (onFollowUp) {
51
+ onFollowUp(key);
52
+ }
53
+ }
54
+ }
55
+ }
56
+
57
+ /**
58
+ * Clean up any pending and active state for a key (e.g., on session deletion)
59
+ * @param {string} key - The key to clean up
60
+ */
61
+ function cleanup(key) {
62
+ activeGenerations.delete(key);
63
+ pendingRegenerations.delete(key);
64
+ }
65
+
66
+ /**
67
+ * Check if a generation is currently active for a key
68
+ * @param {string} key - The concurrency key
69
+ * @returns {boolean}
70
+ */
71
+ function isActive(key) {
72
+ return activeGenerations.has(key);
73
+ }
74
+
75
+ /**
76
+ * Check if a regeneration is pending for a key
77
+ * @param {string} key - The concurrency key
78
+ * @returns {boolean}
79
+ */
80
+ function isPending(key) {
81
+ return pendingRegenerations.has(key);
82
+ }
83
+
84
+ /**
85
+ * Get a snapshot of all active keys
86
+ * @returns {Array<string>}
87
+ */
88
+ function activeKeys() {
89
+ return Array.from(activeGenerations.keys());
90
+ }
91
+
92
+ /**
93
+ * Get a snapshot of all pending keys
94
+ * @returns {Array<string>}
95
+ */
96
+ function pendingKeys() {
97
+ return Array.from(pendingRegenerations);
98
+ }
99
+
100
+ return {
101
+ run,
102
+ cleanup,
103
+ isActive,
104
+ isPending,
105
+ activeKeys,
106
+ pendingKeys,
107
+ activeGenerations,
108
+ pendingRegenerations,
109
+ };
110
+ }
@@ -0,0 +1,10 @@
1
+ // Re-export everything from ws module for backward compatibility
2
+ export {
3
+ WebSocketManager,
4
+ webSocketManager,
5
+ initWebSocket,
6
+ broadcast,
7
+ broadcastToSession,
8
+ broadcastToProject,
9
+ getWebSocketServer,
10
+ } from './ws/index.js';
@@ -0,0 +1,240 @@
1
+ import { WebSocketServer } from 'ws';
2
+ import { WS_MESSAGE_TYPES, parseMessage, createMessage } from '../../../shared/src/index.js';
3
+
4
+ /**
5
+ * WebSocket manager class for handling WebSocket connections and messaging
6
+ */
7
+ export class WebSocketManager {
8
+ /** @type {WebSocketServer|null} */
9
+ #wss = null;
10
+
11
+ /** @type {Set<import('ws').WebSocket>} */
12
+ #clients = new Set();
13
+
14
+ /** @type {Map<string, Set<import('ws').WebSocket>>} */
15
+ #sessionSubscriptions = new Map();
16
+
17
+ /** @type {Map<string, Set<import('ws').WebSocket>>} */
18
+ #projectSubscriptions = new Map();
19
+
20
+ /** @type {Map<string, Array<Object>>} */
21
+ #usageUpdateBuffer = new Map();
22
+
23
+ /**
24
+ * Initialize WebSocket server
25
+ * @param {import('http').Server} server - HTTP server to attach to
26
+ * @returns {WebSocketServer}
27
+ */
28
+ init(server) {
29
+ this.#wss = new WebSocketServer({ server, path: '/ws' });
30
+
31
+ this.#wss.on('connection', (ws) => {
32
+ this.#clients.add(ws);
33
+
34
+ ws.on('message', (data) => {
35
+ const message = parseMessage(data.toString());
36
+ if (!message) return;
37
+
38
+ this.#handleMessage(ws, message);
39
+ });
40
+
41
+ ws.on('close', () => {
42
+ this.#clients.delete(ws);
43
+ // Remove from all session subscriptions
44
+ for (const subscribers of this.#sessionSubscriptions.values()) {
45
+ subscribers.delete(ws);
46
+ }
47
+ // Remove from all project subscriptions
48
+ for (const subscribers of this.#projectSubscriptions.values()) {
49
+ subscribers.delete(ws);
50
+ }
51
+ });
52
+
53
+ ws.on('error', (error) => {
54
+ console.error('WebSocket error:', error);
55
+ });
56
+ });
57
+
58
+ return this.#wss;
59
+ }
60
+
61
+ /**
62
+ * Handle incoming WebSocket message
63
+ * @param {import('ws').WebSocket} ws
64
+ * @param {Object} message
65
+ */
66
+ #handleMessage(ws, message) {
67
+ const handlers = {
68
+ [WS_MESSAGE_TYPES.SUBSCRIBE_SESSION]: () => this.#handleSubscribeSession(ws, message),
69
+ [WS_MESSAGE_TYPES.UNSUBSCRIBE_SESSION]: () => this.#handleUnsubscribeSession(ws, message),
70
+ [WS_MESSAGE_TYPES.SUBSCRIBE_PROJECT]: () => this.#handleSubscribeProject(ws, message),
71
+ [WS_MESSAGE_TYPES.UNSUBSCRIBE_PROJECT]: () => this.#handleUnsubscribeProject(ws, message),
72
+ };
73
+ handlers[message.type]?.();
74
+ }
75
+
76
+ #handleSubscribeSession(ws, message) {
77
+ const { sessionId } = message;
78
+ if (!sessionId) return;
79
+
80
+ if (!this.#sessionSubscriptions.has(sessionId)) {
81
+ this.#sessionSubscriptions.set(sessionId, new Set());
82
+ }
83
+ this.#sessionSubscriptions.get(sessionId).add(ws);
84
+ this.#replayBufferedUsageUpdates(ws, sessionId);
85
+ }
86
+
87
+ #replayBufferedUsageUpdates(ws, sessionId) {
88
+ const buffered = this.#usageUpdateBuffer.get(sessionId);
89
+ if (!buffered || buffered.length === 0) return;
90
+
91
+ for (const bufferedMsg of buffered) {
92
+ const msg = createMessage(bufferedMsg.type, bufferedMsg);
93
+ if (ws.readyState === 1) {
94
+ ws.send(msg);
95
+ }
96
+ }
97
+ this.#usageUpdateBuffer.delete(sessionId);
98
+ }
99
+
100
+ #handleUnsubscribeSession(ws, message) {
101
+ const { sessionId } = message;
102
+ if (!sessionId) return;
103
+ this.#sessionSubscriptions.get(sessionId)?.delete(ws);
104
+ }
105
+
106
+ #handleSubscribeProject(ws, message) {
107
+ const { projectId } = message;
108
+ if (!projectId) return;
109
+
110
+ if (!this.#projectSubscriptions.has(projectId)) {
111
+ this.#projectSubscriptions.set(projectId, new Set());
112
+ }
113
+ this.#projectSubscriptions.get(projectId).add(ws);
114
+ }
115
+
116
+ #handleUnsubscribeProject(ws, message) {
117
+ const { projectId } = message;
118
+ if (!projectId) return;
119
+ this.#projectSubscriptions.get(projectId)?.delete(ws);
120
+ }
121
+
122
+ /**
123
+ * Broadcast message to all connected clients
124
+ * @param {string} type - Message type
125
+ * @param {Object} payload - Message payload
126
+ */
127
+ broadcast(type, payload) {
128
+ const message = createMessage(type, payload);
129
+ for (const client of this.#clients) {
130
+ if (client.readyState === 1) {
131
+ // WebSocket.OPEN
132
+ client.send(message);
133
+ }
134
+ }
135
+ }
136
+
137
+ /**
138
+ * Broadcast message to clients subscribed to a session
139
+ * @param {string} sessionId - Session ID
140
+ * @param {string} type - Message type
141
+ * @param {Object} payload - Message payload
142
+ */
143
+ broadcastToSession(sessionId, type, payload) {
144
+ const subscribers = this.#sessionSubscriptions.get(sessionId);
145
+
146
+ // Buffer SESSION_USAGE_UPDATE messages if no subscribers exist
147
+ if (type === 'session:usage_update' && (!subscribers || subscribers.size === 0)) {
148
+ if (!this.#usageUpdateBuffer.has(sessionId)) {
149
+ this.#usageUpdateBuffer.set(sessionId, []);
150
+ }
151
+ const buffer = this.#usageUpdateBuffer.get(sessionId);
152
+ buffer.push({ type, ...payload });
153
+ // Keep reasonable buffer size (max 50 messages)
154
+ if (buffer.length > 50) {
155
+ buffer.shift();
156
+ }
157
+ return;
158
+ }
159
+
160
+ if (!subscribers || subscribers.size === 0) {
161
+ return;
162
+ }
163
+
164
+ const message = createMessage(type, payload);
165
+ for (const client of subscribers) {
166
+ if (client.readyState === 1) {
167
+ // WebSocket.OPEN
168
+ client.send(message);
169
+ }
170
+ }
171
+ }
172
+
173
+ /**
174
+ * Broadcast message to clients subscribed to a project
175
+ * @param {string} projectId - Project ID
176
+ * @param {string} type - Message type
177
+ * @param {Object} payload - Message payload
178
+ */
179
+ broadcastToProject(projectId, type, payload) {
180
+ const subscribers = this.#projectSubscriptions.get(projectId);
181
+ if (!subscribers || subscribers.size === 0) return;
182
+
183
+ const message = createMessage(type, payload);
184
+ for (const client of subscribers) {
185
+ if (client.readyState === 1) {
186
+ // WebSocket.OPEN
187
+ client.send(message);
188
+ }
189
+ }
190
+ }
191
+
192
+ /**
193
+ * Get WebSocket server instance
194
+ * @returns {WebSocketServer|null}
195
+ */
196
+ getServer() {
197
+ return this.#wss;
198
+ }
199
+
200
+ /**
201
+ * Get all connected clients
202
+ * @returns {Set<import('ws').WebSocket>}
203
+ */
204
+ getClients() {
205
+ return this.#clients;
206
+ }
207
+
208
+ /**
209
+ * Get session subscriptions
210
+ * @returns {Map<string, Set<import('ws').WebSocket>>}
211
+ */
212
+ getSessionSubscriptions() {
213
+ return this.#sessionSubscriptions;
214
+ }
215
+
216
+ /**
217
+ * Get project subscriptions
218
+ * @returns {Map<string, Set<import('ws').WebSocket>>}
219
+ */
220
+ getProjectSubscriptions() {
221
+ return this.#projectSubscriptions;
222
+ }
223
+
224
+ /**
225
+ * Close the WebSocket server
226
+ */
227
+ close() {
228
+ if (this.#wss) {
229
+ this.#wss.close();
230
+ this.#wss = null;
231
+ }
232
+ this.#clients.clear();
233
+ this.#sessionSubscriptions.clear();
234
+ this.#projectSubscriptions.clear();
235
+ this.#usageUpdateBuffer.clear();
236
+ }
237
+ }
238
+
239
+ // Singleton instance
240
+ export const webSocketManager = new WebSocketManager();
@@ -0,0 +1,50 @@
1
+ export { WebSocketManager, webSocketManager } from './WebSocketManager.js';
2
+
3
+ // Legacy function exports for backward compatibility
4
+ import { webSocketManager } from './WebSocketManager.js';
5
+
6
+ /**
7
+ * Initialize WebSocket server
8
+ * @param {import('http').Server} server
9
+ * @returns {import('ws').WebSocketServer}
10
+ */
11
+ export function initWebSocket(server) {
12
+ return webSocketManager.init(server);
13
+ }
14
+
15
+ /**
16
+ * Broadcast message to all connected clients
17
+ * @param {string} type
18
+ * @param {Object} payload
19
+ */
20
+ export function broadcast(type, payload) {
21
+ webSocketManager.broadcast(type, payload);
22
+ }
23
+
24
+ /**
25
+ * Broadcast message to clients subscribed to a session
26
+ * @param {string} sessionId
27
+ * @param {string} type
28
+ * @param {Object} payload
29
+ */
30
+ export function broadcastToSession(sessionId, type, payload) {
31
+ webSocketManager.broadcastToSession(sessionId, type, payload);
32
+ }
33
+
34
+ /**
35
+ * Broadcast message to clients subscribed to a project
36
+ * @param {string} projectId
37
+ * @param {string} type
38
+ * @param {Object} payload
39
+ */
40
+ export function broadcastToProject(projectId, type, payload) {
41
+ webSocketManager.broadcastToProject(projectId, type, payload);
42
+ }
43
+
44
+ /**
45
+ * Get WebSocket server instance
46
+ * @returns {import('ws').WebSocketServer|null}
47
+ */
48
+ export function getWebSocketServer() {
49
+ return webSocketManager.getServer();
50
+ }
@@ -0,0 +1,27 @@
1
+ {
2
+ "name": "@circuschief/shared",
3
+ "version": "1.0.0",
4
+ "license": "Apache-2.0",
5
+ "type": "module",
6
+ "main": "src/index.js",
7
+ "exports": {
8
+ ".": "./src/index.js",
9
+ "./types": "./src/types.js",
10
+ "./protocol": "./src/protocol.js",
11
+ "./constants": "./src/constants.js",
12
+ "./contracts/*": "./src/contracts/*.js",
13
+ "./utils": "./src/utils.js",
14
+ "./routeParams": "./src/routeParams.js"
15
+ },
16
+ "scripts": {
17
+ "test": "vitest run",
18
+ "test:coverage": "vitest run --coverage",
19
+ "test:watch": "vitest"
20
+ },
21
+ "dependencies": {
22
+ "zod": "^4.2.1"
23
+ },
24
+ "devDependencies": {
25
+ "vitest": "^4.0.16"
26
+ }
27
+ }
@@ -0,0 +1,44 @@
1
+ export const DEFAULT_SERVER_PORT = 5000;
2
+
3
+ export const API_PREFIX = '/api';
4
+ export const WS_PATH = '/ws';
5
+
6
+ /**
7
+ * Default token cost weights for calculating Billable Token Equivalent (BTE)
8
+ * These weights represent relative costs compared to input tokens (1.0 = base rate)
9
+ */
10
+ export const DEFAULT_TOKEN_COST_WEIGHTS = {
11
+ input: 1.0, // Base rate
12
+ output: 5.0, // 5x input cost (output tokens are more expensive)
13
+ cacheRead: 0.1, // 90% discount for cache reads
14
+ cacheCreation: 1.25 // 25% premium for cache creation
15
+ };
16
+
17
+ export const MAX_JSON_SIZE = '50mb';
18
+
19
+ export const WS_RECONNECT_BASE_DELAY = 2000;
20
+ export const WS_RECONNECT_MAX_DELAY = 30000;
21
+
22
+ export const TOAST_DURATION = 5000;
23
+
24
+ export const DEFAULT_SYSTEM_PROMPT = `You are Claude Code, an AI coding assistant. You help users with software engineering tasks including writing code, debugging, refactoring, and explaining code. You have full access to the shell and can execute any commands needed to assist the user. Be helpful, accurate, and thorough.
25
+
26
+ IMPORTANT: Your working directory is already set correctly for this session. NEVER use \`cd\` to change to a hardcoded project path before running commands (e.g., \`cd /path/to/project && git status\`). This bypasses git worktree isolation and causes commands to run in the wrong directory. Always run commands directly without changing directory.
27
+
28
+ ## Canvas Behavior
29
+ IMPORTANT: NEVER proactively put artifacts on the canvas unless the user explicitly requests it. Do not put images, markdown documents, code snippets, data visualizations, PDFs, or other artifacts on the canvas without being asked. Only use the canvas when the user specifically asks you to display or share something.
30
+
31
+ ## Plan Files
32
+ When creating plan files or design documents, always write them to a temporary directory:
33
+ - Use \`~/.claude/plans/<descriptive-name>.md\` for plan files
34
+ - Use the Write tool to create these files
35
+ - This keeps plans organized and separate from the main codebase`;
36
+
37
+ /**
38
+ * Default prompt for generating session titles
39
+ */
40
+ export const DEFAULT_SESSION_TITLE_PROMPT = `Guidelines for generating session titles:
41
+ - state the goal of the session - ignore the goal of the conversation, we're interested in the goal of the session as a whole
42
+ - If a PR was created, format as "PR #N: <strategic goal>"
43
+ - Only change the title if the session's fundamental purpose has changed
44
+ - Keep titles concise (max 60 characters)`;
@@ -0,0 +1,25 @@
1
+ import { z } from 'zod';
2
+
3
+ export const CreateCanvasItemRequest = z.object({
4
+ filePath: z.string(),
5
+ });
6
+
7
+ export const CanvasItemResponse = z.object({
8
+ id: z.string().uuid(),
9
+ sessionId: z.string().uuid().nullable(),
10
+ type: z.enum(['image', 'markdown', 'text', 'json', 'pdf', 'code']),
11
+ content: z.string().nullable(),
12
+ data: z.string().nullable(),
13
+ mimeType: z.string().nullable(),
14
+ filename: z.string().nullable(),
15
+ width: z.number().nullable(),
16
+ height: z.number().nullable(),
17
+ createdAt: z.number(),
18
+ updatedAt: z.number(),
19
+ });
20
+
21
+ export const UpdateCanvasItemRequest = z.object({
22
+ content: z.string().min(0),
23
+ });
24
+
25
+ export const CanvasListResponse = z.array(CanvasItemResponse);
@@ -0,0 +1,36 @@
1
+ import { z } from 'zod';
2
+
3
+ export const CreateCommandButtonRequest = z.object({
4
+ label: z.string().min(1, 'Label is required'),
5
+ command: z.string().min(1, 'Command is required'),
6
+ sortOrder: z.number().int().optional().default(0),
7
+ showOnList: z.boolean().optional().default(false),
8
+ });
9
+
10
+ export const UpdateCommandButtonRequest = z.object({
11
+ label: z.string().min(1).optional(),
12
+ command: z.string().min(1).optional(),
13
+ sortOrder: z.number().int().optional(),
14
+ showOnList: z.boolean().optional(),
15
+ }).refine(obj => Object.keys(obj).length > 0, 'At least one field must be provided for update');
16
+
17
+ export const CommandButtonResponse = z.object({
18
+ id: z.string(),
19
+ projectId: z.string(),
20
+ label: z.string(),
21
+ command: z.string(),
22
+ sortOrder: z.number().int(),
23
+ showOnList: z.boolean(),
24
+ createdAt: z.number(),
25
+ updatedAt: z.number(),
26
+ });
27
+
28
+ export const CommandButtonListResponse = z.array(CommandButtonResponse);
29
+
30
+ export const CommandRunResponse = z.object({
31
+ runId: z.string(),
32
+ buttonId: z.string(),
33
+ status: z.enum(['running', 'success', 'error', 'killed']),
34
+ exitCode: z.number().int().nullable(),
35
+ output: z.string().optional(),
36
+ });